diff --git a/blocks/composite/folded_cascode/README.md b/blocks/composite/folded_cascode/README.md new file mode 100644 index 00000000..5bb3f874 --- /dev/null +++ b/blocks/composite/folded_cascode/README.md @@ -0,0 +1,2 @@ +# chipathon_2025_onchipTeam +This repo is to share advance on the Chipathon_2025 onchip team development. diff --git a/blocks/composite/folded_cascode/designs/gf180/deep_rename.sh b/blocks/composite/folded_cascode/designs/gf180/deep_rename.sh new file mode 100755 index 00000000..050acce3 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/deep_rename.sh @@ -0,0 +1,178 @@ +#!/bin/bash + +# ============================================================================== +# Deep Rename Script +# +# Description: +# This script renames a top-level directory, recursively renames any files +# inside it that share the original directory's name, and then finds and +# replaces all occurrences of the original name within the content of all +# text files in the new directory. +# +# Usage: +# ./deep_rename.sh [--dry-run] +# +# Arguments: +# : The name of the folder you want to rename. +# : The new name for the folder and its related files/content. +# --dry-run (optional): If provided, the script will only print the actions +# it would take without executing them. +# +# Example: +# ./deep_rename.sh circuit_to_live circuit_to_die +# +# Example Dry Run: +# ./deep_rename.sh circuit_to_live circuit_to_die --dry-run +# +# ============================================================================== + +# --- Configuration and Argument Handling --- + +ORIGINAL_NAME="$1" +NEW_NAME="$2" +DRY_RUN_FLAG="$3" +DRY_RUN=false + +# Check if this is a dry run +if [[ "$DRY_RUN_FLAG" == "--dry-run" ]]; then + DRY_RUN=true + echo "[INFO] DRY RUN MODE ENABLED. No files or folders will be changed." +fi + +# --- Sanity Checks --- + +# Check if the correct number of arguments was provided +if [ -z "$ORIGINAL_NAME" ] || [ -z "$NEW_NAME" ]; then + echo "ERROR: Missing arguments." + echo "Usage: $0 [--dry-run]" + exit 1 +fi + +# Check if the original directory exists +if [ ! -d "$ORIGINAL_NAME" ]; then + echo "ERROR: The source directory '$ORIGINAL_NAME' does not exist." + exit 1 +fi + +# Check if a file or directory with the new name already exists +if [ -e "$NEW_NAME" ]; then + echo "ERROR: A file or directory named '$NEW_NAME' already exists in this location. Aborting." + exit 1 +fi + +# --- Main Logic --- + +echo "------------------------------------------------------------------" +echo "Deep Rename Plan:" +echo " - Top-level folder: '$ORIGINAL_NAME' -> '$NEW_NAME'" +echo " - Files inside matching '$ORIGINAL_NAME.*' will be renamed to '$NEW_NAME.*'" +echo " - Text content inside all files will be changed from '$ORIGINAL_NAME' to '$NEW_NAME'" +echo "------------------------------------------------------------------" + +# Confirmation prompt before proceeding (unless it's a dry run) +if [ "$DRY_RUN" = false ]; then + read -p "Are you sure you want to proceed? (yes/no): " confirmation + if [[ "$confirmation" != "yes" ]]; then + echo "Aborted by user." + exit 0 + fi +fi + +# --- Step 1: Find all matching files and prepare for rename --- +# We do this *before* renaming the top-level folder to make finding the files easier. + +echo "[INFO] Searching for files to rename..." +# Use find to locate all files matching the pattern and store them in an array +# -print0 and read -d '' handle filenames with spaces or special characters +files_to_rename=() +while IFS= read -r -d '' file; do + files_to_rename+=("$file") +done < <(find "$ORIGINAL_NAME" -type f -name "$ORIGINAL_NAME.*" -print0) + +# --- Step 2: Rename the top-level folder --- + +echo "[ACTION] Renaming top-level folder..." +if [ "$DRY_RUN" = true ]; then + echo " [DRY RUN] Would rename folder '$ORIGINAL_NAME' to '$NEW_NAME'." +else + mv "$ORIGINAL_NAME" "$NEW_NAME" + if [ $? -ne 0 ]; then + echo "ERROR: Failed to rename the top-level folder. Aborting." + exit 1 + fi + echo " - Success: Renamed '$ORIGINAL_NAME' to '$NEW_NAME'." +fi + +# --- Step 3: Recursively rename the found files --- + +echo "[ACTION] Renaming internal files..." +if [ ${#files_to_rename[@]} -eq 0 ]; then + echo " - No files matching '$ORIGINAL_NAME.*' were found inside." +else + for old_path in "${files_to_rename[@]}"; do + # Construct the new path by replacing the top-level folder name in the path string + # This is more robust than just replacing the filename part + new_path=$(echo "$old_path" | sed "s#^$ORIGINAL_NAME/#$NEW_NAME/#" | sed "s/\/$ORIGINAL_NAME\./\/$NEW_NAME\./") + + if [ "$DRY_RUN" = true ]; then + # In dry run, the top-level folder wasn't actually renamed, so we simulate the new path + echo " [DRY RUN] Would rename file '$old_path' to '$new_path'." + else + # In a real run, the path has already partially changed due to the top-level folder rename. + # We need to reference the path inside the *newly renamed* folder. + path_in_new_folder=$(echo "$old_path" | sed "s#^$ORIGINAL_NAME/#$NEW_NAME/#") + + # The final destination path is the same 'new_path' calculated earlier + mv "$path_in_new_folder" "$new_path" + if [ $? -eq 0 ]; then + echo " - Success: Renamed '$path_in_new_folder' to '$new_path'." + else + echo " - ERROR: Failed to rename '$path_in_new_folder'." + fi + fi + done +fi + +# --- Step 4: Find and Replace content in files --- + +echo "[ACTION] Replacing content in all text files..." +# The directory to search in depends on whether this is a dry run or not +search_dir="$NEW_NAME" +if [ "$DRY_RUN" = true ]; then + search_dir="$ORIGINAL_NAME" +fi + +# Find all text files containing the original name string +# grep -rlI: recursive, list-filenames, ignore-binary-files +# -Z and -print0 handle all filenames safely +files_to_modify_content=() +while IFS= read -r -d '' file; do + files_to_modify_content+=("$file") +done < <(grep -rlIZ "$ORIGINAL_NAME" "$search_dir" 2>/dev/null) + +if [ ${#files_to_modify_content[@]} -eq 0 ]; then + echo " - No text files with content matching '$ORIGINAL_NAME' were found." +else + for file_path in "${files_to_modify_content[@]}"; do + if [ "$DRY_RUN" = true ]; then + # Count occurrences for the dry run report + count=$(grep -o "$ORIGINAL_NAME" "$file_path" | wc -l) + echo " [DRY RUN] Would replace $count occurrence(s) of '$ORIGINAL_NAME' in file '$file_path'." + else + # Use sed for in-place replacement. Using # as a delimiter is safer + # if names contain slashes. + sed -i "s#$ORIGINAL_NAME#$NEW_NAME#g" "$file_path" + if [ $? -eq 0 ]; then + echo " - Success: Replaced content in '$file_path'." + else + echo " - ERROR: Failed to replace content in '$file_path'." + fi + fi + done +fi + +echo "------------------------------------------------------------------" +echo "[INFO] Script finished." +echo "------------------------------------------------------------------" + +exit 0 diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/error_amplifier_N_input.yaml b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/error_amplifier_N_input.yaml new file mode 100644 index 00000000..17e31bcb --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/error_amplifier_N_input.yaml @@ -0,0 +1,291 @@ +--- +#-------------------------------------------------------------- +# CACE circuit characterization file +#-------------------------------------------------------------- + +name: error_amplifier_N_input +description: Folded cascode full +PDK: gf180mcuD + +cace_format: 5.2 + +authorship: + designer: Ramon Sarmiento + company: OnChip UIS + creation_date: July 11th, 2025 + license: Apache 2.0 + +paths: + root: .. + schematic: xschem + layout: gds + netlist: netlist + documentation: docs + +pins: + VDD: + description: Positive analog power supply + type: power + direction: inout + Vmin: 1.7 + Vmax: 1.9 + VSS: + description: Analog ground + type: ground + direction: inout + Vout: + description: Output voltage + type: signal + direction: inout + Vcomn: + description: Compensation pin + type: signal + direction: inout + V+: + description: Non inverting input + type: signal + direction: input + V-: + description: Inverting input + type: signal + direction: input + +default_conditions: + vdd: + description: Analog power supply voltage + display: Vdd + unit: V + typical: 1.8 + vref: + description: Voltage reference from BandGAP + display: VrefBG + unit: V + typical: 1.2 + Vy: + description: Fix voltage Mode Voltage + display: Vy + unit: V + typical: -0.3 + Vsweep: + description: Voltage to run the dc for Output swing + display: Vsweep + unit: V + typical: 0 + corner: + description: Process corner + display: Corner + typical: typical + temperature: + description: Ambient temperature + display: Temp + unit: °C + typical: 27 + +parameters: + dc_params: + display: DC Params + spec: + Ivdd: + display: Ivdd + description: Currente from power + unit: uA + minimum: + value: any + typical: + value: any + maximum: + value: any + Vout: + display: Vout + description: Output voltage + unit: V + minimum: + value: any + typical: + value: any + maximum: + value: any + tool: + ngspice: + template: op.sch + format: ascii + suffix: .data + variables: [Vout, Ivdd] + + ac_params: + display: STB Params + spec: + # print A0 UGB PM GM BW + A0: + display: Av + description: Opamp's DC Gain + unit: dB + minimum: + value: 70 + typical: + value: any + maximum: + value: any + UGB: + display: UGB + description: Unitary Gain Bandwidth + unit: MHz + minimum: + value: 10 + typical: + value: any + maximum: + value: any + PM: + display: PM + description: Opamp's Phase Margin + unit: ° + minimum: + value: 45 + typical: + value: any + maximum: + value: any + GM: + display: GM + description: Opamp's Gain Margin + unit: ° + minimum: + value: any + typical: + value: any + maximum: + value: any + BW: + display: BW + description: Opamp's Bandwidth + unit: kHz + minimum: + value: any + typical: + value: any + maximum: + value: any + tool: + ngspice: + template: ac.sch + format: ascii + suffix: .data + variables: [A0, UGB, PM, GM, BW] + + os_params: + display: Output Swing Params + spec: + Output_swing: + display: Output_swing + description: Output voltage swing. + unit: V + minimum: + value: 1 + typical: + value: any + maximum: + value: any + tool: + ngspice: + template: os.sch + format: ascii + suffix: .data + variables: [Output_swing] + + cmrr_params: + display: Common Mode Params (Common mode gain CMRR = Acm/Av) + spec: + Acm: + display: Acm + description: Common mode gain. + unit: dB + minimum: + value: any + typical: + value: any + maximum: + value: any + tool: + ngspice: + template: cmrr.sch + format: ascii + suffix: .data + variables: [Acm] + + magic_area: + spec: + area: + display: Area + description: Total circuit layout area + unit: µm² + maximum: + value: any + width: + display: Width + description: Total circuit layout width + unit: µm + maximum: + value: any + height: + display: Height + description: Total circuit layout height + unit: µm + maximum: + value: any + tool: magic_area + + magic_drc: + description: Magic DRC + display: Magic DRC + spec: + drc_errors: + maximum: + value: 0 + tool: + magic_drc: + gds_flatten: true + + netgen_lvs: + description: Netgen LVS + display: Netgen LVS + spec: + lvs_errors: + maximum: + value: 0 + tool: + netgen_lvs: + script: run_project_lvs.tcl + + klayout_drc_feol: + description: KLayout DRC feol + display: KLayout DRC feol + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ["-rd", "feol=true"] + + klayout_drc_beol: + description: KLayout DRC beol + display: KLayout DRC beol + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ["-rd", "beol=true"] + + klayout_drc_full: + description: KLayout DRC full + display: KLayout DRC full + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ["-rd", "feol=true", "-rd", "beol=true", "-rd", "offgrid=true"] diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/scripts/run_project_lvs.tcl b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/scripts/run_project_lvs.tcl new file mode 100644 index 00000000..5c55246e --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/scripts/run_project_lvs.tcl @@ -0,0 +1,14 @@ +# NOTE: PDK_ROOT, PDK and CACE_ROOT are set in the local environment by CACE +# +# This is an example script to drive LVS; because this is a simple +# example, there is no specific benefit of using this instead of the +# default handling in CACE. + +set PDK_ROOT $::env(PDK_ROOT) +set PDK $::env(PDK) +set CACE_ROOT $::env(CACE_ROOT) + +set circuit1 [readnet spice $CACE_ROOT/netlist/layout/error_amplifier_N_input.spice] +set circuit2 [readnet spice $CACE_ROOT/netlist/schematic/error_amplifier_N_input.spice] + +lvs "$circuit1 error_amplifier_N_input" "$circuit2 error_amplifier_N_input" $PDK_ROOT/$PDK/libs.tech/netgen/${PDK}_setup.tcl error_amplifier_N_input.out -json diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/ac.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/ac.sch new file mode 100644 index 00000000..a2c379fa --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/ac.sch @@ -0,0 +1,162 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 720 -340 780 -340 {lab=Vout} +N 440 -50 520 -50 { +lab=Vx} +N 440 -100 440 -50 { +lab=Vx} +N 300 -50 340 -50 { +lab=#net1} +N 400 -50 440 -50 { +lab=Vx} +N 260 -50 300 -50 { +lab=#net1} +N 850 -340 850 -130 { +lab=Vout} +N 930 -210 930 -130 { +lab=GND} +N 930 -340 930 -280 { +lab=Vout} +N 780 -340 930 -340 { +lab=Vout} +N 440 -200 440 -160 { +lab=Vn} +N 930 -280 930 -270 { +lab=Vout} +N 300 -130 300 -50 {lab=#net1} +N 850 -130 850 -50 {lab=Vout} +N 300 -310 300 -130 {lab=#net1} +N 440 -370 520 -370 {lab=Vn} +N 440 -290 440 -200 {lab=Vn} +N 420 -290 440 -290 {lab=Vn} +N 420 -330 420 -290 {lab=Vn} +N 420 -330 440 -330 {lab=Vn} +N 440 -370 440 -330 {lab=Vn} +N 930 -130 930 -110 {lab=GND} +N 520 -50 540 -50 {lab=Vx} +N 800 -20 850 -20 {lab=Vout} +N 850 -50 850 -20 {lab=Vout} +N 760 30 760 60 {lab=GND} +N 800 20 840 20 {lab=GND} +N 840 20 840 50 {lab=GND} +N 760 50 840 50 {lab=GND} +N 760 -50 760 -30 {lab=Vz} +N 710 -50 760 -50 {lab=Vz} +N 600 -50 650 -50 {lab=Vy} +N 520 -370 550 -370 {lab=Vn} +N 300 -320 550 -320 {lab=#net1} +N 300 -320 300 -310 {lab=#net1} +N -80 -20 -80 20 { +lab=GND} +N 0 -20 0 20 { +lab=GND} +N 100 -20 100 20 { +lab=GND} +N 0 -90 0 -80 {lab=#net2} +N 0 -170 0 -150 {lab=VDD} +N -80 -110 -80 -80 {lab=VSS} +N 100 -110 100 -80 {lab=Vref} +N 660 -280 680 -280 {lab=#net3} +C {devices/launcher.sym} -20 -270 0 0 {name=h15 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op" +} +C {devices/launcher.sym} -20 -340 0 0 {name=h3 +descr="Netlist & sim" +tclcommand="xschem netlist; xschem simulate"} +C {vsource.sym} 440 -130 0 0 {name=V5 value="AC 1" savecurrent=false} +C {capa.sym} 370 -50 1 0 {name=C2 +m=1 +value=10G +footprint=1206 +device="ceramic capacitor"} +C {ind.sym} 570 -50 1 0 {name=L4 +m=1 +value=10G +footprint=1206 +device=inductor} +C {capa.sym} 930 -240 0 0 {name=C1 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {lab_pin.sym} 930 -340 0 1 {name=p2 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 930 -110 0 0 {name=l9 lab=GND} +C {devices/lab_wire.sym} 480 -50 0 0 {name=p1 sig_type=std_logic lab=Vx} +C {devices/lab_wire.sym} 460 -370 0 0 {name=p17 sig_type=std_logic lab=Vn} +C {devices/vsource.sym} 680 -50 1 0 {name=V9 value=CACE\{Vy\}} +C {vcvs.sym} 760 0 0 1 {name=E1 value=1} +C {devices/gnd.sym} 760 60 0 0 {name=l11 lab=GND} +C {devices/lab_wire.sym} 620 -50 0 0 {name=p18 sig_type=std_logic lab=Vy} +C {devices/lab_wire.sym} 760 -50 0 0 {name=p19 sig_type=std_logic lab=Vz} +C {devices/code_shown.sym} 80 -670 0 0 {name=SETUP +simulator=ngspice +only_toplevel=false +value=" +.lib CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/ngspice/sm141064.ngspice CACE\{corner\} + +.include CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/ngspice/design.ngspice +.include CACE\{DUT_path\} + +.temp CACE\{temperature\} + +.option SEED=CACE[CACE\{seed=12345\} + CACE\{iterations=0\}] + +* Flag unsafe operating conditions (exceeds models' specified limits) +.option warn=1 +"} +C {code.sym} 900 -610 0 0 {name=AC only_toplevel=true value=" + + + *remzerovec + *write error_amplifier_core_P_input_ac.raw + *set appendwrite + + +.control +save all + +*DC simulation +op +* run ac simulation +ac dec 20 1 100e7 + + +* measure parameters +let vout_mag = db(abs(v(Vout))) +*let vout_phase = cph(v(Vout)) * (180/pi) +let vout_phase = cph(v(Vout)) * (57.295779513) +let gm = (-1)*db(abs(v(Vout))) + +meas ac A0 find vout_mag at=1 +meas ac UGB when vout_mag=0 fall=1 +meas ac PM find vout_phase when vout_mag=0 +meas ac GM find gm when vout_phase=0 + +let A0_p1 = A0 - 3 +meas ac BW when vout_mag=A0_p1 + +print A0 UGB PM GM BW +echo $&A0 $&UGB $&PM $&GM $&BW > CACE\{simpath\}/CACE\{filename\}_CACE\{N\}.data +.endc +"} +C {error_amplifier_N_input.sym} 640 -340 0 0 {name=x1} +C {devices/vsource.sym} -80 -50 0 0 {name=V0 value=0 savecurrent=false} +C {devices/gnd.sym} -80 20 0 0 {name=l13 lab=GND} +C {devices/vsource.sym} 0 -50 0 0 {name=V10 value=CACE\{vdd\} savecurrent=false} +C {devices/gnd.sym} 0 20 0 0 {name=l14 lab=GND} +C {devices/vsource.sym} 100 -50 0 0 {name=V11 value=CACE\{vref\} savecurrent=false} +C {devices/gnd.sym} 100 20 0 0 {name=l15 lab=GND} +C {lab_pin.sym} 100 -110 2 1 {name=p22 sig_type=std_logic lab=Vref} +C {lab_pin.sym} 0 -170 2 1 {name=p23 sig_type=std_logic lab=VDD} +C {lab_pin.sym} -80 -110 2 1 {name=p24 sig_type=std_logic lab=VSS} +C {ammeter.sym} 0 -120 2 0 {name=vdd_i savecurrent=true spice_ignore=0} +C {lab_pin.sym} 620 -260 2 1 {name=p3 sig_type=std_logic lab=Vref} +C {lab_pin.sym} 620 -240 2 1 {name=p4 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 620 -220 2 1 {name=p12 sig_type=std_logic lab=VSS} +C {noconn.sym} 680 -280 2 0 {name=l1} +C {lab_pin.sym} 260 -50 2 1 {name=p5 sig_type=std_logic lab=Vref} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/cmrr.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/cmrr.sch new file mode 100644 index 00000000..451b8b47 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/cmrr.sch @@ -0,0 +1,118 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 960 -240 960 -180 { +lab=GND} +N 870 -350 960 -350 { +lab=Vout} +N 960 -350 960 -300 { +lab=Vout} +N 570 -380 670 -380 { +lab=V-} +N 80 -110 80 -100 {lab=GND} +N 80 -200 80 -170 {lab=VDD} +N 190 -110 190 -100 {lab=GND} +N 190 -200 190 -170 {lab=VSS} +N 910 -350 910 -90 {lab=Vout} +N 800 -90 910 -90 {lab=Vout} +N 570 -320 570 -90 {lab=V-} +N 270 -340 270 -300 {lab=V+} +N 570 -90 740 -90 {lab=V-} +N 570 -380 570 -320 {lab=V-} +N 620 -320 670 -320 {lab=V+} +N 670 -380 690 -380 {lab=V-} +N 670 -330 670 -320 {lab=V+} +N 670 -330 690 -330 {lab=V+} +N 270 -110 270 -100 {lab=GND} +N 270 -200 270 -170 {lab=Vref} +N 270 -240 270 -200 {lab=Vref} +C {vsource.sym} 270 -270 0 0 {name=V5 value="AC 1" savecurrent=false} +C {capa.sym} 620 -350 0 0 {name=C3 +m=1 +value=10G +footprint=1206 +device="ceramic capacitor"} +C {ind.sym} 770 -90 1 0 {name=L2 +m=1 +value=10G +footprint=1206 +device=inductor} +C {devices/noconn.sym} 800 -290 0 1 {name=l3} +C {devices/lab_wire.sym} 760 -230 0 0 {name=p12 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 760 -250 0 0 {name=p13 sig_type=std_logic lab=VDD} +C {devices/capa.sym} 960 -270 0 0 {name=C4 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {devices/lab_wire.sym} 960 -350 0 0 {name=p15 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 960 -180 0 0 {name=l8 lab=GND} +C {devices/vsource.sym} 80 -140 0 0 {name=V8 value=CACE\{vdd\}} +C {devices/gnd.sym} 80 -100 0 0 {name=l12 lab=GND} +C {devices/lab_wire.sym} 80 -200 0 0 {name=p19 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 190 -140 0 0 {name=V9 value=0} +C {devices/gnd.sym} 190 -100 0 0 {name=l13 lab=GND} +C {devices/lab_wire.sym} 190 -200 0 0 {name=p20 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 570 -380 0 0 {name=p3 sig_type=std_logic lab=V-} +C {devices/lab_wire.sym} 270 -340 0 0 {name=p4 sig_type=std_logic lab=V+} +C {devices/launcher.sym} 120 -480 0 0 {name=h1 +descr="Save & Netlist & sim" +tclcommand="xschem save; xschem netlist; xschem simulate"} +C {launcher.sym} 120 -410 0 0 {name=h2 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op"} +C {devices/lab_wire.sym} 620 -320 2 0 {name=p21 sig_type=std_logic lab=V+} +C {error_amplifier_N_input.sym} 780 -350 0 0 {name=x1} +C {devices/lab_wire.sym} 760 -270 0 0 {name=p1 sig_type=std_logic lab=Vref} +C {devices/vsource.sym} 270 -140 0 0 {name=V1 value=CACE\{vref\}} +C {devices/gnd.sym} 270 -100 0 0 {name=l1 lab=GND +value=\{Vref\}} +C {devices/lab_wire.sym} 270 -200 0 0 {name=p2 sig_type=std_logic lab=Vref +value=\{Vref\}} +C {devices/code_shown.sym} 110 -780 0 0 {name=SETUP +simulator=ngspice +only_toplevel=false +value=" +.lib CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/ngspice/sm141064.ngspice CACE\{corner\} + +.include CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/ngspice/design.ngspice +.include CACE\{DUT_path\} + +.temp CACE\{temperature\} + +.option SEED=CACE[CACE\{seed=12345\} + CACE\{iterations=0\}] + +* Flag unsafe operating conditions (exceeds models' specified limits) +.option warn=1 +"} +C {code.sym} 820 -530 0 0 {name=CMRR only_toplevel=true value=" + + +.control +save all + +** OP simulation +op + +** run ac simulation +ac dec 20 1 100e6 + +setplot ac1 + +* measure parameters +let vout_mag = db(abs(v(Vout))) +let vout_phase = cph(v(Vout)) * 180/pi + +meas ac Acm find vout_mag at=1 + +*plot vout_mag vout_phase + +print Acm +echo $&Acm > CACE\{simpath\}/CACE\{filename\}_CACE\{N\}.data + + +.endc +"} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/op.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/op.sch new file mode 100644 index 00000000..6303c549 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/op.sch @@ -0,0 +1,95 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 390 -260 400 -260 {lab=Vout} +N 400 -130 400 -50 { +lab=VSS} +N 400 -260 400 -190 { +lab=Vout} +N 130 -240 160 -240 {lab=Vref} +N 130 -290 160 -290 {lab=Vn} +N 130 -340 130 -290 {lab=Vn} +N 400 -340 400 -260 {lab=Vout} +N -80 0 -80 40 { +lab=GND} +N 0 0 0 40 { +lab=GND} +N 100 0 100 40 { +lab=GND} +N 0 -70 0 -60 {lab=#net1} +N 0 -150 0 -130 {lab=VDD} +N -80 -90 -80 -60 {lab=VSS} +N 100 -90 100 -60 {lab=Vref} +N 340 -260 390 -260 {lab=Vout} +N 320 -470 370 -470 {lab=Vout} +N 280 -420 280 -390 {lab=GND} +N 320 -430 360 -430 {lab=GND} +N 360 -430 360 -400 {lab=GND} +N 280 -400 360 -400 {lab=GND} +N 280 -500 280 -480 {lab=Vz} +N 230 -500 280 -500 {lab=Vz} +N 400 -470 400 -340 {lab=Vout} +N 370 -470 400 -470 {lab=Vout} +N 130 -500 170 -500 {lab=Vn} +N 130 -500 130 -340 {lab=Vn} +C {devices/code_shown.sym} 490 -200 0 0 {name=SETUP +simulator=ngspice +only_toplevel=false +value=" +.lib CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/ngspice/sm141064.ngspice CACE\{corner\} + +.include CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/ngspice/design.ngspice +.include CACE\{DUT_path\} + +.temp CACE\{temperature\} + +.option SEED=CACE[CACE\{seed=12345\} + CACE\{iterations=0\}] + +* Flag unsafe operating conditions (exceeds models' specified limits) +.option warn=1 +"} +C {lab_pin.sym} 230 -180 2 1 {name=p7 sig_type=std_logic lab=Vref} +C {lab_pin.sym} 230 -160 2 1 {name=p8 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 230 -140 2 1 {name=p9 sig_type=std_logic lab=VSS} +C {lab_pin.sym} 130 -240 2 1 {name=p10 sig_type=std_logic lab=Vref} +C {error_amplifier_N_input.sym} 250 -260 0 0 {name=x1} +C {capa.sym} 400 -160 0 0 {name=C1 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {lab_pin.sym} 400 -50 2 1 {name=p1 sig_type=std_logic lab=VSS} +C {noconn.sym} 270 -200 2 0 {name=l1} +C {lab_pin.sym} 400 -260 0 1 {name=p2 sig_type=std_logic lab=Vout} +C {devices/vsource.sym} -80 -30 0 0 {name=V0 value=0 savecurrent=false} +C {devices/gnd.sym} -80 40 0 0 {name=l4 lab=GND} +C {devices/vsource.sym} 0 -30 0 0 {name=V1 value=CACE\{vdd\} savecurrent=false} +C {devices/gnd.sym} 0 40 0 0 {name=l8 lab=GND} +C {devices/vsource.sym} 100 -30 0 0 {name=V3 value=CACE\{vref\} savecurrent=false} +C {devices/gnd.sym} 100 40 0 0 {name=l9 lab=GND} +C {lab_pin.sym} 100 -90 2 1 {name=p3 sig_type=std_logic lab=Vref} +C {lab_pin.sym} 0 -150 2 1 {name=p4 sig_type=std_logic lab=VDD} +C {lab_pin.sym} -80 -90 2 1 {name=p6 sig_type=std_logic lab=VSS} +C {ammeter.sym} 0 -100 2 0 {name=vdd_i savecurrent=true spice_ignore=0} +C {code.sym} -70 -340 0 0 {name=OP only_toplevel=true value=" +.control +save all + +*DC simulation +op + +let Vout = v(Vout) +let Ivdd = i(vdd_i) + +print Vout Ivdd +echo $&Vout $&Ivdd> CACE\{simpath\}/CACE\{filename\}_CACE\{N\}.data +.endc +"} +C {devices/vsource.sym} 200 -500 1 0 {name=V9 value=CACE\{Vy\}} +C {vcvs.sym} 280 -450 0 1 {name=E1 value=1} +C {devices/gnd.sym} 280 -390 0 0 {name=l11 lab=GND} +C {devices/lab_wire.sym} 280 -500 0 0 {name=p19 sig_type=std_logic lab=Vz} +C {lab_pin.sym} 130 -330 2 1 {name=p5 sig_type=std_logic lab=Vn} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/os.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/os.sch new file mode 100644 index 00000000..2981b178 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/os.sch @@ -0,0 +1,102 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 480 -70 480 -60 {lab=GND} +N 480 -160 480 -130 {lab=Vref} +N 160 -140 160 -130 {lab=GND} +N 160 -230 160 -200 {lab=VDD} +N 240 -140 240 -130 {lab=GND} +N 240 -230 240 -200 {lab=VSS} +N 870 -70 870 -10 { +lab=GND} +N 780 -180 870 -180 { +lab=Vout} +N 870 -180 870 -130 { +lab=Vout} +N 480 -210 580 -210 { +lab=Vn} +N 480 -280 480 -210 { +lab=Vn} +N 870 -280 870 -180 { +lab=Vout} +N 500 -160 600 -160 { +lab=Vref} +N 580 -210 600 -210 {lab=Vn} +N 480 -280 560 -280 {lab=Vn} +N 620 -280 710 -280 {lab=Vx} +N 770 -280 870 -280 {lab=Vout} +N 480 -160 500 -160 {lab=Vref} +C {devices/vsource.sym} 480 -100 0 0 {name=V1 value=CACE\{vref\}} +C {devices/gnd.sym} 480 -60 0 0 {name=l2 lab=GND} +C {devices/lab_wire.sym} 480 -160 0 0 {name=p1 sig_type=std_logic lab=Vref} +C {devices/noconn.sym} 710 -120 0 1 {name=l4} +C {devices/lab_wire.sym} 670 -60 0 0 {name=p7 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 670 -80 0 0 {name=p8 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 160 -170 0 0 {name=V8 value=CACE\{vdd\}} +C {devices/gnd.sym} 160 -130 0 0 {name=l5 lab=GND} +C {devices/lab_wire.sym} 160 -230 0 0 {name=p9 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 240 -170 0 0 {name=V5 value=0} +C {devices/gnd.sym} 240 -130 0 0 {name=l6 lab=GND} +C {devices/lab_wire.sym} 240 -230 0 0 {name=p10 sig_type=std_logic lab=VSS} +C {devices/capa.sym} 870 -100 0 0 {name=C1 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {devices/lab_wire.sym} 870 -180 0 0 {name=p12 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 870 -10 0 0 {name=l8 lab=GND} +C {devices/lab_wire.sym} 670 -100 0 0 {name=p4 sig_type=std_logic lab=Vref} +C {devices/vsource.sym} 740 -280 1 0 {name=Vsweep value=CACE\{Vsweep\}} +C {devices/vsource.sym} 590 -280 3 1 {name=V3 value=CACE\{vref\}} +C {error_amplifier_N_input.sym} 690 -180 0 0 {name=x1} +C {devices/code_shown.sym} -10 -600 0 0 {name=SETUP +simulator=ngspice +only_toplevel=false +value=" +.lib CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/ngspice/sm141064.ngspice CACE\{corner\} + +.include CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/ngspice/design.ngspice +.include CACE\{DUT_path\} + +.temp CACE\{temperature\} + +.option SEED=CACE[CACE\{seed=12345\} + CACE\{iterations=0\}] + +* Flag unsafe operating conditions (exceeds models' specified limits) +.option warn=1 +"} +C {code.sym} 770 -470 0 0 {name=OS only_toplevel=true value=" + + +.control +save all + +** OP simulation +op +** Output swing +dc Vsweep 0 1.8 0.01 + +setplot dc1 +let dvout = deriv(v(Vout)) + +meas dc limmin when dvout=0.98 rise=1 +meas dc limmax when dvout=0.98 fall=1 + +let Output_swing = limmax - limmin + +*print Output_swing +*plot dvout + +print Output_swing +echo $&Output_swing > CACE\{simpath\}/CACE\{filename\}_CACE\{N\}.data + + +.endc +"} +C {devices/lab_wire.sym} 480 -280 0 0 {name=p2 sig_type=std_logic lab=Vn +} +C {devices/lab_wire.sym} 670 -280 0 0 {name=p3 sig_type=std_logic lab=Vx +} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/xschemrc b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/xschemrc new file mode 100644 index 00000000..83f6bd9f --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/cace/templates/xschemrc @@ -0,0 +1,10 @@ +# Source the PDK xschemrc file +if {![info exists PDK]} { + source $env(PDK_ROOT)/$env(PDK)/libs.tech/xschem/xschemrc +} + +# Add current directory +append XSCHEM_LIBRARY_PATH :[file dirname [info script]] + +# Source project xschemrc +source [file dirname [info script]]/../../xschem/xschemrc diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/gds/make_pcells_static.py b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/gds/make_pcells_static.py new file mode 100644 index 00000000..f4b34f89 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/gds/make_pcells_static.py @@ -0,0 +1,21 @@ +import pya +import klayout.db as db + +ly = pya.Layout() +ly.read("folded_cascode_pcells.gds") + +""" +# collect the cells to convert: +insts_to_convert = [] +for inst in ly.top_cell().each_inst(): + if inst.is_pcell(): + insts_to_convert.append(inst) + +for inst in insts_to_convert: + inst.convert_to_static() +""" + +ctx = db.SaveLayoutOptions() +ctx.write_context_info = False + +ly.write("folded_cascode.gds", ctx) diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_N_input.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_N_input.sch new file mode 100644 index 00000000..078b2508 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_N_input.sch @@ -0,0 +1,38 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 0 80 50 80 { +lab=VbiasP2} +N 0 100 50 100 { +lab=VbiasN2} +N 0 120 50 120 { +lab=VbiasN1} +N 50 120 100 120 {lab=VbiasN1} +N 50 100 100 100 {lab=VbiasN2} +N 50 80 100 80 {lab=VbiasP2} +N 0 60 20 60 {lab=#net1} +C {devices/lab_wire.sym} -240 90 0 0 {name=p12 sig_type=std_logic lab=VDD} +C {devices/lab_wire.sym} -240 70 0 0 {name=p3 sig_type=std_logic lab=Vref} +C {devices/lab_wire.sym} -240 110 0 0 {name=p5 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 50 -100 0 0 {name=p6 sig_type=std_logic lab=V-} +C {devices/lab_wire.sym} 50 -40 0 0 {name=p7 sig_type=std_logic lab=V+} +C {devices/lab_wire.sym} 250 -70 0 1 {name=p8 sig_type=std_logic lab=Vout} +C {devices/lab_wire.sym} 100 20 0 0 {name=p4 sig_type=std_logic lab=VDD} +C {devices/lab_wire.sym} 100 40 0 0 {name=p1 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 100 60 0 0 {name=p2 sig_type=std_logic lab=Vcomn} +C {devices/ipin.sym} 400 -130 0 0 {name=p14 lab=V+} +C {devices/iopin.sym} 380 50 0 0 {name=p18 lab=Vout} +C {devices/ipin.sym} 400 -100 0 0 {name=p19 lab=V-} +C {devices/ipin.sym} 400 -70 0 0 {name=p9 lab=Vref} +C {devices/iopin.sym} 380 -40 0 0 {name=p15 lab=VDD} +C {devices/iopin.sym} 380 -10 0 0 {name=p10 lab=VSS} +C {devices/iopin.sym} 380 20 0 0 {name=p11 lab=Vcomn} +C {error_amplifier_core_N_input.sym} 150 -70 0 0 {name=x1} +C {error_amplifier_bias_N_input.sym} -120 90 0 0 {name=x2} +C {noconn.sym} 20 60 2 0 {name=l1} +C {devices/lab_wire.sym} 80 80 0 0 {name=p13 sig_type=std_logic lab=VbiasP2} +C {devices/lab_wire.sym} 80 100 0 0 {name=p16 sig_type=std_logic lab=VbiasN2} +C {devices/lab_wire.sym} 80 120 0 0 {name=p17 sig_type=std_logic lab=VbiasN1} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_N_input.sym b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_N_input.sym new file mode 100644 index 00000000..15dfc62f --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_N_input.sym @@ -0,0 +1,37 @@ +v {xschem version=3.4.6RC file_version=1.2 +} +G {} +K {type=subcircuit +format="@name @pinlist @symname" +template="name=x1" +} +V {} +S {} +E {} +L 4 -90 -30 -70 -30 {} +L 4 -90 20 -70 20 {} +L 4 -20 80 0 80 {} +L 4 -70 40 70 0 {} +L 4 -70 -50 70 0 {} +L 4 0 20 0 120 {} +L 4 -70 -50 -70 40 {} +L 4 0 60 20 60 {} +L 7 70 0 90 0 {} +L 7 -20 100 0 100 {} +L 7 -20 120 0 120 {} +B 5 87.5 -2.5 92.5 2.5 {name=Vout dir=inout} +B 5 -92.5 17.5 -87.5 22.5 {name=V+ dir=in} +B 5 -92.5 -32.5 -87.5 -27.5 {name=V- dir=in} +B 5 -22.5 77.5 -17.5 82.5 {name=Vref dir=in} +B 5 -22.5 97.5 -17.5 102.5 {name=VDD dir=inout} +B 5 -22.5 117.5 -17.5 122.5 {name=VSS dir=inout} +B 5 17.5 57.5 22.5 62.5 {name=Vcomn dir=inout} +T {@symname} -71 -16 0 0 0.3 0.3 {} +T {@name} 15 -52 0 0 0.2 0.2 {} +T {Vout} 85 -14 0 1 0.2 0.2 {} +T {V+} -65 16 0 0 0.2 0.2 {} +T {V-} -65 -34 0 0 0.2 0.2 {} +T {Vref} 5 76 0 0 0.2 0.2 {} +T {VDD} 5 96 0 0 0.2 0.2 {} +T {VSS} 5 116 0 0 0.2 0.2 {} +T {Vcomn} -5 64 2 0 0.2 0.2 {} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_bias_N_input.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_bias_N_input.sch new file mode 120000 index 00000000..f46a4e59 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_bias_N_input.sch @@ -0,0 +1 @@ +../../error_amplifier_bias_N_input/xschem/error_amplifier_bias_N_input.sch \ No newline at end of file diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_bias_N_input.sym b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_bias_N_input.sym new file mode 120000 index 00000000..f900e17b --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_bias_N_input.sym @@ -0,0 +1 @@ +../../error_amplifier_bias_N_input/xschem/error_amplifier_bias_N_input.sym \ No newline at end of file diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_core_N_input.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_core_N_input.sch new file mode 120000 index 00000000..99400b50 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_core_N_input.sch @@ -0,0 +1 @@ +../../error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sch \ No newline at end of file diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_core_N_input.sym b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_core_N_input.sym new file mode 120000 index 00000000..5f1e96af --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/error_amplifier_core_N_input.sym @@ -0,0 +1 @@ +../../error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sym \ No newline at end of file diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_ac.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_ac.sch new file mode 100644 index 00000000..497f7240 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_ac.sch @@ -0,0 +1,296 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 1220 -240 1220 -180 { +lab=GND} +N 1130 -350 1220 -350 { +lab=Vout} +N 1220 -350 1220 -300 { +lab=Vout} +N 850 -380 950 -380 { +lab=V-} +N 290 -100 290 -90 {lab=GND} +N 290 -190 290 -160 {lab=Vin} +N 850 -330 950 -330 { +lab=Vin} +N 140 -100 140 -90 {lab=GND} +N 140 -190 140 -160 {lab=VDD} +N 220 -100 220 -90 {lab=GND} +N 220 -190 220 -160 {lab=VSS} +N 820 -100 1020 -100 {lab=#net1} +N 680 -330 850 -330 {lab=Vin} +N 680 -330 680 -100 {lab=Vin} +N 680 -100 760 -100 {lab=Vin} +N 850 -150 850 -100 {lab=#net1} +N 850 -250 850 -210 {lab=V-} +N 1080 -100 1170 -100 {lab=Vout} +N 1170 -350 1170 -100 {lab=Vout} +N 360 -100 360 -90 {lab=GND} +N 360 -190 360 -160 {lab=Vref} +C {vsource.sym} 850 -180 0 0 {name=V1 value="AC 1" savecurrent=false} +C {capa.sym} 790 -100 1 0 {name=C3 +m=1 +value=10G +footprint=1206 +device="ceramic capacitor"} +C {ind.sym} 1050 -100 1 0 {name=L2 +m=1 +value=10G +footprint=1206 +device=inductor} +C {devices/code_shown.sym} 80 -590 0 0 {name=MODELS only_toplevel=true +format="tcleval( @value )" +value=" +.include $::180MCU_MODELS/design.ngspice +.lib $::180MCU_MODELS/sm141064.ngspice typical +"} +C {devices/noconn.sym} 1060 -290 2 0 {name=l3} +C {devices/lab_wire.sym} 1020 -230 0 0 {name=p12 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 1020 -250 0 0 {name=p13 sig_type=std_logic lab=VDD} +C {devices/capa.sym} 1220 -270 0 0 {name=C4 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {devices/vsource.sym} 290 -130 0 0 {name=V6 value=\{Vin\}} +C {devices/gnd.sym} 290 -90 0 0 {name=l5 lab=GND} +C {devices/lab_wire.sym} 290 -190 0 0 {name=p14 sig_type=std_logic lab=Vin} +C {devices/lab_wire.sym} 1220 -350 0 0 {name=p15 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 1220 -180 0 0 {name=l8 lab=GND} +C {devices/code_shown.sym} 740 -610 0 0 {name=Voltage_sources only_toplevel=true +value=" +.param VDD = 1.8 +.param VSS = 0 +.param Vref = 1 +.param Vin = 1 +"} +C {devices/vsource.sym} 140 -130 0 0 {name=V8 value=\{VDD\}} +C {devices/gnd.sym} 140 -90 0 0 {name=l12 lab=GND} +C {devices/lab_wire.sym} 140 -190 0 0 {name=p19 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 220 -130 0 0 {name=V9 value=\{VSS\}} +C {devices/gnd.sym} 220 -90 0 0 {name=l13 lab=GND} +C {devices/lab_wire.sym} 220 -190 0 0 {name=p20 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 850 -380 0 0 {name=p21 sig_type=std_logic lab=V-} +C {devices/lab_wire.sym} 850 -250 0 0 {name=p22 sig_type=std_logic lab=V-} +C {devices/launcher.sym} 170 -420 0 0 {name=h1 +descr="Save & Netlist & sim" +tclcommand="xschem save; xschem netlist; xschem simulate"} +C {launcher.sym} 170 -350 0 0 {name=h2 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op"} +C {devices/lab_wire.sym} 850 -330 0 0 {name=p23 sig_type=std_logic lab=Vin} +C {devices/lab_wire.sym} 1020 -270 0 0 {name=p5 sig_type=std_logic lab=Vref} +C {gf180/error_amplifier_N_input/xschem/error_amplifier_N_input.sym} 1040 -350 0 0 {name=x1} +C {simulator_commands.sym} 1000 -580 0 0 {name=COMMANDS1 +simulator=ngspice +only_toplevel=false +value=" +.control +save all + +** OP simulation +op + +** run ac simulation +ac dec 20 1 100e6 + +** All OP parameters +setplot op1 + +let #####_M1_nmos_input_##### = 0 +let id_M1 = @m.x1.x1.xm1.m0[id] +let gm_M1 = @m.x1.x1.xm1.m0[gm] +let ro_M1 = 1/@m.x1.x1.xm1.m0[gds] +let Vgs_M1 = @m.x1.x1.xm1.m0[vgs] +let Vds_M1 = @m.x1.x1.xm1.m0[vds] +let Vsb_M1 = -@m.x1.x1.xm1.m0[vbs] +let Vdsat_M1 = @m.x1.x1.xm1.m0[vdsat] +let Vth_M1 = @m.x1.x1.xm1.m0[vth] +let ao_M1 = gm_M1*ro_M1 +let gmid_M1 = gm_M1/id_M1 +let fT_M1 = gm_M1/(6.283185*@m.x1.x1.xm1.m0[cgg]) +print #####_M1_nmos_input_##### id_M1 gm_M1 ro_M1 Vgs_M1 Vds_M1 Vsb_M1 Vdsat_M1 Vth_M1 ao_M1 gmid_M1 fT_M1 + +let #####_M2_nmos_input_##### = 0 +let id_M2 = @m.x1.x1.xm2.m0[id] +let gm_M2 = @m.x1.x1.xm2.m0[gm] +let ro_M2 = 1/@m.x1.x1.xm2.m0[gds] +let Vgs_M2 = @m.x1.x1.xm2.m0[vgs] +let Vds_M2 = @m.x1.x1.xm2.m0[vds] +let Vsb_M2 = -@m.x1.x1.xm2.m0[vbs] +let Vdsat_M2 = @m.x1.x1.xm2.m0[vdsat] +let Vth_M2 = @m.x1.x1.xm2.m0[vth] +let ao_M2 = gm_M2*ro_M2 +let gmid_M2 = gm_M2/id_M2 +let fT_M2 = gm_M2/(6.283185*@m.x1.x1.xm2.m0[cgg]) +print #####_M2_nmos_input_##### id_M2 gm_M2 ro_M2 Vgs_M2 Vds_M2 Vsb_M2 Vdsat_M2 Vth_M2 ao_M2 gmid_M2 fT_M2 + +let #####_M3_pmos_top_##### = 0 +let id_M3 = @m.x1.x1.xm3.m0[id] +let gm_M3 = @m.x1.x1.xm3.m0[gm] +let ro_M3 = 1/@m.x1.x1.xm3.m0[gds] +let Vsg_M3 = @m.x1.x1.xm3.m0[vgs] +let Vsd_M3 = @m.x1.x1.xm3.m0[vds] +let Vbs_M3 = -@m.x1.x1.xm3.m0[vbs] +let Vdsat_M3 = @m.x1.x1.xm3.m0[vdsat] +let Vth_M3 = @m.x1.x1.xm3.m0[vth] +let ao_M3 = gm_M3*ro_M3 +let gmid_M3 = gm_M3/id_M3 +let fT_M3 = gm_M3/(6.283185*@m.x1.x1.xm3.m0[cgg]) +print #####_M3_pmos_top_##### id_M3 gm_M3 ro_M3 Vsg_M3 Vsd_M3 Vbs_M3 Vdsat_M3 Vth_M3 ao_M3 gmid_M3 fT_M3 + +let #####_M4_pmos_top_##### = 0 +let id_M4 = @m.x1.x1.xm4.m0[id] +let gm_M4 = @m.x1.x1.xm4.m0[gm] +let ro_M4 = 1/@m.x1.x1.xm4.m0[gds] +let Vsg_M4 = @m.x1.x1.xm4.m0[vgs] +let Vsd_M4 = @m.x1.x1.xm4.m0[vds] +let Vbs_M4 = -@m.x1.x1.xm4.m0[vbs] +let Vdsat_M4 = @m.x1.x1.xm4.m0[vdsat] +let Vth_M4 = @m.x1.x1.xm4.m0[vth] +let ao_M4 = gm_M4*ro_M4 +let gmid_M4 = gm_M4/id_M4 +let fT_M4 = gm_M4/(6.283185*@m.x1.x1.xm4.m0[cgg]) +print #####_M4_pmos_top_##### id_M4 gm_M4 ro_M4 Vsg_M4 Vsd_M4 Vbs_M4 Vdsat_M4 Vth_M4 ao_M4 gmid_M4 fT_M4 + +let #####_M5_pmos_out_##### = 0 +let id_M5 = @m.x1.x1.xm5.m0[id] +let gm_M5 = @m.x1.x1.xm5.m0[gm] +let ro_M5 = 1/@m.x1.x1.xm5.m0[gds] +let Vsg_M5 = @m.x1.x1.xm5.m0[vgs] +let Vsd_M5 = @m.x1.x1.xm5.m0[vds] +let Vbs_M5 = -@m.x1.x1.xm5.m0[vbs] +let Vdsat_M5 = @m.x1.x1.xm5.m0[vdsat] +let Vth_M5 = @m.x1.x1.xm5.m0[vth] +let ao_M5 = gm_M5*ro_M5 +let gmid_M5 = gm_M5/id_M5 +let fT_M5 = gm_M5/(6.283185*@m.x1.x1.xm5.m0[cgg]) +print #####_M5_pmos_out_##### id_M5 gm_M5 ro_M5 Vsg_M5 Vsd_M5 Vbs_M5 Vdsat_M5 Vth_M5 ao_M5 gmid_M5 fT_M5 + +let #####_M6_pmos_out_##### = 0 +let id_M6 = @m.x1.x1.xm6.m0[id] +let gm_M6 = @m.x1.x1.xm6.m0[gm] +let ro_M6 = 1/@m.x1.x1.xm6.m0[gds] +let Vsg_M6 = @m.x1.x1.xm6.m0[vgs] +let Vsd_M6 = @m.x1.x1.xm6.m0[vds] +let Vbs_M6 = -@m.x1.x1.xm6.m0[vbs] +let Vdsat_M6 = @m.x1.x1.xm6.m0[vdsat] +let Vth_M6 = @m.x1.x1.xm6.m0[vth] +let ao_M6 = gm_M6*ro_M6 +let gmid_M6 = gm_M6/id_M6 +let fT_M6 = gm_M6/(6.283185*@m.x1.x1.xm6.m0[cgg]) +print #####_M6_pmos_out_##### id_M6 gm_M6 ro_M6 Vsg_M6 Vsd_M6 Vbs_M6 Vdsat_M6 Vth_M6 ao_M6 gmid_M6 fT_M6 + +let #####_M7_nmos_out_##### = 0 +let id_M7 = @m.x1.x1.xm7.m0[id] +let gm_M7 = @m.x1.x1.xm7.m0[gm] +let ro_M7 = 1/@m.x1.x1.xm7.m0[gds] +let Vgs_M7 = @m.x1.x1.xm7.m0[vgs] +let Vds_M7 = @m.x1.x1.xm7.m0[vds] +let Vsb_M7 = -@m.x1.x1.xm7.m0[vbs] +let Vdsat_M7 = @m.x1.x1.xm7.m0[vdsat] +let Vth_M7 = @m.x1.x1.xm7.m0[vth] +let ao_M7 = gm_M7*ro_M7 +let gmid_M7 = gm_M7/id_M7 +let fT_M7 = gm_M7/(6.283185*@m.x1.x1.xm7.m0[cgg]) +print #####_M7_nmos_out_##### id_M7 gm_M7 ro_M7 Vgs_M7 Vds_M7 Vsb_M7 Vdsat_M7 Vth_M7 ao_M7 gmid_M7 fT_M7 + +let #####_M8_nmos_out_##### = 0 +let id_M8 = @m.x1.x1.xm8.m0[id] +let gm_M8 = @m.x1.x1.xm8.m0[gm] +let ro_M8 = 1/@m.x1.x1.xm8.m0[gds] +let Vgs_M8 = @m.x1.x1.xm8.m0[vgs] +let Vds_M8 = @m.x1.x1.xm8.m0[vds] +let Vsb_M8 = -@m.x1.x1.xm8.m0[vbs] +let Vdsat_M8 = @m.x1.x1.xm8.m0[vdsat] +let Vth_M8 = @m.x1.x1.xm8.m0[vth] +let ao_M8 = gm_M8*ro_M8 +let gmid_M8 = gm_M8/id_M8 +let fT_M8 = gm_M8/(6.283185*@m.x1.x1.xm8.m0[cgg]) +print #####_M8_nmos_out_##### id_M8 gm_M8 ro_M8 Vgs_M8 Vds_M8 Vsb_M8 Vdsat_M8 Vth_M8 ao_M8 gmid_M8 fT_M8 + +let #####_M9_nmos_bottom_##### = 0 +let id_M9 = @m.x1.x1.xm9.m0[id] +let gm_M9 = @m.x1.x1.xm9.m0[gm] +let ro_M9 = 1/@m.x1.x1.xm9.m0[gds] +let Vgs_M9 = @m.x1.x1.xm9.m0[vgs] +let Vds_M9 = @m.x1.x1.xm9.m0[vds] +let Vsb_M9 = -@m.x1.x1.xm9.m0[vbs] +let Vdsat_M9 = @m.x1.x1.xm9.m0[vdsat] +let Vth_M9 = @m.x1.x1.xm9.m0[vth] +let ao_M9 = gm_M9*ro_M9 +let gmid_M9 = gm_M9/id_M9 +let fT_M9 = gm_M9/(6.283185*@m.x1.x1.xm9.m0[cgg]) +print #####_M9_nmos_bottom_##### id_M9 gm_M9 ro_M9 Vgs_M9 Vds_M9 Vsb_M9 Vdsat_M9 Vth_M9 ao_M9 gmid_M9 fT_M9 + +let #####_M10_nmos_bottom_##### = 0 +let id_M10 = @m.x1.x1.xm10.m0[id] +let gm_M10 = @m.x1.x1.xm10.m0[gm] +let ro_M10 = 1/@m.x1.x1.xm10.m0[gds] +let Vgs_M10 = @m.x1.x1.xm10.m0[vgs] +let Vds_M10 = @m.x1.x1.xm10.m0[vds] +let Vsb_M10 = @m.x1.x1.xm10.m0[vbs] +let Vdsat_M10 = @m.x1.x1.xm10.m0[vdsat] +let Vth_M10 = @m.x1.x1.xm10.m0[vth] +let ao_M10 = gm_M10*ro_M10 +let gmid_M10 = gm_M10/id_M10 +let fT_M10 = gm_M10/(6.283185*@m.x1.x1.xm10.m0[cgg]) +print #####_M10_nmos_bottom_##### id_M10 gm_M10 ro_M10 Vgs_M10 Vds_M10 Vsb_M10 Vdsat_M10 Vth_M10 ao_M10 gmid_M10 fT_M10 + +let #####_M11_nmos_mirror_##### = 0 +let id_M11 = @m.x1.x1.xm11.m0[id] +let gm_M11 = @m.x1.x1.xm11.m0[gm] +let ro_M11 = 1/@m.x1.x1.xm11.m0[gds] +let Vgs_M11 = @m.x1.x1.xm11.m0[vgs] +let Vds_M11 = @m.x1.x1.xm11.m0[vds] +let Vsb_M11 = -@m.x1.x1.xm11.m0[vbs] +let Vdsat_M11 = @m.x1.x1.xm11.m0[vdsat] +let Vth_M11 = @m.x1.x1.xm11.m0[vth] +let ao_M11 = gm_M11*ro_M11 +let gmid_M11 = gm_M11/id_M11 +let fT_M11 = gm_M11/(6.283185*@m.x1.x1.xm11.m0[cgg]) +print #####_M11_nmos_mirror_##### id_M11 gm_M11 ro_M11 Vgs_M11 Vds_M11 Vsb_M11 Vdsat_M11 Vth_M11 ao_M11 gmid_M11 fT_M11 + +** Custom output +let #####_Custom_output_##### = 0 + +* Power +let power = abs(i(V8))*VDD + +* DC_gain +let r1 = ao_M6*ro_M4 +let r2 = ao_M8*((ro_M1*ro_M10)/(ro_M1+ro_M10)) +let Rout = (r1*r2)/(r1+r2) +let Av = db(gm_M1*Rout) +* Bandwidth +let BW = 1/(Rout*1e-12*6.283185) + +print #####_Custom_output_##### Av BW Rout power gm_M1 ro_M1 gm_M6 ro_M6 ro_M4 gm_M8 ro_M8 ro_M10 + +write folded_cascode_ac.raw + +setplot ac1 + +* measure parameters +let vout_mag = db(abs(v(Vout))) +let vout_phase = cph(v(Vout)) * 180/pi +let gm = (-1)*db(abs(v(Vout))) + +meas ac A0 find vout_mag at=1e2 +meas ac UGB when vout_mag=0 fall=1 +meas ac PM find vout_phase when vout_mag=0 +meas ac GM find gm when vout_phase=0 + +let A0_p1 = A0 - 3 +meas ac BW when vout_mag=A0_p1 + +plot vout_mag vout_phase + +.endc +"} +C {devices/vsource.sym} 360 -130 0 0 {name=V2 value=\{Vref\}} +C {devices/gnd.sym} 360 -90 0 0 {name=l1 lab=GND} +C {devices/lab_wire.sym} 360 -190 0 0 {name=p1 sig_type=std_logic lab=Vref} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_cmrr.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_cmrr.sch new file mode 100644 index 00000000..56cfc908 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_cmrr.sch @@ -0,0 +1,292 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 960 -240 960 -180 { +lab=GND} +N 870 -350 960 -350 { +lab=Vout} +N 960 -350 960 -300 { +lab=Vout} +N 270 -110 270 -100 {lab=GND} +N 270 -200 270 -170 {lab=Vin} +N 570 -380 670 -380 { +lab=V-} +N 110 -110 110 -100 {lab=GND} +N 110 -200 110 -170 {lab=VDD} +N 190 -110 190 -100 {lab=GND} +N 190 -200 190 -170 {lab=VSS} +N 910 -350 910 -90 {lab=Vout} +N 800 -90 910 -90 {lab=Vout} +N 570 -320 570 -90 {lab=V-} +N 270 -340 270 -300 {lab=V+} +N 570 -90 740 -90 {lab=V-} +N 270 -240 270 -200 {lab=Vin} +N 570 -380 570 -320 {lab=V-} +N 620 -320 670 -320 {lab=V+} +N 670 -380 690 -380 {lab=V-} +N 670 -330 670 -320 {lab=V+} +N 670 -330 690 -330 {lab=V+} +N 350 -110 350 -100 {lab=GND} +N 350 -200 350 -170 {lab=Vref} +C {vsource.sym} 270 -270 0 0 {name=V5 value="AC 1" savecurrent=false} +C {capa.sym} 620 -350 0 0 {name=C3 +m=1 +value=10G +footprint=1206 +device="ceramic capacitor"} +C {ind.sym} 770 -90 1 0 {name=L2 +m=1 +value=10G +footprint=1206 +device=inductor} +C {devices/code_shown.sym} 50 -600 0 0 {name=MODELS only_toplevel=true +format="tcleval( @value )" +value=" +.include $::180MCU_MODELS/design.ngspice +.lib $::180MCU_MODELS/sm141064.ngspice typical +"} +C {devices/noconn.sym} 800 -290 0 1 {name=l3} +C {devices/lab_wire.sym} 760 -230 0 0 {name=p12 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 760 -250 0 0 {name=p13 sig_type=std_logic lab=VDD} +C {devices/capa.sym} 960 -270 0 0 {name=C4 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {devices/vsource.sym} 270 -140 0 0 {name=V6 value=\{Vin\}} +C {devices/gnd.sym} 270 -100 0 0 {name=l5 lab=GND} +C {devices/lab_wire.sym} 270 -200 0 0 {name=p14 sig_type=std_logic lab=Vin} +C {devices/lab_wire.sym} 960 -350 0 0 {name=p15 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 960 -180 0 0 {name=l8 lab=GND} +C {simulator_commands.sym} 740 -580 0 0 {name=COMMANDS1 +simulator=ngspice +only_toplevel=false +value=" +.control +save all + +** OP simulation +op + +** run ac simulation +ac dec 20 1 100e6 + +** All OP parameters +setplot op1 + +let #####_M1_nmos_input_##### = 0 +let id_M1 = @m.x1.x1.xm1.m0[id] +let gm_M1 = @m.x1.x1.xm1.m0[gm] +let ro_M1 = 1/@m.x1.x1.xm1.m0[gds] +let Vgs_M1 = @m.x1.x1.xm1.m0[vgs] +let Vds_M1 = @m.x1.x1.xm1.m0[vds] +let Vsb_M1 = -@m.x1.x1.xm1.m0[vbs] +let Vdsat_M1 = @m.x1.x1.xm1.m0[vdsat] +let Vth_M1 = @m.x1.x1.xm1.m0[vth] +let ao_M1 = gm_M1*ro_M1 +let gmid_M1 = gm_M1/id_M1 +let fT_M1 = gm_M1/(6.283185*@m.x1.x1.xm1.m0[cgg]) +print #####_M1_nmos_input_##### id_M1 gm_M1 ro_M1 Vgs_M1 Vds_M1 Vsb_M1 Vdsat_M1 Vth_M1 ao_M1 gmid_M1 fT_M1 + +let #####_M2_nmos_input_##### = 0 +let id_M2 = @m.x1.x1.xm2.m0[id] +let gm_M2 = @m.x1.x1.xm2.m0[gm] +let ro_M2 = 1/@m.x1.x1.xm2.m0[gds] +let Vgs_M2 = @m.x1.x1.xm2.m0[vgs] +let Vds_M2 = @m.x1.x1.xm2.m0[vds] +let Vsb_M2 = -@m.x1.x1.xm2.m0[vbs] +let Vdsat_M2 = @m.x1.x1.xm2.m0[vdsat] +let Vth_M2 = @m.x1.x1.xm2.m0[vth] +let ao_M2 = gm_M2*ro_M2 +let gmid_M2 = gm_M2/id_M2 +let fT_M2 = gm_M2/(6.283185*@m.x1.x1.xm2.m0[cgg]) +print #####_M2_nmos_input_##### id_M2 gm_M2 ro_M2 Vgs_M2 Vds_M2 Vsb_M2 Vdsat_M2 Vth_M2 ao_M2 gmid_M2 fT_M2 + +let #####_M3_pmos_top_##### = 0 +let id_M3 = @m.x1.x1.xm3.m0[id] +let gm_M3 = @m.x1.x1.xm3.m0[gm] +let ro_M3 = 1/@m.x1.x1.xm3.m0[gds] +let Vsg_M3 = @m.x1.x1.xm3.m0[vgs] +let Vsd_M3 = @m.x1.x1.xm3.m0[vds] +let Vbs_M3 = -@m.x1.x1.xm3.m0[vbs] +let Vdsat_M3 = @m.x1.x1.xm3.m0[vdsat] +let Vth_M3 = @m.x1.x1.xm3.m0[vth] +let ao_M3 = gm_M3*ro_M3 +let gmid_M3 = gm_M3/id_M3 +let fT_M3 = gm_M3/(6.283185*@m.x1.x1.xm3.m0[cgg]) +print #####_M3_pmos_top_##### id_M3 gm_M3 ro_M3 Vsg_M3 Vsd_M3 Vbs_M3 Vdsat_M3 Vth_M3 ao_M3 gmid_M3 fT_M3 + +let #####_M4_pmos_top_##### = 0 +let id_M4 = @m.x1.x1.xm4.m0[id] +let gm_M4 = @m.x1.x1.xm4.m0[gm] +let ro_M4 = 1/@m.x1.x1.xm4.m0[gds] +let Vsg_M4 = @m.x1.x1.xm4.m0[vgs] +let Vsd_M4 = @m.x1.x1.xm4.m0[vds] +let Vbs_M4 = -@m.x1.x1.xm4.m0[vbs] +let Vdsat_M4 = @m.x1.x1.xm4.m0[vdsat] +let Vth_M4 = @m.x1.x1.xm4.m0[vth] +let ao_M4 = gm_M4*ro_M4 +let gmid_M4 = gm_M4/id_M4 +let fT_M4 = gm_M4/(6.283185*@m.x1.x1.xm4.m0[cgg]) +print #####_M4_pmos_top_##### id_M4 gm_M4 ro_M4 Vsg_M4 Vsd_M4 Vbs_M4 Vdsat_M4 Vth_M4 ao_M4 gmid_M4 fT_M4 + +let #####_M5_pmos_out_##### = 0 +let id_M5 = @m.x1.x1.xm5.m0[id] +let gm_M5 = @m.x1.x1.xm5.m0[gm] +let ro_M5 = 1/@m.x1.x1.xm5.m0[gds] +let Vsg_M5 = @m.x1.x1.xm5.m0[vgs] +let Vsd_M5 = @m.x1.x1.xm5.m0[vds] +let Vbs_M5 = -@m.x1.x1.xm5.m0[vbs] +let Vdsat_M5 = @m.x1.x1.xm5.m0[vdsat] +let Vth_M5 = @m.x1.x1.xm5.m0[vth] +let ao_M5 = gm_M5*ro_M5 +let gmid_M5 = gm_M5/id_M5 +let fT_M5 = gm_M5/(6.283185*@m.x1.x1.xm5.m0[cgg]) +print #####_M5_pmos_out_##### id_M5 gm_M5 ro_M5 Vsg_M5 Vsd_M5 Vbs_M5 Vdsat_M5 Vth_M5 ao_M5 gmid_M5 fT_M5 + +let #####_M6_pmos_out_##### = 0 +let id_M6 = @m.x1.x1.xm6.m0[id] +let gm_M6 = @m.x1.x1.xm6.m0[gm] +let ro_M6 = 1/@m.x1.x1.xm6.m0[gds] +let Vsg_M6 = @m.x1.x1.xm6.m0[vgs] +let Vsd_M6 = @m.x1.x1.xm6.m0[vds] +let Vbs_M6 = -@m.x1.x1.xm6.m0[vbs] +let Vdsat_M6 = @m.x1.x1.xm6.m0[vdsat] +let Vth_M6 = @m.x1.x1.xm6.m0[vth] +let ao_M6 = gm_M6*ro_M6 +let gmid_M6 = gm_M6/id_M6 +let fT_M6 = gm_M6/(6.283185*@m.x1.x1.xm6.m0[cgg]) +print #####_M6_pmos_out_##### id_M6 gm_M6 ro_M6 Vsg_M6 Vsd_M6 Vbs_M6 Vdsat_M6 Vth_M6 ao_M6 gmid_M6 fT_M6 + +let #####_M7_nmos_out_##### = 0 +let id_M7 = @m.x1.x1.xm7.m0[id] +let gm_M7 = @m.x1.x1.xm7.m0[gm] +let ro_M7 = 1/@m.x1.x1.xm7.m0[gds] +let Vgs_M7 = @m.x1.x1.xm7.m0[vgs] +let Vds_M7 = @m.x1.x1.xm7.m0[vds] +let Vsb_M7 = -@m.x1.x1.xm7.m0[vbs] +let Vdsat_M7 = @m.x1.x1.xm7.m0[vdsat] +let Vth_M7 = @m.x1.x1.xm7.m0[vth] +let ao_M7 = gm_M7*ro_M7 +let gmid_M7 = gm_M7/id_M7 +let fT_M7 = gm_M7/(6.283185*@m.x1.x1.xm7.m0[cgg]) +print #####_M7_nmos_out_##### id_M7 gm_M7 ro_M7 Vgs_M7 Vds_M7 Vsb_M7 Vdsat_M7 Vth_M7 ao_M7 gmid_M7 fT_M7 + +let #####_M8_nmos_out_##### = 0 +let id_M8 = @m.x1.x1.xm8.m0[id] +let gm_M8 = @m.x1.x1.xm8.m0[gm] +let ro_M8 = 1/@m.x1.x1.xm8.m0[gds] +let Vgs_M8 = @m.x1.x1.xm8.m0[vgs] +let Vds_M8 = @m.x1.x1.xm8.m0[vds] +let Vsb_M8 = -@m.x1.x1.xm8.m0[vbs] +let Vdsat_M8 = @m.x1.x1.xm8.m0[vdsat] +let Vth_M8 = @m.x1.x1.xm8.m0[vth] +let ao_M8 = gm_M8*ro_M8 +let gmid_M8 = gm_M8/id_M8 +let fT_M8 = gm_M8/(6.283185*@m.x1.x1.xm8.m0[cgg]) +print #####_M8_nmos_out_##### id_M8 gm_M8 ro_M8 Vgs_M8 Vds_M8 Vsb_M8 Vdsat_M8 Vth_M8 ao_M8 gmid_M8 fT_M8 + +let #####_M9_nmos_bottom_##### = 0 +let id_M9 = @m.x1.x1.xm9.m0[id] +let gm_M9 = @m.x1.x1.xm9.m0[gm] +let ro_M9 = 1/@m.x1.x1.xm9.m0[gds] +let Vgs_M9 = @m.x1.x1.xm9.m0[vgs] +let Vds_M9 = @m.x1.x1.xm9.m0[vds] +let Vsb_M9 = -@m.x1.x1.xm9.m0[vbs] +let Vdsat_M9 = @m.x1.x1.xm9.m0[vdsat] +let Vth_M9 = @m.x1.x1.xm9.m0[vth] +let ao_M9 = gm_M9*ro_M9 +let gmid_M9 = gm_M9/id_M9 +let fT_M9 = gm_M9/(6.283185*@m.x1.x1.xm9.m0[cgg]) +print #####_M9_nmos_bottom_##### id_M9 gm_M9 ro_M9 Vgs_M9 Vds_M9 Vsb_M9 Vdsat_M9 Vth_M9 ao_M9 gmid_M9 fT_M9 + +let #####_M10_nmos_bottom_##### = 0 +let id_M10 = @m.x1.x1.xm10.m0[id] +let gm_M10 = @m.x1.x1.xm10.m0[gm] +let ro_M10 = 1/@m.x1.x1.xm10.m0[gds] +let Vgs_M10 = @m.x1.x1.xm10.m0[vgs] +let Vds_M10 = @m.x1.x1.xm10.m0[vds] +let Vsb_M10 = @m.x1.x1.xm10.m0[vbs] +let Vdsat_M10 = @m.x1.x1.xm10.m0[vdsat] +let Vth_M10 = @m.x1.x1.xm10.m0[vth] +let ao_M10 = gm_M10*ro_M10 +let gmid_M10 = gm_M10/id_M10 +let fT_M10 = gm_M10/(6.283185*@m.x1.x1.xm10.m0[cgg]) +print #####_M10_nmos_bottom_##### id_M10 gm_M10 ro_M10 Vgs_M10 Vds_M10 Vsb_M10 Vdsat_M10 Vth_M10 ao_M10 gmid_M10 fT_M10 + +let #####_M11_nmos_mirror_##### = 0 +let id_M11 = @m.x1.x1.xm11.m0[id] +let gm_M11 = @m.x1.x1.xm11.m0[gm] +let ro_M11 = 1/@m.x1.x1.xm11.m0[gds] +let Vgs_M11 = @m.x1.x1.xm11.m0[vgs] +let Vds_M11 = @m.x1.x1.xm11.m0[vds] +let Vsb_M11 = -@m.x1.x1.xm11.m0[vbs] +let Vdsat_M11 = @m.x1.x1.xm11.m0[vdsat] +let Vth_M11 = @m.x1.x1.xm11.m0[vth] +let ao_M11 = gm_M11*ro_M11 +let gmid_M11 = gm_M11/id_M11 +let fT_M11 = gm_M11/(6.283185*@m.x1.x1.xm11.m0[cgg]) +print #####_M11_nmos_mirror_##### id_M11 gm_M11 ro_M11 Vgs_M11 Vds_M11 Vsb_M11 Vdsat_M11 Vth_M11 ao_M11 gmid_M11 fT_M11 + +** Custom output +let #####_Custom_output_##### = 0 + +* Power +let power = abs(i(V8))*VDD + +* DC_gain +let r1 = ao_M6*ro_M4 +let r2 = ao_M8*((ro_M1*ro_M10)/(ro_M1+ro_M10)) +let Rout = (r1*r2)/(r1+r2) +let Av = db(gm_M1*Rout) +* Bandwidth +let BW = 1/(Rout*1e-12*6.283185) + +print #####_Custom_output_##### Av BW Rout power gm_M1 ro_M1 gm_M6 ro_M6 ro_M4 gm_M8 ro_M8 ro_M10 + +write folded_cascode_cmrr.raw + +setplot ac1 + +* measure parameters +let vout_mag = db(abs(v(Vout))) +let vout_phase = cph(v(Vout)) * 180/pi + +meas ac Acm find vout_mag at=1e2 + +plot vout_mag vout_phase + +.endc +"} +C {devices/code_shown.sym} 510 -570 0 0 {name=Voltage_sources only_toplevel=true +value=" +.param VDD = 1.8 +.param VSS = 0 +.param Vref = 1 +.param Vin = 1 +"} +C {devices/vsource.sym} 110 -140 0 0 {name=V8 value=\{VDD\}} +C {devices/gnd.sym} 110 -100 0 0 {name=l12 lab=GND} +C {devices/lab_wire.sym} 110 -200 0 0 {name=p19 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 190 -140 0 0 {name=V9 value=\{VSS\}} +C {devices/gnd.sym} 190 -100 0 0 {name=l13 lab=GND} +C {devices/lab_wire.sym} 190 -200 0 0 {name=p20 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 570 -380 0 0 {name=p3 sig_type=std_logic lab=V-} +C {devices/lab_wire.sym} 270 -340 0 0 {name=p4 sig_type=std_logic lab=V+} +C {devices/launcher.sym} 120 -480 0 0 {name=h1 +descr="Save & Netlist & sim" +tclcommand="xschem save; xschem netlist; xschem simulate"} +C {launcher.sym} 120 -410 0 0 {name=h2 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op"} +C {devices/lab_wire.sym} 620 -320 2 0 {name=p21 sig_type=std_logic lab=V+} +C {gf180/error_amplifier_N_input/xschem/error_amplifier_N_input.sym} 780 -350 0 0 {name=x1} +C {devices/lab_wire.sym} 760 -270 0 0 {name=p1 sig_type=std_logic lab=Vref} +C {devices/vsource.sym} 350 -140 0 0 {name=V1 value=\{Vref\}} +C {devices/gnd.sym} 350 -100 0 0 {name=l1 lab=GND +value=\{Vref\}} +C {devices/lab_wire.sym} 350 -200 0 0 {name=p2 sig_type=std_logic lab=Vref +value=\{Vref\}} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_icmr.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_icmr.sch new file mode 100644 index 00000000..e3b485c8 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_icmr.sch @@ -0,0 +1,175 @@ +v {xschem version=3.4.6 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 220 -140 220 -120 { +lab=GND} +N 220 -240 220 -200 { +lab=VSS} +N 300 -140 300 -120 { +lab=GND} +N 220 -120 220 -100 { +lab=GND} +N 300 -240 300 -200 { +lab=VDD} +N 300 -120 300 -100 { +lab=GND} +N 380 -140 380 -120 { +lab=GND} +N 380 -240 380 -200 { +lab=Vref} +N 380 -120 380 -100 { +lab=GND} +N 880 -510 940 -510 {lab=Vout} +N 1090 -380 1090 -300 { +lab=VSS} +N 1090 -510 1090 -450 { +lab=Vout} +N 940 -510 1090 -510 { +lab=Vout} +N 520 -490 700 -490 { +lab=Vin} +N 1090 -450 1090 -440 { +lab=Vout} +N 590 -540 700 -540 { +lab=Vout} +N 590 -620 590 -540 { +lab=Vout} +N 590 -620 940 -620 { +lab=Vout} +N 940 -620 940 -510 { +lab=Vout} +N 460 -240 460 -200 { +lab=Vin} +N 460 -140 460 -100 { +lab=GND} +C {sky130_fd_pr/corner.sym} 170 -410 0 0 {name=CORNER only_toplevel=true corner=tt} +C {simulator_commands.sym} 320 -410 0 0 {name="COMMANDS" +simulator="ngspice" +only_toplevel="false" +value=" +.param VDD=1.8 +.param Vref=1.2 +.save + +* Operation point of the folded cascode core + +*nfet + ++ @m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[id] + +*pfet + ++ @m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[id] + ++ @m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[id] + ++ @m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[id] + ++ @m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[id] + +* Operation point of the folded cascode bias + + ++ abstol=1e-14 savecurrents +.control + save all + op + remzerovec + write folded_cascode_icmr.raw + set appendwrite + + * run dc simulation + dc V1 0 1.8 0.001 + + * measure parameters + let dVout = deriv(v(Vout)) + + meas dc ICMmin when DVout=0.95 cross=1 + meas dc ICMmax when DVout=0.95 cross=last + let ICMR = ICMmax - ICMmin + print ICMR + plot Vout dVout + + write folded_cascode_icmr.raw +.endc +"} +C {devices/vsource.sym} 220 -170 0 0 {name=V0 value=0 savecurrent=false} +C {devices/gnd.sym} 220 -100 0 0 {name=l5 lab=GND} +C {devices/vsource.sym} 300 -170 0 0 {name=V2 value=\{VDD\} savecurrent=false} +C {devices/lab_wire.sym} 220 -240 0 0 {name=p25 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 300 -240 0 0 {name=p26 sig_type=std_logic lab=VDD} +C {devices/gnd.sym} 300 -100 0 0 {name=l6 lab=GND} +C {devices/vsource.sym} 380 -170 0 0 {name=V4 value=\{Vref\} savecurrent=false} +C {devices/lab_wire.sym} 380 -240 0 0 {name=p27 sig_type=std_logic lab=Vref} +C {devices/gnd.sym} 380 -100 0 0 {name=l7 lab=GND} +C {devices/launcher.sym} 270 -530 0 0 {name=h15 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op" +} +C {devices/launcher.sym} 270 -600 0 0 {name=h3 +descr="Netlist & sim" +tclcommand="xschem netlist; xschem simulate"} +C {lab_pin.sym} 770 -430 2 1 {name=p7 sig_type=std_logic lab=Vref} +C {lab_pin.sym} 770 -410 2 1 {name=p8 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 770 -390 2 1 {name=p9 sig_type=std_logic lab=VSS} +C {lab_pin.sym} 520 -490 2 1 {name=p10 sig_type=std_logic lab=Vin} +C {capa.sym} 1090 -410 0 0 {name=C1 +m=1 +value=1p +footprint=1206 +device="ceramic capacitor"} +C {lab_pin.sym} 1090 -300 2 1 {name=p1 sig_type=std_logic lab=VSS} +C {noconn.sym} 810 -450 2 0 {name=l1} +C {lab_pin.sym} 1090 -510 0 1 {name=p2 sig_type=std_logic lab=Vout} +C {devices/lab_wire.sym} 460 -240 0 0 {name=p3 sig_type=std_logic lab=Vin} +C {devices/gnd.sym} 460 -100 0 0 {name=l2 lab=GND} +C {devices/vsource.sym} 460 -170 0 0 {name=V1 value=\{Vref\} savecurrent=false} +C {/foss/designs/chipathon_2025/designs/sky130/error_amplifier_N_input/xschem/error_amplifier_N_input.sym} 790 -510 0 0 {name=x1} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_op.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_op.sch new file mode 100644 index 00000000..88b15d00 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_op.sch @@ -0,0 +1,258 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 1220 -240 1220 -180 { +lab=GND} +N 1130 -350 1220 -350 { +lab=Vout} +N 1220 -350 1220 -300 { +lab=Vout} +N 850 -380 950 -380 { +lab=Vout} +N 290 -100 290 -90 {lab=GND} +N 290 -190 290 -160 {lab=Vin} +N 850 -330 950 -330 { +lab=Vin} +N 140 -100 140 -90 {lab=GND} +N 140 -190 140 -160 {lab=VDD} +N 220 -100 220 -90 {lab=GND} +N 220 -190 220 -160 {lab=VSS} +N 1170 -350 1170 -100 {lab=Vout} +N 360 -100 360 -90 {lab=GND} +N 360 -190 360 -160 {lab=Vref} +N 770 -380 850 -380 {lab=Vout} +N 770 -380 770 -100 {lab=Vout} +N 770 -100 1170 -100 {lab=Vout} +C {devices/code_shown.sym} 80 -590 0 0 {name=MODELS only_toplevel=true +format="tcleval( @value )" +value=" +.include $::180MCU_MODELS/design.ngspice +.lib $::180MCU_MODELS/sm141064.ngspice typical +"} +C {devices/noconn.sym} 1060 -290 2 0 {name=l3} +C {devices/lab_wire.sym} 1020 -230 0 0 {name=p12 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 1020 -250 0 0 {name=p13 sig_type=std_logic lab=VDD} +C {devices/capa.sym} 1220 -270 0 0 {name=C4 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {devices/vsource.sym} 290 -130 0 0 {name=V6 value=\{Vin\}} +C {devices/gnd.sym} 290 -90 0 0 {name=l5 lab=GND} +C {devices/lab_wire.sym} 290 -190 0 0 {name=p14 sig_type=std_logic lab=Vin} +C {devices/lab_wire.sym} 1220 -350 0 0 {name=p15 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 1220 -180 0 0 {name=l8 lab=GND} +C {devices/code_shown.sym} 740 -610 0 0 {name=Voltage_sources only_toplevel=true +value=" +.param VDD = 1.8 +.param VSS = 0 +.param Vref = 1 +.param Vin = 1 +"} +C {devices/vsource.sym} 140 -130 0 0 {name=V8 value=\{VDD\}} +C {devices/gnd.sym} 140 -90 0 0 {name=l12 lab=GND} +C {devices/lab_wire.sym} 140 -190 0 0 {name=p19 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 220 -130 0 0 {name=V9 value=\{VSS\}} +C {devices/gnd.sym} 220 -90 0 0 {name=l13 lab=GND} +C {devices/lab_wire.sym} 220 -190 0 0 {name=p20 sig_type=std_logic lab=VSS} +C {devices/launcher.sym} 170 -420 0 0 {name=h1 +descr="Save & Netlist & sim" +tclcommand="xschem save; xschem netlist; xschem simulate"} +C {launcher.sym} 170 -350 0 0 {name=h2 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op"} +C {devices/lab_wire.sym} 850 -330 0 0 {name=p23 sig_type=std_logic lab=Vin} +C {devices/lab_wire.sym} 1020 -270 0 0 {name=p5 sig_type=std_logic lab=Vref} +C {/foss/designs/workarea/error_amplifier_N_input/xschem/error_amplifier_N_input.sym} 1040 -350 0 0 {name=x1} +C {simulator_commands.sym} 1000 -580 0 0 {name=COMMANDS1 +simulator=ngspice +only_toplevel=false +value=" +.control +save all + +** OP simulation +op + +** All OP parameters + +let #####_M1_nmos_input_##### = 0 +let id_M1 = @m.x1.x1.xm1.m0[id] +let gm_M1 = @m.x1.x1.xm1.m0[gm] +let ro_M1 = 1/@m.x1.x1.xm1.m0[gds] +let Vgs_M1 = @m.x1.x1.xm1.m0[vgs] +let Vds_M1 = @m.x1.x1.xm1.m0[vds] +let Vsb_M1 = -@m.x1.x1.xm1.m0[vbs] +let Vdsat_M1 = @m.x1.x1.xm1.m0[vdsat] +let Vth_M1 = @m.x1.x1.xm1.m0[vth] +let ao_M1 = gm_M1*ro_M1 +let gmid_M1 = gm_M1/id_M1 +let fT_M1 = gm_M1/(6.283185*@m.x1.x1.xm1.m0[cgg]) +print #####_M1_nmos_input_##### id_M1 gm_M1 ro_M1 Vgs_M1 Vds_M1 Vsb_M1 Vdsat_M1 Vth_M1 ao_M1 gmid_M1 fT_M1 + +let #####_M2_nmos_input_##### = 0 +let id_M2 = @m.x1.x1.xm2.m0[id] +let gm_M2 = @m.x1.x1.xm2.m0[gm] +let ro_M2 = 1/@m.x1.x1.xm2.m0[gds] +let Vgs_M2 = @m.x1.x1.xm2.m0[vgs] +let Vds_M2 = @m.x1.x1.xm2.m0[vds] +let Vsb_M2 = -@m.x1.x1.xm2.m0[vbs] +let Vdsat_M2 = @m.x1.x1.xm2.m0[vdsat] +let Vth_M2 = @m.x1.x1.xm2.m0[vth] +let ao_M2 = gm_M2*ro_M2 +let gmid_M2 = gm_M2/id_M2 +let fT_M2 = gm_M2/(6.283185*@m.x1.x1.xm2.m0[cgg]) +print #####_M2_nmos_input_##### id_M2 gm_M2 ro_M2 Vgs_M2 Vds_M2 Vsb_M2 Vdsat_M2 Vth_M2 ao_M2 gmid_M2 fT_M2 + +let #####_M3_pmos_top_##### = 0 +let id_M3 = @m.x1.x1.xm3.m0[id] +let gm_M3 = @m.x1.x1.xm3.m0[gm] +let ro_M3 = 1/@m.x1.x1.xm3.m0[gds] +let Vsg_M3 = @m.x1.x1.xm3.m0[vgs] +let Vsd_M3 = @m.x1.x1.xm3.m0[vds] +let Vbs_M3 = -@m.x1.x1.xm3.m0[vbs] +let Vdsat_M3 = @m.x1.x1.xm3.m0[vdsat] +let Vth_M3 = @m.x1.x1.xm3.m0[vth] +let ao_M3 = gm_M3*ro_M3 +let gmid_M3 = gm_M3/id_M3 +let fT_M3 = gm_M3/(6.283185*@m.x1.x1.xm3.m0[cgg]) +print #####_M3_pmos_top_##### id_M3 gm_M3 ro_M3 Vsg_M3 Vsd_M3 Vbs_M3 Vdsat_M3 Vth_M3 ao_M3 gmid_M3 fT_M3 + +let #####_M4_pmos_top_##### = 0 +let id_M4 = @m.x1.x1.xm4.m0[id] +let gm_M4 = @m.x1.x1.xm4.m0[gm] +let ro_M4 = 1/@m.x1.x1.xm4.m0[gds] +let Vsg_M4 = @m.x1.x1.xm4.m0[vgs] +let Vsd_M4 = @m.x1.x1.xm4.m0[vds] +let Vbs_M4 = -@m.x1.x1.xm4.m0[vbs] +let Vdsat_M4 = @m.x1.x1.xm4.m0[vdsat] +let Vth_M4 = @m.x1.x1.xm4.m0[vth] +let ao_M4 = gm_M4*ro_M4 +let gmid_M4 = gm_M4/id_M4 +let fT_M4 = gm_M4/(6.283185*@m.x1.x1.xm4.m0[cgg]) +print #####_M4_pmos_top_##### id_M4 gm_M4 ro_M4 Vsg_M4 Vsd_M4 Vbs_M4 Vdsat_M4 Vth_M4 ao_M4 gmid_M4 fT_M4 + +let #####_M5_pmos_out_##### = 0 +let id_M5 = @m.x1.x1.xm5.m0[id] +let gm_M5 = @m.x1.x1.xm5.m0[gm] +let ro_M5 = 1/@m.x1.x1.xm5.m0[gds] +let Vsg_M5 = @m.x1.x1.xm5.m0[vgs] +let Vsd_M5 = @m.x1.x1.xm5.m0[vds] +let Vbs_M5 = -@m.x1.x1.xm5.m0[vbs] +let Vdsat_M5 = @m.x1.x1.xm5.m0[vdsat] +let Vth_M5 = @m.x1.x1.xm5.m0[vth] +let ao_M5 = gm_M5*ro_M5 +let gmid_M5 = gm_M5/id_M5 +let fT_M5 = gm_M5/(6.283185*@m.x1.x1.xm5.m0[cgg]) +print #####_M5_pmos_out_##### id_M5 gm_M5 ro_M5 Vsg_M5 Vsd_M5 Vbs_M5 Vdsat_M5 Vth_M5 ao_M5 gmid_M5 fT_M5 + +let #####_M6_pmos_out_##### = 0 +let id_M6 = @m.x1.x1.xm6.m0[id] +let gm_M6 = @m.x1.x1.xm6.m0[gm] +let ro_M6 = 1/@m.x1.x1.xm6.m0[gds] +let Vsg_M6 = @m.x1.x1.xm6.m0[vgs] +let Vsd_M6 = @m.x1.x1.xm6.m0[vds] +let Vbs_M6 = -@m.x1.x1.xm6.m0[vbs] +let Vdsat_M6 = @m.x1.x1.xm6.m0[vdsat] +let Vth_M6 = @m.x1.x1.xm6.m0[vth] +let ao_M6 = gm_M6*ro_M6 +let gmid_M6 = gm_M6/id_M6 +let fT_M6 = gm_M6/(6.283185*@m.x1.x1.xm6.m0[cgg]) +print #####_M6_pmos_out_##### id_M6 gm_M6 ro_M6 Vsg_M6 Vsd_M6 Vbs_M6 Vdsat_M6 Vth_M6 ao_M6 gmid_M6 fT_M6 + +let #####_M7_nmos_out_##### = 0 +let id_M7 = @m.x1.x1.xm7.m0[id] +let gm_M7 = @m.x1.x1.xm7.m0[gm] +let ro_M7 = 1/@m.x1.x1.xm7.m0[gds] +let Vgs_M7 = @m.x1.x1.xm7.m0[vgs] +let Vds_M7 = @m.x1.x1.xm7.m0[vds] +let Vsb_M7 = -@m.x1.x1.xm7.m0[vbs] +let Vdsat_M7 = @m.x1.x1.xm7.m0[vdsat] +let Vth_M7 = @m.x1.x1.xm7.m0[vth] +let ao_M7 = gm_M7*ro_M7 +let gmid_M7 = gm_M7/id_M7 +let fT_M7 = gm_M7/(6.283185*@m.x1.x1.xm7.m0[cgg]) +print #####_M7_nmos_out_##### id_M7 gm_M7 ro_M7 Vgs_M7 Vds_M7 Vsb_M7 Vdsat_M7 Vth_M7 ao_M7 gmid_M7 fT_M7 + +let #####_M8_nmos_out_##### = 0 +let id_M8 = @m.x1.x1.xm8.m0[id] +let gm_M8 = @m.x1.x1.xm8.m0[gm] +let ro_M8 = 1/@m.x1.x1.xm8.m0[gds] +let Vgs_M8 = @m.x1.x1.xm8.m0[vgs] +let Vds_M8 = @m.x1.x1.xm8.m0[vds] +let Vsb_M8 = -@m.x1.x1.xm8.m0[vbs] +let Vdsat_M8 = @m.x1.x1.xm8.m0[vdsat] +let Vth_M8 = @m.x1.x1.xm8.m0[vth] +let ao_M8 = gm_M8*ro_M8 +let gmid_M8 = gm_M8/id_M8 +let fT_M8 = gm_M8/(6.283185*@m.x1.x1.xm8.m0[cgg]) +print #####_M8_nmos_out_##### id_M8 gm_M8 ro_M8 Vgs_M8 Vds_M8 Vsb_M8 Vdsat_M8 Vth_M8 ao_M8 gmid_M8 fT_M8 + +let #####_M9_nmos_bottom_##### = 0 +let id_M9 = @m.x1.x1.xm9.m0[id] +let gm_M9 = @m.x1.x1.xm9.m0[gm] +let ro_M9 = 1/@m.x1.x1.xm9.m0[gds] +let Vgs_M9 = @m.x1.x1.xm9.m0[vgs] +let Vds_M9 = @m.x1.x1.xm9.m0[vds] +let Vsb_M9 = -@m.x1.x1.xm9.m0[vbs] +let Vdsat_M9 = @m.x1.x1.xm9.m0[vdsat] +let Vth_M9 = @m.x1.x1.xm9.m0[vth] +let ao_M9 = gm_M9*ro_M9 +let gmid_M9 = gm_M9/id_M9 +let fT_M9 = gm_M9/(6.283185*@m.x1.x1.xm9.m0[cgg]) +print #####_M9_nmos_bottom_##### id_M9 gm_M9 ro_M9 Vgs_M9 Vds_M9 Vsb_M9 Vdsat_M9 Vth_M9 ao_M9 gmid_M9 fT_M9 + +let #####_M10_nmos_bottom_##### = 0 +let id_M10 = @m.x1.x1.xm10.m0[id] +let gm_M10 = @m.x1.x1.xm10.m0[gm] +let ro_M10 = 1/@m.x1.x1.xm10.m0[gds] +let Vgs_M10 = @m.x1.x1.xm10.m0[vgs] +let Vds_M10 = @m.x1.x1.xm10.m0[vds] +let Vsb_M10 = @m.x1.x1.xm10.m0[vbs] +let Vdsat_M10 = @m.x1.x1.xm10.m0[vdsat] +let Vth_M10 = @m.x1.x1.xm10.m0[vth] +let ao_M10 = gm_M10*ro_M10 +let gmid_M10 = gm_M10/id_M10 +let fT_M10 = gm_M10/(6.283185*@m.x1.x1.xm10.m0[cgg]) +print #####_M10_nmos_bottom_##### id_M10 gm_M10 ro_M10 Vgs_M10 Vds_M10 Vsb_M10 Vdsat_M10 Vth_M10 ao_M10 gmid_M10 fT_M10 + +let #####_M11_nmos_mirror_##### = 0 +let id_M11 = @m.x1.x1.xm11.m0[id] +let gm_M11 = @m.x1.x1.xm11.m0[gm] +let ro_M11 = 1/@m.x1.x1.xm11.m0[gds] +let Vgs_M11 = @m.x1.x1.xm11.m0[vgs] +let Vds_M11 = @m.x1.x1.xm11.m0[vds] +let Vsb_M11 = -@m.x1.x1.xm11.m0[vbs] +let Vdsat_M11 = @m.x1.x1.xm11.m0[vdsat] +let Vth_M11 = @m.x1.x1.xm11.m0[vth] +let ao_M11 = gm_M11*ro_M11 +let gmid_M11 = gm_M11/id_M11 +let fT_M11 = gm_M11/(6.283185*@m.x1.x1.xm11.m0[cgg]) +print #####_M11_nmos_mirror_##### id_M11 gm_M11 ro_M11 Vgs_M11 Vds_M11 Vsb_M11 Vdsat_M11 Vth_M11 ao_M11 gmid_M11 fT_M11 + +** Custom output +let #####_Custom_output_##### = 0 + +* Power +let power = abs(i(V8))*VDD + +* DC_gain +let r1 = ao_M6*ro_M4 +let r2 = ao_M8*((ro_M1*ro_M10)/(ro_M1+ro_M10)) +let Rout = (r1*r2)/(r1+r2) +let Av = db(gm_M1*Rout) +* Bandwidth +let BW = 1/(Rout*1e-12*6.283185) + +print #####_Custom_output_##### Av BW Rout power gm_M1 ro_M1 ao_M6 ro_M4 ao_M8 ro_M10 + +write folded_cascode_op.raw + +.endc +"} +C {devices/vsource.sym} 360 -130 0 0 {name=V2 value=\{Vref\}} +C {devices/gnd.sym} 360 -90 0 0 {name=l1 lab=GND} +C {devices/lab_wire.sym} 360 -190 0 0 {name=p1 sig_type=std_logic lab=Vref} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_os.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_os.sch new file mode 100644 index 00000000..7f77b84e --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_os.sch @@ -0,0 +1,282 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 240 -60 240 -50 {lab=GND} +N 240 -150 240 -120 {lab=Vref} +N 80 -60 80 -50 {lab=GND} +N 80 -150 80 -120 {lab=VDD} +N 160 -60 160 -50 {lab=GND} +N 160 -150 160 -120 {lab=VSS} +N 960 -110 960 -50 { +lab=GND} +N 870 -220 960 -220 { +lab=Vout} +N 960 -220 960 -170 { +lab=Vout} +N 570 -250 670 -250 { +lab=#net1} +N 570 -320 570 -250 { +lab=#net1} +N 960 -320 960 -220 { +lab=Vout} +N 570 -60 570 -50 {lab=GND} +N 570 -150 570 -120 {lab=Vin} +N 570 -190 570 -150 { +lab=Vin} +N 590 -200 690 -200 { +lab=Vin} +N 670 -250 690 -250 {lab=#net1} +N 570 -200 590 -200 {lab=Vin} +N 570 -200 570 -190 {lab=Vin} +N 570 -320 650 -320 {lab=#net1} +N 710 -320 800 -320 {lab=#net2} +N 860 -320 960 -320 {lab=Vout} +C {devices/vsource.sym} 240 -90 0 0 {name=V1 value=\{Vref\}} +C {devices/gnd.sym} 240 -50 0 0 {name=l2 lab=GND} +C {devices/launcher.sym} 120 -370 0 0 {name=h3 +descr="Save & Netlist & sim" +tclcommand="xschem save; xschem netlist; xschem simulate"} +C {devices/lab_wire.sym} 240 -150 0 0 {name=p1 sig_type=std_logic lab=Vref} +C {devices/noconn.sym} 800 -160 0 1 {name=l4} +C {devices/lab_wire.sym} 760 -100 0 0 {name=p7 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 760 -120 0 0 {name=p8 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 80 -90 0 0 {name=V8 value=\{VDD\}} +C {devices/gnd.sym} 80 -50 0 0 {name=l5 lab=GND} +C {devices/lab_wire.sym} 80 -150 0 0 {name=p9 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 160 -90 0 0 {name=V5 value=\{VSS\}} +C {devices/gnd.sym} 160 -50 0 0 {name=l6 lab=GND} +C {devices/lab_wire.sym} 160 -150 0 0 {name=p10 sig_type=std_logic lab=VSS} +C {devices/capa.sym} 960 -140 0 0 {name=C1 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {devices/vsource.sym} 570 -90 0 0 {name=Vin value=\{Vin\}} +C {devices/gnd.sym} 570 -50 0 0 {name=l7 lab=GND} +C {devices/lab_wire.sym} 570 -150 0 0 {name=p11 sig_type=std_logic lab=Vin} +C {devices/lab_wire.sym} 960 -220 0 0 {name=p12 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 960 -50 0 0 {name=l8 lab=GND} +C {devices/code_shown.sym} 40 -500 0 0 {name=MODELS only_toplevel=true +format="tcleval( @value )" +value=" +.include $::180MCU_MODELS/design.ngspice +.lib $::180MCU_MODELS/sm141064.ngspice typical +"} +C {launcher.sym} 120 -300 0 0 {name=h1 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op"} +C {simulator_commands.sym} 820 -480 0 0 {name=COMMANDS +simulator=ngspice +only_toplevel=false +value=" +.control +save all + +** OP simulation +op +** Output swing +dc Vsweep 0 1.8 0.01 + +** All OP parameters +setplot op1 + +let #####_M1_nmos_input_##### = 0 +let id_M1 = @m.x1.x1.xm1.m0[id] +let gm_M1 = @m.x1.x1.xm1.m0[gm] +let ro_M1 = 1/@m.x1.x1.xm1.m0[gds] +let Vgs_M1 = @m.x1.x1.xm1.m0[vgs] +let Vds_M1 = @m.x1.x1.xm1.m0[vds] +let Vsb_M1 = -@m.x1.x1.xm1.m0[vbs] +let Vdsat_M1 = @m.x1.x1.xm1.m0[vdsat] +let Vth_M1 = @m.x1.x1.xm1.m0[vth] +let ao_M1 = gm_M1*ro_M1 +let gmid_M1 = gm_M1/id_M1 +let fT_M1 = gm_M1/(6.283185*@m.x1.x1.xm1.m0[cgg]) +print #####_M1_nmos_input_##### id_M1 gm_M1 ro_M1 Vgs_M1 Vds_M1 Vsb_M1 Vdsat_M1 Vth_M1 ao_M1 gmid_M1 fT_M1 + +let #####_M2_nmos_input_##### = 0 +let id_M2 = @m.x1.x1.xm2.m0[id] +let gm_M2 = @m.x1.x1.xm2.m0[gm] +let ro_M2 = 1/@m.x1.x1.xm2.m0[gds] +let Vgs_M2 = @m.x1.x1.xm2.m0[vgs] +let Vds_M2 = @m.x1.x1.xm2.m0[vds] +let Vsb_M2 = -@m.x1.x1.xm2.m0[vbs] +let Vdsat_M2 = @m.x1.x1.xm2.m0[vdsat] +let Vth_M2 = @m.x1.x1.xm2.m0[vth] +let ao_M2 = gm_M2*ro_M2 +let gmid_M2 = gm_M2/id_M2 +let fT_M2 = gm_M2/(6.283185*@m.x1.x1.xm2.m0[cgg]) +print #####_M2_nmos_input_##### id_M2 gm_M2 ro_M2 Vgs_M2 Vds_M2 Vsb_M2 Vdsat_M2 Vth_M2 ao_M2 gmid_M2 fT_M2 + +let #####_M3_pmos_top_##### = 0 +let id_M3 = @m.x1.x1.xm3.m0[id] +let gm_M3 = @m.x1.x1.xm3.m0[gm] +let ro_M3 = 1/@m.x1.x1.xm3.m0[gds] +let Vsg_M3 = @m.x1.x1.xm3.m0[vgs] +let Vsd_M3 = @m.x1.x1.xm3.m0[vds] +let Vbs_M3 = -@m.x1.x1.xm3.m0[vbs] +let Vdsat_M3 = @m.x1.x1.xm3.m0[vdsat] +let Vth_M3 = @m.x1.x1.xm3.m0[vth] +let ao_M3 = gm_M3*ro_M3 +let gmid_M3 = gm_M3/id_M3 +let fT_M3 = gm_M3/(6.283185*@m.x1.x1.xm3.m0[cgg]) +print #####_M3_pmos_top_##### id_M3 gm_M3 ro_M3 Vsg_M3 Vsd_M3 Vbs_M3 Vdsat_M3 Vth_M3 ao_M3 gmid_M3 fT_M3 + +let #####_M4_pmos_top_##### = 0 +let id_M4 = @m.x1.x1.xm4.m0[id] +let gm_M4 = @m.x1.x1.xm4.m0[gm] +let ro_M4 = 1/@m.x1.x1.xm4.m0[gds] +let Vsg_M4 = @m.x1.x1.xm4.m0[vgs] +let Vsd_M4 = @m.x1.x1.xm4.m0[vds] +let Vbs_M4 = -@m.x1.x1.xm4.m0[vbs] +let Vdsat_M4 = @m.x1.x1.xm4.m0[vdsat] +let Vth_M4 = @m.x1.x1.xm4.m0[vth] +let ao_M4 = gm_M4*ro_M4 +let gmid_M4 = gm_M4/id_M4 +let fT_M4 = gm_M4/(6.283185*@m.x1.x1.xm4.m0[cgg]) +print #####_M4_pmos_top_##### id_M4 gm_M4 ro_M4 Vsg_M4 Vsd_M4 Vbs_M4 Vdsat_M4 Vth_M4 ao_M4 gmid_M4 fT_M4 + +let #####_M5_pmos_out_##### = 0 +let id_M5 = @m.x1.x1.xm5.m0[id] +let gm_M5 = @m.x1.x1.xm5.m0[gm] +let ro_M5 = 1/@m.x1.x1.xm5.m0[gds] +let Vsg_M5 = @m.x1.x1.xm5.m0[vgs] +let Vsd_M5 = @m.x1.x1.xm5.m0[vds] +let Vbs_M5 = -@m.x1.x1.xm5.m0[vbs] +let Vdsat_M5 = @m.x1.x1.xm5.m0[vdsat] +let Vth_M5 = @m.x1.x1.xm5.m0[vth] +let ao_M5 = gm_M5*ro_M5 +let gmid_M5 = gm_M5/id_M5 +let fT_M5 = gm_M5/(6.283185*@m.x1.x1.xm5.m0[cgg]) +print #####_M5_pmos_out_##### id_M5 gm_M5 ro_M5 Vsg_M5 Vsd_M5 Vbs_M5 Vdsat_M5 Vth_M5 ao_M5 gmid_M5 fT_M5 + +let #####_M6_pmos_out_##### = 0 +let id_M6 = @m.x1.x1.xm6.m0[id] +let gm_M6 = @m.x1.x1.xm6.m0[gm] +let ro_M6 = 1/@m.x1.x1.xm6.m0[gds] +let Vsg_M6 = @m.x1.x1.xm6.m0[vgs] +let Vsd_M6 = @m.x1.x1.xm6.m0[vds] +let Vbs_M6 = -@m.x1.x1.xm6.m0[vbs] +let Vdsat_M6 = @m.x1.x1.xm6.m0[vdsat] +let Vth_M6 = @m.x1.x1.xm6.m0[vth] +let ao_M6 = gm_M6*ro_M6 +let gmid_M6 = gm_M6/id_M6 +let fT_M6 = gm_M6/(6.283185*@m.x1.x1.xm6.m0[cgg]) +print #####_M6_pmos_out_##### id_M6 gm_M6 ro_M6 Vsg_M6 Vsd_M6 Vbs_M6 Vdsat_M6 Vth_M6 ao_M6 gmid_M6 fT_M6 + +let #####_M7_nmos_out_##### = 0 +let id_M7 = @m.x1.x1.xm7.m0[id] +let gm_M7 = @m.x1.x1.xm7.m0[gm] +let ro_M7 = 1/@m.x1.x1.xm7.m0[gds] +let Vgs_M7 = @m.x1.x1.xm7.m0[vgs] +let Vds_M7 = @m.x1.x1.xm7.m0[vds] +let Vsb_M7 = -@m.x1.x1.xm7.m0[vbs] +let Vdsat_M7 = @m.x1.x1.xm7.m0[vdsat] +let Vth_M7 = @m.x1.x1.xm7.m0[vth] +let ao_M7 = gm_M7*ro_M7 +let gmid_M7 = gm_M7/id_M7 +let fT_M7 = gm_M7/(6.283185*@m.x1.x1.xm7.m0[cgg]) +print #####_M7_nmos_out_##### id_M7 gm_M7 ro_M7 Vgs_M7 Vds_M7 Vsb_M7 Vdsat_M7 Vth_M7 ao_M7 gmid_M7 fT_M7 + +let #####_M8_nmos_out_##### = 0 +let id_M8 = @m.x1.x1.xm8.m0[id] +let gm_M8 = @m.x1.x1.xm8.m0[gm] +let ro_M8 = 1/@m.x1.x1.xm8.m0[gds] +let Vgs_M8 = @m.x1.x1.xm8.m0[vgs] +let Vds_M8 = @m.x1.x1.xm8.m0[vds] +let Vsb_M8 = -@m.x1.x1.xm8.m0[vbs] +let Vdsat_M8 = @m.x1.x1.xm8.m0[vdsat] +let Vth_M8 = @m.x1.x1.xm8.m0[vth] +let ao_M8 = gm_M8*ro_M8 +let gmid_M8 = gm_M8/id_M8 +let fT_M8 = gm_M8/(6.283185*@m.x1.x1.xm8.m0[cgg]) +print #####_M8_nmos_out_##### id_M8 gm_M8 ro_M8 Vgs_M8 Vds_M8 Vsb_M8 Vdsat_M8 Vth_M8 ao_M8 gmid_M8 fT_M8 + +let #####_M9_nmos_bottom_##### = 0 +let id_M9 = @m.x1.x1.xm9.m0[id] +let gm_M9 = @m.x1.x1.xm9.m0[gm] +let ro_M9 = 1/@m.x1.x1.xm9.m0[gds] +let Vgs_M9 = @m.x1.x1.xm9.m0[vgs] +let Vds_M9 = @m.x1.x1.xm9.m0[vds] +let Vsb_M9 = -@m.x1.x1.xm9.m0[vbs] +let Vdsat_M9 = @m.x1.x1.xm9.m0[vdsat] +let Vth_M9 = @m.x1.x1.xm9.m0[vth] +let ao_M9 = gm_M9*ro_M9 +let gmid_M9 = gm_M9/id_M9 +let fT_M9 = gm_M9/(6.283185*@m.x1.x1.xm9.m0[cgg]) +print #####_M9_nmos_bottom_##### id_M9 gm_M9 ro_M9 Vgs_M9 Vds_M9 Vsb_M9 Vdsat_M9 Vth_M9 ao_M9 gmid_M9 fT_M9 + +let #####_M10_nmos_bottom_##### = 0 +let id_M10 = @m.x1.x1.xm10.m0[id] +let gm_M10 = @m.x1.x1.xm10.m0[gm] +let ro_M10 = 1/@m.x1.x1.xm10.m0[gds] +let Vgs_M10 = @m.x1.x1.xm10.m0[vgs] +let Vds_M10 = @m.x1.x1.xm10.m0[vds] +let Vsb_M10 = @m.x1.x1.xm10.m0[vbs] +let Vdsat_M10 = @m.x1.x1.xm10.m0[vdsat] +let Vth_M10 = @m.x1.x1.xm10.m0[vth] +let ao_M10 = gm_M10*ro_M10 +let gmid_M10 = gm_M10/id_M10 +let fT_M10 = gm_M10/(6.283185*@m.x1.x1.xm10.m0[cgg]) +print #####_M10_nmos_bottom_##### id_M10 gm_M10 ro_M10 Vgs_M10 Vds_M10 Vsb_M10 Vdsat_M10 Vth_M10 ao_M10 gmid_M10 fT_M10 + +let #####_M11_nmos_mirror_##### = 0 +let id_M11 = @m.x1.x1.xm11.m0[id] +let gm_M11 = @m.x1.x1.xm11.m0[gm] +let ro_M11 = 1/@m.x1.x1.xm11.m0[gds] +let Vgs_M11 = @m.x1.x1.xm11.m0[vgs] +let Vds_M11 = @m.x1.x1.xm11.m0[vds] +let Vsb_M11 = -@m.x1.x1.xm11.m0[vbs] +let Vdsat_M11 = @m.x1.x1.xm11.m0[vdsat] +let Vth_M11 = @m.x1.x1.xm11.m0[vth] +let ao_M11 = gm_M11*ro_M11 +let gmid_M11 = gm_M11/id_M11 +let fT_M11 = gm_M11/(6.283185*@m.x1.x1.xm11.m0[cgg]) +print #####_M11_nmos_mirror_##### id_M11 gm_M11 ro_M11 Vgs_M11 Vds_M11 Vsb_M11 Vdsat_M11 Vth_M11 ao_M11 gmid_M11 fT_M11 + +** Custom output +let #####_Custom_output_##### = 0 +* Power +let power = abs(i(V8))*VDD +* DC_gain +let r1 = ao_M6*ro_M4 +let r2 = ao_M8*((ro_M1*ro_M10)/(ro_M1+ro_M10)) +let Rout = (r1*r2)/(r1+r2) +let Av = db(gm_M1*Rout) +* Bandwidth +let BW = 1/(Rout*1e-12*6.283185) + +print #####_Custom_output_##### Av BW Rout power gm_M1 ro_M1 gm_M6 ro_M6 ro_M4 gm_M8 ro_M8 ro_M10 + +write folded_cascode_os.raw + +setplot dc1 +let dvout = deriv(v(Vout)) + +meas dc limmin when dvout=0.98 rise=1 +meas dc limmax when dvout=0.98 fall=1 + +let Output_swing = limmax - limmin + +print Output_swing +plot dvout + + + +.endc +"} +C {devices/code_shown.sym} 540 -500 0 0 {name=Voltage_sources only_toplevel=true +value=" +.param VDD = 1.8 +.param VSS = 0 +.param Vref = 1 +.param Vin = 1 +.param Vsweep = 0 +"} +C {devices/lab_wire.sym} 760 -140 0 0 {name=p4 sig_type=std_logic lab=Vref} +C {devices/vsource.sym} 830 -320 1 0 {name=Vsweep value=\{Vsweep\}} +C {devices/vsource.sym} 680 -320 3 1 {name=V3 value=\{Vin\}} +C {gf180/error_amplifier_N_input/xschem/error_amplifier_N_input.sym} 780 -220 0 0 {name=x1} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_psrr.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_psrr.sch new file mode 100644 index 00000000..a320bec3 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_psrr.sch @@ -0,0 +1,168 @@ +v {xschem version=3.4.6 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 110 -120 110 -100 { +lab=GND} +N 110 -220 110 -180 { +lab=VSS} +N 190 -120 190 -100 { +lab=GND} +N 110 -100 110 -80 { +lab=GND} +N 190 -220 190 -180 { +lab=VDD} +N 190 -100 190 -80 { +lab=GND} +N 270 -120 270 -100 { +lab=GND} +N 270 -220 270 -180 { +lab=Vref} +N 270 -100 270 -80 { +lab=GND} +N 850 -540 910 -540 {lab=Vout} +N 1060 -410 1060 -330 { +lab=VSS} +N 1060 -540 1060 -480 { +lab=Vout} +N 910 -540 1060 -540 { +lab=Vout} +N 490 -520 670 -520 { +lab=Vref} +N 1060 -480 1060 -470 { +lab=Vout} +N 560 -570 670 -570 { +lab=Vout} +N 560 -650 560 -570 { +lab=Vout} +N 560 -650 910 -650 { +lab=Vout} +N 910 -650 910 -540 { +lab=Vout} +C {sky130_fd_pr/corner.sym} 60 -390 0 0 {name=CORNER only_toplevel=true corner=tt} +C {simulator_commands.sym} 210 -390 0 0 {name="COMMANDS" +simulator="ngspice" +only_toplevel="false" +value=" +.param VDD=1.8 +.param Vref=1.2 +.save + +* Operation point of the folded cascode core + +*nfet + ++ @m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[id] + +*pfet + ++ @m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[id] + ++ @m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[id] + ++ @m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[id] + ++ @m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[id] + +* Operation point of the folded cascode bias + + ++ abstol=1e-14 savecurrents +.control + save all + op + remzerovec + write folded_cascode_psrr.raw + set appendwrite + + * run ac simulation + ac dec 20 1 100e7 + + * measure parameters + let vout_mag = db(abs(v(Vout))) + let vout_phase = cph(v(Vout)) * 180/pi + + meas ac PSR find vout_mag at=1e2 + + + plot vout_mag + + write folded_cascode_psrr.raw +.endc +"} +C {devices/vsource.sym} 110 -150 0 0 {name=V0 value=0 savecurrent=false} +C {devices/gnd.sym} 110 -80 0 0 {name=l5 lab=GND} +C {devices/vsource.sym} 190 -150 0 0 {name=V2 value="dc \{VDD\} ac 1" savecurrent=false} +C {devices/lab_wire.sym} 110 -220 0 0 {name=p25 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 190 -220 0 0 {name=p26 sig_type=std_logic lab=VDD} +C {devices/gnd.sym} 190 -80 0 0 {name=l6 lab=GND} +C {devices/vsource.sym} 270 -150 0 0 {name=V4 value=\{Vref\} savecurrent=false} +C {devices/lab_wire.sym} 270 -220 0 0 {name=p27 sig_type=std_logic lab=Vref} +C {devices/gnd.sym} 270 -80 0 0 {name=l7 lab=GND} +C {devices/launcher.sym} 160 -510 0 0 {name=h15 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op" +} +C {devices/launcher.sym} 160 -580 0 0 {name=h3 +descr="Netlist & sim" +tclcommand="xschem netlist; xschem simulate"} +C {lab_pin.sym} 740 -460 2 1 {name=p7 sig_type=std_logic lab=Vref} +C {lab_pin.sym} 740 -440 2 1 {name=p8 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 740 -420 2 1 {name=p9 sig_type=std_logic lab=VSS} +C {lab_pin.sym} 490 -520 2 1 {name=p10 sig_type=std_logic lab=Vref} +C {capa.sym} 1060 -440 0 0 {name=C1 +m=1 +value=1p +footprint=1206 +device="ceramic capacitor"} +C {lab_pin.sym} 1060 -330 2 1 {name=p1 sig_type=std_logic lab=VSS} +C {noconn.sym} 780 -480 2 0 {name=l1} +C {lab_pin.sym} 1060 -540 0 1 {name=p2 sig_type=std_logic lab=Vout} +C {/foss/designs/chipathon_2025/designs/sky130/error_amplifier_N_input/xschem/error_amplifier_N_input.sym} 760 -540 0 0 {name=x1} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_sr.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_sr.sch new file mode 100644 index 00000000..71c2fb78 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/folded_cascode_sr.sch @@ -0,0 +1,190 @@ +v {xschem version=3.4.6 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 110 -120 110 -100 { +lab=GND} +N 110 -220 110 -180 { +lab=VSS} +N 190 -120 190 -100 { +lab=GND} +N 110 -100 110 -80 { +lab=GND} +N 190 -220 190 -180 { +lab=VDD} +N 190 -100 190 -80 { +lab=GND} +N 270 -120 270 -100 { +lab=GND} +N 270 -220 270 -180 { +lab=Vref} +N 270 -100 270 -80 { +lab=GND} +N 850 -540 910 -540 {lab=Vout} +N 1060 -410 1060 -330 { +lab=VSS} +N 1060 -540 1060 -480 { +lab=Vout} +N 910 -540 1060 -540 { +lab=Vout} +N 490 -520 670 -520 { +lab=Vin} +N 1060 -480 1060 -470 { +lab=Vout} +N 560 -570 670 -570 { +lab=Vout} +N 560 -650 560 -570 { +lab=Vout} +N 560 -650 910 -650 { +lab=Vout} +N 910 -650 910 -540 { +lab=Vout} +N 350 -220 350 -180 { +lab=Vin} +N 350 -120 350 -100 { +lab=GND} +N 350 -100 350 -80 { +lab=GND} +C {sky130_fd_pr/corner.sym} 60 -390 0 0 {name=CORNER only_toplevel=true corner=tt} +C {simulator_commands.sym} 210 -390 0 0 {name="COMMANDS" +simulator="ngspice" +only_toplevel="false" +value=" +.param VDD=1.8 +.param Vref=1.2 +.param V1 = 0.01 +.param V2 = 1.8 +.param TR = 50n +.param TF = TR +.param PER = 2m +.param TD = 0.05*PER +.param PWM = PER/2 +.save + +* Operation point of the folded cascode core + +*nfet + ++ @m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm1.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm2.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm7.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm8.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm9.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm10.msky130_fd_pr__nfet_01v8[id] + ++ @m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[gm] ++ v(@m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[vth]) ++ @m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[gds] ++ @m.x1.x2.xm11.msky130_fd_pr__nfet_01v8[id] + +*pfet + ++ @m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm3.msky130_fd_pr__pfet_01v8_lvt[id] + ++ @m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm4.msky130_fd_pr__pfet_01v8_lvt[id] + ++ @m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm5.msky130_fd_pr__pfet_01v8_lvt[id] + ++ @m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[gm] ++ v(@m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[vth]) ++ @m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[gds] ++ @m.x1.x2.xm6.msky130_fd_pr__pfet_01v8_lvt[id] + +* Operation point of the folded cascode bias + + ++ abstol=1e-14 savecurrents +.control + save all + op + remzerovec + write folded_cascode_sr.raw + set appendwrite + + * run ac simulation + tran 25n 2m + + * measure parameters + let dVout = deriv(Vout)/1e6 + meas tran SRplus MAX dVout + meas tran SRminus MIN dVout + + meas tran Voutmax MAX Vout + meas tran Voutmin MIN Vout + let Output_swing = Voutmax-Voutmin + print Output_swing + + plot Vout Vin + + write folded_cascode_sr.raw +.endc +" +} +C {devices/vsource.sym} 110 -150 0 0 {name=V0 value=0 savecurrent=false} +C {devices/gnd.sym} 110 -80 0 0 {name=l5 lab=GND} +C {devices/vsource.sym} 190 -150 0 0 {name=V2 value=\{VDD\} savecurrent=false} +C {devices/lab_wire.sym} 110 -220 0 0 {name=p25 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 190 -220 0 0 {name=p26 sig_type=std_logic lab=VDD} +C {devices/gnd.sym} 190 -80 0 0 {name=l6 lab=GND} +C {devices/vsource.sym} 270 -150 0 0 {name=V4 value=\{Vref\} savecurrent=false} +C {devices/lab_wire.sym} 270 -220 0 0 {name=p27 sig_type=std_logic lab=Vref} +C {devices/gnd.sym} 270 -80 0 0 {name=l7 lab=GND} +C {devices/launcher.sym} 160 -510 0 0 {name=h15 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op" +} +C {devices/launcher.sym} 160 -580 0 0 {name=h3 +descr="Netlist & sim" +tclcommand="xschem netlist; xschem simulate"} +C {lab_pin.sym} 740 -460 2 1 {name=p7 sig_type=std_logic lab=Vref} +C {lab_pin.sym} 740 -440 2 1 {name=p8 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 740 -420 2 1 {name=p9 sig_type=std_logic lab=VSS} +C {lab_pin.sym} 490 -520 2 1 {name=p10 sig_type=std_logic lab=Vin} +C {capa.sym} 1060 -440 0 0 {name=C1 +m=1 +value=1p +footprint=1206 +device="ceramic capacitor"} +C {lab_pin.sym} 1060 -330 2 1 {name=p1 sig_type=std_logic lab=VSS} +C {noconn.sym} 780 -480 2 0 {name=l1} +C {lab_pin.sym} 1060 -540 0 1 {name=p2 sig_type=std_logic lab=Vout} +C {vsource.sym} 350 -150 0 0 {name=V3 value="pulse(\{V1\} \{V2\} \{TD\} \{TR\} \{TF\} \{PWM\} \{PER\})" savecurrent=false +*pulse(0.01 1.8 \{TD\} \{TR\} \{TF\} \{PWM\} \{PER\}) +*sin(0.9 0.8 1k)} +C {devices/lab_wire.sym} 350 -220 0 0 {name=p3 sig_type=std_logic lab=Vin} +C {devices/gnd.sym} 350 -80 0 0 {name=l2 lab=GND} +C {/foss/designs/chipathon_2025/designs/sky130/error_amplifier_N_input/xschem/error_amplifier_N_input.sym} 760 -540 0 0 {name=x1} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/xschemrc b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/xschemrc new file mode 100644 index 00000000..9a6a4bd6 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_N_input/xschem/xschemrc @@ -0,0 +1,7 @@ +# Source the PDK xschemrc file +if {![info exists PDK]} { + source $env(PDK_ROOT)/$env(PDK)/libs.tech/xschem/xschemrc +} + +# Add current directory to xschem library path +append XSCHEM_LIBRARY_PATH :[file dirname [info script]] diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/error_amplifier_bias_N_input.yaml b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/error_amplifier_bias_N_input.yaml new file mode 100644 index 00000000..3a051e39 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/error_amplifier_bias_N_input.yaml @@ -0,0 +1,241 @@ +#-------------------------------------------------------------- +# CACE circuit characterization file +#-------------------------------------------------------------- + +name: error_amplifier_bias_N_input +description: Bias Circuit for the folded cascode +PDK: sky130A + +cace_format: 5.2 + +authorship: + designer: Jorge Walter + company: Onchip + creation_date: May 10, 2024 + license: Apache 2.0 + +paths: + root: .. + schematic: xschem + layout: gds + netlist: netlist + documentation: docs + +pins: + VDD: + description: Positive analog power supply + type: power + direction: inout + Vmin: 1.7 + Vmax: 1.9 + VSS: + description: Analog ground + type: ground + direction: inout + Vref: + description: Reference BandGap Voltage + type: power + direction: inout + VbiasP2: + description: Output Bias Voltage 1 + type: power + direction: inout + VbiasN2: + description: Output Bias Voltage 2 + type: power + direction: inout + VbiasN1: + description: Output Bias Voltage 3 + type: power + direction: inout + +default_conditions: + VDD: + description: Analog power supply voltage + display: VDD + unit: V + typical: 1.8 + Vref: + description: Input common mode voltage + display: Vref + unit: V + typical: 1.2 + corner: + description: Process corner + display: Corner + typical: tt + temperature: + description: Ambient temperature + display: Temp + unit: °C + typical: 27 + +parameters: + dc_params: + display: DC Params + spec: + VbiasP2: + display: VbiasP2 + description: Voltage of VbiasP2 + unit: V + minimum: + value: 0.55 + typical: + value: 0.65 + maximum: + value: 0.75 + VbiasN2: + display: VbiasN2 + description: Voltage of VbiasN2 + unit: V + minimum: + value: 1.1 + typical: + value: 1.2 + maximum: + value: 1.3 + VbiasN1: + display: VbiasN1 + description: Voltage of VbiasN1 + unit: V + minimum: + value: 0.8 + typical: + value: 0.9 + maximum: + value: 1 + + tool: + ngspice: + template: folded_cascode_bias_OP_CACE.sch + format: ascii + suffix: .data + variables: [VbiasP2, VbiasN2, VbiasN1] + + plot: + VbiasP2_vs_temp: + type: xyplot + xaxis: temperature + yaxis: VbiasP2 + VbiasP2_vs_corner: + type: xyplot + xaxis: corner + yaxis: VbiasP2 + VbiasP2_vs_vdd: + type: xyplot + xaxis: VDD + yaxis: VbiasP2 + VbiasN2_vs_temp: + type: xyplot + xaxis: temperature + yaxis: VbiasN2 + VbiasN2_vs_corner: + type: xyplot + xaxis: corner + yaxis: VbiasN2 + VbiasN2_vs_vdd: + type: xyplot + xaxis: VDD + yaxis: VbiasN2 + VbiasN1_vs_temp: + type: xyplot + xaxis: temperature + yaxis: VbiasN1 + VbiasN1_vs_corner: + type: xyplot + xaxis: corner + yaxis: VbiasN1 + VbiasN1_vs_vdd: + type: xyplot + xaxis: VDD + yaxis: VbiasN1 + + conditions: + corner: + enumerate: [ss, tt, ff, fs, sf] + VDD: + minimum: 1.7 + typical: 1.8 + maximum: 1.9 + temperature: + minimum: -40 + typical: 27 + maximum: 125 + + magic_area: + spec: + area: + display: Area + description: Total circuit layout area + unit: um2 + maximum: + value: any + width: + display: Width + description: Total circuit layout width + unit: um + maximum: + value: any + height: + display: Height + description: Total circuit layout height + unit: um + maximum: + value: any + tool: + magic_area + + magic_drc: + description: Magic DRC + display: Magic DRC + spec: + drc_errors: + maximum: + value: 0 + tool: + magic_drc: + gds_flatten: true + + netgen_lvs: + description: Netgen LVS + display: Netgen LVS + spec: + lvs_errors: + maximum: + value: 0 + tool: + netgen_lvs: + script: run_project_lvs.tcl + + klayout_drc_feol: + description: KLayout DRC feol + display: KLayout DRC feol + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ['-rd', 'feol=true'] + + klayout_drc_beol: + description: KLayout DRC beol + display: KLayout DRC beol + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ['-rd', 'beol=true'] + + klayout_drc_full: + description: KLayout DRC full + display: KLayout DRC full + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ['-rd', 'feol=true', '-rd', 'beol=true', '-rd', 'offgrid=true'] diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/scripts/run_project_lvs.tcl b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/scripts/run_project_lvs.tcl new file mode 100644 index 00000000..cbac0cca --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/scripts/run_project_lvs.tcl @@ -0,0 +1,14 @@ +# NOTE: PDK_ROOT, PDK and CACE_ROOT are set in the local environment by CACE +# +# This is an example script to drive LVS; because this is a simple +# example, there is no specific benefit of using this instead of the +# default handling in CACE. + +set PDK_ROOT $::env(PDK_ROOT) +set PDK $::env(PDK) +set CACE_ROOT $::env(CACE_ROOT) + +set circuit1 [readnet spice $CACE_ROOT/netlist/layout/error_amplifier_bias_N_input.spice] +set circuit2 [readnet spice $CACE_ROOT/netlist/schematic/error_amplifier_bias_N_input.spice] + +lvs "$circuit1 error_amplifier_bias_N_input" "$circuit2 error_amplifier_bias_N_input" $PDK_ROOT/$PDK/libs.tech/netgen/${PDK}_setup.tcl error_amplifier_bias_N_input.out -json diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/templates/folded_cascode_bias_OP_CACE.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/templates/folded_cascode_bias_OP_CACE.sch new file mode 100644 index 00000000..4c6f33cd --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/templates/folded_cascode_bias_OP_CACE.sch @@ -0,0 +1,71 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +P 4 1 400 -580 {} +N 430 -360 430 -320 { +lab=GND} +N 430 -460 430 -420 { +lab=VSS} +N 510 -360 510 -320 { +lab=GND} +N 510 -460 510 -420 { +lab=VDD} +N 590 -360 590 -320 { +lab=GND} +N 590 -460 590 -420 { +lab=Vref} +C {devices/vsource.sym} 430 -390 0 0 {name=V0 value=0 savecurrent=false} +C {devices/gnd.sym} 430 -320 0 0 {name=l3 lab=GND} +C {devices/vsource.sym} 510 -390 0 0 {name=V2 value=CACE\{VDD\} savecurrent=false} +C {devices/lab_wire.sym} 430 -460 0 0 {name=p12 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 510 -460 0 0 {name=p13 sig_type=std_logic lab=VDD} +C {devices/gnd.sym} 510 -320 0 0 {name=l4 lab=GND} +C {devices/vsource.sym} 590 -390 0 0 {name=V4 value=\{Vref\} savecurrent=false} +C {devices/lab_wire.sym} 590 -460 0 0 {name=p14 sig_type=std_logic lab=Vref} +C {devices/gnd.sym} 590 -320 0 0 {name=l5 lab=GND} +C {error_amplifier_bias_N_input.sym} 850 -430 0 0 {name=x1} +C {lab_pin.sym} 730 -450 0 0 {name=p8 sig_type=std_logic lab=Vref} +C {lab_pin.sym} 730 -430 0 0 {name=p1 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 730 -410 0 0 {name=p2 sig_type=std_logic lab=VSS} +C {noconn.sym} 970 -450 2 0 {name=l1} +C {noconn.sym} 970 -430 2 0 {name=l2} +C {noconn.sym} 970 -410 2 0 {name=l6} +C {simulator_commands.sym} 300 -620 0 0 {name=OP only_toplevel="true" value=" +.param Vref=1.2 +.save + +.control +save all +op + +* Obtener voltajes en los nodos +let VbiasP2_voltage = v(net3) +let VbiasN2_voltage = v(net2) +let VbiasN1_voltage = v(net1) + +* Imprimir voltajes en la consola +print VbiasP2_voltage VbiasN2_voltage VbiasN1_voltage + +* Echo para guardar los voltajes en un archivo de datos +echo $&VbiasP2_voltage $&VbiasN2_voltage $&VbiasN1_voltage > CACE\{simpath\}/CACE\{filename\}_CACE\{N\}.data + +.endc +"} +C {devices/code_shown.sym} 450 -700 0 0 {name=SETUP +simulator=ngspice +only_toplevel=false +value=" +.lib CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/combined/sky130.lib.spice CACE\{corner\} + +.include CACE\{DUT_path\} + +.temp CACE\{temperature\} + +.option SEED=CACE[CACE\{seed=12345\} + CACE\{iterations=0\}] + +* Flag unsafe operating conditions (exceeds models' specified limits) +.option warn=1 +"} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/templates/xschemrc b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/templates/xschemrc new file mode 100644 index 00000000..589dc429 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/cace/templates/xschemrc @@ -0,0 +1,10 @@ +# Source the PDK xschemrc file +if {![info exists PDK]} { + source $env(PDK_ROOT)/$env(PDK)/libs.tech/xschem/xschemrc +} + +# Add current directory +append XSCHEM_LIBRARY_PATH :[file dirname [info script]] + +# Source project xschemrc +source [file dirname [info script]]/../../xschem/xschemrc diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/gds/make_pcells_static.py b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/gds/make_pcells_static.py new file mode 100644 index 00000000..7c9c9fd7 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/gds/make_pcells_static.py @@ -0,0 +1,21 @@ +import pya +import klayout.db as db + +ly = pya.Layout() +ly.read("folded_cascode_bias_pcells.gds") + +""" +# collect the cells to convert: +insts_to_convert = [] +for inst in ly.top_cell().each_inst(): + if inst.is_pcell(): + insts_to_convert.append(inst) + +for inst in insts_to_convert: + inst.convert_to_static() +""" + +ctx = db.SaveLayoutOptions() +ctx.write_context_info = False + +ly.write("folded_cascode_bias.gds", ctx) diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/error_amplifier_bias_N_input.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/error_amplifier_bias_N_input.sch new file mode 100644 index 00000000..148360a9 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/error_amplifier_bias_N_input.sch @@ -0,0 +1,437 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +P 4 1 -210 -330 {} +T {BIAS CIRCUIT +} 640 -70 0 1 0.4 0.4 {} +T {650mV} 900 -570 0 1 0.35 0.35 {} +N 130 -290 130 -240 {lab=#net1} +N 70 -320 90 -320 {lab=Vref} +N 70 -210 90 -210 {lab=Vref} +N 70 -320 70 -210 {lab=Vref} +N 130 -180 130 -110 {lab=VSS} +N 130 -320 140 -320 {lab=VSS} +N 130 -210 140 -210 {lab=VSS} +N 140 -320 140 -210 {lab=VSS} +N 140 -210 140 -110 {lab=VSS} +N 130 -110 140 -110 {lab=VSS} +N 130 -550 130 -350 {lab=VbiasP1} +N 130 -670 130 -610 {lab=VDD} +N 130 -690 130 -670 {lab=VDD} +N 120 -580 130 -580 {lab=VDD} +N 120 -690 120 -580 {lab=VDD} +N 120 -690 130 -690 {lab=VDD} +N 170 -580 290 -580 {lab=VbiasP1} +N 130 -510 230 -510 {lab=VbiasP1} +N 230 -580 230 -510 {lab=VbiasP1} +N 130 -690 330 -690 {lab=VDD} +N 330 -690 330 -610 {lab=VDD} +N 330 -580 340 -580 {lab=VDD} +N 340 -690 340 -580 {lab=VDD} +N 330 -690 340 -690 {lab=VDD} +N 330 -550 330 -350 {lab=VbiasN2} +N 330 -290 330 -270 {lab=#net2} +N 330 -210 330 -110 {lab=VSS} +N 140 -110 330 -110 {lab=VSS} +N 320 -320 330 -320 {lab=VSS} +N 320 -240 330 -240 {lab=VSS} +N 320 -320 320 -240 {lab=VSS} +N 320 -240 320 -110 {lab=VSS} +N 330 -410 410 -410 {lab=VbiasN2} +N 410 -410 410 -240 {lab=VbiasN2} +N 370 -240 410 -240 {lab=VbiasN2} +N 370 -320 410 -320 {lab=VbiasN2} +N 340 -690 570 -690 {lab=VDD} +N 570 -690 570 -610 {lab=VDD} +N 570 -580 580 -580 {lab=VDD} +N 580 -690 580 -580 {lab=VDD} +N 570 -690 580 -690 {lab=VDD} +N 470 -580 530 -580 {lab=VbiasP1} +N 330 -110 570 -110 {lab=VSS} +N 570 -140 570 -110 {lab=VSS} +N 560 -170 570 -170 {lab=VSS} +N 560 -170 560 -110 {lab=VSS} +N 560 -250 560 -170 {lab=VSS} +N 560 -250 570 -250 {lab=VSS} +N 570 -340 570 -280 {lab=#net3} +N 570 -550 570 -400 {lab=VbiasN1} +N 610 -250 650 -250 {lab=VbiasN1} +N 650 -250 650 -170 {lab=VbiasN1} +N 610 -170 650 -170 {lab=VbiasN1} +N 830 -340 830 -280 {lab=#net4} +N 830 -220 830 -200 {lab=#net5} +N 830 -140 830 -110 {lab=VSS} +N 570 -110 830 -110 {lab=VSS} +N 790 -250 790 -170 {lab=VbiasN1} +N 790 -210 790 -170 {lab=VbiasN1} +N 650 -210 790 -210 {lab=VbiasN1} +N 570 -450 710 -450 {lab=VbiasN1} +N 710 -450 710 -210 {lab=VbiasN1} +N 610 -370 790 -370 {lab=VbiasN2} +N 830 -370 840 -370 {lab=VSS} +N 840 -370 840 -110 {lab=VSS} +N 830 -110 840 -110 {lab=VSS} +N 830 -170 840 -170 {lab=VSS} +N 830 -250 840 -250 {lab=VSS} +N 830 -490 830 -400 {lab=VbiasP2} +N 830 -590 830 -550 {lab=#net6} +N 830 -690 830 -650 {lab=VDD} +N 580 -690 830 -690 {lab=VDD} +N 820 -620 830 -620 {lab=VDD} +N 820 -690 820 -620 {lab=VDD} +N 820 -520 830 -520 {lab=VDD} +N 820 -620 820 -520 {lab=VDD} +N 870 -620 910 -620 {lab=VbiasP2} +N 910 -620 910 -450 {lab=VbiasP2} +N 830 -450 910 -450 {lab=VbiasP2} +N 870 -520 910 -520 {lab=VbiasP2} +N 830 -690 1040 -690 {lab=VDD} +N 1040 -690 1040 -650 {lab=VDD} +N 1040 -590 1040 -550 {lab=#net7} +N 1040 -490 1040 -450 {lab=#net8} +N 930 -370 1000 -370 {lab=VbiasN2} +N 1000 -250 1000 -170 {lab=VbiasN1} +N 970 -210 1000 -210 {lab=VbiasN1} +N 840 -110 1040 -110 {lab=VSS} +N 1040 -140 1040 -110 {lab=VSS} +N 1040 -450 1040 -410 {lab=#net8} +N 1040 -340 1040 -280 {lab=#net9} +N 1080 -620 1130 -620 {lab=#net8} +N 1130 -620 1130 -450 {lab=#net8} +N 1040 -450 1130 -450 {lab=#net8} +N 1080 -520 1210 -520 {lab=VbiasP2} +N 1040 -370 1050 -370 {lab=VSS} +N 1050 -370 1050 -110 {lab=VSS} +N 1040 -110 1050 -110 {lab=VSS} +N 1040 -170 1050 -170 {lab=VSS} +N 1040 -250 1050 -250 {lab=VSS} +N 1030 -620 1040 -620 {lab=VDD} +N 1030 -690 1030 -620 {lab=VDD} +N 1030 -690 1030 -620 {lab=VDD} +N 1030 -620 1030 -520 {lab=VDD} +N 1030 -520 1040 -520 {lab=VDD} +N 1040 -410 1040 -400 { +lab=#net8} +N 1040 -220 1040 -200 { +lab=#net10} +N 570 -220 570 -200 { +lab=#net11} +N 560 -370 570 -370 { +lab=VSS} +N 560 -370 560 -250 { +lab=VSS} +C {symbols/nfet_03v3.sym} 350 -320 0 1 {name=M1 +L=6u +W=0.5u +nf=1 +m=1 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/pfet_03v3.sym} 150 -580 0 1 {name=M2 +L=2u +W=0.5u +nf=1 +m=1 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 110 -320 0 0 {name=M3 +L=6u +W=0.5u +nf=1 +m=1 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/pfet_03v3.sym} 310 -580 0 0 {name=M4 +L=2u +W=0.5u +nf=1 +m=1 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {symbols/pfet_03v3.sym} 550 -580 0 0 {name=M5 +L=2u +W=0.5u +nf=1 +m=1 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {symbols/pfet_03v3.sym} 850 -620 0 1 {name=M6 +L=2u +W=0.5u +nf=1 +m=1 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {symbols/pfet_03v3.sym} 850 -520 0 1 {name=M7 +L=2u +W=0.5u +nf=1 +m=1 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {symbols/pfet_03v3.sym} 1060 -620 0 1 {name=M8 +L=2u +W=0.5u +nf=1 +m=3 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {symbols/pfet_03v3.sym} 1060 -520 0 1 {name=M9 +L=2u +W=0.5u +nf=1 +m=2 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 1020 -170 0 0 {name=M10 +L=6u +W=0.5u +nf=1 +m=4 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 590 -370 0 1 {name=M11 +L=6u +W=0.5u +nf=1 +m=5 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 810 -370 0 0 {name=M12 +L=6u +W=0.5u +nf=1 +m=5 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 1020 -370 0 0 {name=M13 +L=6u +W=0.5u +nf=1 +m=5 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 350 -240 0 1 {name=M14 +L=6u +W=0.5u +nf=1 +m=1 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 590 -250 0 1 {name=M15 +L=6u +W=0.5u +nf=1 +m=4 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 810 -250 0 0 {name=M16 +L=6u +W=0.5u +nf=1 +m=4 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 1020 -250 0 0 {name=M17 +L=6u +W=0.5u +nf=1 +m=4 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 110 -210 0 0 {name=M18 +L=6u +W=0.5u +nf=1 +m=1 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 810 -170 0 0 {name=M19 +L=6u +W=0.5u +nf=1 +m=4 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 590 -170 0 1 {name=M20 +L=6u +W=0.5u +nf=1 +m=4 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {devices/lab_wire.sym} 470 -580 0 0 {name=p1 sig_type=std_logic lab=VbiasP1 +} +C {devices/lab_wire.sym} 230 -510 0 0 {name=p2 sig_type=std_logic lab=VbiasP1 +} +C {devices/lab_wire.sym} 410 -410 0 0 {name=p3 sig_type=std_logic lab=VbiasN2 +} +C {devices/lab_wire.sym} 680 -370 0 0 {name=p4 sig_type=std_logic lab=VbiasN2 +} +C {devices/lab_wire.sym} 970 -370 0 0 {name=p5 sig_type=std_logic lab=VbiasN2 +} +C {devices/lab_wire.sym} 910 -570 0 0 {name=p6 sig_type=std_logic lab=VbiasP2 +} +C {devices/lab_wire.sym} 1210 -520 0 0 {name=p7 sig_type=std_logic lab=VbiasP2 +} +C {devices/lab_wire.sym} 690 -450 0 0 {name=p8 sig_type=std_logic lab=VbiasN1 +} +C {devices/lab_wire.sym} 990 -210 0 0 {name=p9 sig_type=std_logic lab=VbiasN1 +} +C {devices/lab_wire.sym} 70 -270 0 0 {name=p10 sig_type=std_logic lab=Vref +} +C {devices/lab_wire.sym} 460 -690 0 0 {name=p11 sig_type=std_logic lab=VDD +} +C {devices/lab_wire.sym} 460 -110 0 0 {name=p12 sig_type=std_logic lab=VSS +} +C {devices/ipin.sym} 1280 -220 0 0 {name=p14 lab=Vref} +C {devices/iopin.sym} 1260 -320 0 0 {name=p21 lab=VbiasN1 +} +C {devices/iopin.sym} 1260 -300 0 0 {name=p13 lab=VbiasN2} +C {devices/iopin.sym} 1260 -260 0 0 {name=p15 lab=VDD} +C {devices/iopin.sym} 1260 -280 0 0 {name=p16 lab=VbiasP2} +C {devices/iopin.sym} 1260 -240 0 0 {name=p17 lab=VSS} +C {devices/iopin.sym} 1260 -340 0 0 {name=p18 lab=VbiasP1} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/error_amplifier_bias_N_input.sym b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/error_amplifier_bias_N_input.sym new file mode 100644 index 00000000..d0b84836 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/error_amplifier_bias_N_input.sym @@ -0,0 +1,37 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {type=subcircuit +format="@name @pinlist @symname" +template="name=x1" +} +V {} +S {} +E {} +B 5 117.5 27.5 122.5 32.5 {name=VbiasN1 dir=inout} +B 5 117.5 7.5 122.5 12.5 {name=VbiasN2 dir=inout} +B 5 117.5 -12.5 122.5 -7.5 {name=VbiasP2 dir=inout} +B 5 -122.5 -2.5 -117.5 2.5 {name=VDD dir=inout} +B 5 -122.5 17.5 -117.5 22.5 {name=VSS dir=inout} +B 5 -122.5 -22.5 -117.5 -17.5 {name=Vref dir=in} +B 5 117.5 -32.5 122.5 -27.5 {name=VbiasP1 dir=inout} +A 4 0 0 25 126.869897645844 360 {} +P 4 2 6 -16 -6 -16 {} +P 4 2 0 -22 0 -10 {} +P 4 2 6 18 -6 18 {} +P 4 5 -80 -40 -80 40 80 40 80 -40 -80 -40 {} +P 4 2 -120 -20 -80 -20 {} +P 4 2 -120 -0 -80 -0 {} +P 4 2 -120 20 -80 20 {} +P 4 2 80 -10 120 -10 {} +P 4 2 80 10 120 10 {} +P 4 3 80 30 120 30 120 30 {} +P 4 2 80 -30 120 -30 {} +T {@symname} -43.5 44 0 0 0.3 0.3 {} +T {@name} -45 -52 0 0 0.2 0.2 {} +T {VbiasN1} 75 26 0 1 0.2 0.2 {} +T {VbiasN2} 75 6 0 1 0.2 0.2 {} +T {VbiasP2} 75 -14 0 1 0.2 0.2 {} +T {VDD} -52 -3 0 1 0.2 0.2 {} +T {VSS} -54 17 0 1 0.2 0.2 {} +T {Vref} -75 -24 0 0 0.2 0.2 {} +T {VbiasP1} 75 -34 0 1 0.2 0.2 {} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/error_amplifier_bias_OP.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/error_amplifier_bias_OP.sch new file mode 100644 index 00000000..a8ae9975 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/error_amplifier_bias_OP.sch @@ -0,0 +1,72 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +P 4 1 360 -260 {} +P 4 1 360 -280 {} +P 4 1 360 -300 {} +N 130 -60 130 -20 { +lab=GND} +N 130 -160 130 -120 { +lab=VSS} +N 210 -60 210 -20 { +lab=GND} +N 210 -160 210 -120 { +lab=VDD} +N 290 -60 290 -20 { +lab=GND} +N 290 -160 290 -120 { +lab=Vref} +N 320 -280 350 -280 {lab=VbiasP2} +N 320 -260 350 -260 {lab=VbiasN2} +N 320 -240 350 -240 {lab=VbiasN1} +N 320 -300 350 -300 {lab=VbiasP1} +C {devices/vsource.sym} 130 -90 0 0 {name=V0 value=0 savecurrent=false} +C {devices/gnd.sym} 130 -20 0 0 {name=l3 lab=GND} +C {devices/vsource.sym} 210 -90 0 0 {name=V2 value=1.8 savecurrent=false} +C {devices/lab_wire.sym} 130 -160 0 0 {name=p12 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 210 -160 0 0 {name=p13 sig_type=std_logic lab=VDD} +C {devices/gnd.sym} 210 -20 0 0 {name=l4 lab=GND} +C {devices/vsource.sym} 290 -90 0 0 {name=V4 value=1.2 savecurrent=false} +C {devices/lab_wire.sym} 290 -160 0 0 {name=p14 sig_type=std_logic lab=Vref} +C {devices/gnd.sym} 290 -20 0 0 {name=l5 lab=GND} +C {devices/lab_pin.sym} 80 -290 0 0 {name=p1 sig_type=std_logic lab=Vref} +C {devices/lab_pin.sym} 80 -270 0 0 {name=p2 sig_type=std_logic lab=VDD} +C {devices/lab_pin.sym} 80 -250 0 0 {name=p3 sig_type=std_logic lab=VSS} +C {devices/code_shown.sym} 20 -510 0 0 {name=MODELS only_toplevel=true +format="tcleval( @value )" +value=" +.include /foss/pdks/gf180mcuC/libs.tech/ngspice/design.ngspice +.lib /foss/pdks/gf180mcuC/libs.tech/ngspice/sm141064.ngspice typical +"} +C {devices/launcher.sym} 140 -380 0 0 {name=h1 +descr="Save & Netlist & sim" +tclcommand="xschem save; xschem netlist; xschem simulate"} +C {devices/code_shown.sym} 440 -320 0 0 {name=s1 only_toplevel=false value=" +.control +save all +op + +save V(VbiasP2) +print V(VbiasP2) + +save V(VbiasN2) +print V(VbiasN2) + +save V(VbiasN1) +print V(VbiasN1) + +.endc +" +} +C {devices/noconn.sym} 350 -280 0 1 {name=l1} +C {devices/noconn.sym} 350 -260 0 1 {name=l2} +C {devices/noconn.sym} 350 -240 0 1 {name=l6} +C {devices/lab_pin.sym} 340 -280 0 0 {name=p4 sig_type=std_logic lab=VbiasP2} +C {devices/lab_pin.sym} 340 -260 0 0 {name=p5 sig_type=std_logic lab=VbiasN2} +C {devices/lab_pin.sym} 340 -240 0 0 {name=p6 sig_type=std_logic lab=VbiasN1} +C {gf180/error_amplifier_bias_N_input/xschem/error_amplifier_bias_N_input.sym} 200 -270 0 0 {name=x1} +C {devices/noconn.sym} 350 -300 0 1 {name=l7} +C {devices/lab_pin.sym} 340 -300 0 0 {name=p7 sig_type=std_logic lab=VbiasP1} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/xschemrc b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/xschemrc new file mode 100644 index 00000000..3b753a38 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_bias_N_input/xschem/xschemrc @@ -0,0 +1,7 @@ +# Source the PDK xschemrc file +if {![info exists PDK]} { + source $env(PDK_ROOT)/$env(PDK)/libs.tech/xschem/xschemrc +} + +# Add current directory to xschem library path +append XSCHEM_LIBRARY_PATH :[file dirname [info script]] diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/error_amplifier_core_N_input.yaml b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/error_amplifier_core_N_input.yaml new file mode 100644 index 00000000..39a988a2 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/error_amplifier_core_N_input.yaml @@ -0,0 +1,287 @@ +--- +#-------------------------------------------------------------- +# CACE circuit characterization file +#-------------------------------------------------------------- + +name: error_amplifier_core_N_input +description: Folded cascode's core +PDK: gf180mcuD + +cace_format: 5.2 + +authorship: + designer: Ramon Sarmiento + company: OnChip UIS + creation_date: Apr 21, 2025 + license: Apache 2.0 + +paths: + root: .. + schematic: xschem + layout: gds + netlist: netlist + documentation: docs + +pins: + VDD: + description: Positive analog power supply + type: power + direction: inout + Vmin: 1.7 + Vmax: 1.9 + VSS: + description: Analog ground + type: ground + direction: inout + Vout: + description: Output voltage + type: signal + direction: inout + Vcomn: + description: Compensation pin + type: signal + direction: inout + V+: + description: Non inverting input + type: signal + direction: input + V-: + description: Inverting input + type: signal + direction: input + VbiasP1: + description: Bias of PMOS tail transistor + type: signal + direction: input + VbiasP2: + description: Bias of cascode pmos + type: signal + direction: input + VbiasN2: + description: Bias of cascode nmos + type: signal + direction: input + VbiasN1: + description: Bias of current mirror nmos + type: signal + direction: input + +default_conditions: + VDD: + description: Analog power supply voltage + display: VDD + unit: V + typical: 1.8 + Vin_CM: + description: Input Common Mode Voltage + display: Vin_CM + unit: V + typical: 0.8 + Vout_CM: + description: Output Common Mode Voltage + display: Vout_CM + unit: V + typical: 0.9 + Vy: + description: Fix voltage Mode Voltage + display: Vy + unit: V + typical: 0.1 + VbiasP1: + description: Bias of PMOS tail transistor + display: VbiasP1 + unit: V + typical: 0.95 + VbiasP2: + description: Bias of cascode pmos + display: VbiasP2 + unit: V + typical: 0.4 + VbiasN2: + description: Bias of cascode nmos + display: VbiasN2 + unit: V + typical: 1.28 + VbiasN1: + description: Bias of current mirror nmos + display: VbiasN1 + unit: V + typical: 0.81 + corner: + description: Process corner + display: Corner + typical: typical + temperature: + description: Ambient temperature + display: Temp + unit: °C + typical: 27 + +parameters: + dc_params: + display: DC Params + spec: + Ivdd: + display: Ivdd + description: Currente from power + unit: uA + minimum: + value: any + typical: + value: any + maximum: + value: any + Vout: + display: Vout + description: Output voltage + unit: V + minimum: + value: any + typical: + value: any + maximum: + value: any + tool: + ngspice: + template: dc.sch + format: ascii + suffix: .data + variables: [Vout, Ivdd] + + ac_params: + display: STB Params + spec: + # print A0 UGB PM GM BW + A0: + display: Av + description: Opamp's DC Gain + unit: dB + minimum: + value: 70 + typical: + value: any + maximum: + value: any + UGB: + display: UGB + description: Unitary Gain Bandwidth + unit: MHz + minimum: + value: 10 + typical: + value: any + maximum: + value: any + PM: + display: PM + description: Opamp's Phase Margin + unit: ° + minimum: + value: 45 + typical: + value: any + maximum: + value: any + GM: + display: GM + description: Opamp's Gain Margin + unit: ° + minimum: + value: any + typical: + value: any + maximum: + value: any + BW: + display: BW + description: Opamp's Bandwidth + unit: kHz + minimum: + value: any + typical: + value: any + maximum: + value: any + tool: + ngspice: + template: ac.sch + format: ascii + suffix: .data + variables: [A0, UGB, PM, GM, BW] + + magic_area: + spec: + area: + display: Area + description: Total circuit layout area + unit: µm² + maximum: + value: any + width: + display: Width + description: Total circuit layout width + unit: µm + maximum: + value: any + height: + display: Height + description: Total circuit layout height + unit: µm + maximum: + value: any + tool: magic_area + + magic_drc: + description: Magic DRC + display: Magic DRC + spec: + drc_errors: + maximum: + value: 0 + tool: + magic_drc: + gds_flatten: true + + netgen_lvs: + description: Netgen LVS + display: Netgen LVS + spec: + lvs_errors: + maximum: + value: 0 + tool: + netgen_lvs: + script: run_project_lvs.tcl + + klayout_drc_feol: + description: KLayout DRC feol + display: KLayout DRC feol + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ["-rd", "feol=true"] + + klayout_drc_beol: + description: KLayout DRC beol + display: KLayout DRC beol + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ["-rd", "beol=true"] + + klayout_drc_full: + description: KLayout DRC full + display: KLayout DRC full + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ["-rd", "feol=true", "-rd", "beol=true", "-rd", "offgrid=true"] diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/folded_cascode_core.yaml b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/folded_cascode_core.yaml new file mode 100644 index 00000000..943b097d --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/folded_cascode_core.yaml @@ -0,0 +1,207 @@ +#-------------------------------------------------------------- +# CACE circuit characterization file +#-------------------------------------------------------------- + +name: folded_cascode_core +description: Folded cascode's core +PDK: sky130A + +cace_format: 5.2 + +authorship: + designer: Ramon Sarmiento + company: OnChip UIS + creation_date: Apr 21, 2025 + license: Apache 2.0 + +paths: + root: .. + schematic: xschem + layout: gds + netlist: netlist + documentation: docs + +pins: + VDD: + description: Positive analog power supply + type: power + direction: inout + Vmin: 1.7 + Vmax: 1.9 + VSS: + description: Analog ground + type: ground + direction: inout + Vout: + description: Output voltage + type: signal + direction: inout + Vcomn: + description: Compensation pin + type: signal + direction: inout + V+: + description: Non inverting input + type: signal + direction: input + V-: + description: Inverting input + type: signal + direction: input + VbiasP2: + description: Bias of cascode pmos + type: signal + direction: input + VbiasN2: + description: Bias of cascode nmos + type: signal + direction: input + VbiasN1: + description: Bias of current mirror nmos + type: signal + direction: input + +default_conditions: + vdd: + description: Analog power supply voltage + display: Vdd + unit: V + typical: 1.8 + vref: + description: Voltage reference from BandGAP + display: VrefBG + unit: V + typical: 1.2 + VbiasP2: + description: Bias of cascode pmos + display: VbiasP2 + unit: V + typical: 0.65 + VbiasN2: + description: Bias of cascode nmos + display: VbiasN2 + unit: V + typical: 1.2 + VbiasN1: + description: Bias of current mirror nmos + display: VbiasN1 + unit: V + typical: 0.9 + corner: + description: Process corner + display: Corner + typical: tt + temperature: + description: Ambient temperature + display: Temp + unit: °C + typical: 27 + +parameters: + dc_params: + display: DC Params + spec: + Ivdd: + display: Ivdd + description: Currente from power + unit: uA + minimum: + value: any + typical: + value: any + maximum: + value: any + Vout: + display: Vout + description: Output voltage + unit: V + minimum: + value: any + typical: + value: any + maximum: + value: any + tool: + ngspice: + template: dc.sch + format: ascii + suffix: .data + variables: [Vout, Ivdd] + + magic_area: + spec: + area: + display: Area + description: Total circuit layout area + unit: µm² + maximum: + value: any + width: + display: Width + description: Total circuit layout width + unit: µm + maximum: + value: any + height: + display: Height + description: Total circuit layout height + unit: µm + maximum: + value: any + tool: + magic_area + + magic_drc: + description: Magic DRC + display: Magic DRC + spec: + drc_errors: + maximum: + value: 0 + tool: + magic_drc: + gds_flatten: true + + netgen_lvs: + description: Netgen LVS + display: Netgen LVS + spec: + lvs_errors: + maximum: + value: 0 + tool: + netgen_lvs: + script: run_project_lvs.tcl + + klayout_drc_feol: + description: KLayout DRC feol + display: KLayout DRC feol + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ['-rd', 'feol=true'] + + klayout_drc_beol: + description: KLayout DRC beol + display: KLayout DRC beol + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ['-rd', 'beol=true'] + + klayout_drc_full: + description: KLayout DRC full + display: KLayout DRC full + spec: + drc_errors: + maximum: + value: 0 + tool: + klayout_drc: + args: ['-rd', 'feol=true', '-rd', 'beol=true', '-rd', 'offgrid=true'] diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/scripts/run_project_lvs.tcl b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/scripts/run_project_lvs.tcl new file mode 100644 index 00000000..6463d2d9 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/scripts/run_project_lvs.tcl @@ -0,0 +1,14 @@ +# NOTE: PDK_ROOT, PDK and CACE_ROOT are set in the local environment by CACE +# +# This is an example script to drive LVS; because this is a simple +# example, there is no specific benefit of using this instead of the +# default handling in CACE. + +set PDK_ROOT $::env(PDK_ROOT) +set PDK $::env(PDK) +set CACE_ROOT $::env(CACE_ROOT) + +set circuit1 [readnet spice $CACE_ROOT/netlist/layout/folded_cascode_core.spice] +set circuit2 [readnet spice $CACE_ROOT/netlist/schematic/folded_cascode_core.spice] + +lvs "$circuit1 folded_cascode_core" "$circuit2 folded_cascode_core" $PDK_ROOT/$PDK/libs.tech/netgen/${PDK}_setup.tcl folded_cascode_core_comp.out -json diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/templates/ac.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/templates/ac.sch new file mode 100644 index 00000000..0b28cb17 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/templates/ac.sch @@ -0,0 +1,226 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +L 4 1050 -630 1470 -630 {} +L 4 1050 -580 1470 -580 {} +L 4 1180 -630 1180 -270 {} +L 4 1270 -630 1270 -270 {} +L 4 1360 -630 1360 -270 {} +L 4 1470 -630 1470 -270 {} +L 4 1050 -630 1050 -270 {} +L 4 1050 -270 1470 -270 {} +T {Expected values for inputs:} 1130 -680 0 0 0.4 0.4 {} +T {Input} 1090 -620 0 0 0.4 0.4 {} +T {Min} 1210 -620 0 0 0.4 0.4 {} +T {Typ} 1300 -620 0 0 0.4 0.4 {} +T {Max} 1400 -620 0 0 0.4 0.4 {} +T {VDD} 1090 -570 0 0 0.4 0.4 {} +T {1.8} 1300 -570 0 0 0.4 0.4 {} +T {VIN_CM} 1070 -520 0 0 0.4 0.4 {} +T {0.8} 1400 -520 0 0 0.4 0.4 {} +T {VbiasP1} 1070 -470 0 0 0.4 0.4 {} +T {VbiasP2} 1070 -420 0 0 0.4 0.4 {} +T {VbiasN1} 1070 -370 0 0 0.4 0.4 {} +T {VbiasN2} 1070 -320 0 0 0.4 0.4 {} +T {0.95} 1295 -470 0 0 0.4 0.4 {} +T {0.81} 1300 -370 0 0 0.4 0.4 {} +T {1.28} 1295 -320 0 0 0.4 0.4 {} +T {0.4} 1295 -420 0 0 0.4 0.4 {} +N 690 -640 750 -640 {lab=Vout} +N 410 -350 490 -350 { +lab=Vx} +N 410 -400 410 -350 { +lab=Vx} +N 270 -350 310 -350 { +lab=Vin} +N 370 -350 410 -350 { +lab=Vx} +N 230 -350 270 -350 { +lab=Vin} +N 820 -640 820 -430 { +lab=Vout} +N 900 -510 900 -430 { +lab=GND} +N 900 -640 900 -580 { +lab=Vout} +N 750 -640 900 -640 { +lab=Vout} +N 410 -500 410 -460 { +lab=Vn} +N 900 -580 900 -570 { +lab=Vout} +N 270 -430 270 -350 {lab=Vin} +N 820 -430 820 -350 {lab=Vout} +N 270 -610 490 -610 {lab=Vin} +N 270 -610 270 -430 {lab=Vin} +N 410 -670 490 -670 {lab=Vn} +N 410 -590 410 -500 {lab=Vn} +N 390 -590 410 -590 {lab=Vn} +N 390 -630 390 -590 {lab=Vn} +N 390 -630 410 -630 {lab=Vn} +N 410 -670 410 -630 {lab=Vn} +N 460 -30 460 -20 {lab=GND} +N 460 -120 460 -90 {lab=VbiasP2} +N 580 -30 580 -20 {lab=GND} +N 580 -120 580 -90 {lab=VbiasN2} +N 710 -30 710 -20 {lab=GND} +N 710 -120 710 -90 {lab=VbiasN1} +N 240 -30 240 -20 {lab=GND} +N 240 -120 240 -90 {lab=VDD} +N 350 -30 350 -20 {lab=GND} +N 350 -120 350 -90 {lab=VSS} +N 840 -120 840 -90 {lab=VbiasP1} +N 840 -30 840 -20 {lab=GND} +N 230 -260 230 -250 {lab=GND} +N 230 -350 230 -320 {lab=Vin} +N 900 -430 900 -410 {lab=GND} +N 490 -510 540 -510 {lab=Vcom} +N 490 -350 510 -350 {lab=Vx} +N 770 -320 820 -320 {lab=Vout} +N 820 -350 820 -320 {lab=Vout} +N 730 -270 730 -240 {lab=GND} +N 770 -280 810 -280 {lab=GND} +N 810 -280 810 -250 {lab=GND} +N 730 -250 810 -250 {lab=GND} +N 730 -350 730 -330 {lab=Vz} +N 680 -350 730 -350 {lab=Vz} +N 570 -350 620 -350 {lab=Vy} +N 1220 -50 1220 -20 {lab=GND} +N 1260 -60 1300 -60 {lab=GND} +N 1300 -60 1300 -30 {lab=GND} +N 1220 -30 1300 -30 {lab=GND} +N 1260 -100 1400 -100 {lab=VbiasP1} +N 1220 -170 1220 -110 {lab=Vaa} +N 1220 -180 1220 -170 {lab=Vaa} +N 1090 -180 1220 -180 {lab=Vaa} +N 1070 -180 1070 -130 {lab=Vaa} +N 1070 -180 1090 -180 {lab=Vaa} +N 1070 -70 1070 -40 {lab=GND} +N 1070 -40 1220 -40 {lab=GND} +C {devices/launcher.sym} 70 -430 0 0 {name=h15 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op" +} +C {devices/launcher.sym} 70 -500 0 0 {name=h3 +descr="Netlist & sim" +tclcommand="xschem netlist; xschem simulate"} +C {vsource.sym} 410 -430 0 0 {name=V5 value="AC 1" savecurrent=false} +C {capa.sym} 340 -350 1 0 {name=C2 +m=1 +value=10G +footprint=1206 +device="ceramic capacitor"} +C {ind.sym} 540 -350 1 0 {name=L4 +m=1 +value=10G +footprint=1206 +device=inductor} +C {lab_pin.sym} 540 -550 2 1 {name=p8 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 540 -530 2 1 {name=p9 sig_type=std_logic lab=VSS} +C {capa.sym} 900 -540 0 0 {name=C1 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {noconn.sym} 490 -510 2 1 {name=l1} +C {lab_pin.sym} 900 -640 0 1 {name=p2 sig_type=std_logic lab=Vout} +C {lab_pin.sym} 540 -490 2 1 {name=p5 sig_type=std_logic lab=VbiasP1} +C {lab_pin.sym} 540 -470 2 1 {name=p6 sig_type=std_logic lab=VbiasP2} +C {lab_pin.sym} 540 -450 2 1 {name=p7 sig_type=std_logic lab=VbiasN2} +C {lab_pin.sym} 540 -430 2 1 {name=p11 sig_type=std_logic lab=VbiasN1} +C {devices/vsource.sym} 460 -60 0 0 {name=V1 value=CACE\{VbiasP2\}} +C {devices/gnd.sym} 460 -20 0 0 {name=l2 lab=GND} +C {devices/lab_wire.sym} 460 -120 0 0 {name=p3 sig_type=std_logic lab=VbiasP2} +C {devices/vsource.sym} 580 -60 0 0 {name=V2 value=CACE\{VbiasN2\}} +C {devices/gnd.sym} 580 -20 0 0 {name=l3 lab=GND} +C {devices/lab_wire.sym} 580 -120 0 0 {name=p4 sig_type=std_logic lab=VbiasN2} +C {devices/vsource.sym} 710 -60 0 0 {name=V3 value=CACE\{VbiasN1\}} +C {devices/gnd.sym} 710 -20 0 0 {name=l5 lab=GND} +C {devices/lab_wire.sym} 710 -120 0 0 {name=p12 sig_type=std_logic lab=VbiasN1} +C {devices/vsource.sym} 240 -60 0 0 {name=V4 value=CACE\{VDD\}} +C {devices/gnd.sym} 240 -20 0 0 {name=l6 lab=GND} +C {devices/lab_wire.sym} 240 -120 0 0 {name=p13 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 350 -60 0 0 {name=V6 value=0} +C {devices/gnd.sym} 350 -20 0 0 {name=l7 lab=GND} +C {devices/lab_wire.sym} 350 -120 0 0 {name=p14 sig_type=std_logic lab=VSS} +C {devices/vsource.sym} 840 -60 0 0 {name=V8 value=CACE\{VbiasP1\} savecurrent=false} +C {devices/gnd.sym} 840 -20 0 0 {name=l10 lab=GND} +C {devices/lab_wire.sym} 840 -120 0 0 {name=p15 sig_type=std_logic lab=VbiasP1 +} +C {devices/vsource.sym} 230 -290 0 0 {name=V7 value=CACE\{Vin_CM\}} +C {devices/gnd.sym} 230 -250 0 0 {name=l8 lab=GND} +C {devices/lab_wire.sym} 230 -350 0 0 {name=p10 sig_type=std_logic lab=Vin} +C {devices/gnd.sym} 900 -410 0 0 {name=l9 lab=GND} +C {devices/lab_wire.sym} 450 -350 0 0 {name=p1 sig_type=std_logic lab=Vx} +C {devices/lab_wire.sym} 520 -510 0 0 {name=p16 sig_type=std_logic lab=Vcom} +C {devices/lab_wire.sym} 430 -670 0 0 {name=p17 sig_type=std_logic lab=Vn} +C {devices/vsource.sym} 650 -350 1 0 {name=V9 value=CACE\{Vy\}} +C {vcvs.sym} 730 -300 0 1 {name=E1 value=1} +C {devices/gnd.sym} 730 -240 0 0 {name=l11 lab=GND} +C {devices/lab_wire.sym} 590 -350 0 0 {name=p18 sig_type=std_logic lab=Vy} +C {devices/lab_wire.sym} 730 -350 0 0 {name=p19 sig_type=std_logic lab=Vz} +C {vcvs.sym} 1220 -80 0 1 {name=E2 value=1} +C {devices/gnd.sym} 1220 -20 0 0 {name=l12 lab=GND} +C {devices/lab_wire.sym} 1400 -100 0 0 {name=p20 sig_type=std_logic lab=VbiasP1 +} +C {res.sym} 1070 -100 0 0 {name=R1 +value=1k +footprint=1206 +device=resistor +m=1} +C {devices/lab_wire.sym} 1140 -180 0 0 {name=p21 sig_type=std_logic lab=Vaa} +C {devices/code_shown.sym} 50 -970 0 0 {name=SETUP +simulator=ngspice +only_toplevel=false +value=" +.lib CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/ngspice/sm141064.ngspice CACE\{corner\} + +.include CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/ngspice/design.ngspice +.include CACE\{DUT_path\} + +.temp CACE\{temperature\} + +.option SEED=CACE[CACE\{seed=12345\} + CACE\{iterations=0\}] + +* Flag unsafe operating conditions (exceeds models' specified limits) +.option warn=1 +"} +C {code.sym} 970 -880 0 0 {name=OP only_toplevel=true value=" + + + *remzerovec + *write error_amplifier_core_N_input_ac.raw + *set appendwrite + + +.control +save all + +*DC simulation +op +* run ac simulation +ac dec 20 1 100e7 + + +* measure parameters +let vout_mag = db(abs(v(Vout))) +*let vout_phase = cph(v(Vout)) * (180/pi) +let vout_phase = cph(v(Vout)) * (57.295779513) +let gm = (-1)*db(abs(v(Vout))) + +meas ac A0 find vout_mag at=1 +meas ac UGB when vout_mag=0 fall=1 +meas ac PM find vout_phase when vout_mag=0 +meas ac GM find gm when vout_phase=0 + +let A0_p1 = A0 - 3 +meas ac BW when vout_mag=A0_p1 + +print A0 UGB PM GM BW +echo $&A0 $&UGB $&PM $&GM $&BW > CACE\{simpath\}/CACE\{filename\}_CACE\{N\}.data +.endc +"} +C {error_amplifier_core_N_input.sym} 590 -640 0 0 {name=x1} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/templates/dc.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/templates/dc.sch new file mode 100644 index 00000000..cd55daa4 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/templates/dc.sch @@ -0,0 +1,107 @@ +v {xschem version=3.4.6 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 100 -160 100 -140 { +lab=GND} +N 180 -160 180 -140 { +lab=GND} +N 100 -140 100 -120 { +lab=GND} +N 180 -140 180 -120 { +lab=GND} +N 280 -160 280 -140 { +lab=GND} +N 280 -140 280 -120 { +lab=GND} +N 640 -370 660 -370 {lab=#net1} +N 380 -160 380 -140 { +lab=GND} +N 380 -140 380 -120 { +lab=GND} +N 510 -160 510 -140 { +lab=GND} +N 510 -140 510 -120 { +lab=GND} +N 590 -530 610 -530 {lab=Vout} +N 590 -580 590 -530 {lab=Vout} +N 590 -580 840 -580 {lab=Vout} +N 840 -580 840 -500 {lab=Vout} +N 810 -500 840 -500 {lab=Vout} +N 840 -500 870 -500 {lab=Vout} +N 580 -470 610 -470 {lab=Vref} +N 630 -160 630 -140 { +lab=GND} +N 630 -140 630 -120 { +lab=GND} +N 180 -230 180 -220 {lab=#net2} +N 180 -310 180 -290 {lab=VDD} +N 100 -250 100 -220 {lab=VSS} +N 280 -250 280 -220 {lab=Vref} +N 380 -250 380 -220 {lab=VbiasP2} +N 510 -250 510 -220 {lab=VbiasN2} +N 630 -250 630 -220 {lab=VbiasN1} +N 640 -350 660 -350 {lab=VbiasP2} +N 640 -330 660 -330 {lab=VbiasN2} +N 640 -310 660 -310 {lab=VbiasN1} +N 640 -390 660 -390 {lab=VSS} +N 640 -410 660 -410 {lab=VDD} +C {devices/code_shown.sym} 0 -860 0 0 {name=SETUP +simulator=ngspice +only_toplevel=false +value=" +.lib CACE\{PDK_ROOT\}/CACE\{PDK\}/libs.tech/combined/sky130.lib.spice CACE\{corner\} + +.include CACE\{DUT_path\} + +.temp CACE\{temperature\} + +.option SEED=CACE[CACE\{seed=12345\} + CACE\{iterations=0\}] + +* Flag unsafe operating conditions (exceeds models' specified limits) +.option warn=1 +"} +C {/foss/designs/chipathon_2025/designs/folded_cascode_core/xschem/folded_cascode_core.sym} 710 -500 0 0 {name=x1} +C {devices/vsource.sym} 100 -190 0 0 {name=V0 value=0 savecurrent=false} +C {devices/gnd.sym} 100 -120 0 0 {name=l4 lab=GND} +C {devices/vsource.sym} 180 -190 0 0 {name=V1 value=CACE\{vdd\} savecurrent=false} +C {devices/gnd.sym} 180 -120 0 0 {name=l8 lab=GND} +C {devices/vsource.sym} 280 -190 0 0 {name=V3 value=CACE\{vref\} savecurrent=false} +C {devices/gnd.sym} 280 -120 0 0 {name=l9 lab=GND} +C {noconn.sym} 640 -370 0 0 {name=l1} +C {devices/vsource.sym} 380 -190 0 0 {name=V2 value=CACE\{VbiasP2\} savecurrent=false} +C {devices/gnd.sym} 380 -120 0 0 {name=l2 lab=GND} +C {devices/vsource.sym} 510 -190 0 0 {name=V4 value=CACE\{VbiasN2\} savecurrent=false} +C {devices/gnd.sym} 510 -120 0 0 {name=l3 lab=GND} +C {lab_pin.sym} 580 -470 2 1 {name=p1 sig_type=std_logic lab=Vref} +C {lab_pin.sym} 280 -250 2 1 {name=p2 sig_type=std_logic lab=Vref} +C {lab_pin.sym} 180 -310 2 1 {name=p3 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 380 -250 2 1 {name=p4 sig_type=std_logic lab=VbiasP2} +C {lab_pin.sym} 510 -250 2 1 {name=p5 sig_type=std_logic lab=VbiasN2} +C {lab_pin.sym} 100 -250 2 1 {name=p6 sig_type=std_logic lab=VSS} +C {lab_pin.sym} 640 -410 2 1 {name=p7 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 640 -390 2 1 {name=p8 sig_type=std_logic lab=VSS} +C {devices/vsource.sym} 630 -190 0 0 {name=V5 value=CACE\{VbiasN1\} savecurrent=false} +C {devices/gnd.sym} 630 -120 0 0 {name=l5 lab=GND} +C {lab_pin.sym} 630 -250 2 1 {name=p9 sig_type=std_logic lab=VbiasN1} +C {lab_pin.sym} 870 -500 0 1 {name=p10 sig_type=std_logic lab=Vout} +C {ammeter.sym} 180 -260 2 0 {name=vdd_i savecurrent=true spice_ignore=0} +C {lab_pin.sym} 640 -350 2 1 {name=p11 sig_type=std_logic lab=VbiasP2} +C {lab_pin.sym} 640 -330 2 1 {name=p12 sig_type=std_logic lab=VbiasN2} +C {lab_pin.sym} 640 -310 2 1 {name=p13 sig_type=std_logic lab=VbiasN1} +C {code.sym} 230 -550 0 0 {name=OP only_toplevel=true value=" +.control +save all + +*DC simulation +op + +let Vout = v(Vout) +let Ivdd = i(vdd_i) + +print Vout Ivdd +echo $&Vout $&Ivdd> CACE\{simpath\}/CACE\{filename\}_CACE\{N\}.data +.endc +"} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/templates/xschemrc b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/templates/xschemrc new file mode 100644 index 00000000..589dc429 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/cace/templates/xschemrc @@ -0,0 +1,10 @@ +# Source the PDK xschemrc file +if {![info exists PDK]} { + source $env(PDK_ROOT)/$env(PDK)/libs.tech/xschem/xschemrc +} + +# Add current directory +append XSCHEM_LIBRARY_PATH :[file dirname [info script]] + +# Source project xschemrc +source [file dirname [info script]]/../../xschem/xschemrc diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/gds/folded_cascode_core.gds b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/gds/folded_cascode_core.gds new file mode 100644 index 00000000..dc3d060f Binary files /dev/null and b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/gds/folded_cascode_core.gds differ diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/gds/folded_cascode_core_pcells.gds b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/gds/folded_cascode_core_pcells.gds new file mode 100644 index 00000000..e69fe9fe Binary files /dev/null and b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/gds/folded_cascode_core_pcells.gds differ diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/gds/make_pcells_static.py b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/gds/make_pcells_static.py new file mode 100644 index 00000000..6a2666b9 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/gds/make_pcells_static.py @@ -0,0 +1,21 @@ +import pya +import klayout.db as db + +ly = pya.Layout() +ly.read("folded_cascode_core_pcells.gds") + +""" +# collect the cells to convert: +insts_to_convert = [] +for inst in ly.top_cell().each_inst(): + if inst.is_pcell(): + insts_to_convert.append(inst) + +for inst in insts_to_convert: + inst.convert_to_static() +""" + +ctx = db.SaveLayoutOptions() +ctx.write_context_info = False + +ly.write("folded_cascode_core.gds", ctx) diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sch new file mode 100644 index 00000000..a6a22e5c --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sch @@ -0,0 +1,421 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +T {FOLDED CASCODE OTA} 570 -100 0 0 0.4 0.4 {} +T {FOLDED CASCODE DUMMYS} 1240 -100 0 0 0.4 0.4 {} +N 730 -640 730 -550 { +lab=Vdm5} +N 910 -610 910 -550 { +lab=Vdm6} +N 730 -380 730 -290 { +lab=#net1} +N 910 -380 910 -290 { +lab=Vcomn} +N 910 -490 910 -440 { +lab=Vout} +N 730 -470 730 -440 { +lab=Val} +N 820 -520 870 -520 { +lab=VbiasP2} +N 820 -690 870 -690 { +lab=Val} +N 730 -470 800 -470 { +lab=Val} +N 800 -690 800 -470 { +lab=Val} +N 820 -410 870 -410 { +lab=VbiasN2} +N 820 -260 870 -260 { +lab=VbiasN1} +N 730 -770 730 -690 { +lab=VDD} +N 820 -770 910 -770 { +lab=VDD} +N 910 -770 910 -690 { +lab=VDD} +N 350 -630 730 -630 { +lab=Vdm5} +N 820 -210 910 -210 { +lab=VSS} +N 820 -560 820 -520 { +lab=VbiasP2} +N 910 -260 910 -210 { +lab=VSS} +N 730 -260 730 -210 { +lab=VSS} +N 720 -410 730 -410 { +lab=VSS} +N 720 -410 720 -210 { +lab=VSS} +N 910 -410 920 -410 { +lab=VSS} +N 920 -410 920 -210 { +lab=VSS} +N 910 -210 920 -210 { +lab=VSS} +N 720 -520 730 -520 { +lab=VDD} +N 720 -770 720 -520 { +lab=VDD} +N 720 -770 730 -770 { +lab=VDD} +N 910 -770 920 -770 { +lab=VDD} +N 920 -770 920 -520 { +lab=VDD} +N 910 -520 920 -520 { +lab=VDD} +N 820 -830 820 -770 { +lab=VDD} +N 820 -450 820 -410 { +lab=VbiasN2} +N 820 -300 820 -260 { +lab=VbiasN1} +N 430 -210 720 -210 { +lab=VSS} +N 820 -210 820 -150 { +lab=VSS} +N 720 -210 730 -210 { +lab=VSS} +N 820 -730 820 -690 {lab=Val} +N 730 -490 730 -470 { +lab=Val} +N 770 -690 800 -690 { +lab=Val} +N 730 -660 730 -640 { +lab=Vdm5} +N 910 -660 910 -610 { +lab=Vdm6} +N 770 -520 820 -520 { +lab=VbiasP2} +N 730 -770 820 -770 { +lab=VDD} +N 770 -410 820 -410 { +lab=VbiasN2} +N 770 -260 820 -260 { +lab=VbiasN1} +N 730 -210 820 -210 { +lab=VSS} +N 800 -690 820 -690 { +lab=Val} +N 1210 -780 1210 -740 {lab=VDD} +N 1210 -680 1210 -640 {lab=VDD} +N 1210 -710 1270 -710 {lab=VDD} +N 1130 -710 1170 -710 {lab=VDD} +N 1460 -780 1460 -740 {lab=VDD} +N 1460 -680 1460 -640 {lab=VDD} +N 1460 -710 1520 -710 {lab=VDD} +N 1380 -710 1420 -710 {lab=VDD} +N 1460 -580 1460 -540 {lab=VSS} +N 1460 -480 1460 -440 {lab=VSS} +N 1460 -510 1520 -510 {lab=VSS} +N 1380 -510 1420 -510 {lab=VSS} +N 1210 -580 1210 -540 {lab=VSS} +N 1210 -480 1210 -440 {lab=VSS} +N 1210 -510 1270 -510 {lab=VSS} +N 1130 -510 1170 -510 {lab=VSS} +N 1210 -380 1210 -340 {lab=VSS} +N 1210 -280 1210 -240 {lab=VSS} +N 1210 -310 1270 -310 {lab=VSS} +N 1130 -310 1170 -310 {lab=VSS} +N 280 -390 310 -390 { +lab=V+} +N 550 -390 580 -390 { +lab=V-} +N 350 -360 350 -310 { +lab=#net2} +N 510 -360 510 -310 { +lab=#net2} +N 430 -310 430 -290 { +lab=#net2} +N 360 -260 390 -260 { +lab=VbiasN1} +N 430 -260 430 -210 { +lab=VSS} +N 440 -390 510 -390 {lab=VSS} +N 430 -440 430 -390 {lab=VSS} +N 350 -310 430 -310 { +lab=#net2} +N 350 -390 430 -390 {lab=VSS} +N 430 -310 510 -310 {lab=#net2} +N 430 -390 440 -390 {lab=VSS} +N 510 -600 910 -600 {lab=Vdm6} +N 510 -600 510 -420 {lab=Vdm6} +N 350 -630 350 -420 {lab=Vdm5} +C {devices/ipin.sym} 150 -530 0 0 {name=p45 lab=VbiasN2} +C {devices/iopin.sym} 130 -380 0 0 {name=p46 lab=VDD} +C {devices/ipin.sym} 150 -560 0 0 {name=p14 lab=VbiasP2} +C {devices/ipin.sym} 150 -500 0 0 {name=p9 lab=VbiasN1} +C {devices/ipin.sym} 150 -470 0 0 {name=p22 lab=V+} +C {devices/ipin.sym} 150 -440 0 0 {name=p15 lab=V-} +C {devices/iopin.sym} 130 -350 0 0 {name=p2 lab=VSS} +C {devices/lab_wire.sym} 820 -150 0 0 {name=p5 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 820 -830 0 0 {name=p1 sig_type=std_logic lab=VDD} +C {devices/lab_wire.sym} 820 -730 0 1 {name=p17 sig_type=std_logic lab=Val} +C {symbols/pfet_03v3.sym} 890 -690 0 0 {name=M4 +L=0.3u +W=4u +nf=1 +m=12 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {symbols/pfet_03v3.sym} 750 -690 0 1 {name=M3 +L=0.3u +W=4u +nf=1 +m=12 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {devices/lab_wire.sym} 820 -560 0 1 {name=p16 sig_type=std_logic lab=VbiasP2} +C {symbols/pfet_03v3.sym} 750 -520 0 1 {name=M5 +L=2u +W=6u +nf=1 +m=2 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {symbols/pfet_03v3.sym} 890 -520 0 0 {name=M6 +L=2u +W=6u +nf=1 +m=2 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {devices/lab_wire.sym} 910 -460 0 1 {name=p4 sig_type=std_logic lab=Vout} +C {devices/lab_wire.sym} 820 -450 0 1 {name=p24 sig_type=std_logic lab=VbiasN2} +C {symbols/nfet_03v3.sym} 750 -260 0 1 {name=M9 +L=2u +W=2u +nf=1 +m=2 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 890 -410 0 0 {name=M8 +L=2u +W=5u +nf=1 +m=1 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {devices/lab_wire.sym} 910 -330 0 1 {name=p8 sig_type=std_logic lab=Vcomn} +C {devices/lab_wire.sym} 820 -300 0 1 {name=p3 sig_type=std_logic lab=VbiasN1} +C {symbols/nfet_03v3.sym} 750 -410 0 1 {name=M7 +L=2u +W=5u +nf=1 +m=1 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 890 -260 0 0 {name=M10 +L=2u +W=2u +nf=1 +m=2 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/pfet_03v3.sym} 1190 -710 0 0 {name=M15 +L=3u +W=1u +nf=1 +m=28 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {devices/lab_wire.sym} 1210 -780 0 1 {name=p11 sig_type=std_logic lab=VDD +} +C {devices/lab_wire.sym} 1270 -710 0 1 {name=p31 sig_type=std_logic lab=VDD +} +C {devices/lab_wire.sym} 1130 -710 0 0 {name=p32 sig_type=std_logic lab=VDD +} +C {devices/lab_wire.sym} 1210 -640 0 1 {name=p47 sig_type=std_logic lab=VDD +} +C {symbols/pfet_03v3.sym} 1440 -710 0 0 {name=M16 +L=1.5u +W=1u +nf=1 +m=20 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=pfet_03v3 +spiceprefix=X +} +C {devices/lab_wire.sym} 1460 -780 0 1 {name=p36 sig_type=std_logic lab=VDD +L=1.5u +m=20} +C {devices/lab_wire.sym} 1520 -710 0 1 {name=p37 sig_type=std_logic lab=VDD +} +C {devices/lab_wire.sym} 1380 -710 0 0 {name=p38 sig_type=std_logic lab=VDD} +C {devices/lab_wire.sym} 1460 -640 0 1 {name=p39 sig_type=std_logic lab=VDD} +C {devices/lab_wire.sym} 1460 -580 0 1 {name=p40 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 1520 -510 0 1 {name=p41 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 1380 -510 0 0 {name=p42 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 1460 -440 0 1 {name=p43 sig_type=std_logic lab=VSS} +C {symbols/nfet_03v3.sym} 1440 -510 0 0 {name=M13 +L=3u +W=1u +nf=1 +m=18 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {devices/lab_wire.sym} 1210 -580 0 1 {name=p18 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 1270 -510 0 1 {name=p19 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 1130 -510 0 0 {name=p20 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 1210 -440 0 1 {name=p25 sig_type=std_logic lab=VSS} +C {symbols/nfet_03v3.sym} 1190 -510 0 0 {name=M12 +L=6.5u +W=0.5u +nf=1 +m=36 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {devices/lab_wire.sym} 1210 -380 0 1 {name=p26 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 1270 -310 0 1 {name=p27 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 1130 -310 0 0 {name=p28 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 1210 -240 0 1 {name=p29 sig_type=std_logic lab=VSS} +C {symbols/nfet_03v3.sym} 1190 -310 0 0 {name=M14 +L=1u +W=1u +nf=1 +m=30 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {devices/iopin.sym} 130 -320 0 0 {name=p23 lab=Vcomn} +C {devices/iopin.sym} 130 -410 0 0 {name=p21 lab=Vout} +C {devices/lab_wire.sym} 350 -630 0 0 {name=p30 sig_type=std_logic lab=Vdm5} +C {devices/lab_wire.sym} 430 -440 0 0 {name=p33 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 280 -390 0 0 {name=p34 sig_type=std_logic lab=V+} +C {devices/lab_wire.sym} 580 -390 0 1 {name=p35 sig_type=std_logic lab=V-} +C {devices/lab_wire.sym} 360 -260 0 0 {name=p48 sig_type=std_logic lab=VbiasN1} +C {devices/lab_wire.sym} 510 -600 0 0 {name=p49 sig_type=std_logic lab=Vdm6} +C {symbols/nfet_03v3.sym} 530 -390 0 1 {name=M1 +L=1u +W=10u +nf=1 +m=20 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 330 -390 0 0 {name=M2 +L=1u +W=10u +nf=1 +m=20 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} +C {symbols/nfet_03v3.sym} 410 -260 0 0 {name=M11 +L=2u +W=2u +nf=1 +m=40 +ad="'int((nf+1)/2) * W/nf * 0.18u'" +pd="'2*int((nf+1)/2) * (W/nf + 0.18u)'" +as="'int((nf+2)/2) * W/nf * 0.18u'" +ps="'2*int((nf+2)/2) * (W/nf + 0.18u)'" +nrd="'0.18u / W'" nrs="'0.18u / W'" +sa=0 sb=0 sd=0 +model=nfet_03v3 +spiceprefix=X +} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sym b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sym new file mode 100644 index 00000000..6f825439 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sym @@ -0,0 +1,44 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {type=subcircuit +format="@name @pinlist @symname" +template="name=x1" +} +V {} +S {} +E {} +B 5 -52.5 147.5 -47.5 152.5 {name=VbiasP2 dir=in} +B 5 -52.5 167.5 -47.5 172.5 {name=VbiasN2 dir=in} +B 5 -52.5 187.5 -47.5 192.5 {name=VbiasN1 dir=in} +B 5 97.5 -2.5 102.5 2.5 {name=Vout dir=inout} +B 5 -102.5 27.5 -97.5 32.5 {name=V+ dir=in} +B 5 -102.5 -32.5 -97.5 -27.5 {name=V- dir=in} +B 5 -52.5 87.5 -47.5 92.5 {name=VDD dir=inout} +B 5 -52.5 107.5 -47.5 112.5 {name=VSS dir=inout} +B 5 -52.5 127.5 -47.5 132.5 {name=Vcomn dir=inout} +P 4 4 -60 -60 -60 60 60 0 -60 -60 {} +P 4 2 -50 90 0 90 {} +P 4 2 -50 110 0 110 {} +P 4 2 60 0 100 0 {} +P 4 2 -100 -30 -60 -30 {} +P 4 2 -100 30 -60 30 {} +P 4 2 -40 20 -40 40 {} +P 4 2 -50 -30 -30 -30 {} +P 4 2 -50 30 -30 30 {} +P 4 2 -50 130 0 130 {} +P 4 2 -50 150 0 150 {} +P 4 2 -50 170 0 170 {} +P 4 2 -50 190 0 190 {} +P 4 2 0 190 0 30 {} +P 4 2 0 170 0 190 {} +T {@symname} -13.5 14 0 0 0.3 0.3 {} +T {@name} -5 -52 0 0 0.2 0.2 {} +T {VbiasP2} -45 136 0 0 0.2 0.2 {} +T {VbiasN2} -45 156 0 0 0.2 0.2 {} +T {VbiasN1} -45 176 0 0 0.2 0.2 {} +T {Vout} 95 -14 0 1 0.2 0.2 {} +T {V+} -85 16 0 0 0.2 0.2 {} +T {V-} -85 -44 0 0 0.2 0.2 {} +T {VDD} -15 76 0 1 0.2 0.2 {} +T {VSS} -15 96 0 1 0.2 0.2 {} +T {Vcomn} -5 116 0 1 0.2 0.2 {} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_Out_Swing.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_Out_Swing.sch new file mode 100644 index 00000000..9d94fa68 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_Out_Swing.sch @@ -0,0 +1,171 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +L 4 1035 -380 1455 -380 {} +L 4 1035 -330 1455 -330 {} +L 4 1165 -380 1165 -20 {} +L 4 1255 -380 1255 -20 {} +L 4 1345 -380 1345 -20 {} +L 4 1455 -380 1455 -20 {} +L 4 1035 -380 1035 -20 {} +L 4 1035 -20 1455 -20 {} +T {Expected values for inputs:} 1115 -430 0 0 0.4 0.4 {} +T {Input} 1075 -370 0 0 0.4 0.4 {} +T {Min} 1195 -370 0 0 0.4 0.4 {} +T {Typ} 1285 -370 0 0 0.4 0.4 {} +T {Max} 1385 -370 0 0 0.4 0.4 {} +T {VDD} 1075 -320 0 0 0.4 0.4 {} +T {1.8} 1285 -320 0 0 0.4 0.4 {} +T {VIN_CM} 1055 -270 0 0 0.4 0.4 {} +T {0.8} 1385 -270 0 0 0.4 0.4 {} +T {VbiasP1} 1055 -220 0 0 0.4 0.4 {} +T {VbiasP2} 1055 -170 0 0 0.4 0.4 {} +T {VbiasN1} 1055 -120 0 0 0.4 0.4 {} +T {VbiasN2} 1055 -70 0 0 0.4 0.4 {} +T {0.95} 1280 -220 0 0 0.4 0.4 {} +T {0.81} 1280 -120 0 0 0.4 0.4 {} +T {1.2} 1285 -70 0 0 0.4 0.4 {} +T {0.5} 1285 -170 0 0 0.4 0.4 {} +N 190 -20 190 -10 {lab=GND} +N 190 -110 190 -80 {lab=VbiasP2} +N 270 -20 270 -10 {lab=GND} +N 270 -110 270 -80 {lab=VbiasN2} +N 350 -20 350 -10 {lab=GND} +N 350 -110 350 -80 {lab=VbiasN1} +N 30 -20 30 -10 {lab=GND} +N 30 -110 30 -80 {lab=VDD} +N 110 -20 110 -10 {lab=GND} +N 110 -110 110 -80 {lab=VSS} +N 950 -60 950 0 { +lab=GND} +N 860 -170 950 -170 { +lab=Vout} +N 950 -170 950 -120 { +lab=Vout} +N 560 -200 660 -200 { +lab=Vn} +N 560 -270 560 -200 { +lab=Vn} +N 950 -270 950 -170 { +lab=Vout} +N 560 -10 560 0 {lab=GND} +N 560 -100 560 -70 {lab=Vin} +N 560 -140 560 -100 { +lab=Vin} +N 560 -140 660 -140 { +lab=Vin} +N 430 -110 430 -80 {lab=VbiasP1} +N 430 -20 430 -10 {lab=GND} +N 860 -400 910 -400 {lab=Vout} +N 820 -350 820 -320 {lab=GND} +N 860 -360 900 -360 {lab=GND} +N 900 -360 900 -330 {lab=GND} +N 820 -330 900 -330 {lab=GND} +N 820 -430 820 -410 {lab=Vz} +N 770 -430 820 -430 {lab=Vz} +N 910 -400 950 -400 {lab=Vout} +N 950 -400 950 -270 {lab=Vout} +N 560 -430 560 -270 {lab=Vn} +N 660 -40 710 -40 {lab=Vcom} +N 660 -430 690 -430 {lab=#net1} +N 750 -430 770 -430 {lab=Vz} +N 560 -430 600 -430 {lab=Vn} +C {devices/vsource.sym} 190 -50 0 0 {name=V1 value=\{VbiasP2\}} +C {devices/gnd.sym} 190 -10 0 0 {name=l2 lab=GND} +C {devices/launcher.sym} 110 -330 0 0 {name=h3 +descr="Save & Netlist & sim" +tclcommand="xschem save; xschem netlist; xschem simulate"} +C {devices/lab_wire.sym} 190 -110 0 0 {name=p1 sig_type=std_logic lab=VbiasP2} +C {devices/vsource.sym} 270 -50 0 0 {name=V2 value=\{VbiasN2\}} +C {devices/gnd.sym} 270 -10 0 0 {name=l1 lab=GND} +C {devices/lab_wire.sym} 270 -110 0 0 {name=p2 sig_type=std_logic lab=VbiasN2} +C {devices/vsource.sym} 350 -50 0 0 {name=V3 value=\{VbiasN1\}} +C {devices/gnd.sym} 350 -10 0 0 {name=l3 lab=GND} +C {devices/lab_wire.sym} 350 -110 0 0 {name=p3 sig_type=std_logic lab=VbiasN1} +C {devices/lab_wire.sym} 710 40 0 0 {name=p4 sig_type=std_logic lab=VbiasN1} +C {devices/lab_wire.sym} 710 20 0 0 {name=p5 sig_type=std_logic lab=VbiasN2} +C {devices/lab_wire.sym} 710 0 0 0 {name=p6 sig_type=std_logic lab=VbiasP2} +C {devices/lab_wire.sym} 710 -60 0 0 {name=p7 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 710 -80 0 0 {name=p8 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 30 -50 0 0 {name=V4 value=\{VDD\}} +C {devices/gnd.sym} 30 -10 0 0 {name=l5 lab=GND} +C {devices/lab_wire.sym} 30 -110 0 0 {name=p9 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 110 -50 0 0 {name=V5 value=\{VSS\}} +C {devices/gnd.sym} 110 -10 0 0 {name=l6 lab=GND} +C {devices/lab_wire.sym} 110 -110 0 0 {name=p10 sig_type=std_logic lab=VSS} +C {devices/capa.sym} 950 -90 0 0 {name=C1 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {devices/vsource.sym} 560 -40 0 0 {name=V6 value=\{Vin_CM\}} +C {devices/gnd.sym} 560 0 0 0 {name=l7 lab=GND} +C {devices/lab_wire.sym} 560 -140 0 0 {name=p11 sig_type=std_logic lab=Vin} +C {devices/lab_wire.sym} 950 -170 0 0 {name=p12 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 950 0 0 0 {name=l8 lab=GND} +C {gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sym} 760 -170 0 0 {name=x1} +C {launcher.sym} 110 -260 0 0 {name=h1 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op"} +C {simulator_commands.sym} 100 -500 0 0 {name=COMMANDS +simulator=ngspice +only_toplevel=false +value=" + +* --- Include PDK and Model Files --- +.include /foss/pdks/gf180mcuD/libs.tech/ngspice/design.ngspice +.lib /foss/pdks/gf180mcuD/libs.tech/ngspice/sm141064.ngspice typical + +* --- Define Parameters for the Simulation --- +.param VDD = 1.8 +.param VSS = 0 +.param VbiasN1 = 0.81 +.param VbiasN2 = 1.2 +.param VbiasP1 = 0.95 +.param VbiasP2 = 0.5 +.param Vin_CM = 0.8 +.param Vout_CM = 0.9 +.param Vy = (Vout_CM - Vin_CM) +.param load_cap = 5*1e-12 + +* --- Simulation Commands and Analysis --- +.control +save all + +** OP & DC simulations +op +dc V9 0 1.8 0.001 + +** DC measurements +setplot dc1 +let dvout = deriv(v(Vout)) + +meas dc limmin when dvout=0.98 rise=1 +meas dc limmax when dvout=0.98 fall=1 + +let Output_swing = limmax - limmin + +print Output_swing +plot dvout + + +write error_amplifier_core_N_input_op.raw +.endc +"} +C {devices/vsource.sym} 430 -50 0 0 {name=Vsb1 value=\{VbiasP1\} savecurrent=false} +C {devices/gnd.sym} 430 -10 0 0 {name=l10 lab=GND} +C {devices/lab_wire.sym} 430 -110 0 0 {name=p13 sig_type=std_logic lab=VbiasP1 +} +C {devices/lab_wire.sym} 710 -20 0 0 {name=p14 sig_type=std_logic lab=VbiasP1} +C {devices/vsource.sym} 630 -430 1 0 {name=V9 value=\{Vout_CM\}} +C {vcvs.sym} 820 -380 0 1 {name=E1 value=1} +C {devices/gnd.sym} 820 -320 0 0 {name=l11 lab=GND} +C {devices/lab_wire.sym} 820 -430 0 0 {name=p19 sig_type=std_logic lab=Vz} +C {devices/lab_wire.sym} 560 -300 0 0 {name=p15 sig_type=std_logic lab=Vn} +C {noconn.sym} 660 -40 2 1 {name=l9} +C {devices/lab_wire.sym} 690 -40 0 0 {name=p16 sig_type=std_logic lab=Vcom} +C {devices/vsource.sym} 720 -430 3 0 {name=V7 value=\{Vin_CM\} +} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_Out_Swing_v2.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_Out_Swing_v2.sch new file mode 100644 index 00000000..72caeda6 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_Out_Swing_v2.sch @@ -0,0 +1,382 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +L 4 990 -560 1410 -560 {} +L 4 990 -510 1410 -510 {} +L 4 1120 -560 1120 -200 {} +L 4 1210 -560 1210 -200 {} +L 4 1300 -560 1300 -200 {} +L 4 1410 -560 1410 -200 {} +L 4 990 -560 990 -200 {} +L 4 990 -200 1410 -200 {} +T {Expected values for inputs:} 1070 -610 0 0 0.4 0.4 {} +T {Input} 1030 -550 0 0 0.4 0.4 {} +T {Min} 1150 -550 0 0 0.4 0.4 {} +T {Typ} 1240 -550 0 0 0.4 0.4 {} +T {Max} 1340 -550 0 0 0.4 0.4 {} +T {VDD} 1030 -500 0 0 0.4 0.4 {} +T {1.8} 1240 -500 0 0 0.4 0.4 {} +T {VIN_CM} 1010 -450 0 0 0.4 0.4 {} +T {0.8} 1340 -450 0 0 0.4 0.4 {} +T {VbiasP1} 1010 -400 0 0 0.4 0.4 {} +T {VbiasP2} 1010 -350 0 0 0.4 0.4 {} +T {VbiasN1} 1010 -300 0 0 0.4 0.4 {} +T {VbiasN2} 1010 -250 0 0 0.4 0.4 {} +T {0.95} 1235 -400 0 0 0.4 0.4 {} +T {0.81} 1240 -300 0 0 0.4 0.4 {} +T {1.28} 1235 -250 0 0 0.4 0.4 {} +T {0.4} 1235 -350 0 0 0.4 0.4 {} +N 630 -570 690 -570 {lab=Vout} +N 350 -280 430 -280 { +lab=Vx} +N 350 -330 350 -280 { +lab=Vx} +N 210 -280 250 -280 { +lab=Vin} +N 310 -280 350 -280 { +lab=Vx} +N 170 -280 210 -280 { +lab=Vin} +N 760 -570 760 -360 { +lab=Vout} +N 840 -440 840 -360 { +lab=GND} +N 840 -570 840 -510 { +lab=Vout} +N 690 -570 840 -570 { +lab=Vout} +N 350 -430 350 -390 { +lab=Vn} +N 840 -510 840 -500 { +lab=Vout} +N 210 -360 210 -280 {lab=Vin} +N 760 -360 760 -280 {lab=Vout} +N 210 -540 430 -540 {lab=Vin} +N 210 -540 210 -360 {lab=Vin} +N 350 -600 430 -600 {lab=Vn} +N 350 -520 350 -430 {lab=Vn} +N 330 -520 350 -520 {lab=Vn} +N 330 -560 330 -520 {lab=Vn} +N 330 -560 350 -560 {lab=Vn} +N 350 -600 350 -560 {lab=Vn} +N 390 -20 390 -10 {lab=GND} +N 390 -110 390 -80 {lab=VbiasP2} +N 470 -20 470 -10 {lab=GND} +N 470 -110 470 -80 {lab=VbiasN2} +N 550 -20 550 -10 {lab=GND} +N 550 -110 550 -80 {lab=VbiasN1} +N 230 -20 230 -10 {lab=GND} +N 230 -110 230 -80 {lab=VDD} +N 310 -20 310 -10 {lab=GND} +N 310 -110 310 -80 {lab=VSS} +N 630 -110 630 -80 {lab=VbiasP1} +N 630 -20 630 -10 {lab=GND} +N 170 -190 170 -180 {lab=GND} +N 170 -280 170 -250 {lab=Vin} +N 840 -360 840 -340 {lab=GND} +N 430 -440 480 -440 {lab=Vcom} +N 430 -280 450 -280 {lab=Vx} +N 710 -250 760 -250 {lab=Vout} +N 760 -280 760 -250 {lab=Vout} +N 670 -200 670 -170 {lab=GND} +N 710 -210 750 -210 {lab=GND} +N 750 -210 750 -180 {lab=GND} +N 670 -180 750 -180 {lab=GND} +N 670 -280 670 -260 {lab=Vz} +N 620 -280 670 -280 {lab=Vz} +N 510 -280 560 -280 {lab=Vy} +C {simulator_commands.sym} -20 -410 0 0 {name="COMMANDS" +simulator="ngspice" +only_toplevel="false" +value=" + +* --- Include PDK and Model Files --- +.include /foss/pdks/gf180mcuD/libs.tech/ngspice/design.ngspice +.lib /foss/pdks/gf180mcuD/libs.tech/ngspice/sm141064.ngspice typical + +* --- Define Parameters for the Simulation --- +.param VDD = 1.8 +.param VSS = 0 +.param VbiasN1 = 0.81 +.param VbiasN2 = 1.28 +.param VbiasP1 = 0.95 +.param VbiasP2 = 0.4 +.param Vin_CM = 0.8 +.param Vout_CM = 0.9 +.param Vy = (Vout_CM - Vin_CM) +.param load_cap = 5*1e-12 + +* --- Simulation Commands and Analysis --- + + +*+ abstol=1e-14 savecurrents +.control + save all + +** OP simulation +op + +** All OP parameters + +let #####_M1_pmos_input_##### = 0 +let id_M1 = @m.x1.xm1.m0[id] +let gm_M1 = @m.x1.xm1.m0[gm] +let ro_M1 = 1/@m.x1.xm1.m0[gds] +let Vsg_M1 = @m.x1.xm1.m0[vgs] +let Vsd_M1 = @m.x1.xm1.m0[vds] +let Vbs_M1 = -@m.x1.xm1.m0[vbs] +let Vdsat_M1 = @m.x1.xm1.m0[vdsat] +let Vth_M1 = @m.x1.xm1.m0[vth] +let ao_M1 = gm_M1*ro_M1 +let gmid_M1 = gm_M1/id_M1 +let fT_M1 = gm_M1/(6.283185*@m.x1.xm1.m0[cgg]) +print #####_M1_pmos_input_##### id_M1 gm_M1 ro_M1 Vsg_M1 Vsd_M1 Vbs_M1 Vdsat_M1 Vth_M1 ao_M1 gmid_M1 fT_M1 + +let #####_M2_pmos_input_##### = 0 +let id_M2 = @m.x1.xm2.m0[id] +let gm_M2 = @m.x1.xm2.m0[gm] +let ro_M2 = 1/@m.x1.xm2.m0[gds] +let Vsg_M2 = @m.x1.xm2.m0[vgs] +let Vsd_M2 = @m.x1.xm2.m0[vds] +let Vbs_M2 = -@m.x1.xm2.m0[vbs] +let Vdsat_M2 = @m.x1.xm2.m0[vdsat] +let Vth_M2 = @m.x1.xm2.m0[vth] +let ao_M2 = gm_M2*ro_M2 +let gmid_M2 = gm_M2/id_M2 +let fT_M2 = gm_M2/(6.283185*@m.x1.xm2.m0[cgg]) +print #####_M2_pmos_input_##### id_M2 gm_M2 ro_M2 Vsg_M2 Vsd_M2 Vbs_M2 Vdsat_M2 Vth_M2 ao_M2 gmid_M2 fT_M2 + +let #####_M3_pmos_top_##### = 0 +let id_M3 = @m.x1.xm3.m0[id] +let gm_M3 = @m.x1.xm3.m0[gm] +let ro_M3 = 1/@m.x1.xm3.m0[gds] +let Vsg_M3 = @m.x1.xm3.m0[vgs] +let Vsd_M3 = @m.x1.xm3.m0[vds] +let Vbs_M3 = -@m.x1.xm3.m0[vbs] +let Vdsat_M3 = @m.x1.xm3.m0[vdsat] +let Vth_M3 = @m.x1.xm3.m0[vth] +let ao_M3 = gm_M3*ro_M3 +let gmid_M3 = gm_M3/id_M3 +let fT_M3 = gm_M3/(6.283185*@m.x1.xm3.m0[cgg]) +print #####_M3_pmos_top_##### id_M3 gm_M3 ro_M3 Vsg_M3 Vsd_M3 Vbs_M3 Vdsat_M3 Vth_M3 ao_M3 gmid_M3 fT_M3 + +let #####_M4_pmos_top_##### = 0 +let id_M4 = @m.x1.xm4.m0[id] +let gm_M4 = @m.x1.xm4.m0[gm] +let ro_M4 = 1/@m.x1.xm4.m0[gds] +let Vsg_M4 = @m.x1.xm4.m0[vgs] +let Vsd_M4 = @m.x1.xm4.m0[vds] +let Vbs_M4 = -@m.x1.xm4.m0[vbs] +let Vdsat_M4 = @m.x1.xm4.m0[vdsat] +let Vth_M4 = @m.x1.xm4.m0[vth] +let ao_M4 = gm_M4*ro_M4 +let gmid_M4 = gm_M4/id_M4 +let fT_M4 = gm_M4/(6.283185*@m.x1.xm4.m0[cgg]) +print #####_M4_pmos_top_##### id_M4 gm_M4 ro_M4 Vsg_M4 Vsd_M4 Vbs_M4 Vdsat_M4 Vth_M4 ao_M4 gmid_M4 fT_M4 + +let #####_M5_pmos_out_##### = 0 +let id_M5 = @m.x1.xm5.m0[id] +let gm_M5 = @m.x1.xm5.m0[gm] +let ro_M5 = 1/@m.x1.xm5.m0[gds] +let Vsg_M5 = @m.x1.xm5.m0[vgs] +let Vsd_M5 = @m.x1.xm5.m0[vds] +let Vbs_M5 = -@m.x1.xm5.m0[vbs] +let Vdsat_M5 = @m.x1.xm5.m0[vdsat] +let Vth_M5 = @m.x1.xm5.m0[vth] +let ao_M5 = gm_M5*ro_M5 +let gmid_M5 = gm_M5/id_M5 +let fT_M5 = gm_M5/(6.283185*@m.x1.xm5.m0[cgg]) +print #####_M5_pmos_out_##### id_M5 gm_M5 ro_M5 Vsg_M5 Vsd_M5 Vbs_M5 Vdsat_M5 Vth_M5 ao_M5 gmid_M5 fT_M5 + +let #####_M6_pmos_out_##### = 0 +let id_M6 = @m.x1.xm6.m0[id] +let gm_M6 = @m.x1.xm6.m0[gm] +let ro_M6 = 1/@m.x1.xm6.m0[gds] +let Vsg_M6 = @m.x1.xm6.m0[vgs] +let Vsd_M6 = @m.x1.xm6.m0[vds] +let Vbs_M6 = -@m.x1.xm6.m0[vbs] +let Vdsat_M6 = @m.x1.xm6.m0[vdsat] +let Vth_M6 = @m.x1.xm6.m0[vth] +let ao_M6 = gm_M6*ro_M6 +let gmid_M6 = gm_M6/id_M6 +let fT_M6 = gm_M6/(6.283185*@m.x1.xm6.m0[cgg]) +print #####_M6_pmos_out_##### id_M6 gm_M6 ro_M6 Vsg_M6 Vsd_M6 Vbs_M6 Vdsat_M6 Vth_M6 ao_M6 gmid_M6 fT_M6 + +let #####_M7_nmos_out_##### = 0 +let id_M7 = @m.x1.xm7.m0[id] +let gm_M7 = @m.x1.xm7.m0[gm] +let ro_M7 = 1/@m.x1.xm7.m0[gds] +let Vgs_M7 = @m.x1.xm7.m0[vgs] +let Vds_M7 = @m.x1.xm7.m0[vds] +let Vsb_M7 = -@m.x1.xm7.m0[vbs] +let Vdsat_M7 = @m.x1.xm7.m0[vdsat] +let Vth_M7 = @m.x1.xm7.m0[vth] +let ao_M7 = gm_M7*ro_M7 +let gmid_M7 = gm_M7/id_M7 +let fT_M7 = gm_M7/(6.283185*@m.x1.xm7.m0[cgg]) +print #####_M7_nmos_out_##### id_M7 gm_M7 ro_M7 Vgs_M7 Vds_M7 Vsb_M7 Vdsat_M7 Vth_M7 ao_M7 gmid_M7 fT_M7 + +let #####_M8_nmos_out_##### = 0 +let id_M8 = @m.x1.xm8.m0[id] +let gm_M8 = @m.x1.xm8.m0[gm] +let ro_M8 = 1/@m.x1.xm8.m0[gds] +let Vgs_M8 = @m.x1.xm8.m0[vgs] +let Vds_M8 = @m.x1.xm8.m0[vds] +let Vsb_M8 = -@m.x1.xm8.m0[vbs] +let Vdsat_M8 = @m.x1.xm8.m0[vdsat] +let Vth_M8 = @m.x1.xm8.m0[vth] +let ao_M8 = gm_M8*ro_M8 +let gmid_M8 = gm_M8/id_M8 +let fT_M8 = gm_M8/(6.283185*@m.x1.xm8.m0[cgg]) +print #####_M8_nmos_out_##### id_M8 gm_M8 ro_M8 Vgs_M8 Vds_M8 Vsb_M8 Vdsat_M8 Vth_M8 ao_M8 gmid_M8 fT_M8 +let #####_M9_nmos_bottom_##### = 0 +let id_M9 = @m.x1.xm9.m0[id] +let gm_M9 = @m.x1.xm9.m0[gm] +let ro_M9 = 1/@m.x1.xm9.m0[gds] +let Vgs_M9 = @m.x1.xm9.m0[vgs] +let Vds_M9 = @m.x1.xm9.m0[vds] +let Vsb_M9 = -@m.x1.xm9.m0[vbs] +let Vdsat_M9 = @m.x1.xm9.m0[vdsat] +let Vth_M9 = @m.x1.xm9.m0[vth] +let ao_M9 = gm_M9*ro_M9 +let gmid_M9 = gm_M9/id_M9 +let fT_M9 = gm_M9/(6.283185*@m.x1.xm9.m0[cgg]) +print #####_M9_nmos_bottom_##### id_M9 gm_M9 ro_M9 Vgs_M9 Vds_M9 Vsb_M9 Vdsat_M9 Vth_M9 ao_M9 gmid_M9 fT_M9 + +let #####_M10_nmos_bottom_##### = 0 +let id_M10 = @m.x1.xm10.m0[id] +let gm_M10 = @m.x1.xm10.m0[gm] +let ro_M10 = 1/@m.x1.xm10.m0[gds] +let Vgs_M10 = @m.x1.xm10.m0[vgs] +let Vds_M10 = @m.x1.xm10.m0[vds] +let Vsb_M10 = @m.x1.xm10.m0[vbs] +let Vdsat_M10 = @m.x1.xm10.m0[vdsat] +let Vth_M10 = @m.x1.xm10.m0[vth] +let ao_M10 = gm_M10*ro_M10 +let gmid_M10 = gm_M10/id_M10 +let fT_M10 = gm_M10/(6.283185*@m.x1.xm10.m0[cgg]) +print #####_M10_nmos_bottom_##### id_M10 gm_M10 ro_M10 Vgs_M10 Vds_M10 Vsb_M10 Vdsat_M10 Vth_M10 ao_M10 gmid_M10 fT_M10 + +let #####_M11_pmos_mirror_##### = 0 +let id_M11 = @m.x1.xm11.m0[id] +let gm_M11 = @m.x1.xm11.m0[gm] +let ro_M11 = 1/@m.x1.xm11.m0[gds] +let Vsg_M11 = @m.x1.xm11.m0[vgs] +let Vsd_M11 = @m.x1.xm11.m0[vds] +let Vbs_M11 = -@m.x1.xm11.m0[vbs] +let Vdsat_M11 = @m.x1.xm11.m0[vdsat] +let Vth_M11 = @m.x1.xm11.m0[vth] +let ao_M11 = gm_M11*ro_M11 +let gmid_M11 = gm_M11/id_M11 +let fT_M11 = gm_M11/(6.283185*@m.x1.xm11.m0[cgg]) +print #####_M11_pmos_mirror_##### id_M11 gm_M11 ro_M11 Vsg_M11 Vsd_M11 Vbs_M11 Vdsat_M11 Vth_M11 ao_M11 gmid_M11 fT_M11 + +** Custom output +let #####_Custom_output_##### = 0 + +* DC_gain +let r1 = ao_M6*ro_M4 +let r2 = ao_M8*((ro_M1*ro_M10)/(ro_M1+ro_M10)) +let Rout = (r1*r2)/(r1+r2) +let Av = db(gm_M1*Rout) +* Bandwidth +let BW = 1/(Rout*1e-12*6.283185) +let BW_2 = 1/(Rout*5p*6.283185) + + +print #####_Custom_output_##### Av BW BW_2 Rout gm_M1 ro_M1 gm_M6 ro_M6 ro_M4 gm_M8 ro_M8 ro_M10 + + + remzerovec + write error_amplifier_core_N_input_ac.raw + set appendwrite + + * run ac simulation + ac dec 20 1 100e7 + + * measure parameters + let vout_mag_VV = abs(v(Vout)) + let vout_mag = db(abs(v(Vout))) + let vout_phase = cph(v(Vout)) * 180/pi + let gm = (-1)*db(abs(v(Vout))) + + meas ac A0 find vout_mag at=1 + meas ac UGB when vout_mag=0 fall=1 + meas ac PM find vout_phase when vout_mag=0 + meas ac GM find gm when vout_phase=0 + + let A0_p1 = A0 - 3 + meas ac BW when vout_mag=A0_p1 + + *plot vout_mag + *plot vout_phase + + write error_amplifier_core_N_input_ac.raw +.endc +"} +C {devices/launcher.sym} 0 -570 0 0 {name=h15 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op" +} +C {devices/launcher.sym} 0 -640 0 0 {name=h3 +descr="Netlist & sim" +tclcommand="xschem netlist; xschem simulate"} +C {vsource.sym} 350 -360 0 0 {name=V5 value="AC 1" savecurrent=false} +C {capa.sym} 280 -280 1 0 {name=C2 +m=1 +value=10G +footprint=1206 +device="ceramic capacitor"} +C {ind.sym} 480 -280 1 0 {name=L4 +m=1 +value=10G +footprint=1206 +device=inductor} +C {lab_pin.sym} 480 -480 2 1 {name=p8 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 480 -460 2 1 {name=p9 sig_type=std_logic lab=VSS} +C {gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sym} 530 -570 0 0 {name=x1} +C {capa.sym} 840 -470 0 0 {name=C1 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {noconn.sym} 430 -440 2 1 {name=l1} +C {lab_pin.sym} 840 -570 0 1 {name=p2 sig_type=std_logic lab=Vout} +C {lab_pin.sym} 480 -420 2 1 {name=p5 sig_type=std_logic lab=VbiasP1} +C {lab_pin.sym} 480 -400 2 1 {name=p6 sig_type=std_logic lab=VbiasP2} +C {lab_pin.sym} 480 -380 2 1 {name=p7 sig_type=std_logic lab=VbiasN2} +C {lab_pin.sym} 480 -360 2 1 {name=p11 sig_type=std_logic lab=VbiasN1} +C {devices/vsource.sym} 390 -50 0 0 {name=V1 value=\{VbiasP2\}} +C {devices/gnd.sym} 390 -10 0 0 {name=l2 lab=GND} +C {devices/lab_wire.sym} 390 -110 0 0 {name=p3 sig_type=std_logic lab=VbiasP2} +C {devices/vsource.sym} 470 -50 0 0 {name=V2 value=\{VbiasN2\}} +C {devices/gnd.sym} 470 -10 0 0 {name=l3 lab=GND} +C {devices/lab_wire.sym} 470 -110 0 0 {name=p4 sig_type=std_logic lab=VbiasN2} +C {devices/vsource.sym} 550 -50 0 0 {name=V3 value=\{VbiasN1\}} +C {devices/gnd.sym} 550 -10 0 0 {name=l5 lab=GND} +C {devices/lab_wire.sym} 550 -110 0 0 {name=p12 sig_type=std_logic lab=VbiasN1} +C {devices/vsource.sym} 230 -50 0 0 {name=V4 value=\{VDD\}} +C {devices/gnd.sym} 230 -10 0 0 {name=l6 lab=GND} +C {devices/lab_wire.sym} 230 -110 0 0 {name=p13 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 310 -50 0 0 {name=V6 value=\{VSS\}} +C {devices/gnd.sym} 310 -10 0 0 {name=l7 lab=GND} +C {devices/lab_wire.sym} 310 -110 0 0 {name=p14 sig_type=std_logic lab=VSS} +C {devices/vsource.sym} 630 -50 0 0 {name=V8 value=\{VbiasP1\} savecurrent=false} +C {devices/gnd.sym} 630 -10 0 0 {name=l10 lab=GND} +C {devices/lab_wire.sym} 630 -110 0 0 {name=p15 sig_type=std_logic lab=VbiasP1 +} +C {devices/vsource.sym} 170 -220 0 0 {name=V7 value=\{Vin_CM\}} +C {devices/gnd.sym} 170 -180 0 0 {name=l8 lab=GND} +C {devices/lab_wire.sym} 170 -280 0 0 {name=p10 sig_type=std_logic lab=Vin} +C {devices/gnd.sym} 840 -340 0 0 {name=l9 lab=GND} +C {devices/lab_wire.sym} 390 -280 0 0 {name=p1 sig_type=std_logic lab=Vx} +C {devices/lab_wire.sym} 460 -440 0 0 {name=p16 sig_type=std_logic lab=Vcom} +C {devices/lab_wire.sym} 370 -600 0 0 {name=p17 sig_type=std_logic lab=Vn} +C {devices/vsource.sym} 590 -280 1 0 {name=V9 value=\{Vy\}} +C {vcvs.sym} 670 -230 0 1 {name=E1 value=1} +C {devices/gnd.sym} 670 -170 0 0 {name=l11 lab=GND} +C {devices/lab_wire.sym} 530 -280 0 0 {name=p18 sig_type=std_logic lab=Vy} +C {devices/lab_wire.sym} 670 -280 0 0 {name=p19 sig_type=std_logic lab=Vz} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_ac.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_ac.sch new file mode 100644 index 00000000..4c4b3def --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_ac.sch @@ -0,0 +1,310 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 1210 -240 1210 -180 { +lab=GND} +N 1120 -350 1210 -350 { +lab=Vout} +N 1210 -350 1210 -300 { +lab=Vout} +N 820 -380 920 -380 { +lab=V-} +N 510 -90 510 -80 {lab=GND} +N 510 -180 510 -150 {lab=Vin} +N 820 -320 920 -320 { +lab=Vin} +N 270 -90 270 -80 {lab=GND} +N 270 -180 270 -150 {lab=VbiasP2} +N 350 -90 350 -80 {lab=GND} +N 350 -180 350 -150 {lab=VbiasN2} +N 430 -90 430 -80 {lab=GND} +N 430 -180 430 -150 {lab=VbiasN1} +N 110 -90 110 -80 {lab=GND} +N 110 -180 110 -150 {lab=VDD} +N 190 -90 190 -80 {lab=GND} +N 190 -180 190 -150 {lab=VSS} +N 1160 -350 1160 -90 {lab=Vout} +N 1050 -90 1160 -90 {lab=Vout} +N 790 -90 990 -90 {lab=#net1} +N 650 -320 820 -320 {lab=Vin} +N 650 -320 650 -90 {lab=Vin} +N 650 -90 730 -90 {lab=Vin} +N 820 -140 820 -90 {lab=#net1} +N 820 -240 820 -200 {lab=V-} +C {vsource.sym} 820 -170 0 0 {name=V5 value="AC 1" savecurrent=false} +C {capa.sym} 760 -90 1 0 {name=C2 +m=1 +value=10G +footprint=1206 +device="ceramic capacitor"} +C {ind.sym} 1020 -90 1 0 {name=L4 +m=1 +value=10G +footprint=1206 +device=inductor} +C {devices/code_shown.sym} 50 -580 0 0 {name=MODELS only_toplevel=true +format="tcleval( @value )" +value=" +.include $::180MCU_MODELS/design.ngspice +.lib $::180MCU_MODELS/sm141064.ngspice typical +"} +C {devices/lab_wire.sym} 970 -160 0 0 {name=p5 sig_type=std_logic lab=VbiasN1} +C {devices/lab_wire.sym} 970 -180 0 0 {name=p6 sig_type=std_logic lab=VbiasN2} +C {devices/lab_wire.sym} 970 -200 0 0 {name=p11 sig_type=std_logic lab=VbiasP2} +C {devices/noconn.sym} 970 -220 0 0 {name=l2} +C {devices/lab_wire.sym} 970 -240 0 0 {name=p12 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 970 -260 0 0 {name=p13 sig_type=std_logic lab=VDD} +C {devices/capa.sym} 1210 -270 0 0 {name=C3 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {devices/vsource.sym} 510 -120 0 0 {name=V6 value=\{Vin\}} +C {devices/gnd.sym} 510 -80 0 0 {name=l3 lab=GND} +C {devices/lab_wire.sym} 510 -180 0 0 {name=p14 sig_type=std_logic lab=Vin} +C {devices/lab_wire.sym} 1210 -350 0 0 {name=p15 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 1210 -180 0 0 {name=l8 lab=GND} +C {simulator_commands.sym} 990 -580 0 0 {name=COMMANDS1 +simulator=ngspice +only_toplevel=false +value=" +.control +save all + +** OP simulation +op + +** run ac simulation +ac dec 20 1 100e6 + +** All OP parameters +setplot op1 + +let #####_M1_nmos_input_##### = 0 +let id_M1 = @m.x1.xm1.m0[id] +let gm_M1 = @m.x1.xm1.m0[gm] +let ro_M1 = 1/@m.x1.xm1.m0[gds] +let Vgs_M1 = @m.x1.xm1.m0[vgs] +let Vds_M1 = @m.x1.xm1.m0[vds] +let Vsb_M1 = -@m.x1.xm1.m0[vbs] +let Vdsat_M1 = @m.x1.xm1.m0[vdsat] +let Vth_M1 = @m.x1.xm1.m0[vth] +let ao_M1 = gm_M1*ro_M1 +let gmid_M1 = gm_M1/id_M1 +let fT_M1 = gm_M1/(6.283185*@m.x1.xm1.m0[cgg]) +print #####_M1_nmos_input_##### id_M1 gm_M1 ro_M1 Vgs_M1 Vds_M1 Vsb_M1 Vdsat_M1 Vth_M1 ao_M1 gmid_M1 fT_M1 + +let #####_M2_nmos_input_##### = 0 +let id_M2 = @m.x1.xm2.m0[id] +let gm_M2 = @m.x1.xm2.m0[gm] +let ro_M2 = 1/@m.x1.xm2.m0[gds] +let Vgs_M2 = @m.x1.xm2.m0[vgs] +let Vds_M2 = @m.x1.xm2.m0[vds] +let Vsb_M2 = -@m.x1.xm2.m0[vbs] +let Vdsat_M2 = @m.x1.xm2.m0[vdsat] +let Vth_M2 = @m.x1.xm2.m0[vth] +let ao_M2 = gm_M2*ro_M2 +let gmid_M2 = gm_M2/id_M2 +let fT_M2 = gm_M2/(6.283185*@m.x1.xm2.m0[cgg]) +print #####_M2_nmos_input_##### id_M2 gm_M2 ro_M2 Vgs_M2 Vds_M2 Vsb_M2 Vdsat_M2 Vth_M2 ao_M2 gmid_M2 fT_M2 + +let #####_M3_pmos_top_##### = 0 +let id_M3 = @m.x1.xm3.m0[id] +let gm_M3 = @m.x1.xm3.m0[gm] +let ro_M3 = 1/@m.x1.xm3.m0[gds] +let Vsg_M3 = @m.x1.xm3.m0[vgs] +let Vsd_M3 = @m.x1.xm3.m0[vds] +let Vbs_M3 = -@m.x1.xm3.m0[vbs] +let Vdsat_M3 = @m.x1.xm3.m0[vdsat] +let Vth_M3 = @m.x1.xm3.m0[vth] +let ao_M3 = gm_M3*ro_M3 +let gmid_M3 = gm_M3/id_M3 +let fT_M3 = gm_M3/(6.283185*@m.x1.xm3.m0[cgg]) +print #####_M3_pmos_top_##### id_M3 gm_M3 ro_M3 Vsg_M3 Vsd_M3 Vbs_M3 Vdsat_M3 Vth_M3 ao_M3 gmid_M3 fT_M3 + +let #####_M4_pmos_top_##### = 0 +let id_M4 = @m.x1.xm4.m0[id] +let gm_M4 = @m.x1.xm4.m0[gm] +let ro_M4 = 1/@m.x1.xm4.m0[gds] +let Vsg_M4 = @m.x1.xm4.m0[vgs] +let Vsd_M4 = @m.x1.xm4.m0[vds] +let Vbs_M4 = -@m.x1.xm4.m0[vbs] +let Vdsat_M4 = @m.x1.xm4.m0[vdsat] +let Vth_M4 = @m.x1.xm4.m0[vth] +let ao_M4 = gm_M4*ro_M4 +let gmid_M4 = gm_M4/id_M4 +let fT_M4 = gm_M4/(6.283185*@m.x1.xm4.m0[cgg]) +print #####_M4_pmos_top_##### id_M4 gm_M4 ro_M4 Vsg_M4 Vsd_M4 Vbs_M4 Vdsat_M4 Vth_M4 ao_M4 gmid_M4 fT_M4 + +let #####_M5_pmos_out_##### = 0 +let id_M5 = @m.x1.xm5.m0[id] +let gm_M5 = @m.x1.xm5.m0[gm] +let ro_M5 = 1/@m.x1.xm5.m0[gds] +let Vsg_M5 = @m.x1.xm5.m0[vgs] +let Vsd_M5 = @m.x1.xm5.m0[vds] +let Vbs_M5 = -@m.x1.xm5.m0[vbs] +let Vdsat_M5 = @m.x1.xm5.m0[vdsat] +let Vth_M5 = @m.x1.xm5.m0[vth] +let ao_M5 = gm_M5*ro_M5 +let gmid_M5 = gm_M5/id_M5 +let fT_M5 = gm_M5/(6.283185*@m.x1.xm5.m0[cgg]) +print #####_M5_pmos_out_##### id_M5 gm_M5 ro_M5 Vsg_M5 Vsd_M5 Vbs_M5 Vdsat_M5 Vth_M5 ao_M5 gmid_M5 fT_M5 + +let #####_M6_pmos_out_##### = 0 +let id_M6 = @m.x1.xm6.m0[id] +let gm_M6 = @m.x1.xm6.m0[gm] +let ro_M6 = 1/@m.x1.xm6.m0[gds] +let Vsg_M6 = @m.x1.xm6.m0[vgs] +let Vsd_M6 = @m.x1.xm6.m0[vds] +let Vbs_M6 = -@m.x1.xm6.m0[vbs] +let Vdsat_M6 = @m.x1.xm6.m0[vdsat] +let Vth_M6 = @m.x1.xm6.m0[vth] +let ao_M6 = gm_M6*ro_M6 +let gmid_M6 = gm_M6/id_M6 +let fT_M6 = gm_M6/(6.283185*@m.x1.xm6.m0[cgg]) +print #####_M6_pmos_out_##### id_M6 gm_M6 ro_M6 Vsg_M6 Vsd_M6 Vbs_M6 Vdsat_M6 Vth_M6 ao_M6 gmid_M6 fT_M6 + +let #####_M7_nmos_out_##### = 0 +let id_M7 = @m.x1.xm7.m0[id] +let gm_M7 = @m.x1.xm7.m0[gm] +let ro_M7 = 1/@m.x1.xm7.m0[gds] +let Vgs_M7 = @m.x1.xm7.m0[vgs] +let Vds_M7 = @m.x1.xm7.m0[vds] +let Vsb_M7 = -@m.x1.xm7.m0[vbs] +let Vdsat_M7 = @m.x1.xm7.m0[vdsat] +let Vth_M7 = @m.x1.xm7.m0[vth] +let ao_M7 = gm_M7*ro_M7 +let gmid_M7 = gm_M7/id_M7 +let fT_M7 = gm_M7/(6.283185*@m.x1.xm7.m0[cgg]) +print #####_M7_nmos_out_##### id_M7 gm_M7 ro_M7 Vgs_M7 Vds_M7 Vsb_M7 Vdsat_M7 Vth_M7 ao_M7 gmid_M7 fT_M7 + +let #####_M8_nmos_out_##### = 0 +let id_M8 = @m.x1.xm8.m0[id] +let gm_M8 = @m.x1.xm8.m0[gm] +let ro_M8 = 1/@m.x1.xm8.m0[gds] +let Vgs_M8 = @m.x1.xm8.m0[vgs] +let Vds_M8 = @m.x1.xm8.m0[vds] +let Vsb_M8 = -@m.x1.xm8.m0[vbs] +let Vdsat_M8 = @m.x1.xm8.m0[vdsat] +let Vth_M8 = @m.x1.xm8.m0[vth] +let ao_M8 = gm_M8*ro_M8 +let gmid_M8 = gm_M8/id_M8 +let fT_M8 = gm_M8/(6.283185*@m.x1.xm8.m0[cgg]) +print #####_M8_nmos_out_##### id_M8 gm_M8 ro_M8 Vgs_M8 Vds_M8 Vsb_M8 Vdsat_M8 Vth_M8 ao_M8 gmid_M8 fT_M8 + +let #####_M9_nmos_bottom_##### = 0 +let id_M9 = @m.x1.xm9.m0[id] +let gm_M9 = @m.x1.xm9.m0[gm] +let ro_M9 = 1/@m.x1.xm9.m0[gds] +let Vgs_M9 = @m.x1.xm9.m0[vgs] +let Vds_M9 = @m.x1.xm9.m0[vds] +let Vsb_M9 = -@m.x1.xm9.m0[vbs] +let Vdsat_M9 = @m.x1.xm9.m0[vdsat] +let Vth_M9 = @m.x1.xm9.m0[vth] +let ao_M9 = gm_M9*ro_M9 +let gmid_M9 = gm_M9/id_M9 +let fT_M9 = gm_M9/(6.283185*@m.x1.xm9.m0[cgg]) +print #####_M9_nmos_bottom_##### id_M9 gm_M9 ro_M9 Vgs_M9 Vds_M9 Vsb_M9 Vdsat_M9 Vth_M9 ao_M9 gmid_M9 fT_M9 + +let #####_M10_nmos_bottom_##### = 0 +let id_M10 = @m.x1.xm10.m0[id] +let gm_M10 = @m.x1.xm10.m0[gm] +let ro_M10 = 1/@m.x1.xm10.m0[gds] +let Vgs_M10 = @m.x1.xm10.m0[vgs] +let Vds_M10 = @m.x1.xm10.m0[vds] +let Vsb_M10 = @m.x1.xm10.m0[vbs] +let Vdsat_M10 = @m.x1.xm10.m0[vdsat] +let Vth_M10 = @m.x1.xm10.m0[vth] +let ao_M10 = gm_M10*ro_M10 +let gmid_M10 = gm_M10/id_M10 +let fT_M10 = gm_M10/(6.283185*@m.x1.xm10.m0[cgg]) +print #####_M10_nmos_bottom_##### id_M10 gm_M10 ro_M10 Vgs_M10 Vds_M10 Vsb_M10 Vdsat_M10 Vth_M10 ao_M10 gmid_M10 fT_M10 + +let #####_M11_nmos_mirror_##### = 0 +let id_M11 = @m.x1.xm11.m0[id] +let gm_M11 = @m.x1.xm11.m0[gm] +let ro_M11 = 1/@m.x1.xm11.m0[gds] +let Vgs_M11 = @m.x1.xm11.m0[vgs] +let Vds_M11 = @m.x1.xm11.m0[vds] +let Vsb_M11 = -@m.x1.xm11.m0[vbs] +let Vdsat_M11 = @m.x1.xm11.m0[vdsat] +let Vth_M11 = @m.x1.xm11.m0[vth] +let ao_M11 = gm_M11*ro_M11 +let gmid_M11 = gm_M11/id_M11 +let fT_M11 = gm_M11/(6.283185*@m.x1.xm11.m0[cgg]) +print #####_M11_nmos_mirror_##### id_M11 gm_M11 ro_M11 Vgs_M11 Vds_M11 Vsb_M11 Vdsat_M11 Vth_M11 ao_M11 gmid_M11 fT_M11 + +** Custom output +let #####_Custom_output_##### = 0 + +* Power +let power = (id_M11 + id_M10 + id_M9)*VDD + +* DC_gain +let r1 = ao_M6*ro_M4 +let r2 = ao_M8*((ro_M1*ro_M10)/(ro_M1+ro_M10)) +let Rout = (r1*r2)/(r1+r2) +let Av = db(gm_M1*Rout) +* Bandwidth +let BW = 1/(Rout*1e-12*6.283185) + +print #####_Custom_output_##### Av BW Rout power gm_M1 ro_M1 gm_M6 ro_M6 ro_M4 gm_M8 ro_M8 ro_M10 + +write error_amplifier_core_N_input_ac.raw + +setplot ac1 + +* measure parameters +let vout_mag = db(abs(v(Vout))) +let vout_phase = cph(v(Vout)) * 180/pi +let gm = (-1)*db(abs(v(Vout))) + +meas ac A0 find vout_mag at=1e2 +meas ac UGB when vout_mag=0 fall=1 +meas ac PM find vout_phase when vout_mag=0 +meas ac GM find gm when vout_phase=0 + +let A0_p1 = A0 - 3 +meas ac BW when vout_mag=A0_p1 + +plot vout_mag vout_phase + +.endc +"} +C {devices/code_shown.sym} 710 -600 0 0 {name=Voltage_sources only_toplevel=true +value=" +.param VDD = 1.8 +.param VSS = 0 +.param VbiasN1 = 0.77 +.param VbiasN2 = 1.28 +.param VbiasP2 = 0.46 +.param Vin = 1 +"} +C {/foss/designs/workarea/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sym} 1020 -350 0 0 {name=x1} +C {devices/vsource.sym} 270 -120 0 0 {name=V1 value=\{VbiasP2\}} +C {devices/gnd.sym} 270 -80 0 0 {name=l9 lab=GND} +C {devices/lab_wire.sym} 270 -180 0 0 {name=p16 sig_type=std_logic lab=VbiasP2} +C {devices/vsource.sym} 350 -120 0 0 {name=V3 value=\{VbiasN2\}} +C {devices/gnd.sym} 350 -80 0 0 {name=l10 lab=GND} +C {devices/lab_wire.sym} 350 -180 0 0 {name=p17 sig_type=std_logic lab=VbiasN2} +C {devices/vsource.sym} 430 -120 0 0 {name=V7 value=\{VbiasN1\}} +C {devices/gnd.sym} 430 -80 0 0 {name=l11 lab=GND} +C {devices/lab_wire.sym} 430 -180 0 0 {name=p18 sig_type=std_logic lab=VbiasN1} +C {devices/vsource.sym} 110 -120 0 0 {name=V8 value=\{VDD\}} +C {devices/gnd.sym} 110 -80 0 0 {name=l12 lab=GND} +C {devices/lab_wire.sym} 110 -180 0 0 {name=p19 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 190 -120 0 0 {name=V9 value=\{VSS\}} +C {devices/gnd.sym} 190 -80 0 0 {name=l13 lab=GND} +C {devices/lab_wire.sym} 190 -180 0 0 {name=p20 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 820 -380 0 0 {name=p1 sig_type=std_logic lab=V-} +C {devices/lab_wire.sym} 820 -240 0 0 {name=p2 sig_type=std_logic lab=V-} +C {devices/launcher.sym} 140 -410 0 0 {name=h1 +descr="Save & Netlist & sim" +tclcommand="xschem save; xschem netlist; xschem simulate"} +C {launcher.sym} 140 -340 0 0 {name=h2 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op"} +C {devices/lab_wire.sym} 820 -320 0 0 {name=p3 sig_type=std_logic lab=Vin} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_ac_alex.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_ac_alex.sch new file mode 100644 index 00000000..ca81bf64 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_ac_alex.sch @@ -0,0 +1,382 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +L 4 1010 -445 1430 -445 {} +L 4 1010 -395 1430 -395 {} +L 4 1140 -445 1140 -85 {} +L 4 1230 -445 1230 -85 {} +L 4 1320 -445 1320 -85 {} +L 4 1430 -445 1430 -85 {} +L 4 1010 -445 1010 -85 {} +L 4 1010 -85 1430 -85 {} +T {Expected values for inputs:} 1090 -495 0 0 0.4 0.4 {} +T {Input} 1050 -435 0 0 0.4 0.4 {} +T {Min} 1170 -435 0 0 0.4 0.4 {} +T {Typ} 1260 -435 0 0 0.4 0.4 {} +T {Max} 1360 -435 0 0 0.4 0.4 {} +T {VDD} 1050 -385 0 0 0.4 0.4 {} +T {1.8} 1260 -385 0 0 0.4 0.4 {} +T {VIN_CM} 1030 -335 0 0 0.4 0.4 {} +T {0.8} 1360 -335 0 0 0.4 0.4 {} +T {VbiasP1} 1030 -285 0 0 0.4 0.4 {} +T {VbiasP2} 1030 -235 0 0 0.4 0.4 {} +T {VbiasN1} 1030 -185 0 0 0.4 0.4 {} +T {VbiasN2} 1030 -135 0 0 0.4 0.4 {} +T {0.95} 1255 -285 0 0 0.4 0.4 {} +T {0.81} 1255 -185 0 0 0.4 0.4 {} +T {1.2} 1260 -135 0 0 0.4 0.4 {} +T {0.5} 1260 -235 0 0 0.4 0.4 {} +N 680 -570 740 -570 {lab=Vout} +N 400 -280 480 -280 { +lab=Vx} +N 400 -330 400 -280 { +lab=Vx} +N 260 -280 300 -280 { +lab=Vin} +N 360 -280 400 -280 { +lab=Vx} +N 220 -280 260 -280 { +lab=Vin} +N 810 -570 810 -360 { +lab=Vout} +N 890 -440 890 -360 { +lab=GND} +N 890 -570 890 -510 { +lab=Vout} +N 740 -570 890 -570 { +lab=Vout} +N 400 -430 400 -390 { +lab=Vn} +N 890 -510 890 -500 { +lab=Vout} +N 260 -360 260 -280 {lab=Vin} +N 810 -360 810 -280 {lab=Vout} +N 260 -540 480 -540 {lab=Vin} +N 260 -540 260 -360 {lab=Vin} +N 400 -600 480 -600 {lab=Vn} +N 400 -520 400 -430 {lab=Vn} +N 380 -520 400 -520 {lab=Vn} +N 380 -560 380 -520 {lab=Vn} +N 380 -560 400 -560 {lab=Vn} +N 400 -600 400 -560 {lab=Vn} +N 440 -20 440 -10 {lab=GND} +N 440 -110 440 -80 {lab=VbiasP2} +N 520 -20 520 -10 {lab=GND} +N 520 -110 520 -80 {lab=VbiasN2} +N 600 -20 600 -10 {lab=GND} +N 600 -110 600 -80 {lab=VbiasN1} +N 280 -20 280 -10 {lab=GND} +N 280 -110 280 -80 {lab=VDD} +N 360 -20 360 -10 {lab=GND} +N 360 -110 360 -80 {lab=VSS} +N 680 -110 680 -80 {lab=VbiasP1} +N 680 -20 680 -10 {lab=GND} +N 220 -190 220 -180 {lab=GND} +N 220 -280 220 -250 {lab=Vin} +N 890 -360 890 -340 {lab=GND} +N 480 -440 530 -440 {lab=Vcom} +N 480 -280 500 -280 {lab=Vx} +N 760 -250 810 -250 {lab=Vout} +N 810 -280 810 -250 {lab=Vout} +N 720 -200 720 -170 {lab=GND} +N 760 -210 800 -210 {lab=GND} +N 800 -210 800 -180 {lab=GND} +N 720 -180 800 -180 {lab=GND} +N 720 -280 720 -260 {lab=Vz} +N 670 -280 720 -280 {lab=Vz} +N 560 -280 610 -280 {lab=Vy} +C {simulator_commands.sym} 30 -410 0 0 {name="COMMANDS" +simulator="ngspice" +only_toplevel="false" +value=" + +* --- Include PDK and Model Files --- +.include /foss/pdks/gf180mcuD/libs.tech/ngspice/design.ngspice +.lib /foss/pdks/gf180mcuD/libs.tech/ngspice/sm141064.ngspice typical + +* --- Define Parameters for the Simulation --- +.param VDD = 1.8 +.param VSS = 0 +.param VbiasN1 = 0.81 +.param VbiasN2 = 1.2 +.param VbiasP1 = 0.95 +.param VbiasP2 = 0.5 +.param Vin_CM = 0.8 +.param Vout_CM = 0.9 +.param Vy = (Vout_CM - Vin_CM) +.param load_cap = 5*1e-12 + +* --- Simulation Commands and Analysis --- + + +*+ abstol=1e-14 savecurrents +.control + save all + +** OP simulation +op + +** All OP parameters + +let #####_M1_pmos_input_##### = 0 +let id_M1 = @m.x1.xm1.m0[id] +let gm_M1 = @m.x1.xm1.m0[gm] +let ro_M1 = 1/@m.x1.xm1.m0[gds] +let Vsg_M1 = @m.x1.xm1.m0[vgs] +let Vsd_M1 = @m.x1.xm1.m0[vds] +let Vbs_M1 = -@m.x1.xm1.m0[vbs] +let Vdsat_M1 = @m.x1.xm1.m0[vdsat] +let Vth_M1 = @m.x1.xm1.m0[vth] +let ao_M1 = gm_M1*ro_M1 +let gmid_M1 = gm_M1/id_M1 +let fT_M1 = gm_M1/(6.283185*@m.x1.xm1.m0[cgg]) +print #####_M1_pmos_input_##### id_M1 gm_M1 ro_M1 Vsg_M1 Vsd_M1 Vbs_M1 Vdsat_M1 Vth_M1 ao_M1 gmid_M1 fT_M1 + +let #####_M2_pmos_input_##### = 0 +let id_M2 = @m.x1.xm2.m0[id] +let gm_M2 = @m.x1.xm2.m0[gm] +let ro_M2 = 1/@m.x1.xm2.m0[gds] +let Vsg_M2 = @m.x1.xm2.m0[vgs] +let Vsd_M2 = @m.x1.xm2.m0[vds] +let Vbs_M2 = -@m.x1.xm2.m0[vbs] +let Vdsat_M2 = @m.x1.xm2.m0[vdsat] +let Vth_M2 = @m.x1.xm2.m0[vth] +let ao_M2 = gm_M2*ro_M2 +let gmid_M2 = gm_M2/id_M2 +let fT_M2 = gm_M2/(6.283185*@m.x1.xm2.m0[cgg]) +print #####_M2_pmos_input_##### id_M2 gm_M2 ro_M2 Vsg_M2 Vsd_M2 Vbs_M2 Vdsat_M2 Vth_M2 ao_M2 gmid_M2 fT_M2 + +let #####_M3_pmos_top_##### = 0 +let id_M3 = @m.x1.xm3.m0[id] +let gm_M3 = @m.x1.xm3.m0[gm] +let ro_M3 = 1/@m.x1.xm3.m0[gds] +let Vsg_M3 = @m.x1.xm3.m0[vgs] +let Vsd_M3 = @m.x1.xm3.m0[vds] +let Vbs_M3 = -@m.x1.xm3.m0[vbs] +let Vdsat_M3 = @m.x1.xm3.m0[vdsat] +let Vth_M3 = @m.x1.xm3.m0[vth] +let ao_M3 = gm_M3*ro_M3 +let gmid_M3 = gm_M3/id_M3 +let fT_M3 = gm_M3/(6.283185*@m.x1.xm3.m0[cgg]) +print #####_M3_pmos_top_##### id_M3 gm_M3 ro_M3 Vsg_M3 Vsd_M3 Vbs_M3 Vdsat_M3 Vth_M3 ao_M3 gmid_M3 fT_M3 + +let #####_M4_pmos_top_##### = 0 +let id_M4 = @m.x1.xm4.m0[id] +let gm_M4 = @m.x1.xm4.m0[gm] +let ro_M4 = 1/@m.x1.xm4.m0[gds] +let Vsg_M4 = @m.x1.xm4.m0[vgs] +let Vsd_M4 = @m.x1.xm4.m0[vds] +let Vbs_M4 = -@m.x1.xm4.m0[vbs] +let Vdsat_M4 = @m.x1.xm4.m0[vdsat] +let Vth_M4 = @m.x1.xm4.m0[vth] +let ao_M4 = gm_M4*ro_M4 +let gmid_M4 = gm_M4/id_M4 +let fT_M4 = gm_M4/(6.283185*@m.x1.xm4.m0[cgg]) +print #####_M4_pmos_top_##### id_M4 gm_M4 ro_M4 Vsg_M4 Vsd_M4 Vbs_M4 Vdsat_M4 Vth_M4 ao_M4 gmid_M4 fT_M4 + +let #####_M5_pmos_out_##### = 0 +let id_M5 = @m.x1.xm5.m0[id] +let gm_M5 = @m.x1.xm5.m0[gm] +let ro_M5 = 1/@m.x1.xm5.m0[gds] +let Vsg_M5 = @m.x1.xm5.m0[vgs] +let Vsd_M5 = @m.x1.xm5.m0[vds] +let Vbs_M5 = -@m.x1.xm5.m0[vbs] +let Vdsat_M5 = @m.x1.xm5.m0[vdsat] +let Vth_M5 = @m.x1.xm5.m0[vth] +let ao_M5 = gm_M5*ro_M5 +let gmid_M5 = gm_M5/id_M5 +let fT_M5 = gm_M5/(6.283185*@m.x1.xm5.m0[cgg]) +print #####_M5_pmos_out_##### id_M5 gm_M5 ro_M5 Vsg_M5 Vsd_M5 Vbs_M5 Vdsat_M5 Vth_M5 ao_M5 gmid_M5 fT_M5 + +let #####_M6_pmos_out_##### = 0 +let id_M6 = @m.x1.xm6.m0[id] +let gm_M6 = @m.x1.xm6.m0[gm] +let ro_M6 = 1/@m.x1.xm6.m0[gds] +let Vsg_M6 = @m.x1.xm6.m0[vgs] +let Vsd_M6 = @m.x1.xm6.m0[vds] +let Vbs_M6 = -@m.x1.xm6.m0[vbs] +let Vdsat_M6 = @m.x1.xm6.m0[vdsat] +let Vth_M6 = @m.x1.xm6.m0[vth] +let ao_M6 = gm_M6*ro_M6 +let gmid_M6 = gm_M6/id_M6 +let fT_M6 = gm_M6/(6.283185*@m.x1.xm6.m0[cgg]) +print #####_M6_pmos_out_##### id_M6 gm_M6 ro_M6 Vsg_M6 Vsd_M6 Vbs_M6 Vdsat_M6 Vth_M6 ao_M6 gmid_M6 fT_M6 + +let #####_M7_nmos_out_##### = 0 +let id_M7 = @m.x1.xm7.m0[id] +let gm_M7 = @m.x1.xm7.m0[gm] +let ro_M7 = 1/@m.x1.xm7.m0[gds] +let Vgs_M7 = @m.x1.xm7.m0[vgs] +let Vds_M7 = @m.x1.xm7.m0[vds] +let Vsb_M7 = -@m.x1.xm7.m0[vbs] +let Vdsat_M7 = @m.x1.xm7.m0[vdsat] +let Vth_M7 = @m.x1.xm7.m0[vth] +let ao_M7 = gm_M7*ro_M7 +let gmid_M7 = gm_M7/id_M7 +let fT_M7 = gm_M7/(6.283185*@m.x1.xm7.m0[cgg]) +print #####_M7_nmos_out_##### id_M7 gm_M7 ro_M7 Vgs_M7 Vds_M7 Vsb_M7 Vdsat_M7 Vth_M7 ao_M7 gmid_M7 fT_M7 + +let #####_M8_nmos_out_##### = 0 +let id_M8 = @m.x1.xm8.m0[id] +let gm_M8 = @m.x1.xm8.m0[gm] +let ro_M8 = 1/@m.x1.xm8.m0[gds] +let Vgs_M8 = @m.x1.xm8.m0[vgs] +let Vds_M8 = @m.x1.xm8.m0[vds] +let Vsb_M8 = -@m.x1.xm8.m0[vbs] +let Vdsat_M8 = @m.x1.xm8.m0[vdsat] +let Vth_M8 = @m.x1.xm8.m0[vth] +let ao_M8 = gm_M8*ro_M8 +let gmid_M8 = gm_M8/id_M8 +let fT_M8 = gm_M8/(6.283185*@m.x1.xm8.m0[cgg]) +print #####_M8_nmos_out_##### id_M8 gm_M8 ro_M8 Vgs_M8 Vds_M8 Vsb_M8 Vdsat_M8 Vth_M8 ao_M8 gmid_M8 fT_M8 +let #####_M9_nmos_bottom_##### = 0 +let id_M9 = @m.x1.xm9.m0[id] +let gm_M9 = @m.x1.xm9.m0[gm] +let ro_M9 = 1/@m.x1.xm9.m0[gds] +let Vgs_M9 = @m.x1.xm9.m0[vgs] +let Vds_M9 = @m.x1.xm9.m0[vds] +let Vsb_M9 = -@m.x1.xm9.m0[vbs] +let Vdsat_M9 = @m.x1.xm9.m0[vdsat] +let Vth_M9 = @m.x1.xm9.m0[vth] +let ao_M9 = gm_M9*ro_M9 +let gmid_M9 = gm_M9/id_M9 +let fT_M9 = gm_M9/(6.283185*@m.x1.xm9.m0[cgg]) +print #####_M9_nmos_bottom_##### id_M9 gm_M9 ro_M9 Vgs_M9 Vds_M9 Vsb_M9 Vdsat_M9 Vth_M9 ao_M9 gmid_M9 fT_M9 + +let #####_M10_nmos_bottom_##### = 0 +let id_M10 = @m.x1.xm10.m0[id] +let gm_M10 = @m.x1.xm10.m0[gm] +let ro_M10 = 1/@m.x1.xm10.m0[gds] +let Vgs_M10 = @m.x1.xm10.m0[vgs] +let Vds_M10 = @m.x1.xm10.m0[vds] +let Vsb_M10 = @m.x1.xm10.m0[vbs] +let Vdsat_M10 = @m.x1.xm10.m0[vdsat] +let Vth_M10 = @m.x1.xm10.m0[vth] +let ao_M10 = gm_M10*ro_M10 +let gmid_M10 = gm_M10/id_M10 +let fT_M10 = gm_M10/(6.283185*@m.x1.xm10.m0[cgg]) +print #####_M10_nmos_bottom_##### id_M10 gm_M10 ro_M10 Vgs_M10 Vds_M10 Vsb_M10 Vdsat_M10 Vth_M10 ao_M10 gmid_M10 fT_M10 + +let #####_M11_pmos_mirror_##### = 0 +let id_M11 = @m.x1.xm11.m0[id] +let gm_M11 = @m.x1.xm11.m0[gm] +let ro_M11 = 1/@m.x1.xm11.m0[gds] +let Vsg_M11 = @m.x1.xm11.m0[vgs] +let Vsd_M11 = @m.x1.xm11.m0[vds] +let Vbs_M11 = -@m.x1.xm11.m0[vbs] +let Vdsat_M11 = @m.x1.xm11.m0[vdsat] +let Vth_M11 = @m.x1.xm11.m0[vth] +let ao_M11 = gm_M11*ro_M11 +let gmid_M11 = gm_M11/id_M11 +let fT_M11 = gm_M11/(6.283185*@m.x1.xm11.m0[cgg]) +print #####_M11_pmos_mirror_##### id_M11 gm_M11 ro_M11 Vsg_M11 Vsd_M11 Vbs_M11 Vdsat_M11 Vth_M11 ao_M11 gmid_M11 fT_M11 + +** Custom output +let #####_Custom_output_##### = 0 + +* DC_gain +let r1 = ao_M6*ro_M4 +let r2 = ao_M8*((ro_M1*ro_M10)/(ro_M1+ro_M10)) +let Rout = (r1*r2)/(r1+r2) +let Av = db(gm_M1*Rout) +* Bandwidth +let BW = 1/(Rout*1e-12*6.283185) +let BW_2 = 1/(Rout*5p*6.283185) + + +print #####_Custom_output_##### Av BW BW_2 Rout gm_M1 ro_M1 gm_M6 ro_M6 ro_M4 gm_M8 ro_M8 ro_M10 + + + remzerovec + write error_amplifier_core_N_input_ac.raw + set appendwrite + + * run ac simulation + ac dec 20 1 100e7 + + * measure parameters + let vout_mag_VV = abs(v(Vout)) + let vout_mag = db(abs(v(Vout))) + let vout_phase = cph(v(Vout)) * 180/pi + let gm = (-1)*db(abs(v(Vout))) + + meas ac A0 find vout_mag at=1 + meas ac UGB when vout_mag=0 fall=1 + meas ac PM find vout_phase when vout_mag=0 + meas ac GM find gm when vout_phase=0 + + let A0_p1 = A0 - 3 + meas ac BW when vout_mag=A0_p1 + + *plot vout_mag + *plot vout_phase + + write error_amplifier_core_N_input_ac.raw +.endc +"} +C {devices/launcher.sym} 50 -570 0 0 {name=h15 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op" +} +C {devices/launcher.sym} 50 -640 0 0 {name=h3 +descr="Netlist & sim" +tclcommand="xschem netlist; xschem simulate"} +C {vsource.sym} 400 -360 0 0 {name=V5 value="AC 1" savecurrent=false} +C {capa.sym} 330 -280 1 0 {name=C2 +m=1 +value=10G +footprint=1206 +device="ceramic capacitor"} +C {ind.sym} 530 -280 1 0 {name=L4 +m=1 +value=10G +footprint=1206 +device=inductor} +C {lab_pin.sym} 530 -480 2 1 {name=p8 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 530 -460 2 1 {name=p9 sig_type=std_logic lab=VSS} +C {gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sym} 580 -570 0 0 {name=x1} +C {capa.sym} 890 -470 0 0 {name=C1 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {noconn.sym} 480 -440 2 1 {name=l1} +C {lab_pin.sym} 890 -570 0 1 {name=p2 sig_type=std_logic lab=Vout} +C {lab_pin.sym} 530 -420 2 1 {name=p5 sig_type=std_logic lab=VbiasP1} +C {lab_pin.sym} 530 -400 2 1 {name=p6 sig_type=std_logic lab=VbiasP2} +C {lab_pin.sym} 530 -380 2 1 {name=p7 sig_type=std_logic lab=VbiasN2} +C {lab_pin.sym} 530 -360 2 1 {name=p11 sig_type=std_logic lab=VbiasN1} +C {devices/vsource.sym} 440 -50 0 0 {name=V1 value=\{VbiasP2\}} +C {devices/gnd.sym} 440 -10 0 0 {name=l2 lab=GND} +C {devices/lab_wire.sym} 440 -110 0 0 {name=p3 sig_type=std_logic lab=VbiasP2} +C {devices/vsource.sym} 520 -50 0 0 {name=V2 value=\{VbiasN2\}} +C {devices/gnd.sym} 520 -10 0 0 {name=l3 lab=GND} +C {devices/lab_wire.sym} 520 -110 0 0 {name=p4 sig_type=std_logic lab=VbiasN2} +C {devices/vsource.sym} 600 -50 0 0 {name=V3 value=\{VbiasN1\}} +C {devices/gnd.sym} 600 -10 0 0 {name=l5 lab=GND} +C {devices/lab_wire.sym} 600 -110 0 0 {name=p12 sig_type=std_logic lab=VbiasN1} +C {devices/vsource.sym} 280 -50 0 0 {name=V4 value=\{VDD\}} +C {devices/gnd.sym} 280 -10 0 0 {name=l6 lab=GND} +C {devices/lab_wire.sym} 280 -110 0 0 {name=p13 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 360 -50 0 0 {name=V6 value=\{VSS\}} +C {devices/gnd.sym} 360 -10 0 0 {name=l7 lab=GND} +C {devices/lab_wire.sym} 360 -110 0 0 {name=p14 sig_type=std_logic lab=VSS} +C {devices/vsource.sym} 680 -50 0 0 {name=V8 value=\{VbiasP1\} savecurrent=false} +C {devices/gnd.sym} 680 -10 0 0 {name=l10 lab=GND} +C {devices/lab_wire.sym} 680 -110 0 0 {name=p15 sig_type=std_logic lab=VbiasP1 +} +C {devices/vsource.sym} 220 -220 0 0 {name=V7 value=\{Vin_CM\}} +C {devices/gnd.sym} 220 -180 0 0 {name=l8 lab=GND} +C {devices/lab_wire.sym} 220 -280 0 0 {name=p10 sig_type=std_logic lab=Vin} +C {devices/gnd.sym} 890 -340 0 0 {name=l9 lab=GND} +C {devices/lab_wire.sym} 440 -280 0 0 {name=p1 sig_type=std_logic lab=Vx} +C {devices/lab_wire.sym} 510 -440 0 0 {name=p16 sig_type=std_logic lab=Vcom} +C {devices/lab_wire.sym} 420 -600 0 0 {name=p17 sig_type=std_logic lab=Vn} +C {devices/vsource.sym} 640 -280 1 0 {name=V9 value=\{Vy\}} +C {vcvs.sym} 720 -230 0 1 {name=E1 value=1} +C {devices/gnd.sym} 720 -170 0 0 {name=l11 lab=GND} +C {devices/lab_wire.sym} 580 -280 0 0 {name=p18 sig_type=std_logic lab=Vy} +C {devices/lab_wire.sym} 720 -280 0 0 {name=p19 sig_type=std_logic lab=Vz} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_cmrr.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_cmrr.sch new file mode 100644 index 00000000..d1501284 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_cmrr.sch @@ -0,0 +1,301 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 1210 -240 1210 -180 { +lab=GND} +N 1120 -350 1210 -350 { +lab=Vout} +N 1210 -350 1210 -300 { +lab=Vout} +N 510 -90 510 -80 {lab=GND} +N 510 -180 510 -150 {lab=Vin} +N 820 -380 920 -380 { +lab=V-} +N 270 -90 270 -80 {lab=GND} +N 270 -180 270 -150 {lab=VbiasP2} +N 350 -90 350 -80 {lab=GND} +N 350 -180 350 -150 {lab=VbiasN2} +N 430 -90 430 -80 {lab=GND} +N 430 -180 430 -150 {lab=VbiasN1} +N 110 -90 110 -80 {lab=GND} +N 110 -180 110 -150 {lab=VDD} +N 190 -90 190 -80 {lab=GND} +N 190 -180 190 -150 {lab=VSS} +N 1160 -350 1160 -90 {lab=Vout} +N 1050 -90 1160 -90 {lab=Vout} +N 820 -320 820 -90 {lab=V-} +N 510 -320 510 -280 {lab=V+} +N 820 -90 990 -90 {lab=V-} +N 510 -220 510 -180 {lab=Vin} +N 820 -380 820 -320 {lab=V-} +N 870 -320 920 -320 {lab=V+} +C {vsource.sym} 510 -250 0 0 {name=V5 value="AC 1" savecurrent=false} +C {capa.sym} 870 -350 0 0 {name=C2 +m=1 +value=10G +footprint=1206 +device="ceramic capacitor"} +C {ind.sym} 1020 -90 1 0 {name=L4 +m=1 +value=10G +footprint=1206 +device=inductor} +C {devices/code_shown.sym} 50 -580 0 0 {name=MODELS only_toplevel=true +format="tcleval( @value )" +value=" +.include $::180MCU_MODELS/design.ngspice +.lib $::180MCU_MODELS/sm141064.ngspice typical +"} +C {devices/lab_wire.sym} 970 -160 0 0 {name=p5 sig_type=std_logic lab=VbiasN1} +C {devices/lab_wire.sym} 970 -180 0 0 {name=p6 sig_type=std_logic lab=VbiasN2} +C {devices/lab_wire.sym} 970 -200 0 0 {name=p11 sig_type=std_logic lab=VbiasP2} +C {devices/noconn.sym} 970 -220 0 0 {name=l2} +C {devices/lab_wire.sym} 970 -240 0 0 {name=p12 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 970 -260 0 0 {name=p13 sig_type=std_logic lab=VDD} +C {devices/capa.sym} 1210 -270 0 0 {name=C3 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {devices/vsource.sym} 510 -120 0 0 {name=V6 value=\{Vin\}} +C {devices/gnd.sym} 510 -80 0 0 {name=l3 lab=GND} +C {devices/lab_wire.sym} 510 -180 0 0 {name=p14 sig_type=std_logic lab=Vin} +C {devices/lab_wire.sym} 1210 -350 0 0 {name=p15 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 1210 -180 0 0 {name=l8 lab=GND} +C {simulator_commands.sym} 990 -580 0 0 {name=COMMANDS1 +simulator=ngspice +only_toplevel=false +value=" +.control +save all + +** OP simulation +op + +** run ac simulation +ac dec 20 1 100e6 + +** All OP parameters +setplot op1 + +let #####_M1_nmos_input_##### = 0 +let id_M1 = @m.x1.xm1.m0[id] +let gm_M1 = @m.x1.xm1.m0[gm] +let ro_M1 = 1/@m.x1.xm1.m0[gds] +let Vgs_M1 = @m.x1.xm1.m0[vgs] +let Vds_M1 = @m.x1.xm1.m0[vds] +let Vsb_M1 = -@m.x1.xm1.m0[vbs] +let Vdsat_M1 = @m.x1.xm1.m0[vdsat] +let Vth_M1 = @m.x1.xm1.m0[vth] +let ao_M1 = gm_M1*ro_M1 +let gmid_M1 = gm_M1/id_M1 +let fT_M1 = gm_M1/(6.283185*@m.x1.xm1.m0[cgg]) +print #####_M1_nmos_input_##### id_M1 gm_M1 ro_M1 Vgs_M1 Vds_M1 Vsb_M1 Vdsat_M1 Vth_M1 ao_M1 gmid_M1 fT_M1 + +let #####_M2_nmos_input_##### = 0 +let id_M2 = @m.x1.xm2.m0[id] +let gm_M2 = @m.x1.xm2.m0[gm] +let ro_M2 = 1/@m.x1.xm2.m0[gds] +let Vgs_M2 = @m.x1.xm2.m0[vgs] +let Vds_M2 = @m.x1.xm2.m0[vds] +let Vsb_M2 = -@m.x1.xm2.m0[vbs] +let Vdsat_M2 = @m.x1.xm2.m0[vdsat] +let Vth_M2 = @m.x1.xm2.m0[vth] +let ao_M2 = gm_M2*ro_M2 +let gmid_M2 = gm_M2/id_M2 +let fT_M2 = gm_M2/(6.283185*@m.x1.xm2.m0[cgg]) +print #####_M2_nmos_input_##### id_M2 gm_M2 ro_M2 Vgs_M2 Vds_M2 Vsb_M2 Vdsat_M2 Vth_M2 ao_M2 gmid_M2 fT_M2 + +let #####_M3_pmos_top_##### = 0 +let id_M3 = @m.x1.xm3.m0[id] +let gm_M3 = @m.x1.xm3.m0[gm] +let ro_M3 = 1/@m.x1.xm3.m0[gds] +let Vsg_M3 = @m.x1.xm3.m0[vgs] +let Vsd_M3 = @m.x1.xm3.m0[vds] +let Vbs_M3 = -@m.x1.xm3.m0[vbs] +let Vdsat_M3 = @m.x1.xm3.m0[vdsat] +let Vth_M3 = @m.x1.xm3.m0[vth] +let ao_M3 = gm_M3*ro_M3 +let gmid_M3 = gm_M3/id_M3 +let fT_M3 = gm_M3/(6.283185*@m.x1.xm3.m0[cgg]) +print #####_M3_pmos_top_##### id_M3 gm_M3 ro_M3 Vsg_M3 Vsd_M3 Vbs_M3 Vdsat_M3 Vth_M3 ao_M3 gmid_M3 fT_M3 + +let #####_M4_pmos_top_##### = 0 +let id_M4 = @m.x1.xm4.m0[id] +let gm_M4 = @m.x1.xm4.m0[gm] +let ro_M4 = 1/@m.x1.xm4.m0[gds] +let Vsg_M4 = @m.x1.xm4.m0[vgs] +let Vsd_M4 = @m.x1.xm4.m0[vds] +let Vbs_M4 = -@m.x1.xm4.m0[vbs] +let Vdsat_M4 = @m.x1.xm4.m0[vdsat] +let Vth_M4 = @m.x1.xm4.m0[vth] +let ao_M4 = gm_M4*ro_M4 +let gmid_M4 = gm_M4/id_M4 +let fT_M4 = gm_M4/(6.283185*@m.x1.xm4.m0[cgg]) +print #####_M4_pmos_top_##### id_M4 gm_M4 ro_M4 Vsg_M4 Vsd_M4 Vbs_M4 Vdsat_M4 Vth_M4 ao_M4 gmid_M4 fT_M4 + +let #####_M5_pmos_out_##### = 0 +let id_M5 = @m.x1.xm5.m0[id] +let gm_M5 = @m.x1.xm5.m0[gm] +let ro_M5 = 1/@m.x1.xm5.m0[gds] +let Vsg_M5 = @m.x1.xm5.m0[vgs] +let Vsd_M5 = @m.x1.xm5.m0[vds] +let Vbs_M5 = -@m.x1.xm5.m0[vbs] +let Vdsat_M5 = @m.x1.xm5.m0[vdsat] +let Vth_M5 = @m.x1.xm5.m0[vth] +let ao_M5 = gm_M5*ro_M5 +let gmid_M5 = gm_M5/id_M5 +let fT_M5 = gm_M5/(6.283185*@m.x1.xm5.m0[cgg]) +print #####_M5_pmos_out_##### id_M5 gm_M5 ro_M5 Vsg_M5 Vsd_M5 Vbs_M5 Vdsat_M5 Vth_M5 ao_M5 gmid_M5 fT_M5 + +let #####_M6_pmos_out_##### = 0 +let id_M6 = @m.x1.xm6.m0[id] +let gm_M6 = @m.x1.xm6.m0[gm] +let ro_M6 = 1/@m.x1.xm6.m0[gds] +let Vsg_M6 = @m.x1.xm6.m0[vgs] +let Vsd_M6 = @m.x1.xm6.m0[vds] +let Vbs_M6 = -@m.x1.xm6.m0[vbs] +let Vdsat_M6 = @m.x1.xm6.m0[vdsat] +let Vth_M6 = @m.x1.xm6.m0[vth] +let ao_M6 = gm_M6*ro_M6 +let gmid_M6 = gm_M6/id_M6 +let fT_M6 = gm_M6/(6.283185*@m.x1.xm6.m0[cgg]) +print #####_M6_pmos_out_##### id_M6 gm_M6 ro_M6 Vsg_M6 Vsd_M6 Vbs_M6 Vdsat_M6 Vth_M6 ao_M6 gmid_M6 fT_M6 + +let #####_M7_nmos_out_##### = 0 +let id_M7 = @m.x1.xm7.m0[id] +let gm_M7 = @m.x1.xm7.m0[gm] +let ro_M7 = 1/@m.x1.xm7.m0[gds] +let Vgs_M7 = @m.x1.xm7.m0[vgs] +let Vds_M7 = @m.x1.xm7.m0[vds] +let Vsb_M7 = -@m.x1.xm7.m0[vbs] +let Vdsat_M7 = @m.x1.xm7.m0[vdsat] +let Vth_M7 = @m.x1.xm7.m0[vth] +let ao_M7 = gm_M7*ro_M7 +let gmid_M7 = gm_M7/id_M7 +let fT_M7 = gm_M7/(6.283185*@m.x1.xm7.m0[cgg]) +print #####_M7_nmos_out_##### id_M7 gm_M7 ro_M7 Vgs_M7 Vds_M7 Vsb_M7 Vdsat_M7 Vth_M7 ao_M7 gmid_M7 fT_M7 + +let #####_M8_nmos_out_##### = 0 +let id_M8 = @m.x1.xm8.m0[id] +let gm_M8 = @m.x1.xm8.m0[gm] +let ro_M8 = 1/@m.x1.xm8.m0[gds] +let Vgs_M8 = @m.x1.xm8.m0[vgs] +let Vds_M8 = @m.x1.xm8.m0[vds] +let Vsb_M8 = -@m.x1.xm8.m0[vbs] +let Vdsat_M8 = @m.x1.xm8.m0[vdsat] +let Vth_M8 = @m.x1.xm8.m0[vth] +let ao_M8 = gm_M8*ro_M8 +let gmid_M8 = gm_M8/id_M8 +let fT_M8 = gm_M8/(6.283185*@m.x1.xm8.m0[cgg]) +print #####_M8_nmos_out_##### id_M8 gm_M8 ro_M8 Vgs_M8 Vds_M8 Vsb_M8 Vdsat_M8 Vth_M8 ao_M8 gmid_M8 fT_M8 + +let #####_M9_nmos_bottom_##### = 0 +let id_M9 = @m.x1.xm9.m0[id] +let gm_M9 = @m.x1.xm9.m0[gm] +let ro_M9 = 1/@m.x1.xm9.m0[gds] +let Vgs_M9 = @m.x1.xm9.m0[vgs] +let Vds_M9 = @m.x1.xm9.m0[vds] +let Vsb_M9 = -@m.x1.xm9.m0[vbs] +let Vdsat_M9 = @m.x1.xm9.m0[vdsat] +let Vth_M9 = @m.x1.xm9.m0[vth] +let ao_M9 = gm_M9*ro_M9 +let gmid_M9 = gm_M9/id_M9 +let fT_M9 = gm_M9/(6.283185*@m.x1.xm9.m0[cgg]) +print #####_M9_nmos_bottom_##### id_M9 gm_M9 ro_M9 Vgs_M9 Vds_M9 Vsb_M9 Vdsat_M9 Vth_M9 ao_M9 gmid_M9 fT_M9 + +let #####_M10_nmos_bottom_##### = 0 +let id_M10 = @m.x1.xm10.m0[id] +let gm_M10 = @m.x1.xm10.m0[gm] +let ro_M10 = 1/@m.x1.xm10.m0[gds] +let Vgs_M10 = @m.x1.xm10.m0[vgs] +let Vds_M10 = @m.x1.xm10.m0[vds] +let Vsb_M10 = @m.x1.xm10.m0[vbs] +let Vdsat_M10 = @m.x1.xm10.m0[vdsat] +let Vth_M10 = @m.x1.xm10.m0[vth] +let ao_M10 = gm_M10*ro_M10 +let gmid_M10 = gm_M10/id_M10 +let fT_M10 = gm_M10/(6.283185*@m.x1.xm10.m0[cgg]) +print #####_M10_nmos_bottom_##### id_M10 gm_M10 ro_M10 Vgs_M10 Vds_M10 Vsb_M10 Vdsat_M10 Vth_M10 ao_M10 gmid_M10 fT_M10 + +let #####_M11_nmos_mirror_##### = 0 +let id_M11 = @m.x1.xm11.m0[id] +let gm_M11 = @m.x1.xm11.m0[gm] +let ro_M11 = 1/@m.x1.xm11.m0[gds] +let Vgs_M11 = @m.x1.xm11.m0[vgs] +let Vds_M11 = @m.x1.xm11.m0[vds] +let Vsb_M11 = -@m.x1.xm11.m0[vbs] +let Vdsat_M11 = @m.x1.xm11.m0[vdsat] +let Vth_M11 = @m.x1.xm11.m0[vth] +let ao_M11 = gm_M11*ro_M11 +let gmid_M11 = gm_M11/id_M11 +let fT_M11 = gm_M11/(6.283185*@m.x1.xm11.m0[cgg]) +print #####_M11_nmos_mirror_##### id_M11 gm_M11 ro_M11 Vgs_M11 Vds_M11 Vsb_M11 Vdsat_M11 Vth_M11 ao_M11 gmid_M11 fT_M11 + +** Custom output +let #####_Custom_output_##### = 0 + +* Power +let power = (id_M11 + id_M10 + id_M9)*VDD + +* DC_gain +let r1 = ao_M6*ro_M4 +let r2 = ao_M8*((ro_M1*ro_M10)/(ro_M1+ro_M10)) +let Rout = (r1*r2)/(r1+r2) +let Av = db(gm_M1*Rout) +* Bandwidth +let BW = 1/(Rout*1e-12*6.283185) + +print #####_Custom_output_##### Av BW Rout power gm_M1 ro_M1 gm_M6 ro_M6 ro_M4 gm_M8 ro_M8 ro_M10 + +write error_amplifier_core_N_input_cmrr.raw + +setplot ac1 + +* measure parameters +let vout_mag = db(abs(v(Vout))) +let vout_phase = cph(v(Vout)) * 180/pi + +meas ac Acm find vout_mag at=1e2 + +plot vout_mag vout_phase + +.endc +"} +C {devices/code_shown.sym} 710 -600 0 0 {name=Voltage_sources only_toplevel=true +value=" +.param VDD = 1.8 +.param VSS = 0 +.param VbiasN1 = 0.77 +.param VbiasN2 = 1.28 +.param VbiasP2 = 0.46 +.param Vin = 1 +"} +C {/foss/designs/workarea/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sym} 1020 -350 0 0 {name=x1} +C {devices/vsource.sym} 270 -120 0 0 {name=V1 value=\{VbiasP2\}} +C {devices/gnd.sym} 270 -80 0 0 {name=l9 lab=GND} +C {devices/lab_wire.sym} 270 -180 0 0 {name=p16 sig_type=std_logic lab=VbiasP2} +C {devices/vsource.sym} 350 -120 0 0 {name=V3 value=\{VbiasN2\}} +C {devices/gnd.sym} 350 -80 0 0 {name=l10 lab=GND} +C {devices/lab_wire.sym} 350 -180 0 0 {name=p17 sig_type=std_logic lab=VbiasN2} +C {devices/vsource.sym} 430 -120 0 0 {name=V7 value=\{VbiasN1\}} +C {devices/gnd.sym} 430 -80 0 0 {name=l11 lab=GND} +C {devices/lab_wire.sym} 430 -180 0 0 {name=p18 sig_type=std_logic lab=VbiasN1} +C {devices/vsource.sym} 110 -120 0 0 {name=V8 value=\{VDD\}} +C {devices/gnd.sym} 110 -80 0 0 {name=l12 lab=GND} +C {devices/lab_wire.sym} 110 -180 0 0 {name=p19 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 190 -120 0 0 {name=V9 value=\{VSS\}} +C {devices/gnd.sym} 190 -80 0 0 {name=l13 lab=GND} +C {devices/lab_wire.sym} 190 -180 0 0 {name=p20 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 820 -380 0 0 {name=p1 sig_type=std_logic lab=V-} +C {devices/lab_wire.sym} 510 -320 0 0 {name=p2 sig_type=std_logic lab=V+} +C {devices/launcher.sym} 140 -410 0 0 {name=h1 +descr="Save & Netlist & sim" +tclcommand="xschem save; xschem netlist; xschem simulate"} +C {launcher.sym} 140 -340 0 0 {name=h2 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op"} +C {devices/lab_wire.sym} 870 -320 2 0 {name=p4 sig_type=std_logic lab=V+} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_op.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_op.sch new file mode 100644 index 00000000..d4808acc --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_op.sch @@ -0,0 +1,272 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 240 -60 240 -50 {lab=GND} +N 240 -150 240 -120 {lab=VbiasP2} +N 320 -60 320 -50 {lab=GND} +N 320 -150 320 -120 {lab=VbiasN2} +N 400 -60 400 -50 {lab=GND} +N 400 -150 400 -120 {lab=VbiasN1} +N 80 -60 80 -50 {lab=GND} +N 80 -150 80 -120 {lab=VDD} +N 160 -60 160 -50 {lab=GND} +N 160 -150 160 -120 {lab=VSS} +N 960 -110 960 -50 { +lab=GND} +N 870 -220 960 -220 { +lab=Vout} +N 960 -220 960 -170 { +lab=Vout} +N 570 -250 670 -250 { +lab=Vout} +N 570 -320 570 -250 { +lab=Vout} +N 570 -320 960 -320 { +lab=Vout} +N 960 -320 960 -220 { +lab=Vout} +N 570 -60 570 -50 {lab=GND} +N 570 -150 570 -120 {lab=Vin} +N 570 -190 570 -150 { +lab=Vin} +N 570 -190 670 -190 { +lab=Vin} +C {devices/vsource.sym} 240 -90 0 0 {name=V1 value=\{VbiasP2\}} +C {devices/gnd.sym} 240 -50 0 0 {name=l2 lab=GND} +C {devices/launcher.sym} 120 -370 0 0 {name=h3 +descr="Save & Netlist & sim" +tclcommand="xschem save; xschem netlist; xschem simulate"} +C {devices/lab_wire.sym} 240 -150 0 0 {name=p1 sig_type=std_logic lab=VbiasP2} +C {devices/vsource.sym} 320 -90 0 0 {name=V2 value=\{VbiasN2\}} +C {devices/gnd.sym} 320 -50 0 0 {name=l1 lab=GND} +C {devices/lab_wire.sym} 320 -150 0 0 {name=p2 sig_type=std_logic lab=VbiasN2} +C {devices/vsource.sym} 400 -90 0 0 {name=V3 value=\{VbiasN1\}} +C {devices/gnd.sym} 400 -50 0 0 {name=l3 lab=GND} +C {devices/lab_wire.sym} 400 -150 0 0 {name=p3 sig_type=std_logic lab=VbiasN1} +C {devices/lab_wire.sym} 720 -30 0 0 {name=p4 sig_type=std_logic lab=VbiasN1} +C {devices/lab_wire.sym} 720 -50 0 0 {name=p5 sig_type=std_logic lab=VbiasN2} +C {devices/lab_wire.sym} 720 -70 0 0 {name=p6 sig_type=std_logic lab=VbiasP2} +C {devices/noconn.sym} 720 -90 0 0 {name=l4} +C {devices/lab_wire.sym} 720 -110 0 0 {name=p7 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 720 -130 0 0 {name=p8 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 80 -90 0 0 {name=V4 value=\{VDD\}} +C {devices/gnd.sym} 80 -50 0 0 {name=l5 lab=GND} +C {devices/lab_wire.sym} 80 -150 0 0 {name=p9 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 160 -90 0 0 {name=V5 value=\{VSS\}} +C {devices/gnd.sym} 160 -50 0 0 {name=l6 lab=GND} +C {devices/lab_wire.sym} 160 -150 0 0 {name=p10 sig_type=std_logic lab=VSS} +C {devices/capa.sym} 960 -140 0 0 {name=C1 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {devices/vsource.sym} 570 -90 0 0 {name=V6 value=\{Vin\}} +C {devices/gnd.sym} 570 -50 0 0 {name=l7 lab=GND} +C {devices/lab_wire.sym} 570 -150 0 0 {name=p11 sig_type=std_logic lab=Vin} +C {devices/lab_wire.sym} 960 -220 0 0 {name=p12 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 960 -50 0 0 {name=l8 lab=GND} +C {devices/code_shown.sym} 40 -500 0 0 {name=MODELS only_toplevel=true +format="tcleval( @value )" +value=" +.include $::180MCU_MODELS/design.ngspice +.lib $::180MCU_MODELS/sm141064.ngspice typical +"} +C {launcher.sym} 120 -300 0 0 {name=h1 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op"} +C {simulator_commands.sym} 820 -480 0 0 {name=COMMANDS +simulator=ngspice +only_toplevel=false +value=" +.control +save all + +** OP simulation +op + +** All OP parameters + +let #####_M1_nmos_input_##### = 0 +let id_M1 = @m.x1.xm1.m0[id] +let gm_M1 = @m.x1.xm1.m0[gm] +let ro_M1 = 1/@m.x1.xm1.m0[gds] +let Vgs_M1 = @m.x1.xm1.m0[vgs] +let Vds_M1 = @m.x1.xm1.m0[vds] +let Vsb_M1 = -@m.x1.xm1.m0[vbs] +let Vdsat_M1 = @m.x1.xm1.m0[vdsat] +let Vth_M1 = @m.x1.xm1.m0[vth] +let ao_M1 = gm_M1*ro_M1 +let gmid_M1 = gm_M1/id_M1 +let fT_M1 = gm_M1/(6.283185*@m.x1.xm1.m0[cgg]) +print #####_M1_nmos_input_##### id_M1 gm_M1 ro_M1 Vgs_M1 Vds_M1 Vsb_M1 Vdsat_M1 Vth_M1 ao_M1 gmid_M1 fT_M1 + +let #####_M2_nmos_input_##### = 0 +let id_M2 = @m.x1.xm2.m0[id] +let gm_M2 = @m.x1.xm2.m0[gm] +let ro_M2 = 1/@m.x1.xm2.m0[gds] +let Vgs_M2 = @m.x1.xm2.m0[vgs] +let Vds_M2 = @m.x1.xm2.m0[vds] +let Vsb_M2 = -@m.x1.xm2.m0[vbs] +let Vdsat_M2 = @m.x1.xm2.m0[vdsat] +let Vth_M2 = @m.x1.xm2.m0[vth] +let ao_M2 = gm_M2*ro_M2 +let gmid_M2 = gm_M2/id_M2 +let fT_M2 = gm_M2/(6.283185*@m.x1.xm2.m0[cgg]) +print #####_M2_nmos_input_##### id_M2 gm_M2 ro_M2 Vgs_M2 Vds_M2 Vsb_M2 Vdsat_M2 Vth_M2 ao_M2 gmid_M2 fT_M2 + +let #####_M3_pmos_top_##### = 0 +let id_M3 = @m.x1.xm3.m0[id] +let gm_M3 = @m.x1.xm3.m0[gm] +let ro_M3 = 1/@m.x1.xm3.m0[gds] +let Vsg_M3 = @m.x1.xm3.m0[vgs] +let Vsd_M3 = @m.x1.xm3.m0[vds] +let Vbs_M3 = -@m.x1.xm3.m0[vbs] +let Vdsat_M3 = @m.x1.xm3.m0[vdsat] +let Vth_M3 = @m.x1.xm3.m0[vth] +let ao_M3 = gm_M3*ro_M3 +let gmid_M3 = gm_M3/id_M3 +let fT_M3 = gm_M3/(6.283185*@m.x1.xm3.m0[cgg]) +print #####_M3_pmos_top_##### id_M3 gm_M3 ro_M3 Vsg_M3 Vsd_M3 Vbs_M3 Vdsat_M3 Vth_M3 ao_M3 gmid_M3 fT_M3 + +let #####_M4_pmos_top_##### = 0 +let id_M4 = @m.x1.xm4.m0[id] +let gm_M4 = @m.x1.xm4.m0[gm] +let ro_M4 = 1/@m.x1.xm4.m0[gds] +let Vsg_M4 = @m.x1.xm4.m0[vgs] +let Vsd_M4 = @m.x1.xm4.m0[vds] +let Vbs_M4 = -@m.x1.xm4.m0[vbs] +let Vdsat_M4 = @m.x1.xm4.m0[vdsat] +let Vth_M4 = @m.x1.xm4.m0[vth] +let ao_M4 = gm_M4*ro_M4 +let gmid_M4 = gm_M4/id_M4 +let fT_M4 = gm_M4/(6.283185*@m.x1.xm4.m0[cgg]) +print #####_M4_pmos_top_##### id_M4 gm_M4 ro_M4 Vsg_M4 Vsd_M4 Vbs_M4 Vdsat_M4 Vth_M4 ao_M4 gmid_M4 fT_M4 + +let #####_M5_pmos_out_##### = 0 +let id_M5 = @m.x1.xm5.m0[id] +let gm_M5 = @m.x1.xm5.m0[gm] +let ro_M5 = 1/@m.x1.xm5.m0[gds] +let Vsg_M5 = @m.x1.xm5.m0[vgs] +let Vsd_M5 = @m.x1.xm5.m0[vds] +let Vbs_M5 = -@m.x1.xm5.m0[vbs] +let Vdsat_M5 = @m.x1.xm5.m0[vdsat] +let Vth_M5 = @m.x1.xm5.m0[vth] +let ao_M5 = gm_M5*ro_M5 +let gmid_M5 = gm_M5/id_M5 +let fT_M5 = gm_M5/(6.283185*@m.x1.xm5.m0[cgg]) +print #####_M5_pmos_out_##### id_M5 gm_M5 ro_M5 Vsg_M5 Vsd_M5 Vbs_M5 Vdsat_M5 Vth_M5 ao_M5 gmid_M5 fT_M5 + +let #####_M6_pmos_out_##### = 0 +let id_M6 = @m.x1.xm6.m0[id] +let gm_M6 = @m.x1.xm6.m0[gm] +let ro_M6 = 1/@m.x1.xm6.m0[gds] +let Vsg_M6 = @m.x1.xm6.m0[vgs] +let Vsd_M6 = @m.x1.xm6.m0[vds] +let Vbs_M6 = -@m.x1.xm6.m0[vbs] +let Vdsat_M6 = @m.x1.xm6.m0[vdsat] +let Vth_M6 = @m.x1.xm6.m0[vth] +let ao_M6 = gm_M6*ro_M6 +let gmid_M6 = gm_M6/id_M6 +let fT_M6 = gm_M6/(6.283185*@m.x1.xm6.m0[cgg]) +print #####_M6_pmos_out_##### id_M6 gm_M6 ro_M6 Vsg_M6 Vsd_M6 Vbs_M6 Vdsat_M6 Vth_M6 ao_M6 gmid_M6 fT_M6 + +let #####_M7_nmos_out_##### = 0 +let id_M7 = @m.x1.xm7.m0[id] +let gm_M7 = @m.x1.xm7.m0[gm] +let ro_M7 = 1/@m.x1.xm7.m0[gds] +let Vgs_M7 = @m.x1.xm7.m0[vgs] +let Vds_M7 = @m.x1.xm7.m0[vds] +let Vsb_M7 = -@m.x1.xm7.m0[vbs] +let Vdsat_M7 = @m.x1.xm7.m0[vdsat] +let Vth_M7 = @m.x1.xm7.m0[vth] +let ao_M7 = gm_M7*ro_M7 +let gmid_M7 = gm_M7/id_M7 +let fT_M7 = gm_M7/(6.283185*@m.x1.xm7.m0[cgg]) +print #####_M7_nmos_out_##### id_M7 gm_M7 ro_M7 Vgs_M7 Vds_M7 Vsb_M7 Vdsat_M7 Vth_M7 ao_M7 gmid_M7 fT_M7 + +let #####_M8_nmos_out_##### = 0 +let id_M8 = @m.x1.xm8.m0[id] +let gm_M8 = @m.x1.xm8.m0[gm] +let ro_M8 = 1/@m.x1.xm8.m0[gds] +let Vgs_M8 = @m.x1.xm8.m0[vgs] +let Vds_M8 = @m.x1.xm8.m0[vds] +let Vsb_M8 = -@m.x1.xm8.m0[vbs] +let Vdsat_M8 = @m.x1.xm8.m0[vdsat] +let Vth_M8 = @m.x1.xm8.m0[vth] +let ao_M8 = gm_M8*ro_M8 +let gmid_M8 = gm_M8/id_M8 +let fT_M8 = gm_M8/(6.283185*@m.x1.xm8.m0[cgg]) +print #####_M8_nmos_out_##### id_M8 gm_M8 ro_M8 Vgs_M8 Vds_M8 Vsb_M8 Vdsat_M8 Vth_M8 ao_M8 gmid_M8 fT_M8 + +let #####_M9_nmos_bottom_##### = 0 +let id_M9 = @m.x1.xm9.m0[id] +let gm_M9 = @m.x1.xm9.m0[gm] +let ro_M9 = 1/@m.x1.xm9.m0[gds] +let Vgs_M9 = @m.x1.xm9.m0[vgs] +let Vds_M9 = @m.x1.xm9.m0[vds] +let Vsb_M9 = -@m.x1.xm9.m0[vbs] +let Vdsat_M9 = @m.x1.xm9.m0[vdsat] +let Vth_M9 = @m.x1.xm9.m0[vth] +let ao_M9 = gm_M9*ro_M9 +let gmid_M9 = gm_M9/id_M9 +let fT_M9 = gm_M9/(6.283185*@m.x1.xm9.m0[cgg]) +print #####_M9_nmos_bottom_##### id_M9 gm_M9 ro_M9 Vgs_M9 Vds_M9 Vsb_M9 Vdsat_M9 Vth_M9 ao_M9 gmid_M9 fT_M9 + +let #####_M10_nmos_bottom_##### = 0 +let id_M10 = @m.x1.xm10.m0[id] +let gm_M10 = @m.x1.xm10.m0[gm] +let ro_M10 = 1/@m.x1.xm10.m0[gds] +let Vgs_M10 = @m.x1.xm10.m0[vgs] +let Vds_M10 = @m.x1.xm10.m0[vds] +let Vsb_M10 = @m.x1.xm10.m0[vbs] +let Vdsat_M10 = @m.x1.xm10.m0[vdsat] +let Vth_M10 = @m.x1.xm10.m0[vth] +let ao_M10 = gm_M10*ro_M10 +let gmid_M10 = gm_M10/id_M10 +let fT_M10 = gm_M10/(6.283185*@m.x1.xm10.m0[cgg]) +print #####_M10_nmos_bottom_##### id_M10 gm_M10 ro_M10 Vgs_M10 Vds_M10 Vsb_M10 Vdsat_M10 Vth_M10 ao_M10 gmid_M10 fT_M10 + +let #####_M11_nmos_mirror_##### = 0 +let id_M11 = @m.x1.xm11.m0[id] +let gm_M11 = @m.x1.xm11.m0[gm] +let ro_M11 = 1/@m.x1.xm11.m0[gds] +let Vgs_M11 = @m.x1.xm11.m0[vgs] +let Vds_M11 = @m.x1.xm11.m0[vds] +let Vsb_M11 = -@m.x1.xm11.m0[vbs] +let Vdsat_M11 = @m.x1.xm11.m0[vdsat] +let Vth_M11 = @m.x1.xm11.m0[vth] +let ao_M11 = gm_M11*ro_M11 +let gmid_M11 = gm_M11/id_M11 +let fT_M11 = gm_M11/(6.283185*@m.x1.xm11.m0[cgg]) +print #####_M11_nmos_mirror_##### id_M11 gm_M11 ro_M11 Vgs_M11 Vds_M11 Vsb_M11 Vdsat_M11 Vth_M11 ao_M11 gmid_M11 fT_M11 + +** Custom output +let #####_Custom_output_##### = 0 +* Power +let power = (id_M11 + id_M10 + id_M9)*VDD +* DC_gain +let r1 = ao_M6*ro_M4 +let r2 = ao_M8*((ro_M1*ro_M10)/(ro_M1+ro_M10)) +let Rout = (r1*r2)/(r1+r2) +let Av = db(gm_M1*Rout) +* Bandwidth +let BW = 1/(Rout*1e-12*6.283185) + +print #####_Custom_output_##### Av BW Rout power gm_M1 ro_M1 gm_M6 ro_M6 ro_M4 gm_M8 ro_M8 ro_M10 + +write error_amplifier_core_N_input_op.raw +.endc +"} +C {devices/code_shown.sym} 540 -500 0 0 {name=Voltage_sources only_toplevel=true +value=" +.param VDD = 1.8 +.param VSS = 0 +.param VbiasN1 = 0.77 +.param VbiasN2 = 1.28 +.param VbiasP2 = 0.46 +.param Vin = 1.2 +"} +C {/foss/designs/workarea/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sym} 770 -220 0 0 {name=x1} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_os.sch b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_os.sch new file mode 100644 index 00000000..802dd296 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/error_amplifier_core_os.sch @@ -0,0 +1,288 @@ +v {xschem version=3.4.7 file_version=1.2} +G {} +K {} +V {} +S {} +E {} +N 240 -60 240 -50 {lab=GND} +N 240 -150 240 -120 {lab=VbiasP2} +N 320 -60 320 -50 {lab=GND} +N 320 -150 320 -120 {lab=VbiasN2} +N 400 -60 400 -50 {lab=GND} +N 400 -150 400 -120 {lab=VbiasN1} +N 80 -60 80 -50 {lab=GND} +N 80 -150 80 -120 {lab=VDD} +N 160 -60 160 -50 {lab=GND} +N 160 -150 160 -120 {lab=VSS} +N 960 -110 960 -50 { +lab=GND} +N 870 -220 960 -220 { +lab=Vout} +N 960 -220 960 -170 { +lab=Vout} +N 570 -250 670 -250 { +lab=Vout} +N 570 -320 570 -250 { +lab=Vout} +N 570 -320 960 -320 { +lab=Vout} +N 960 -320 960 -220 { +lab=Vout} +N 570 -60 570 -50 {lab=GND} +N 570 -150 570 -120 {lab=Vin} +N 570 -190 570 -150 { +lab=Vin} +N 570 -190 670 -190 { +lab=Vin} +C {devices/vsource.sym} 240 -90 0 0 {name=V1 value=\{VbiasP2\}} +C {devices/gnd.sym} 240 -50 0 0 {name=l2 lab=GND} +C {devices/launcher.sym} 120 -370 0 0 {name=h3 +descr="Save & Netlist & sim" +tclcommand="xschem save; xschem netlist; xschem simulate"} +C {devices/lab_wire.sym} 240 -150 0 0 {name=p1 sig_type=std_logic lab=VbiasP2} +C {devices/vsource.sym} 320 -90 0 0 {name=V2 value=\{VbiasN2\}} +C {devices/gnd.sym} 320 -50 0 0 {name=l1 lab=GND} +C {devices/lab_wire.sym} 320 -150 0 0 {name=p2 sig_type=std_logic lab=VbiasN2} +C {devices/vsource.sym} 400 -90 0 0 {name=V3 value=\{VbiasN1\}} +C {devices/gnd.sym} 400 -50 0 0 {name=l3 lab=GND} +C {devices/lab_wire.sym} 400 -150 0 0 {name=p3 sig_type=std_logic lab=VbiasN1} +C {devices/lab_wire.sym} 720 -30 0 0 {name=p4 sig_type=std_logic lab=VbiasN1} +C {devices/lab_wire.sym} 720 -50 0 0 {name=p5 sig_type=std_logic lab=VbiasN2} +C {devices/lab_wire.sym} 720 -70 0 0 {name=p6 sig_type=std_logic lab=VbiasP2} +C {devices/noconn.sym} 720 -90 0 0 {name=l4} +C {devices/lab_wire.sym} 720 -110 0 0 {name=p7 sig_type=std_logic lab=VSS} +C {devices/lab_wire.sym} 720 -130 0 0 {name=p8 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 80 -90 0 0 {name=V4 value=\{VDD\}} +C {devices/gnd.sym} 80 -50 0 0 {name=l5 lab=GND} +C {devices/lab_wire.sym} 80 -150 0 0 {name=p9 sig_type=std_logic lab=VDD} +C {devices/vsource.sym} 160 -90 0 0 {name=V5 value=\{VSS\}} +C {devices/gnd.sym} 160 -50 0 0 {name=l6 lab=GND} +C {devices/lab_wire.sym} 160 -150 0 0 {name=p10 sig_type=std_logic lab=VSS} +C {devices/capa.sym} 960 -140 0 0 {name=C1 +m=1 +value=5p +footprint=1206 +device="ceramic capacitor"} +C {devices/vsource.sym} 570 -90 0 0 {name=Vin value=\{Vin\}} +C {devices/gnd.sym} 570 -50 0 0 {name=l7 lab=GND} +C {devices/lab_wire.sym} 570 -150 0 0 {name=p11 sig_type=std_logic lab=Vin} +C {devices/lab_wire.sym} 960 -220 0 0 {name=p12 sig_type=std_logic lab=Vout} +C {devices/gnd.sym} 960 -50 0 0 {name=l8 lab=GND} +C {devices/code_shown.sym} 40 -500 0 0 {name=MODELS only_toplevel=true +format="tcleval( @value )" +value=" +.include $::180MCU_MODELS/design.ngspice +.lib $::180MCU_MODELS/sm141064.ngspice typical +"} +C {launcher.sym} 120 -300 0 0 {name=h1 +descr="Annotate OP" +tclcommand="set show_hidden_texts 1; xschem annotate_op"} +C {simulator_commands.sym} 820 -480 0 0 {name=COMMANDS +simulator=ngspice +only_toplevel=false +value=" +.control +save all + +** OP simulation +op +** Output swing +dc Vin 0 1.8 0.01 + +** All OP parameters +setplot op1 +let #####_M1_nmos_input_##### = 0 +let id_M1 = @m.x1.xm1.m0[id] +let gm_M1 = @m.x1.xm1.m0[gm] +let ro_M1 = 1/@m.x1.xm1.m0[gds] +let Vgs_M1 = @m.x1.xm1.m0[vgs] +let Vds_M1 = @m.x1.xm1.m0[vds] +let Vsb_M1 = -@m.x1.xm1.m0[vbs] +let Vdsat_M1 = @m.x1.xm1.m0[vdsat] +let Vth_M1 = @m.x1.xm1.m0[vth] +let ao_M1 = gm_M1*ro_M1 +let gmid_M1 = gm_M1/id_M1 +let fT_M1 = gm_M1/(6.283185*@m.x1.xm1.m0[cgg]) +print #####_M1_nmos_input_##### id_M1 gm_M1 ro_M1 Vgs_M1 Vds_M1 Vsb_M1 Vdsat_M1 Vth_M1 ao_M1 gmid_M1 fT_M1 + +let #####_M2_nmos_input_##### = 0 +let id_M2 = @m.x1.xm2.m0[id] +let gm_M2 = @m.x1.xm2.m0[gm] +let ro_M2 = 1/@m.x1.xm2.m0[gds] +let Vgs_M2 = @m.x1.xm2.m0[vgs] +let Vds_M2 = @m.x1.xm2.m0[vds] +let Vsb_M2 = -@m.x1.xm2.m0[vbs] +let Vdsat_M2 = @m.x1.xm2.m0[vdsat] +let Vth_M2 = @m.x1.xm2.m0[vth] +let ao_M2 = gm_M2*ro_M2 +let gmid_M2 = gm_M2/id_M2 +let fT_M2 = gm_M2/(6.283185*@m.x1.xm2.m0[cgg]) +print #####_M2_nmos_input_##### id_M2 gm_M2 ro_M2 Vgs_M2 Vds_M2 Vsb_M2 Vdsat_M2 Vth_M2 ao_M2 gmid_M2 fT_M2 + +let #####_M3_pmos_top_##### = 0 +let id_M3 = @m.x1.xm3.m0[id] +let gm_M3 = @m.x1.xm3.m0[gm] +let ro_M3 = 1/@m.x1.xm3.m0[gds] +let Vsg_M3 = @m.x1.xm3.m0[vgs] +let Vsd_M3 = @m.x1.xm3.m0[vds] +let Vbs_M3 = -@m.x1.xm3.m0[vbs] +let Vdsat_M3 = @m.x1.xm3.m0[vdsat] +let Vth_M3 = @m.x1.xm3.m0[vth] +let ao_M3 = gm_M3*ro_M3 +let gmid_M3 = gm_M3/id_M3 +let fT_M3 = gm_M3/(6.283185*@m.x1.xm3.m0[cgg]) +print #####_M3_pmos_top_##### id_M3 gm_M3 ro_M3 Vsg_M3 Vsd_M3 Vbs_M3 Vdsat_M3 Vth_M3 ao_M3 gmid_M3 fT_M3 + +let #####_M4_pmos_top_##### = 0 +let id_M4 = @m.x1.xm4.m0[id] +let gm_M4 = @m.x1.xm4.m0[gm] +let ro_M4 = 1/@m.x1.xm4.m0[gds] +let Vsg_M4 = @m.x1.xm4.m0[vgs] +let Vsd_M4 = @m.x1.xm4.m0[vds] +let Vbs_M4 = -@m.x1.xm4.m0[vbs] +let Vdsat_M4 = @m.x1.xm4.m0[vdsat] +let Vth_M4 = @m.x1.xm4.m0[vth] +let ao_M4 = gm_M4*ro_M4 +let gmid_M4 = gm_M4/id_M4 +let fT_M4 = gm_M4/(6.283185*@m.x1.xm4.m0[cgg]) +print #####_M4_pmos_top_##### id_M4 gm_M4 ro_M4 Vsg_M4 Vsd_M4 Vbs_M4 Vdsat_M4 Vth_M4 ao_M4 gmid_M4 fT_M4 + +let #####_M5_pmos_out_##### = 0 +let id_M5 = @m.x1.xm5.m0[id] +let gm_M5 = @m.x1.xm5.m0[gm] +let ro_M5 = 1/@m.x1.xm5.m0[gds] +let Vsg_M5 = @m.x1.xm5.m0[vgs] +let Vsd_M5 = @m.x1.xm5.m0[vds] +let Vbs_M5 = -@m.x1.xm5.m0[vbs] +let Vdsat_M5 = @m.x1.xm5.m0[vdsat] +let Vth_M5 = @m.x1.xm5.m0[vth] +let ao_M5 = gm_M5*ro_M5 +let gmid_M5 = gm_M5/id_M5 +let fT_M5 = gm_M5/(6.283185*@m.x1.xm5.m0[cgg]) +print #####_M5_pmos_out_##### id_M5 gm_M5 ro_M5 Vsg_M5 Vsd_M5 Vbs_M5 Vdsat_M5 Vth_M5 ao_M5 gmid_M5 fT_M5 + +let #####_M6_pmos_out_##### = 0 +let id_M6 = @m.x1.xm6.m0[id] +let gm_M6 = @m.x1.xm6.m0[gm] +let ro_M6 = 1/@m.x1.xm6.m0[gds] +let Vsg_M6 = @m.x1.xm6.m0[vgs] +let Vsd_M6 = @m.x1.xm6.m0[vds] +let Vbs_M6 = -@m.x1.xm6.m0[vbs] +let Vdsat_M6 = @m.x1.xm6.m0[vdsat] +let Vth_M6 = @m.x1.xm6.m0[vth] +let ao_M6 = gm_M6*ro_M6 +let gmid_M6 = gm_M6/id_M6 +let fT_M6 = gm_M6/(6.283185*@m.x1.xm6.m0[cgg]) +print #####_M6_pmos_out_##### id_M6 gm_M6 ro_M6 Vsg_M6 Vsd_M6 Vbs_M6 Vdsat_M6 Vth_M6 ao_M6 gmid_M6 fT_M6 + +let #####_M7_nmos_out_##### = 0 +let id_M7 = @m.x1.xm7.m0[id] +let gm_M7 = @m.x1.xm7.m0[gm] +let ro_M7 = 1/@m.x1.xm7.m0[gds] +let Vgs_M7 = @m.x1.xm7.m0[vgs] +let Vds_M7 = @m.x1.xm7.m0[vds] +let Vsb_M7 = -@m.x1.xm7.m0[vbs] +let Vdsat_M7 = @m.x1.xm7.m0[vdsat] +let Vth_M7 = @m.x1.xm7.m0[vth] +let ao_M7 = gm_M7*ro_M7 +let gmid_M7 = gm_M7/id_M7 +let fT_M7 = gm_M7/(6.283185*@m.x1.xm7.m0[cgg]) +print #####_M7_nmos_out_##### id_M7 gm_M7 ro_M7 Vgs_M7 Vds_M7 Vsb_M7 Vdsat_M7 Vth_M7 ao_M7 gmid_M7 fT_M7 + +let #####_M8_nmos_out_##### = 0 +let id_M8 = @m.x1.xm8.m0[id] +let gm_M8 = @m.x1.xm8.m0[gm] +let ro_M8 = 1/@m.x1.xm8.m0[gds] +let Vgs_M8 = @m.x1.xm8.m0[vgs] +let Vds_M8 = @m.x1.xm8.m0[vds] +let Vsb_M8 = -@m.x1.xm8.m0[vbs] +let Vdsat_M8 = @m.x1.xm8.m0[vdsat] +let Vth_M8 = @m.x1.xm8.m0[vth] +let ao_M8 = gm_M8*ro_M8 +let gmid_M8 = gm_M8/id_M8 +let fT_M8 = gm_M8/(6.283185*@m.x1.xm8.m0[cgg]) +print #####_M8_nmos_out_##### id_M8 gm_M8 ro_M8 Vgs_M8 Vds_M8 Vsb_M8 Vdsat_M8 Vth_M8 ao_M8 gmid_M8 fT_M8 + +let #####_M9_nmos_bottom_##### = 0 +let id_M9 = @m.x1.xm9.m0[id] +let gm_M9 = @m.x1.xm9.m0[gm] +let ro_M9 = 1/@m.x1.xm9.m0[gds] +let Vgs_M9 = @m.x1.xm9.m0[vgs] +let Vds_M9 = @m.x1.xm9.m0[vds] +let Vsb_M9 = -@m.x1.xm9.m0[vbs] +let Vdsat_M9 = @m.x1.xm9.m0[vdsat] +let Vth_M9 = @m.x1.xm9.m0[vth] +let ao_M9 = gm_M9*ro_M9 +let gmid_M9 = gm_M9/id_M9 +let fT_M9 = gm_M9/(6.283185*@m.x1.xm9.m0[cgg]) +print #####_M9_nmos_bottom_##### id_M9 gm_M9 ro_M9 Vgs_M9 Vds_M9 Vsb_M9 Vdsat_M9 Vth_M9 ao_M9 gmid_M9 fT_M9 + +let #####_M10_nmos_bottom_##### = 0 +let id_M10 = @m.x1.xm10.m0[id] +let gm_M10 = @m.x1.xm10.m0[gm] +let ro_M10 = 1/@m.x1.xm10.m0[gds] +let Vgs_M10 = @m.x1.xm10.m0[vgs] +let Vds_M10 = @m.x1.xm10.m0[vds] +let Vsb_M10 = @m.x1.xm10.m0[vbs] +let Vdsat_M10 = @m.x1.xm10.m0[vdsat] +let Vth_M10 = @m.x1.xm10.m0[vth] +let ao_M10 = gm_M10*ro_M10 +let gmid_M10 = gm_M10/id_M10 +let fT_M10 = gm_M10/(6.283185*@m.x1.xm10.m0[cgg]) +print #####_M10_nmos_bottom_##### id_M10 gm_M10 ro_M10 Vgs_M10 Vds_M10 Vsb_M10 Vdsat_M10 Vth_M10 ao_M10 gmid_M10 fT_M10 + +let #####_M11_nmos_mirror_##### = 0 +let id_M11 = @m.x1.xm11.m0[id] +let gm_M11 = @m.x1.xm11.m0[gm] +let ro_M11 = 1/@m.x1.xm11.m0[gds] +let Vgs_M11 = @m.x1.xm11.m0[vgs] +let Vds_M11 = @m.x1.xm11.m0[vds] +let Vsb_M11 = -@m.x1.xm11.m0[vbs] +let Vdsat_M11 = @m.x1.xm11.m0[vdsat] +let Vth_M11 = @m.x1.xm11.m0[vth] +let ao_M11 = gm_M11*ro_M11 +let gmid_M11 = gm_M11/id_M11 +let fT_M11 = gm_M11/(6.283185*@m.x1.xm11.m0[cgg]) +print #####_M11_nmos_mirror_##### id_M11 gm_M11 ro_M11 Vgs_M11 Vds_M11 Vsb_M11 Vdsat_M11 Vth_M11 ao_M11 gmid_M11 fT_M11 + +** Custom output +let #####_Custom_output_##### = 0 +* Power +let power = (id_M11 + id_M10 + id_M9)*VDD +* DC_gain +let r1 = ao_M6*ro_M4 +let r2 = ao_M8*((ro_M1*ro_M10)/(ro_M1+ro_M10)) +let Rout = (r1*r2)/(r1+r2) +let Av = db(gm_M1*Rout) +* Bandwidth +let BW = 1/(Rout*1e-12*6.283185) + +print #####_Custom_output_##### Av BW Rout power gm_M1 ro_M1 gm_M6 ro_M6 ro_M4 gm_M8 ro_M8 ro_M10 + +write error_amplifier_core_N_input_os.raw + +setplot dc1 +let dvout = deriv(v(Vout)) + +meas dc limmin when dvout=0.98 rise=1 +meas dc limmax when dvout=0.98 fall=1 + +let Output_swing = limmax - limmin + +print Output_swing +plot dvout + + + +.endc +"} +C {devices/code_shown.sym} 540 -500 0 0 {name=Voltage_sources only_toplevel=true +value=" +.param VDD = 1.8 +.param VSS = 0 +.param VbiasN1 = 0.77 +.param VbiasN2 = 1.28 +.param VbiasP2 = 0.46 +.param Vin = 1.2 +"} +C {/foss/designs/workarea/error_amplifier_core_N_input/xschem/error_amplifier_core_N_input.sym} 770 -220 0 0 {name=x1} diff --git a/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/xschemrc b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/xschemrc new file mode 100644 index 00000000..3b753a38 --- /dev/null +++ b/blocks/composite/folded_cascode/designs/gf180/error_amplifier_core_N_input/xschem/xschemrc @@ -0,0 +1,7 @@ +# Source the PDK xschemrc file +if {![info exists PDK]} { + source $env(PDK_ROOT)/$env(PDK)/libs.tech/xschem/xschemrc +} + +# Add current directory to xschem library path +append XSCHEM_LIBRARY_PATH :[file dirname [info script]] diff --git a/blocks/composite/folded_cascode/glayout/Biasing.py b/blocks/composite/folded_cascode/glayout/Biasing.py new file mode 100644 index 00000000..595df676 --- /dev/null +++ b/blocks/composite/folded_cascode/glayout/Biasing.py @@ -0,0 +1,487 @@ +from glayout import MappedPDK, sky130, gf180 +from glayout import nmos, pmos, multiplier, tapring, via_stack, via_array + +from glayout.spice.netlist import Netlist +from glayout.routing import c_route, L_route, straight_route + +from gdsfactory.cell import cell +from gdsfactory.component import Component, copy +from gdsfactory.components.rectangle import rectangle +from gdsfactory.routing.route_quad import route_quad +from gdsfactory.routing.route_sharp import route_sharp + +from glayout.util.comp_utils import ( + align_comp_to_port, + evaluate_bbox, + movex, + movey, + prec_ref_center, + prec_array, +) +from glayout.util.port_utils import ( + add_ports_perimeter, + get_orientation, + print_ports, + rename_ports_by_list, + rename_ports_by_orientation, + set_port_orientation, +) +from glayout.util.snap_to_grid import component_snap_to_grid +from glayout.placement.common_centroid_ab_ba import common_centroid_ab_ba + +from gdsfactory.functions import transformed +from gdsfactory.components import text_freetype +from gdsfactory.components.rectangular_ring import rectangular_ring +from typing import Optional, Union, Literal +import time +import copy + +# Import custom functions (Matrix generator) +from custom_functions import macro_two_transistor_placement_Onchip +from custom_functions import pin_label_creation +from custom_functions import center_component_with_ports +from custom_functions import filtrar_puertos +from primitives import diode, transistor +from custom_functions import interdigitado_placement_Onchip +from custom_functions import interdigitado_cascode_placement_Onchip +from custom_functions import layer_pin_and_label, Boundary_layer, rails +import gdsfactory as gf + +def Component_Biasing(pdk: MappedPDK, + devices_info, + arrays_info, + width_route: float = None) -> Component: + """ + This function creates transistors needed for the biasing generator + """ + # Width configuration + if width_route == None or width_route == 0: + separation_interdigitado = 0 + width_horizontal = evaluate_bbox(via_stack(pdk,'met2','met3'))[1] + else: + separation_interdigitado = width_route + width_horizontal = width_route + # Create the component + min_separation_met3 = pdk.get_grule('met3')['min_separation'] + biasing = Component() + pmirrors = interdigitado_placement_Onchip(pdk, output='via', common_route=(False, True), output_separation=(separation_interdigitado, 2*separation_interdigitado + min_separation_met3), deviceA_and_B='pfet', width=devices_info[2]['width'], length=devices_info[2]['length'], fingers=devices_info[2]['fingers'], with_dummy=True, array=arrays_info[2], with_tie=True, with_lvt_layer=devices_info[2]['lvt']) + transistor_vref = interdigitado_placement_Onchip(pdk, output='via', output_separation=(separation_interdigitado, separation_interdigitado), deviceA_and_B=devices_info[0]['type'], width=devices_info[0]['width'], length=devices_info[0]['length'], fingers=devices_info[0]['fingers'], + with_dummy=devices_info[0]['with_dummy'], array=arrays_info[0], with_tie=devices_info[0]['with_tie'], with_substrate_tap=devices_info[0]['with_substrate_tap'], with_lvt_layer=devices_info[0]['lvt']) + + transistor_p_18_12 = interdigitado_placement_Onchip(pdk, output='via', output_separation=(separation_interdigitado, separation_interdigitado), deviceA_and_B=devices_info[1]['type'], width=devices_info[1]['width'], length=devices_info[1]['length'], fingers=devices_info[1]['fingers'], + with_dummy=devices_info[1]['with_dummy'], array=arrays_info[1], with_tie=devices_info[1]['with_tie'], with_substrate_tap=devices_info[1]['with_substrate_tap'], with_lvt_layer=devices_info[1]['lvt']) + transistors_p_13_14 = interdigitado_placement_Onchip(pdk, output='via', output_separation=(separation_interdigitado, separation_interdigitado), gate_common=False, deviceA_and_B=devices_info[1]['type'], width=devices_info[1]['width'], length=devices_info[1]['length'], fingers=devices_info[1]['fingers'], + with_dummy=devices_info[1]['with_dummy'], array=arrays_info[3], with_tie=devices_info[1]['with_tie'], with_substrate_tap=devices_info[1]['with_substrate_tap'], with_lvt_layer=devices_info[1]['lvt']) + + #Add the components to the biasing component + pmirrors_ref = biasing << pmirrors + m1_m15 = biasing << transistor_vref + m2_m16 = biasing << transistor_vref + m12_m18 = biasing << transistor_p_18_12 + m13_m14 = biasing << transistors_p_13_14 + #x reflection + pmirrors_ref.mirror(p1=(0,0), p2=(1,0)) + m1_m15.mirror(p1=(0,0), p2=(1,0)) + m2_m16.mirror(p1=(0,0), p2=(1,0)) + m12_m18.mirror(p1=(0,0), p2=(1,0)) + m13_m14.mirror(p1=(0,0), p2=(1,0)) + + #Components size + pmirrors_size = evaluate_bbox(pmirrors_ref) + m1_m15_size = evaluate_bbox(m1_m15) + m2_m16_size = evaluate_bbox(m2_m16) + m12_m18_size = evaluate_bbox(m12_m18) + m13_m14_size = evaluate_bbox(m13_m14) + #min separation between components + min_separation = pdk.get_grule('nwell')['min_separation'] + size_via = evaluate_bbox(via_stack(pdk, 'met2', 'met3')) + #amount of movement + pmirrors_movement = [0] + m1_m15_movement = [(pmirrors_size[0] + m1_m15_size[0])/2 + min_separation] + m2_m16_movement = [(pmirrors_size[0] + m2_m16_size[0])/2 + min_separation] + m12_m18_movement = [(m1_m15_size[0] + m12_m18_size[0])/2 + m1_m15_movement[0] + min_separation] + m13_m14_movement = [(m12_m18_size[0] + m13_m14_size[0])/2 + m12_m18_movement[0] + min_separation] + #move the componentes + pmirrors_ref.movex(pdk.snap_to_2xgrid(pmirrors_movement[0])) + m1_m15.movex(pdk.snap_to_2xgrid(m1_m15_movement[0])) + m2_m16.movex(pdk.snap_to_2xgrid(-m2_m16_movement[0])) + m12_m18.movex(pdk.snap_to_2xgrid(m12_m18_movement[0])) + m13_m14.movex(pdk.snap_to_2xgrid(m13_m14_movement[0])).movey(pdk.snap_to_2xgrid(size_via[1])) + #Total size + size_biasing = evaluate_bbox(biasing) + #Extension + size_via = evaluate_bbox(via_stack(pdk, 'met2', 'met3'))[1] + pdk.get_grule("met3")["min_separation"]*2 + #Vias + via_3_4 = via_stack(pdk, 'met3', 'met4') + #Routing the components + #Pmirrors + #Source routes + + VDD1 = biasing << straight_route(pdk, pmirrors_ref.ports['source_1_2_0_W'], pmirrors_ref.ports['source_3_3_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width = width_horizontal) + via_pmirror1 = biasing << via_3_4 + via_pmirror2 = biasing << via_3_4 + via_pmirror3 = biasing << via_3_4 + + via_pmirror1.movex(pdk.snap_to_2xgrid(pmirrors_ref.ports['source_1_2_0_N'].center[0])).movey(pdk.snap_to_2xgrid(pmirrors_ref.ports['source_1_2_0_E'].center[1])) + via_pmirror2.movex(pdk.snap_to_2xgrid(pmirrors_ref.ports['source_2_1_0_N'].center[0])).movey(pdk.snap_to_2xgrid(pmirrors_ref.ports['source_2_1_0_E'].center[1])) + via_pmirror3.movex(pdk.snap_to_2xgrid(pmirrors_ref.ports['source_3_3_0_N'].center[0])).movey(pdk.snap_to_2xgrid(pmirrors_ref.ports['source_3_3_0_E'].center[1])) + biasing << straight_route(pdk, via_pmirror1.ports['top_met_W'], via_pmirror3.ports['top_met_E'], width = width_horizontal) + + biasing << c_route(pdk, pmirrors_ref.ports['source_3_3_0_S'], m12_m18.ports['source_2_2_0_S'], cglayer='met2', cwidth = width_horizontal) + + #Bulk route + biasing << straight_route(pdk, pmirrors_ref.ports['source_2_1_0_S'], pmirrors_ref.ports['bulk_down_N']) + #Drain route + biasing << L_route(pdk, pmirrors_ref.ports['drain_2_1_0_E'], pmirrors_ref.ports['gate1_S'], hglayer='met2', vglayer='met3', vwidth = width_horizontal) + biasing << L_route(pdk, pmirrors_ref.ports['drain_2_1_0_E'], pmirrors_ref.ports['gate2_S'], hglayer='met2', vglayer='met3', vwidth = width_horizontal) + biasing << straight_route(pdk, pmirrors_ref.ports['drain_1_2_0_E'], m2_m16.ports['drain_2_2_0_W'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width = width_horizontal) + biasing << straight_route(pdk, pmirrors_ref.ports['drain_2_1_0_W'], m1_m15.ports['drain_1_1_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width = width_horizontal) + + ############################################ + #Falta la conexión con transistores 3 5 y 7 + ############################################ + + #M1-M15 + #Bulk route + biasing << straight_route(pdk, m1_m15.ports['source_2_2_0_S'], m1_m15.ports['bulk_down_N']) + #Drain route + biasing << L_route(pdk, m1_m15.ports['source_1_1_0_E'], m1_m15.ports['drain_2_2_0_N'], hglayer='met2') + #Source route + VSS1 = biasing << c_route(pdk, m1_m15.ports['source_2_2_0_S'], m2_m16.ports['source_1_1_0_S'], cglayer='met4', extension=size_via+width_horizontal, cwidth = width_horizontal) + + #M2-16 + #Gate route + biasing << L_route(pdk, m2_m16.ports['gate2_S'], m2_m16.ports['drain_2_2_0_E'], vglayer='met3', hglayer='met2', vwidth = width_horizontal) + biasing << L_route(pdk, m2_m16.ports['gate1_S'], m2_m16.ports['drain_2_2_0_E'], vglayer='met3', hglayer='met2', vwidth = width_horizontal) + + #Bulk route + biasing << straight_route(pdk, m2_m16.ports['source_1_1_0_S'], m2_m16.ports['bulk_down_N']) + #drain route + biasing << L_route(pdk, m2_m16.ports['source_2_2_0_S'], m2_m16.ports['drain_1_1_0_W'], hglayer='met2', vwidth = width_horizontal) + + ############################################ + #Falta la conexión con transistores 3 5 y 7 + ############################################ + + #M12-M18 + #Source route + if width_route == None or width_route == 0: + biasing << straight_route(pdk, m13_m14.ports['source_5_1_0_W'], m12_m18.ports['source_2_2_0_W'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width = width_horizontal) + else: + biasing << L_route(pdk, m13_m14.ports['source_5_1_0_E'], m12_m18.ports['source_2_2_0_S'], vglayer='met3', hglayer='met2', vwidth = 0.75*width_horizontal) + + #Bulk route + biasing << straight_route(pdk, m12_m18.ports['source_2_2_0_S'], m12_m18.ports['bulk_down_N']) + #Gate route + biasing << L_route(pdk, m12_m18.ports['gate1_S'], m12_m18.ports['drain_1_1_0_W'], vglayer='met3', hglayer='met2', vwidth = width_horizontal) + biasing << L_route(pdk, m12_m18.ports['gate2_S'], m12_m18.ports['drain_1_1_0_W'], vglayer='met3', hglayer='met2', vwidth = width_horizontal) + #drain route + biasing << L_route(pdk, m12_m18.ports['drain_2_2_0_E'], m12_m18.ports['source_1_1_0_S'], hglayer='met2') + ############################################ + #Falta la conexión con transistores 3 5 y 7 + ############################################ + + #M13-M14 + #Bulk route + biasing << straight_route(pdk, m13_m14.ports['source_1_1_0_S'], m12_m18.ports['bulk_down_S'], via2_alignment_layer='met2') + biasing << straight_route(pdk, m13_m14.ports['source_3_1_0_S'], m12_m18.ports['bulk_down_S'], via2_alignment_layer='met2') + biasing << straight_route(pdk, m13_m14.ports['source_5_1_0_S'], m12_m18.ports['bulk_down_S'], via2_alignment_layer='met2') + #Common route + biasing << straight_route(pdk, m13_m14.ports['source_2_2_0_W'], m13_m14.ports['source_4_2_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width = width_horizontal) + VDD2 = biasing << straight_route(pdk, m13_m14.ports['source_1_1_0_W'], m13_m14.ports['source_5_1_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width = width_horizontal) + via_m13_1 = biasing << via_3_4 + via_m13_2 = biasing << via_3_4 + via_m13_3 = biasing << via_3_4 + via_m13_1.movex(pdk.snap_to_2xgrid(m13_m14.ports['source_1_1_0_N'].center[0])).movey(pdk.snap_to_2xgrid(m13_m14.ports['source_1_1_0_E'].center[1])) + via_m13_2.movex(pdk.snap_to_2xgrid(m13_m14.ports['source_3_1_0_N'].center[0])).movey(pdk.snap_to_2xgrid(m13_m14.ports['source_3_1_0_E'].center[1])) + via_m13_3.movex(pdk.snap_to_2xgrid(m13_m14.ports['source_5_1_0_N'].center[0])).movey(pdk.snap_to_2xgrid(m13_m14.ports['source_5_1_0_E'].center[1])) + biasing << straight_route(pdk, via_m13_1.ports['top_met_W'], via_m13_3.ports['top_met_E'], width = width_horizontal) + + biasing << straight_route(pdk, m13_m14.ports['drain_1_1_0_W'], m13_m14.ports['drain_5_1_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width = width_horizontal) + biasing << straight_route(pdk, m13_m14.ports['drain_2_2_0_W'], m13_m14.ports['drain_4_2_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width = width_horizontal) + #drain route + biasing << L_route(pdk, m13_m14.ports['source_2_2_0_S'], m13_m14.ports['drain_1_1_0_E'], hglayer='met2', vwidth = width_horizontal) + biasing << L_route(pdk, m13_m14.ports['source_4_2_0_S'], m13_m14.ports['drain_1_1_0_E'], hglayer='met2', vwidth = width_horizontal) + #gate route + biasing << straight_route(pdk, m13_m14.ports['1_1_gate_W'], m13_m14.ports['5_1_gate_E']) + biasing << L_route(pdk, m13_m14.ports['drain_2_2_0_S'], m13_m14.ports['1_1_gate_W']) + biasing << L_route(pdk, m13_m14.ports['drain_4_2_0_S'], m13_m14.ports['1_1_gate_W']) + biasing << L_route(pdk, m13_m14.ports['4_2_gate_W'], m12_m18.ports['gate2_N']) + + ############################################ + #Falta la conexión con transistores 3 5 y 7 y puentear los gates comunes + ############################################ + min_separation = pdk.get_grule('met3')['min_separation'] + + #input port + via_ref = via_stack(pdk, 'met2', 'met3') + + V_ref = biasing << via_ref + align_comp_to_port(V_ref, m1_m15.ports['source_2_2_0_S']) + V_ref.movey(pdk.snap_to_2xgrid(size_via+2*min_separation+2*width_horizontal)).movex(pdk.snap_to_2xgrid(-evaluate_bbox(m1_m15)[0]/4)) + biasing << L_route(pdk, m1_m15.ports['gate1_N'], V_ref.ports['bottom_met_E'], vwidth = width_horizontal) + biasing << L_route(pdk, m1_m15.ports['gate2_N'], V_ref.ports['bottom_met_W'], vwidth = width_horizontal) + + V_dd = biasing << via_ref + align_comp_to_port(V_dd, m13_m14.ports['source_5_1_0_W']) + V_dd.movex(pdk.snap_to_2xgrid(evaluate_bbox(m13_m14)[0]/5)) + biasing << straight_route(pdk, m13_m14.ports['source_5_1_0_W'], V_dd.ports['bottom_met_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width = width_horizontal) + + #Output port + V_biasp = biasing << via_ref + V_biasp.movex(pdk.snap_to_2xgrid(pmirrors_ref.ports['drain_2_1_0_S'].center[0])).movey(pdk.snap_to_2xgrid(-size_biasing[1]/2 - evaluate_bbox(via_ref)[1] - min_separation)) + biasing << straight_route(pdk, pmirrors_ref.ports['drain_2_1_0_S'], V_biasp['top_met_S']) + + V_biasp2 = biasing << via_ref + align_comp_to_port(V_biasp2, m13_m14.ports['4_2_gate_E']) + V_biasp2.movex(pdk.snap_to_2xgrid(2*evaluate_bbox(m1_m15)[0]/7)) + biasing << straight_route(pdk, m13_m14.ports['4_2_gate_E'], V_biasp2['bottom_met_E']) + + #Add the ports to the component + biasing.add_ports(pmirrors_ref.ports, prefix='pmirror_') + biasing.add_ports(m1_m15.ports, prefix='m1_') + biasing.add_ports(m2_m16.ports, prefix='m2_') + biasing.add_ports(m12_m18.ports, prefix='m12_') + biasing.add_ports(m13_m14.ports, prefix='m13_') + biasing.add_ports(V_ref.ports, prefix = 'Vref_') + biasing.add_ports(V_dd.ports, prefix = 'Vdd_') + biasing.add_ports(V_biasp.ports, prefix = 'VbiasP1_') + biasing.add_ports(V_biasp2.ports, prefix = 'VbiasP2_') + + biasing.add_ports(VDD1.ports, prefix = 'VDD1_') + biasing.add_ports(VDD2.ports, prefix = 'VDD2_') + biasing.add_ports(VSS1.ports, prefix = 'VSS1_') + + #Center the component + component_centered = center_component_with_ports(biasing) + + #component_centered = component_centered.flatten() + return component_centered + +def Biasing_generator(pdk, + devices_info, + arrays_info, + width_route: float = None) -> Component: + """ + This function creates a biasing circuit using the MappedPDK and the custom functions + """ + # Width configuration + if width_route == None or width_route == 0: + separation_interdigitado = 0 + width_horizontal = evaluate_bbox(via_stack(pdk,'met2','met3'))[1] + else: + separation_interdigitado = width_route + width_horizontal = width_route + # Division devices info + devices_info_top = [devices_info[0], devices_info[1], devices_info[2]] + devices_info_ntop = [devices_info[3]] + devices_info_nbot = [devices_info[4]] + arrays_info_top = [arrays_info[0], arrays_info[1], arrays_info[2], arrays_info[3]] + array_nmirrors_top = arrays_info[4] + array_nmirrors_bot = arrays_info[5] + min_separation_met3 = pdk.get_grule('met3')['min_separation'] + # Create the component + biasing = Component() + + nmirrors_top = interdigitado_placement_Onchip(pdk, output='via', output_separation=(separation_interdigitado, separation_interdigitado+min_separation_met3), deviceA_and_B=devices_info_ntop[0]['type'], width=devices_info_ntop[0]['width'], length=devices_info_ntop[0]['length'], + fingers=devices_info_ntop[0]['fingers'], with_dummy=devices_info_ntop[0]['with_dummy'], array=array_nmirrors_top, with_tie=devices_info_ntop[0]['with_tie'], with_lvt_layer=devices_info_ntop[0]['lvt']) + + nmirrors_bot = interdigitado_cascode_placement_Onchip(pdk, output='via', common_route=(False, True), output_separation=separation_interdigitado, deviceA_and_B=devices_info_nbot[0]['type'], width=devices_info_nbot[0]['width'], length=devices_info_nbot[0]['length'], + fingers=devices_info_nbot[0]['fingers'], with_dummy=devices_info_nbot[0]['with_dummy'], array=array_nmirrors_bot, with_tie=devices_info_nbot[0]['with_tie'], with_lvt_layer=devices_info_nbot[0]['lvt']) + + top_components = Component_Biasing(pdk, devices_info_top, arrays_info_top, width_route) + # Add the components to the biasing component + nmirrors_top_ref = biasing << nmirrors_top + nmirrors_bot_ref_1 = biasing << nmirrors_bot + top_components_ref = biasing << top_components + #Components size + nmirrors_top_size = evaluate_bbox(nmirrors_top_ref) + nmirrors_bot_size = evaluate_bbox(nmirrors_bot_ref_1) + top_components_size = evaluate_bbox(top_components_ref) + #min separation between components + min_separation = pdk.get_grule('nwell')['min_separation'] + #amount of movement + nmirror_top_movement = [0,0] + nmirror_bot_1_movement = [0, (nmirrors_top_size[1] + nmirrors_bot_size[1])/2 + min_separation + separation_interdigitado] + top_components_movement = [0, (nmirrors_top_size[1] + top_components_size[1])/2 + min_separation + separation_interdigitado] + # move the componentes + nmirrors_top_ref.movey(pdk.snap_to_2xgrid(nmirror_top_movement[1])) + nmirrors_bot_ref_1.movey(pdk.snap_to_2xgrid(-nmirror_bot_1_movement[1])) + top_components_ref.movey(pdk.snap_to_2xgrid(top_components_movement[1])) + #Add ports + biasing.add_ports(nmirrors_top_ref.get_ports_list(), prefix='nmirror_top_') + biasing.add_ports(nmirrors_bot_ref_1.get_ports_list(), prefix='nmirror_bot_') + biasing.add_ports(top_components_ref.get_ports_list(), prefix='top_ref_') + #Vias aux + via_3_4 = via_stack(pdk, 'met3', 'met4') + #Routing + #Common nodes + biasing << straight_route(pdk, nmirrors_top_ref.ports['source_6_1_0_W'], nmirrors_top_ref.ports['source_10_1_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + biasing << straight_route(pdk, nmirrors_top_ref.ports['drain_6_1_0_W'], nmirrors_top_ref.ports['drain_10_1_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + + biasing << straight_route(pdk, nmirrors_top_ref.ports['source_1_2_0_W'], nmirrors_top_ref.ports['source_15_2_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + biasing << straight_route(pdk, nmirrors_top_ref.ports['drain_1_2_0_W'], nmirrors_top_ref.ports['drain_15_2_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + + biasing << straight_route(pdk, nmirrors_top_ref.ports['source_3_3_0_W'], nmirrors_top_ref.ports['source_12_3_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + biasing << straight_route(pdk, nmirrors_top_ref.ports['drain_3_3_0_W'], nmirrors_top_ref.ports['drain_12_3_0_W'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + #Cascode nmos + #biasing << straight_route(pdk, nmirrors_bot_ref_1.ports['source_15_1_0_W'], nmirrors_bot_ref_1.ports['source_18_1_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', via2_alignment_layer='met3', width=width_horizontal) + biasing << straight_route(pdk, nmirrors_bot_ref_1.ports['drain_25_1_0_W'], nmirrors_bot_ref_1.ports['drain_28_1_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', via2_alignment_layer='met3', width=width_horizontal) + + VSS1 = biasing << straight_route(pdk, nmirrors_bot_ref_1.ports['source_11_2_0_W'], nmirrors_bot_ref_1.ports['source_112_2_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + vias_nmirror = list() + for i in range(12): + vias_nmirror.append(biasing << via_3_4) + vias_nmirror[-1].movex(pdk.snap_to_2xgrid(nmirrors_bot_ref_1.ports['source_1'+str(i+1)+'_'+str(array_nmirrors_bot[0][i])+'_0_N'].center[0])).movey(pdk.snap_to_2xgrid(nmirrors_bot_ref_1.ports['source_1'+str(i+1)+'_'+str(array_nmirrors_bot[0][i])+'_0_E'].center[1])) + biasing << straight_route(pdk, vias_nmirror[0].ports['top_met_W'], vias_nmirror[-1].ports['top_met_E'], width = width_horizontal) + + biasing.add_ports(VSS1.ports, prefix = 'VSS1_') + biasing << straight_route(pdk, nmirrors_bot_ref_1.ports['drain_21_2_0_W'], nmirrors_bot_ref_1.ports['drain_212_2_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + + #biasing << straight_route(pdk, nmirrors_bot_ref_1.ports['source_12_3_0_W'], nmirrors_bot_ref_1.ports['source_111_3_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + biasing << straight_route(pdk, nmirrors_bot_ref_1.ports['drain_22_3_0_W'], nmirrors_bot_ref_1.ports['drain_211_3_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + + #nmirror top + #source route + for i in range(len(array_nmirrors_top[0])): + if array_nmirrors_top[0][i] == 1: + biasing << L_route(pdk, nmirrors_top_ref.ports['source_'+str(i+1)+'_1_0_S'], nmirrors_bot_ref_1.ports['drain_25_1_0_E'], hglayer='met2', vglayer = 'met3', vwidth = width_horizontal) + elif array_nmirrors_top[0][i] == 2: + biasing << L_route(pdk, nmirrors_top_ref.ports['source_'+str(i+1)+'_2_0_S'], nmirrors_bot_ref_1.ports['drain_21_2_0_E'], hglayer='met2', vglayer = 'met3', vwidth = width_horizontal) + elif array_nmirrors_top[0][i] == 3: + biasing << L_route(pdk, nmirrors_top_ref.ports['source_'+str(i+1)+'_3_0_S'], nmirrors_bot_ref_1.ports['drain_22_3_0_E'], hglayer='met2', vglayer = 'met3', vwidth = width_horizontal) + + # Bulk route + biasing << c_route(pdk, nmirrors_bot_ref_1.ports['bulk_up_E'], nmirrors_top_ref.ports['bulk_down_E']) + biasing << c_route(pdk, nmirrors_bot_ref_1.ports['bulk_up_W'], nmirrors_top_ref.ports['bulk_down_W']) + + for i in range(len(array_nmirrors_bot[0])): + if array_nmirrors_bot[0][i] == 1: + biasing << straight_route(pdk, nmirrors_bot_ref_1.ports['source_1'+str(i+1)+'_1_0_N'], nmirrors_bot_ref_1.ports['bulk_down_S'], via2_alignment_layer='met2') + elif array_nmirrors_bot[0][i] == 2: + biasing << straight_route(pdk, nmirrors_bot_ref_1.ports['source_1'+str(i+1)+'_2_0_N'], nmirrors_bot_ref_1.ports['bulk_down_S'], via2_alignment_layer='met2') + elif array_nmirrors_bot[0][i] == 3: + biasing << straight_route(pdk, nmirrors_bot_ref_1.ports['source_1'+str(i+1)+'_3_0_N'], nmirrors_bot_ref_1.ports['bulk_down_S'], via2_alignment_layer='met2') + + # gate route + biasing << straight_route(pdk, nmirrors_bot_ref_1.ports['gate_1_l_S'], nmirrors_bot_ref_1.ports['gate_2_l_N'], glayer1='met3', glayer2='met3', via2_alignment_layer='met2') + biasing << straight_route(pdk, nmirrors_bot_ref_1.ports['gate_1_r_S'], nmirrors_bot_ref_1.ports['gate_2_r_N'], glayer1='met3', glayer2='met3', via2_alignment_layer='met2') + + for i in range(len(array_nmirrors_top[0])): + if array_nmirrors_top[0][i] == 1: + biasing << L_route(pdk, nmirrors_top_ref.ports['drain_'+str(i+1)+'_1_0_S'], nmirrors_bot_ref_1.ports['gate_2_l_E'], hglayer='met2') + + #M1 connection + #biasing << L_route(pdk, top_components_ref.ports['m1_source_2_2_0_S'], nmirrors_bot_ref_1.ports['source_18_1_0_E'], hglayer='met2', vwidth = width_horizontal) + + #M2 connection + #biasing << c_route(pdk, top_components_ref.ports['m2_source_1_1_0_W'], nmirrors_bot_ref_1.ports['source_15_1_0_W'], e1glayer = 'met2', cglayer = 'met3', e2glayer = 'met2', width1=width_horizontal, width2=width_horizontal) + + biasing << L_route(pdk, top_components_ref.ports['m2_gate1_S'], nmirrors_top_ref.ports['gate1_E'], hglayer = 'met2') + + #Pmirror connection + biasing << L_route(pdk, top_components_ref.ports['pmirror_drain_3_3_0_S'], nmirrors_top_ref.ports['drain_10_1_0_E'], hglayer = 'met2', vwidth = width_horizontal) + + #M12 connection + biasing << L_route(pdk, top_components_ref.ports['m12_drain_1_1_0_S'], nmirrors_top_ref.ports['drain_1_2_0_E'], hglayer = 'met2', vwidth = width_horizontal) + biasing << L_route(pdk, top_components_ref.ports['m12_gate1_S'], nmirrors_top_ref.ports['drain_1_2_0_E'], hglayer = 'met2', vwidth = width_horizontal) + biasing << c_route(pdk, top_components_ref.ports['m12_gate2_E'], nmirrors_top_ref.ports['drain_1_2_0_E'], e1glayer = 'met2', cglayer = 'met3', e2glayer = 'met2', width2=width_horizontal) + + #M13 connection + biasing << L_route(pdk, top_components_ref.ports['m13_drain_2_2_0_S'], nmirrors_top_ref.ports['drain_12_3_0_W'], hglayer='met2', vwidth = width_horizontal) + biasing << L_route(pdk, top_components_ref.ports['m13_drain_4_2_0_S'], nmirrors_top_ref.ports['drain_12_3_0_W'], hglayer='met2', vwidth = width_horizontal) + + min_separation = pdk.get_grule('met3')['min_separation'] + + biasing_centered = center_component_with_ports(biasing) + + boundary = Boundary_layer(pdk, biasing_centered) + boundary_dim = evaluate_bbox(boundary) + + #Input Port + rectangle_ref = rectangle((0.5,0.5), layer=pdk.get_glayer('met2'), centered=True) + + Vref = biasing_centered << rectangle_ref + Vref.movey(pdk.snap_to_2xgrid(biasing_centered.ports['top_ref_Vref_bottom_met_W'].center[1])) + Vref.movex(pdk.snap_to_2xgrid(-boundary_dim[0]/2+evaluate_bbox(rectangle_ref)[0]/2)) + biasing_centered << straight_route(pdk, Vref.ports['e1'], biasing_centered.ports['top_ref_Vref_bottom_met_W'], width=width_horizontal) + biasing_centered.add_ports(Vref.get_ports_list(), prefix='V_REF_') + + #Output port + V_bias_N1 = biasing_centered << rectangle_ref + V_bias_N1.movey(pdk.snap_to_2xgrid(biasing_centered.ports['nmirror_bot_gate_2_r_E'].center[1])) + V_bias_N1.movex(pdk.snap_to_2xgrid(boundary_dim[0]/2-evaluate_bbox(rectangle_ref)[0]/2)).movey(pdk.snap_to_2xgrid((biasing_centered.ports['nmirror_bot_gate_1_r_E'].center[1]-biasing_centered.ports['nmirror_bot_gate_2_r_E'].center[1])/2)) + biasing_centered << L_route(pdk, biasing_centered.ports['nmirror_bot_gate_2_r_N'], V_bias_N1.ports['e1']) + biasing_centered.add_ports(V_bias_N1.get_ports_list(), prefix='V_BIASN1_') + + V_bias_N2 = biasing_centered << rectangle_ref + V_bias_N2.movey(pdk.snap_to_2xgrid(biasing_centered.ports['nmirror_top_gate2_E'].center[1])) + V_bias_N2.movex(pdk.snap_to_2xgrid(boundary_dim[0]/2-evaluate_bbox(rectangle_ref)[0]/2)) + biasing_centered << straight_route(pdk, V_bias_N2.ports['e1'], biasing_centered.ports['nmirror_top_gate2_W'], glayer1='met2', glayer2='met2') + biasing_centered.add_ports(V_bias_N2.get_ports_list(), prefix='V_BIASN2_') + + V_bias_P1 = biasing_centered << rectangle_ref + V_bias_P1.movey(pdk.snap_to_2xgrid(biasing_centered.ports['top_ref_VbiasP1_top_met_E'].center[1])) + V_bias_P1.movex(pdk.snap_to_2xgrid(boundary_dim[0]/2-evaluate_bbox(rectangle_ref)[0]/2)) + biasing_centered << straight_route(pdk, V_bias_P1.ports['e3'], biasing_centered.ports['top_ref_VbiasP1_bottom_met_W'], glayer1='met2', glayer2='met2') + biasing_centered.add_ports(V_bias_P1.get_ports_list(), prefix='V_BIASP1_') + + biasing_centered = center_component_with_ports(biasing_centered) + rename_ports_by_orientation(biasing_centered) + #name = [name for name in biasing_centered.ports if 'bulk' in name] + #print(name) + route_list = [['VSS1_route_', 'VSS'], ['top_ref_VSS1_con_', 'VSS'], ['nmirror_bot_bulk_down_', 'VSS'], ['nmirror_bot_bulk_up_', 'VSS'], ['nmirror_top_bulk_down_', 'VSS'], + ['nmirror_top_bulk_up_', 'VSS'], ['top_ref_m1_bulk_up_', 'VSS'], ['top_ref_m1_bulk_down_', 'VSS'], ['top_ref_m2_bulk_up_', 'VSS'], ['top_ref_m2_bulk_down_', 'VSS'], + ['top_ref_VDD1_route_', 'VDD'], ['top_ref_VDD2_route_', 'VDD'], ['top_ref_pmirror_bulk_up_', 'VDD'], ['top_ref_pmirror_bulk_down_', 'VDD'], + ['top_ref_m12_bulk_up_', 'VDD'], ['top_ref_m12_bulk_down_', 'VDD'], ['top_ref_m13_bulk_up_', 'VDD'], ['top_ref_m13_bulk_down_', 'VDD']] + + rails(pdk, biasing_centered, 1, route_list) + + component = Component() + component << biasing_centered + + + filtrar_puertos(biasing_centered, component, 'V_REF_', 'VREF_') + #filtrar_puertos(biasing_centered, component, 'top_ref_Vdd_bottom_met_', 'Vdd_') + #filtrar_puertos(biasing_centered, component, 'VSS_bottom_met_', 'Vss_') + filtrar_puertos(biasing_centered, component, 'V_BIASN1_', 'VBIASN1_') + filtrar_puertos(biasing_centered, component, 'V_BIASN2_', 'VBIASN2_') + filtrar_puertos(biasing_centered, component, 'V_BIASP1_', 'VBIASP1_') + filtrar_puertos(biasing_centered, component, 'top_ref_VbiasP2_bottom_met_', 'VBIASP2_') + + # add the pin and label + #pin_label_creation('Vss', 'VSS', 'met3', component) + pin_label_creation(pdk, 'VBIASN1', 'VbiasN1', 'met2', component) + pin_label_creation(pdk, 'VBIASN2', 'VbiasN2', 'met2', component) + pin_label_creation(pdk, 'VREF', 'Vref', 'met2', component) + #pin_label_creation(pdk, 'Vdd', 'VDD', 'met3', component) + pin_label_creation(pdk, 'VBIASP1', 'VbiasP1', 'met2', component) + pin_label_creation(pdk, 'VBIASP2', 'VbiasP2', 'met2', component) + + rename_ports_by_orientation(component) + + return component + +# Information of the transistors +array_m1_m15 = [[1,2]] +array_m13_m14 = [[1,2,1,2,1]] +array_m12_m18 = [[1,2]] +array_pmirrors = [[2,1,3]] +array_nmirrors_top = [[2,2,3,3,3,1,1,1,1,1,3,3,2,2,2]] +array_nmirrors_bot = [[2,3,2,3,1,1,1,1,3,2,3,2]] + + +devices_info_m1_m15 = {'type':'nfet', 'name':'M1', 'width':0.5, 'length':6, 'width_route_mult':1, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'lvt':False} +devices_info_m12_m18 = {'type':'pfet', 'name':'M12', 'width':0.5, 'length':2, 'width_route_mult':1, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'lvt':False} +devices_info_pmirrors = {'type':'pfet', 'name':'Pmirrors', 'width':0.5, 'length':2, 'width_route_mult':1, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'lvt':False} +devices_info_ntop = {'type':'nfet', 'name':'nmirror_top', 'width':0.5, 'length':6, 'width_route_mult':1, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'lvt':False} +devices_info_nbot = {'type':'nfet', 'name':'nmirror_bot', 'width':0.5, 'length':6, 'width_route_mult':1, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'lvt':False} +devices_info = [devices_info_m1_m15, devices_info_m12_m18, devices_info_pmirrors, devices_info_ntop, devices_info_nbot] +arrays_info = [array_m1_m15, array_m12_m18, array_pmirrors, array_m13_m14, array_nmirrors_top, array_nmirrors_bot] + +Test = Biasing_generator(gf180, devices_info, arrays_info, width_route=1) +Test.name = "folded_cascode_bias" +Test.write_gds("folded_cascode_bias_pcells.gds") +#ports = [name for name in Test.ports if 'V' in name] +#print(ports) +Test.show() \ No newline at end of file diff --git a/blocks/composite/folded_cascode/glayout/OTA_Building_blocks.py b/blocks/composite/folded_cascode/glayout/OTA_Building_blocks.py new file mode 100644 index 00000000..a70c50e3 --- /dev/null +++ b/blocks/composite/folded_cascode/glayout/OTA_Building_blocks.py @@ -0,0 +1,358 @@ +from glayout import MappedPDK, sky130, gf180 +from glayout import nmos, pmos, multiplier, tapring, via_stack, via_array + +from glayout.spice.netlist import Netlist +from glayout.routing import c_route, L_route, straight_route + +from gdsfactory.cell import cell +from gdsfactory.component import Component, copy +from gdsfactory.components.rectangle import rectangle +from gdsfactory.routing.route_quad import route_quad +from gdsfactory.routing.route_sharp import route_sharp + +from glayout.util.comp_utils import ( + align_comp_to_port, + evaluate_bbox, + movex, + movey, + prec_ref_center, + prec_array, +) +from glayout.util.port_utils import ( + add_ports_perimeter, + get_orientation, + print_ports, + rename_ports_by_list, + rename_ports_by_orientation, + set_port_orientation, +) +from glayout.util.snap_to_grid import component_snap_to_grid +from glayout.placement.common_centroid_ab_ba import common_centroid_ab_ba + +from gdsfactory.functions import transformed +from gdsfactory.components import text_freetype +from gdsfactory.components.rectangular_ring import rectangular_ring +from typing import Optional, Union, Literal +import time +import copy + +# Import custom functions (Matrix generator) +from primitives import (mirror, Cascode, current_source, transistor, diode, differential_pair, Bi_current_source, Pair_bias) +from custom_functions import filtrar_puertos, pin_label_creation, interdigitado_placement_Onchip, macro_two_transistor_placement_Onchip +from custom_functions import center_component_with_ports +from custom_functions import Boundary_layer + + +def place_cascode(pdk: MappedPDK) -> Component: + place_cascode = Component() + + # Use of second order primitive + # We define the parameters of our primitive + + m1 = {'type':'pfet', 'name':'M3_M4', 'width':1, 'length':1.5, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'width_route_mult':1, 'lvt':True} + m2 = {'type':'pfet', 'name':'M5_M6', 'width':1, 'length':3, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'width_route_mult':1, 'lvt':True} + + array = [[[2,1,2,1,1,2,1,2,1,2],[1,2,1,2,2,1,2,1,2,1]],[[1,2,2,1,1,2],[2,1,1,2,2,1]]] + + devices_info = [m1,m2] + + # We call the cascode primitive + Cascode_call = Cascode(pdk,devices_info,array) + + + Cascode_component = place_cascode << Cascode_call + + place_cascode.add_ports(Cascode_component.get_ports_list(),prefix='CASC_') + + #component = Component() + #component << place_cascode + + place_cascode_centered = center_component_with_ports(place_cascode) + component = Component() + component << place_cascode_centered + + filtrar_puertos(place_cascode_centered, component, 'CASC_VREF_', 'VREF_') + filtrar_puertos(place_cascode_centered, component, 'CASC_VIP_', 'VIP_') + filtrar_puertos(place_cascode_centered, component, 'CASC_VIN_', 'VIN_') + filtrar_puertos(place_cascode_centered, component, 'CASC_VB1_', 'VB1_') + filtrar_puertos(place_cascode_centered, component, 'CASC_VB2_', 'VB2_') + filtrar_puertos(place_cascode_centered, component, 'CASC_VD1_', 'VD1_') + filtrar_puertos(place_cascode_centered, component, 'CASC_VOUT_', 'VOUT_') + + return component + +def place_bi_current(pdk: MappedPDK) -> Component: + place_bi_current = Component() + + # Use of second order primitive + m1 = {'type':'nfet', 'name':'M9_M10', 'width':0.5, 'length':6.5, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'width_route_mult':1, 'lvt':False} + m2 = {'type':'nfet', 'name':'M7_M8', 'width':1, 'length':3, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'width_route_mult':1, 'lvt':False} + + array = [[[1,2,1,2,1],[2,1,2,1,2]],[[1,2,1,2,1],[2,1,2,1,2]]] + + devices_info = [m1,m2] + + # We call the Bi_current primitive + Bi_current_call = Bi_current_source(pdk,devices_info,array) + + Bi_current_component = place_bi_current << Bi_current_call + + place_bi_current.add_ports(Bi_current_component.get_ports_list(),prefix='BIC_') + + #component = Component() + #component << place_bi_current + + place_bi_current_centered = center_component_with_ports(place_bi_current) + component = Component() + component << place_bi_current_centered + + filtrar_puertos(place_bi_current_centered, component, 'BIC_VOUT_', 'VOUT_') + filtrar_puertos(place_bi_current_centered, component, 'BIC_VD1_', 'VD1_') + filtrar_puertos(place_bi_current_centered, component, 'BIC_VB2_', 'VB2_') + filtrar_puertos(place_bi_current_centered, component, 'BIC_VB2R_', 'VB2R_') + filtrar_puertos(place_bi_current_centered, component, 'BIC_VB3_', 'VB3_') + filtrar_puertos(place_bi_current_centered, component, 'BIC_VREF_', 'VREF_') + filtrar_puertos(place_bi_current_centered, component, 'BIC_VCOMM_', 'VCOMM_') + + return component + +def place_par_bias(pdk: MappedPDK) -> Component: + place_par_bias = Component() + + # Use of second order primitive + m1 = {'type':'nfet', 'name':'M1_M2', 'width':1, 'length':1, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'width_route_mult':1, 'lvt':False} + m2 = {'type':'nfet', 'name':'M11', 'width':0.5, 'length':6.5, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'width_route_mult':1, 'lvt':False} + + array = [[[1, 2, 1, 2, 1, 1, 2, 1, 2, 1], # Row 1: ABABA ABABA + [2, 1, 2, 1, 2, 2, 1, 2, 1, 2], # Row 2: BABAB BABAB + [2, 1, 2, 1, 2, 2, 1, 2, 1, 2], # Row 3: BABAB BABAB + [1, 2, 1, 2, 1, 1, 2, 1, 2, 1], # Row 4: ABABA ABABA + ] + ,[[1,1],[1,1],[1,1],[1,1],[1,1]]] # + + devices_info = [m1,m2] + + # We call the Bi_current primitive + Par_bias_call = Pair_bias(pdk,devices_info,array) + + Par_bias_component = place_par_bias << Par_bias_call + + place_par_bias.add_ports(Par_bias_component.get_ports_list(),prefix='PBI_') + + #routing bulks + pos_der = (place_par_bias.ports['PBI_P_VBC_D_N'].center[0]-place_par_bias.ports['PBI_P_VBC_D_W'].center[0])/2 + pos_iz = (place_par_bias.ports['PBI_P_VBC_D_N'].center[0]-place_par_bias.ports['PBI_P_VBC_D_E'].center[0])/2 + via_ref = via_array(pdk, 'met2', 'met3', (pos_der/2, 0.5)) + + bulk_par_1 = place_par_bias << via_ref + bulk_par_1.movex(pos_der).movey(place_par_bias.ports['PBI_P_VBC_D_E'].center[1]) + + bulk_par_2 = place_par_bias << via_ref + bulk_par_2.movex(pos_iz).movey(place_par_bias.ports['PBI_P_VBC_D_E'].center[1]) + + bulk_tail_1 = place_par_bias << via_ref + bulk_tail_1.movex(pos_der).movey(place_par_bias.ports['PBI_T_VBC_U_E'].center[1]) + + bulk_tail_2 = place_par_bias << via_ref + bulk_tail_2.movex(pos_iz).movey(place_par_bias.ports['PBI_T_VBC_U_E'].center[1]) + + place_par_bias << straight_route(pdk, bulk_par_1.ports['top_met_N'], bulk_tail_1.ports['top_met_S']) + place_par_bias << straight_route(pdk, bulk_par_2.ports['top_met_N'], bulk_tail_2.ports['top_met_S']) + + #component = Component() + #component << place_par_bias + + place_par_bias_centered = center_component_with_ports(place_par_bias) + component = Component() + component << place_par_bias_centered + + filtrar_puertos(place_par_bias_centered, component, 'PBI_VGP_', 'VGP_') + filtrar_puertos(place_par_bias_centered, component, 'PBI_VGN_', 'VGN_') + filtrar_puertos(place_par_bias_centered, component, 'PBI_VDP_', 'VDP_') + filtrar_puertos(place_par_bias_centered, component, 'PBI_VDN_', 'VDN_') + filtrar_puertos(place_par_bias_centered, component, 'PBI_VBIAS_', 'VBIAS_') + filtrar_puertos(place_par_bias_centered, component, 'PBI_VREF_', 'VREF_') + + return component, devices_info +''' +def nmos_bot(pdk: MappedPDK, + width_route: float = None)-> Component: + nmos_bot = Component() + m = {'type':'nfet', 'name':'M9_10_11', 'width':0.5, 'length':6.5, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'width_route_mult':1, 'lvt':False} + array = [[1,1,1,2,2,3,3,3,1,1,1,1,3,3,2,2,2,1,1,1]] + # Width configuration + if width_route == None or width_route == 0: + separation_interdigitado = 0 + width_horizontal = evaluate_bbox(via_stack(pdk,'met2','met3'))[1] + else: + separation_interdigitado = width_route + width_horizontal = width_route + nmos_ref = interdigitado_placement_Onchip(pdk, output='via', output_separation=separation_interdigitado, deviceA_and_B=m['type'], width=m['width'], length=m['length'], + fingers=m['fingers'], with_dummy=m['with_dummy'], array=array, with_tie=m['with_tie'], with_lvt_layer=m['lvt'], common_route=(False, True)) + nmos = nmos_bot << nmos_ref + #Common routes + nmos_bot << straight_route(pdk, nmos.ports['source_1_1_0_W'], nmos.ports['source_20_1_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + nmos_bot << straight_route(pdk, nmos.ports['drain_1_1_0_W'], nmos.ports['drain_20_1_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + + nmos_bot << straight_route(pdk, nmos.ports['drain_4_2_0_W'], nmos.ports['drain_17_2_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + + nmos_bot << straight_route(pdk, nmos.ports['drain_6_3_0_W'], nmos.ports['drain_14_3_0_E'], glayer1='met2', glayer2='met2', via1_alignment_layer='met3', width=width_horizontal) + + #Bulk routes + for i in range(len(array[0])): + if array[0][i] == 1: + nmos_bot << straight_route(pdk, nmos.ports['source_'+str(i+1)+'_1_0_N'], nmos.ports['bulk_down_S'], via2_alignment_layer='met2') + elif array[0][i] == 2: + nmos_bot << straight_route(pdk, nmos.ports['source_'+str(i+1)+'_2_0_N'], nmos.ports['bulk_down_S'], via2_alignment_layer='met2') + elif array[0][i] == 3: + nmos_bot << straight_route(pdk, nmos.ports['source_'+str(i+1)+'_3_0_N'], nmos.ports['bulk_down_S'], via2_alignment_layer='met2') + + return nmos_bot + +def currents_mirrors(pdk: MappedPDK, + width_route: float = None) -> Component: + + currents_mirrors = Component() + m7_8_data = {'type':'nfet', 'name':'M7_8', 'width':1, 'length':3, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'width_route_mult':1, 'lvt':False} + m5_m6_data = {'type':'pfet', 'name':'M5_6', 'width':1, 'length':1.5, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'width_route_mult':1, 'lvt':True} + m3_m4_data = {'type':'pfet', 'name':'M3_4', 'width':1, 'length':3, 'fingers':1, 'with_substrate_tap':False, 'with_tie':True, 'with_dummy':True, 'width_route_mult':1, 'lvt':True} + array_m7_8 = [[1,2,1,2,1],[2,1,2,1,2]] + array_m5_6 = [[1,2,1,2,1,2,1,2,1,2],[2,1,2,1,2,1,2,1,2,1]] + array_m3_4 = [[1,1,2,2,1,1],[2,2,1,1,2,2]] + + m7_8_ref = macro_two_transistor_placement_Onchip(pdk=pdk, deviceA_and_B=m7_8_data['type'], with_substrate_tap=m7_8_data['with_substrate_tap'], + with_tie=m7_8_data['with_tie'], width1=m7_8_data['width'], length1=m7_8_data['length'], + fingers1=m7_8_data['fingers'], matriz=array_m7_8, with_dummy=m7_8_data['with_dummy'], + width_route_mult=m7_8_data['width_route_mult'], with_lvt_layer=m7_8_data['lvt']) + m5_6_ref = macro_two_transistor_placement_Onchip(pdk=pdk, deviceA_and_B=m5_m6_data['type'], with_substrate_tap=m5_m6_data['with_substrate_tap'], + with_tie=m5_m6_data['with_tie'], width1=m5_m6_data['width'], length1=m5_m6_data['length'], + fingers1=m5_m6_data['fingers'], matriz=array_m5_6, with_dummy=m5_m6_data['with_dummy'], + width_route_mult=m5_m6_data['width_route_mult'], with_lvt_layer=m5_m6_data['lvt']) + m3_4_ref = macro_two_transistor_placement_Onchip(pdk=pdk, deviceA_and_B=m3_m4_data['type'], with_substrate_tap=m3_m4_data['with_substrate_tap'], + with_tie=m3_m4_data['with_tie'], width1=m3_m4_data['width'], length1=m3_m4_data['length'], + fingers1=m3_m4_data['fingers'], matriz=array_m3_4, with_dummy=m3_m4_data['with_dummy'], + width_route_mult=m3_m4_data['width_route_mult'], with_lvt_layer=m3_m4_data['lvt']) +''' +def OTA_Core(pdk: MappedPDK) -> Component: + OTA_core = Component() + + #nmos = nmos_bot(pdk) + BI1 = place_bi_current(pdk) + CAS1= place_cascode(pdk) + PB1, type_par = place_par_bias(pdk) + + #M9_10_11 = OTA << nmos + TOP_BI1 = OTA_core << BI1 + TOP_CAS1 = OTA_core << CAS1 + TOP_PB1 = OTA_core << PB1 + + size_BI1 = evaluate_bbox(TOP_BI1) + size_CAS1 = evaluate_bbox(TOP_CAS1) + size_PB1 = evaluate_bbox(TOP_PB1) + + max_size_y = pdk.snap_to_2xgrid((size_BI1[1] + size_CAS1[1])/2) + max_size_x = pdk.snap_to_2xgrid((size_BI1[0] + size_PB1[0])/2) + mov_par_tail = pdk.snap_to_2xgrid((size_PB1[1] - size_BI1[1])/2) + + if type_par[0]['type']=='nfet': + + TOP_CAS1.movey(max_size_y +pdk.get_grule('met4')['min_separation']) + TOP_PB1.movey(mov_par_tail) + TOP_PB1.movex(-(max_size_x+5*pdk.get_grule('met4')['min_separation'])) + + OTA_core.add_ports(TOP_BI1.get_ports_list(),prefix='BI_') + OTA_core.add_ports(TOP_CAS1.get_ports_list(),prefix='CAS_') + OTA_core.add_ports(TOP_PB1.get_ports_list(),prefix='PB_') + + #Routing + Route_VDS1 = OTA_core << L_route(pdk, TOP_BI1.ports['VD1_E'], TOP_CAS1.ports['VD1_S']) + Route_VDS2 = OTA_core << L_route(pdk, TOP_BI1.ports['VOUT_E'], TOP_CAS1.ports['VOUT_S']) + + Route_CN = OTA_core << L_route(pdk, TOP_PB1.ports['VDN_S'], TOP_CAS1.ports['VIN_W'], hwidth=1) + Route_CP = OTA_core << L_route(pdk, TOP_PB1.ports['VDP_S'], TOP_CAS1.ports['VIP_W'], hwidth=1) + Route_Bias = OTA_core << c_route(pdk, TOP_PB1.ports['VBIAS_S'],TOP_BI1.ports['VB2_S'], extension=2*pdk.get_grule('met4')['min_separation']) + Route_VSS = OTA_core << c_route(pdk, TOP_PB1.ports['VREF_S'], TOP_BI1.ports['VREF_S'], extension=3*pdk.get_grule('met4')['min_separation']) + + else: + TOP_PB1.mirror((1,0)) + TOP_CAS1.movey(max_size_y +pdk.get_grule('met4')['min_separation']) + TOP_PB1.movey((max_size_y +pdk.get_grule('met4')['min_separation'])-(pdk.snap_to_2xgrid((size_PB1[1] - size_CAS1[1])/2))) + TOP_PB1.movex(-(max_size_x+5*pdk.get_grule('met4')['min_separation'])) + + OTA_core.add_ports(TOP_BI1.get_ports_list(),prefix='BI_') + OTA_core.add_ports(TOP_CAS1.get_ports_list(),prefix='CAS_') + OTA_core.add_ports(TOP_PB1.get_ports_list(),prefix='PB_') + + #Routing + Route_VDS1 = OTA_core << L_route(pdk, TOP_BI1.ports['VD1_E'], TOP_CAS1.ports['VD1_S']) + Route_VDS2 = OTA_core << L_route(pdk, TOP_BI1.ports['VOUT_E'], TOP_CAS1.ports['VOUT_S']) + + Route_D1Par_D1M9 = OTA_core << L_route(pdk, TOP_PB1.ports['VDN_S'], TOP_BI1.ports['VD1_E'], hwidth=1) + Route_D2Par_D2M10 = OTA_core << L_route(pdk, TOP_PB1.ports['VDP_S'], TOP_BI1.ports['VOUT_E'], hwidth=1) + #Route_Bias = OTA_core << c_route(pdk, TOP_PB1.ports['VBIAS_S'],TOP_BI1.ports['VB2_S'], extension=2*pdk.get_grule('met4')['min_separation']) + Route_VDD = OTA_core << c_route(pdk, TOP_PB1.ports['VREF_S'], TOP_CAS1.ports['VREF_S'], extension=3*pdk.get_grule('met4')['min_separation']) + + + + #Add via for output + via_ref = via_stack(pdk,'met3', 'met4') + + VSS_out = OTA_core << via_ref + align_comp_to_port(VSS_out, OTA_core.ports['BI_VREF_W']) + VSS_out.movex(pdk.get_grule('met4')['min_separation'] + evaluate_bbox(TOP_BI1)[0]/2) + OTA_core << straight_route(pdk, VSS_out.ports['top_met_E'], TOP_BI1.ports['VREF_W'], glayer1='met4', glayer2='met4', via1_alignment_layer='met3') + OTA_core.add_ports(VSS_out.get_ports_list(), prefix='VSS_') + + VDD_out = OTA_core << via_ref + align_comp_to_port(VDD_out, OTA_core.ports['CAS_VREF_W']) + VDD_out.movex(pdk.get_grule('met4')['min_separation'] + evaluate_bbox(TOP_CAS1)[0]/2) + OTA_core << straight_route(pdk, VDD_out.ports['top_met_E'], TOP_CAS1.ports['VREF_W'], glayer1='met4', glayer2='met4', via1_alignment_layer='met3') + OTA_core.add_ports(VDD_out.get_ports_list(), prefix='VDD_') + + + #component = Component() + #component << OTA_core + + #Guardar ports + component = Component() + component << OTA_core + + OTA_core_centered = center_component_with_ports(OTA_core) + component = Component() + component << OTA_core_centered + + boundary = Boundary_layer(pdk, component) + boundary_dim = evaluate_bbox(boundary) + + filtrar_puertos(OTA_core_centered, component, 'PB_VGP_', 'P_V+_', True) + filtrar_puertos(OTA_core_centered, component, 'PB_VGN_', 'P_V-_', True) + filtrar_puertos(OTA_core_centered, component, 'BI_VB2R_', 'P_VbiasN1_', True) # + filtrar_puertos(OTA_core_centered, component, 'VDD_top_met_', 'P_VDD_', True) + filtrar_puertos(OTA_core_centered, component, 'CAS_VOUT_', 'P_Vout_', True) + filtrar_puertos(OTA_core_centered, component, 'CAS_VB2_', 'P_VbiasP1_', True) # + filtrar_puertos(OTA_core_centered, component, 'CAS_VB1_', 'P_VbiasP2_', True) # + filtrar_puertos(OTA_core_centered, component, 'BI_VB3_', 'P_VbiasN2_', True) # + filtrar_puertos(OTA_core_centered, component, 'VSS_top_met_', 'P_VSS_', True) + filtrar_puertos(OTA_core_centered, component, 'BI_VCOMM_', 'P_Vcomn_', True) + + pin_label_creation(pdk, 'P_V+','V+','met3',component, True) + pin_label_creation(pdk, 'P_V-','V-','met3',component, True) + pin_label_creation(pdk, 'P_VbiasN1','VbiasN1','met3',component, True) + pin_label_creation(pdk, 'P_VDD','VDD','met3',component, True) + pin_label_creation(pdk, 'P_Vout','Vout','met3',component, True) + pin_label_creation(pdk, 'P_VbiasP1','VbiasP1','met3',component, True) + pin_label_creation(pdk, 'P_VbiasP2','VbiasP2','met3',component, True) + pin_label_creation(pdk, 'P_VbiasN2','VbiasN2','met3',component, True) + pin_label_creation(pdk, 'P_VSS','VSS','met3',component, True) + pin_label_creation(pdk, 'P_Vcomn', 'Vcomn', 'met3',component, True) + + rename_ports_by_orientation(component) + + return component + +Test = OTA_Core(gf180) +#Test.name = "folded_cascode_core" +#Test.write_gds("folded_cascode_core_pcells.gds") +Test.show() +ports_name = [name for name in Test.ports if '_' in name] +print(ports_name) diff --git a/blocks/composite/folded_cascode/glayout/custom_functions.py b/blocks/composite/folded_cascode/glayout/custom_functions.py new file mode 100644 index 00000000..5bf3c41a --- /dev/null +++ b/blocks/composite/folded_cascode/glayout/custom_functions.py @@ -0,0 +1,3343 @@ +from glayout import MappedPDK, sky130, gf180 +from glayout import nmos, pmos, multiplier, tapring, via_stack, via_array + +from glayout.spice.netlist import Netlist +from glayout.routing import c_route, L_route, straight_route + +from gdsfactory.cell import cell +from gdsfactory.component import Component, copy +from gdsfactory.components.rectangle import rectangle +from gdsfactory.routing.route_quad import route_quad +from gdsfactory.routing.route_sharp import route_sharp + +from glayout.util.comp_utils import ( + align_comp_to_port, + evaluate_bbox, + movex, + movey, + prec_ref_center, + prec_array, +) +from glayout.util.port_utils import ( + add_ports_perimeter, + get_orientation, + print_ports, + rename_ports_by_list, + rename_ports_by_orientation, + set_port_orientation, +) +from glayout.util.snap_to_grid import component_snap_to_grid +from glayout.placement.common_centroid_ab_ba import common_centroid_ab_ba + +from gdsfactory.functions import transformed +from gdsfactory.components import text_freetype +from gdsfactory.components.rectangular_ring import rectangular_ring +from typing import Optional, Union, Literal +import time +import copy + + +def macro_two_transistor_placement_Onchip( + pdk: MappedPDK, + deviceA_and_B: Literal["nfet", "pfet"], + width_route_mult: float = 1, + with_substrate_tap: bool = False, + with_tie: bool = True, + width1: float = 1, + length1: float = 2, + fingers1: int = 1, + matriz: list = [[1, 2, 1], [2, 1, 2]], + with_dummy: bool = False, + with_lvt_layer: bool = True, + full_output_size: bool = False, + **kwargs, +) -> Component: + # This code was made by Sebastian Suarez y Jose Algarin, UIS Electronic engineering students + """Two transistors Placement generator + args: + pdk = pdk to use + deviceA_and_B = the device to place for both transistors (either nfet or pfet) + width_route_mult = thickness of metal routes escaled (int only) + with_substrate_tap = add substrate tap + with_tie = Add Bulk connections + width1 = expands the transistor A in the y direction + width2 = expands the transistor B in the y direction + length1 = transitor A length + length2 = transitor B length + fingers1 = introduces additional fingers to transistor A (sharing s/d) of width=width1 + fingers2 = introduces additional fingers to transistor B (sharing s/d) of width=width2 + matriz = Devices array for placement + with_dummy = Add dummys around placement + with_lvt_layer = add lvt layer + + ports (one port for each edge), + ****NOTE: source is below drain: + A_source_... all edges (met3 vertical met4 horizontal) + B_source_... all edges (met3 vertical met4 horizontal) + A_gate_... all edges (met3 vertical met4 horizontal) + B_gate_... all edges (met3 vertical met4 horizontal) + A_drain_... all edges (met3 vertical met4 horizontal) + B_drain_... all edges (met3 vertical met4 horizontal) + bulk_... all edges (met3 vertical met4 horizontal) + """ + pdk_gf180 = False + pdk_sky130 = True + if pdk is gf180: + pdk_gf180 = True + pdk_sky130 = False + elif pdk is sky130: + pdk_gf180 = False + pdk_sky130 = True + + if width_route_mult > 5 or width_route_mult < 0: + raise ValueError("width_route is out of range") + + matplace = Component() + matriz = copy.deepcopy(matriz) + enable_B = False + for fila in matriz: + for transistor in fila: + if transistor == 2: + enable_B = True + break + # Add dummys to array (matriz) + if with_dummy: + len_matriz_with_dumys = len(matriz[0]) + 2 + for row in matriz: + row.insert(0, 0) + row.append(0) + matriz.insert(0, [0] * len_matriz_with_dumys) + matriz.insert(len(matriz), [0] * len_matriz_with_dumys) + # Check if rows are are odd or even + if (len(matriz)) % 2 == 0: + middle_transistor = len(matriz) // 2 + even = True + else: + even = False + matrizT = [list(fila) for fila in zip(*matriz)] + # Overwrite kwargs for needed options + kwargs["sdlayer"] = "n+s/d" if deviceA_and_B == "nfet" else "p+s/d" + kwargs["pdk"] = pdk + kwargs["dummy"] = (False, False) + # Insert modifications for dummies + kwargs["routing"] = False + kwargs["gate_route_extension"] = pdk.snap_to_2xgrid(0) + if with_dummy: + dummy_single_down = multiplier( + width=width1, length=length1, fingers=1, gate_down=True, **kwargs + ) + dummy_single_up = multiplier( + width=width1, length=length1, fingers=1, gate_up=True, **kwargs + ) + devDT = multiplier( + width=width1, length=length1, fingers=fingers1, gate_up=True, **kwargs + ) + devDB = multiplier( + width=width1, length=length1, fingers=fingers1, gate_down=True, **kwargs + ) + # Insert modifications for device A + kwargs["routing"] = True + devA_gate_extension = ( + abs(pdk.get_grule("met2")["min_separation"] + devDT.ports["gate_W"].width) + if with_dummy + else abs(pdk.get_grule("met2")["min_separation"]) + ) + devA_sd_extension = abs(pdk.get_grule("met2")["min_separation"]) + kwargs["gate_route_extension"] = pdk.snap_to_2xgrid(devA_gate_extension) + kwargs["sd_route_extension"] = pdk.snap_to_2xgrid(devA_sd_extension) + devA = multiplier( + width=width1, length=length1, fingers=fingers1, rmult=width_route_mult, **kwargs + ) + # Insert kwarg modfications for device B + devB_sd_extension = abs( + devA.ports["drain_N"].center[1] - devA.ports["diff_N"].center[1] + ) + devB_gate_extension = ( + abs(2 * (pdk.get_grule("met2")["min_separation"] + devA.ports["gate_W"].width)) + if with_dummy + else abs( + 2 * pdk.get_grule("met2")["min_separation"] + devA.ports["gate_W"].width + ) + ) + kwargs["sd_route_extension"] = pdk.snap_to_2xgrid(devB_sd_extension) + kwargs["gate_route_extension"] = pdk.snap_to_2xgrid(devB_gate_extension) + devB = multiplier( + width=width1, length=length1, fingers=fingers1, rmult=width_route_mult, **kwargs + ) + # Create the array of transistors + transistors = list() + for i in range(len(matriz)): + transistors_in_row = list() + for j in range(len(matriz[i])): + if i == 0 or i == len(matriz) - 1: # first and last row + if j == 0 or j == len(matriz[i]) - 1: # first and last column + # corner transistors + if matriz[i][j] == 0 and i == 0: + # small dummy + transistors_in_row.append(matplace << dummy_single_down) + elif matriz[i][j] == 0 and i == len(matriz) - 1: + # small dummy + transistors_in_row.append(matplace << dummy_single_up) + else: + if matriz[i][j] == 1: + transistors_in_row.append(matplace << devA) + elif matriz[i][j] == 2: + transistors_in_row.append(matplace << devB) + elif i == 0: # first row + # first row transistors + if matriz[i][j] == 0: + # dummy + transistors_in_row.append(matplace << devDB) + else: + if matriz[i][j] == 1: + transistors_in_row.append(matplace << devA) + elif matriz[i][j] == 2: + transistors_in_row.append(matplace << devB) + else: # last row + # last row transistors + if matriz[i][j] == 0: + # dummy + transistors_in_row.append(matplace << devDT) + else: + if matriz[i][j] == 1: + transistors_in_row.append(matplace << devA) + elif matriz[i][j] == 2: + transistors_in_row.append(matplace << devB) + else: # middle rows + if matriz[i][j] == 0: + # small dummy + transistors_in_row.append(matplace << dummy_single_down) + else: + if matriz[i][j] == 1: + transistors_in_row.append(matplace << devA) + elif matriz[i][j] == 2: + transistors_in_row.append(matplace << devB) + + # Add the transistors in the row + transistors.append(transistors_in_row) + # min separation + min_separation_x = pdk.snap_to_2xgrid(pdk.get_grule("p+s/d")["min_separation"]) + if pdk == sky130: + min_separation = pdk.get_grule("poly")["min_separation"] + elif pdk == gf180: + min_separation = pdk.get_grule("met2")["min_separation"] + for i in range(len(transistors)): + # Move the transistors in y direction + if i == 0: + # first row dont move + ymove = 0 + else: # find max y size in the row + distance_center2bottom_ref = transistors[i][0].bbox[0][1] # Temporal + distance_center2top_pre_ref = ( + transistors[i - 1][0].bbox[1][1] - ymove + ) # Temporal // Minus the ymove because this one was already moved + for k in range(len(transistors[i])): + distance_center2bottom_temp = transistors[i][k].bbox[0][ + 1 + ] # distance center to bottom of the transistor that will be moved + distance_center2top_pre_temp = ( + transistors[i - 1][k].bbox[1][1] - ymove + ) # distance center to top of the transistor above the one that will be moved + if ( + distance_center2bottom_temp < distance_center2bottom_ref + ): # minus because the distance is negative + distance_center2bottom_ref = distance_center2bottom_temp + if distance_center2top_pre_temp > distance_center2top_pre_ref: + distance_center2top_pre_ref = distance_center2top_pre_temp + + ymove_temp = ( + abs(distance_center2bottom_ref) + + abs(distance_center2top_pre_ref) + + min_separation + ) + ymove += ymove_temp + if even and i == middle_transistor: + # If even need more space in the middle row for the output + extra_space = pdk.snap_to_2xgrid( + evaluate_bbox(via_stack(pdk, "met2", "met3"))[1] + + 2 * pdk.get_grule("met2")["min_separation"] + ) + ymove += extra_space + for j in range(len(transistors[i])): + size_transistor = evaluate_bbox(transistors[i][j]) + # Move the transistors in x direction + if j == 0: + # first transistor dont move + xmove = 0 + else: + pre_last_size = evaluate_bbox(transistors[i][j - 1]) + # rest of transistors + xmove += (size_transistor[0] + pre_last_size[0]) / 2 + min_separation_x + transistors[i][j].movex(pdk.snap_to_2xgrid(xmove)) + transistors[i][j].movey(pdk.snap_to_2xgrid(ymove)) + if matriz[i][j] == 0: + devletter = "D" + elif matriz[i][j] == 1: + devletter = "A" + elif matriz[i][j] == 2: + devletter = "B" + + prefix = devletter + "i" + str(int(i)) + "_j" + str(int(j)) + "" + matplace.add_ports(transistors[i][j].get_ports_list(), prefix=prefix) + + matplace = rename_ports_by_orientation(matplace) + + # Define dictionaries to organize ports by type and orientation + ports_A = { + "source_W": [], + "source_E": [], + "drain_W": [], + "drain_E": [], + "gate_W": [], + "gate_E": [], + } + ports_B = { + "source_W": [], + "source_E": [], + "drain_W": [], + "drain_E": [], + "gate_W": [], + "gate_E": [], + } + ports_D = { + "source_W": [], + "source_E": [], + "drain_W": [], + "drain_E": [], + "gate_W": [], + "gate_E": [], + } + + # List of device types and ports to be searched + busqueda = [ + ("A", "source"), + ("A", "drain"), + ("A", "gate"), + ("B", "source"), + ("B", "drain"), + ("B", "gate"), + ("D", "source"), + ("D", "drain"), + ("D", "gate"), + ] + # Cycle through every combination of device and port + for dispositivo, puerto in busqueda: + for i in range(len(matriz)): # Iterate over the matrix rows + # Get all ports in row i with W and E orientation + encontrados_W = [ + name + for name in matplace.ports + if f"{dispositivo}i{i}" in name + and f"{puerto}_W" in name + and "row" not in name + ] + encontrados_E = [ + name + for name in matplace.ports + if f"{dispositivo}i{i}" in name + and f"{puerto}_E" in name + and "row" not in name + ] + # Assign the corresponding row only if there are found elements + if dispositivo == "A": + if encontrados_W: + ports_A[f"{puerto}_W"].append(encontrados_W) + if encontrados_E: + ports_A[f"{puerto}_E"].append(encontrados_E) + elif dispositivo == "B": + if encontrados_W: + ports_B[f"{puerto}_W"].append(encontrados_W) + if encontrados_E: + ports_B[f"{puerto}_E"].append(encontrados_E) + elif dispositivo == "D": + if encontrados_W: + ports_D[f"{puerto}_W"].append(encontrados_W) + if encontrados_E: + ports_D[f"{puerto}_E"].append(encontrados_E) + + # Component centering + matplace_centered = Component() + matplace_ref = matplace_centered << transformed(prec_ref_center(matplace)) + matplace_centered.add_ports(matplace_ref.get_ports_list()) + dims = evaluate_bbox(matplace_centered) + xmove = pdk.snap_to_2xgrid(dims[0] / 2) + if pdk == sky130: + min_separation = pdk.snap_to_2xgrid( + ( + pdk.get_grule("met3")["min_separation"] + + pdk.get_grule("met3")["min_width"] + + pdk.get_grule("via3")["min_separation"] + + pdk.get_grule("via3")["min_width"] + ) + ) + elif pdk == gf180: + min_separation = pdk.snap_to_2xgrid( + ( + pdk.get_grule("met3")["min_separation"] + + pdk.get_grule("met3")["min_width"] + + pdk.get_grule("via3")["min_separation"] + + evaluate_bbox(via_stack(pdk, "met2", "met3"))[1] + ) + ) + + # Rings + # Define configurations according to transistor type + device_config = { + "nfet": { + "sdlayer": "p+s/d", + "well_layer": "pwell", + "tap_enclosure_rule": "p+s/d", + }, + "pfet": { + "sdlayer": "n+s/d", + "well_layer": "nwell", + "tap_enclosure_rule": "n+s/d", + "substrate_tap_layer": "p+s/d", + }, + } + + # Obtaining the correct configuration + config = device_config.get(deviceA_and_B) + # Add tie if necessary + if with_tie: + tie_layers = ["met2", "met1"] + + tap_separation = max( + pdk.get_grule("met2")["min_separation"], + pdk.get_grule("met1")["min_separation"], + pdk.get_grule("active_diff", "active_tap")["min_separation"], + ) + tap_separation += pdk.get_grule(config["tap_enclosure_rule"], "active_tap")[ + "min_enclosure" + ] + + tap_encloses = ( + 2 * (tap_separation + matplace_centered.xmax), + 2 * (tap_separation + matplace_centered.ymax), + ) + tapring_ref = matplace_centered << create_tapring_onchip( + pdk, + enclosed_rectangle=tap_encloses, + sdlayer=config["sdlayer"], + horizontal_glayer=tie_layers[0], + vertical_glayer=tie_layers[1], + with_lvt_layer=with_lvt_layer, + ) + matplace_centered.add_ports(tapring_ref.get_ports_list(), prefix="tie_") + if with_dummy: + first_mos_ds = matplace_centered.ports[ + "Di0_j0leftsd_met_array_row0_col0_top_met_W" + ] + first_mos_gate = matplace_centered.ports["Di0_j0gate_W"] + first_mos_ds_R = matplace_centered.ports[ + "Di0_j" + + str(len(matrizT) - 1) + + "row0_col" + + str(fingers1 - 1) + + "_rightsd_met_array_row0_col0_top_met_E" + ] + first_mos_gate_R = matplace_centered.ports[ + "Di0_j" + str(len(matrizT) - 1) + "gate_E" + ] + last_mos_ds = matplace_centered.ports[ + "Di" + str(len(matriz) - 1) + "_j0leftsd_met_array_row0_col0_top_met_W" + ] + last_mos_gate = matplace_centered.ports[ + "Di" + str(len(matriz) - 1) + "_j0gate_W" + ] + last_mos_ds_R = matplace_centered.ports[ + "Di" + + str(len(matriz) - 1) + + "_j" + + str(len(matrizT) - 1) + + "row0_col" + + str(fingers1 - 1) + + "_rightsd_met_array_row0_col0_top_met_E" + ] + last_mos_gate_R = matplace_centered.ports[ + "Di" + str(len(matriz) - 1) + "_j" + str(len(matrizT) - 1) + "gate_E" + ] + tie_left_W = matplace_centered.ports["tie_W_array_row0_col0_top_met_W"] + tie_right = matplace_centered.ports["tie_E_array_row0_col0_top_met_E"] + width_route_dummy = 1 if width1 >= 1 else width1 + for i in range(len(matriz)): + if i == 0: + # First Dummys + matplace_centered << straight_route( + pdk, first_mos_ds_R, tie_left_W, width=width_route_dummy + ) + matplace_centered << straight_route( + pdk, first_mos_ds, tie_right, width=width_route_dummy + ) + matplace_centered << straight_route( + pdk, first_mos_gate_R, tie_left_W + ) + matplace_centered << straight_route(pdk, first_mos_gate, tie_right) + elif i == len(matriz) - 1: + # Last Dummys + matplace_centered << straight_route( + pdk, last_mos_ds_R, tie_left_W, width=width_route_dummy + ) + matplace_centered << straight_route( + pdk, last_mos_ds, tie_right, width=width_route_dummy + ) + matplace_centered << straight_route( + pdk, last_mos_gate_R, tie_left_W + ) + matplace_centered << straight_route(pdk, last_mos_gate, tie_right) + else: + matplace_centered << straight_route( + pdk, + matplace_centered.ports[ + "Di" + + str(i) + + "_j0row0_col" + + str(fingers1 - 1) + + "_rightsd_met_array_row0_col0_top_met_E" + ], + tie_left_W, + width=width_route_dummy, + ) + matplace_centered << straight_route( + pdk, + matplace_centered.ports[ + "Di" + + str(i) + + "_j" + + str(len(matriz[0]) - 1) + + "leftsd_met_array_row0_col0_top_met_W" + ], + tie_right, + width=width_route_dummy, + ) + matplace_centered << straight_route( + pdk, + matplace_centered.ports["Di" + str(i) + "_j0gate_E"], + tie_left_W, + ) + matplace_centered << straight_route( + pdk, + matplace_centered.ports[ + "Di" + str(i) + "_j" + str(len(matriz[0]) - 1) + "gate_W" + ], + tie_right, + ) + + # Add well + matplace_centered.add_padding( + layers=(pdk.get_glayer(config["well_layer"]),), + default=pdk.get_grule(config["well_layer"], "active_tap")["min_enclosure"], + ) + + # Adding taps on the perimeter + matplace_centered = add_ports_perimeter( + matplace_centered, layer=pdk.get_glayer(config["well_layer"]), prefix="well_" + ) + dims_post_tie = evaluate_bbox(matplace_centered) + + # Add substrate tap if necessary + if deviceA_and_B == "pfet": + if with_substrate_tap: + substrate_tap_separation = pdk.get_grule("dnwell", "active_tap")[ + "min_separation" + ] + substrate_tap_encloses = ( + 2 * (substrate_tap_separation + matplace_centered.xmax), + 2 * (substrate_tap_separation + matplace_centered.ymax), + ) + ringtoadd = create_tapring_onchip( + pdk, + enclosed_rectangle=substrate_tap_encloses, + sdlayer=config["substrate_tap_layer"], + horizontal_glayer="met2", + vertical_glayer="met1", + with_lvt_layer=False, + ) + tapring_ref = matplace_centered << ringtoadd + matplace_centered.add_ports( + tapring_ref.get_ports_list(), prefix="substratetap_" + ) + + # Creation of ports and lanes for column routing + via = via_stack(pdk, "met1", "met2") + dims = evaluate_bbox(matplace_centered) + xmove = pdk.snap_to_2xgrid(dims[0] / 2) + min_separation = pdk.snap_to_2xgrid( + matplace_centered.ports[ports_A["drain_W"][0][0]].width + + pdk.get_grule("met3")["min_separation"] + ) + if enable_B: + name_vias = [ + ["A_drain_L", -1 * min_separation - xmove], + ["A_drain_R", 1 * min_separation + xmove], + ["A_source_L", -2 * min_separation - xmove], + ["A_source_R", 2 * min_separation + xmove], + ["A_gate_L", -6 * min_separation - xmove], + ["A_gate_R", 3 * min_separation + xmove], + ["B_drain_L", -4 * min_separation - xmove], + ["B_drain_R", 4 * min_separation + xmove], + ["B_source_L", -5 * min_separation - xmove], + ["B_source_R", 5 * min_separation + xmove], + ["B_gate_L", -3 * min_separation - xmove], + ["B_gate_R", 6 * min_separation + xmove], + ] + else: + name_vias = [ + ["A_drain_L", -1 * min_separation - xmove], + ["A_drain_R", 1 * min_separation + xmove], + ["A_source_L", -2 * min_separation - xmove], + ["A_source_R", 2 * min_separation + xmove], + ["A_gate_L", -3 * min_separation - xmove], + ["A_gate_R", 3 * min_separation + xmove], + ] + + via_met12 = list() + via_met23 = list() + # check if center up and center down transistor are different size + center_transistor = (len(matriz) // 2, len(matriz) // 2 - 1) + up_transistors = matriz[center_transistor[0]] + down_transistors = matriz[center_transistor[1]] + no_dummys_up = [x for x in up_transistors if x != 0] + no_dummys_down = [x for x in down_transistors if x != 0] + + if all(x == 1 for x in no_dummys_down) and all(x == 2 for x in no_dummys_up): + not_middle = True + elif all(x == 2 for x in no_dummys_down) and all(x == 1 for x in no_dummys_up): + not_middle = True + else: + not_middle = False + + if even and not_middle: + ypos = ( + devA.ports["source_W"].width * 2 + pdk.get_grule("met2")["min_separation"] + ) + elif even and not_middle == False: + ypos = 0 + else: + center_transistor = len(matriz) // 2 + if with_dummy: + ypos = ( + matplace_centered.ports[ + "Di" + str(center_transistor) + "_j0gate_S" + ].center[1] + + evaluate_bbox(dummy_single_down)[1] / 2 + + 1 * pdk.get_grule("met2")["min_separation"] + ) + else: + if matriz[center_transistor][0] == 1: + devletter_center = "A" + ypos = ( + evaluate_bbox(devA)[1] / 2 + + 1 * pdk.get_grule("met2")["min_separation"] + ) + elif matriz[center_transistor][0] == 2: + devletter_center = "B" + ypos = ( + evaluate_bbox(devB)[1] / 2 + + 3 * pdk.get_grule("met2")["min_separation"] + ) + ypos += matplace_centered.ports[ + str(devletter_center) + "i" + str(center_transistor) + "_j0gate_S" + ].center[1] + + for via, pos in name_vias: + via_met12.append( + matplace_centered << via_stack(pdk, "met1", "met2", centered=True) + ) + via_met12[-1].movex(pos) + via_met12[-1].movey(ypos) + matplace_centered.add_ports(via_met12[-1].get_ports_list(), prefix=via + "_12_") + via_met23.append( + matplace_centered << via_stack(pdk, "met2", "met3", centered=True) + ) + via_met23[-1].movex(pos) + via_met23[-1].movey(ypos) + matplace_centered.add_ports(via_met23[-1].get_ports_list(), prefix=via + "_23_") + widht_route_vertical = matplace_centered.ports[ports_A["drain_W"][0][0]].width + + for i in range(len(ports_A["drain_E"])): + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_A["drain_W"][i][0]], + matplace_centered.ports["A_drain_L_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_A["drain_E"][i][0]], + matplace_centered.ports["A_drain_R_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_A["source_W"][i][0]], + matplace_centered.ports["A_source_L_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_A["source_E"][i][0]], + matplace_centered.ports["A_source_R_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_A["gate_W"][i][0]], + matplace_centered.ports["A_gate_L_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_A["gate_E"][i][0]], + matplace_centered.ports["A_gate_R_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + for i in range(len(ports_B["drain_E"])): + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_B["drain_W"][i][0]], + matplace_centered.ports["B_drain_L_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_B["drain_E"][i][0]], + matplace_centered.ports["B_drain_R_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_B["source_W"][i][0]], + matplace_centered.ports["B_source_L_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_B["source_E"][i][0]], + matplace_centered.ports["B_source_R_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_B["gate_W"][i][0]], + matplace_centered.ports["B_gate_L_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + matplace_centered << L_route( + pdk, + matplace_centered.ports[ports_B["gate_E"][i][0]], + matplace_centered.ports["B_gate_R_12_bottom_met_N"], + hwidth=widht_route_vertical, + ) + + dims = evaluate_bbox(matplace_centered) + size_out_ports = evaluate_bbox(via_stack(pdk, "met3", "met4")) + min_separation = pdk.snap_to_2xgrid(pdk.get_grule("met4")["min_separation"]) + + # Gate port + gateA = matplace_centered << via_stack(pdk, "met3", "met4") + gateA_bot = matplace_centered << via_stack(pdk, "met2", "met3") + gateA.movex(pdk.snap_to_2xgrid(-dims[0] / 2 - min_separation)) + gateA_bot.movex(pdk.snap_to_2xgrid(-dims[0] / 2 - min_separation)) + gateA.movey(ypos) + gateA_bot.movey(ypos) + matplace_centered.add_ports(gateA_bot.get_ports_list(), prefix="A_gate_bot_") + matplace_centered.add_ports(gateA.get_ports_list(), prefix="A_gate_") + if enable_B: + gateB = matplace_centered << via_stack(pdk, "met3", "met4") + gateB_bot = matplace_centered << via_stack(pdk, "met2", "met3") + gateB.movex(pdk.snap_to_2xgrid(dims[0] / 2 + min_separation)) + gateB_bot.movex(pdk.snap_to_2xgrid(dims[0] / 2 + min_separation)) + gateB.movey(ypos) + gateB_bot.movey(ypos) + matplace_centered.add_ports(gateB_bot.get_ports_list(), prefix="B_gate_bot_") + matplace_centered.add_ports(gateB.get_ports_list(), prefix="B_gate_") + + # Source port + sourceA = matplace_centered << via_stack(pdk, "met3", "met4") + sourceA.movey(pdk.snap_to_2xgrid(-dims[1] / 2 - size_out_ports[0] / 2)).movex( + pdk.snap_to_2xgrid(-min_separation - size_out_ports[0] / 2) + ) + matplace_centered.add_ports(sourceA.get_ports_list(), prefix="A_source_") + if enable_B: + sourceB = matplace_centered << via_stack(pdk, "met3", "met4") + sourceB.movey( + pdk.snap_to_2xgrid(-dims[1] / 2 - 1.5 * size_out_ports[0] - min_separation) + ).movex(pdk.snap_to_2xgrid(min_separation + size_out_ports[0] / 2)) + matplace_centered.add_ports(sourceB.get_ports_list(), prefix="B_source_") + + # Drain port + drainA = matplace_centered << via_stack(pdk, "met3", "met4") + if with_substrate_tap and deviceA_and_B == "pfet": + drainA.movey(pdk.snap_to_2xgrid(dims[1] / 2 + size_out_ports[0] / 2)).movex( + pdk.snap_to_2xgrid(-min_separation - size_out_ports[0] / 2) + ) + elif with_substrate_tap == False or deviceA_and_B == "nfet": + drainA.movey( + pdk.snap_to_2xgrid( + dims[1] / 2 + + size_out_ports[0] / 2 + + pdk.get_grule("met5")["min_separation"] + + pdk.get_grule("active_tap", "mcon")["min_enclosure"] + ) + ).movex(pdk.snap_to_2xgrid(-min_separation - size_out_ports[0] / 2)) + matplace_centered.add_ports(drainA.get_ports_list(), prefix="A_drain_") + if enable_B: + drainB = matplace_centered << via_stack(pdk, "met3", "met4") + if with_substrate_tap and deviceA_and_B == "pfet": + drainB.movey( + pdk.snap_to_2xgrid( + dims[1] / 2 + 1.5 * size_out_ports[0] + min_separation + ) + ).movex(pdk.snap_to_2xgrid(min_separation + size_out_ports[0] / 2)) + elif with_substrate_tap == False or deviceA_and_B == "nfet": + drainB.movey( + pdk.snap_to_2xgrid( + dims[1] / 2 + + 1.5 * size_out_ports[0] + + min_separation + + pdk.get_grule("met5")["min_separation"] + + pdk.get_grule("active_tap", "mcon")["min_enclosure"] + ) + ).movex(pdk.snap_to_2xgrid(min_separation + size_out_ports[0] / 2)) + matplace_centered.add_ports(drainB.get_ports_list(), prefix="B_drain_") + + matplace_centered = rename_ports_by_orientation(matplace_centered) + # Gates routes + matplace_centered << straight_route( + pdk, + matplace_centered.ports["A_gate_L_23_bottom_met_W"], + matplace_centered.ports["A_gate_bot_bottom_met_E"], + ) + if enable_B: + matplace_centered << straight_route( + pdk, + matplace_centered.ports["B_gate_R_23_bottom_met_E"], + matplace_centered.ports["B_gate_bot_bottom_met_W"], + ) + # Source routes + L1 = matplace_centered << L_route( + pdk, + matplace_centered.ports["A_source_L_23_top_met_S"], + matplace_centered.ports["A_source_top_met_W"], + hwidth=widht_route_vertical, + ) + L2 = matplace_centered << L_route( + pdk, + matplace_centered.ports["A_source_R_23_top_met_S"], + matplace_centered.ports["A_source_top_met_E"], + hwidth=widht_route_vertical, + ) + if enable_B: + L3 = matplace_centered << L_route( + pdk, + matplace_centered.ports["B_source_L_23_top_met_S"], + matplace_centered.ports["B_source_top_met_W"], + hwidth=widht_route_vertical, + ) + L4 = matplace_centered << L_route( + pdk, + matplace_centered.ports["B_source_R_23_top_met_S"], + matplace_centered.ports["B_source_top_met_E"], + hwidth=widht_route_vertical, + ) + # Drain routes + L5 = matplace_centered << L_route( + pdk, + matplace_centered.ports["A_drain_L_23_top_met_N"], + matplace_centered.ports["A_drain_top_met_W"], + hwidth=widht_route_vertical, + ) + L6 = matplace_centered << L_route( + pdk, + matplace_centered.ports["A_drain_R_23_top_met_N"], + matplace_centered.ports["A_drain_top_met_E"], + hwidth=widht_route_vertical, + ) + if enable_B: + L7 = matplace_centered << L_route( + pdk, + matplace_centered.ports["B_drain_L_23_top_met_N"], + matplace_centered.ports["B_drain_top_met_W"], + hwidth=widht_route_vertical, + ) + L8 = matplace_centered << L_route( + pdk, + matplace_centered.ports["B_drain_R_23_top_met_N"], + matplace_centered.ports["B_drain_top_met_E"], + hwidth=widht_route_vertical, + ) + + component = Component() + component << matplace_centered + + # Get all ports of the original component + all_ports = matplace_centered.ports + if enable_B: + filtros = [ + "A_source_", + "B_source_", + "A_drain_", + "B_drain_", + "A_gate_", + "B_gate_", + ] + else: + filtros = ["A_source_", "A_gate_", "A_drain_"] + # Filter only the ones you need (by name, coordinates, etc.) + selected_ports = dict() + for filtro in filtros: + buscar_w = filtro + "top_met_W" + buscar_e = filtro + "top_met_E" + buscar_n = filtro + "bottom_met_N" + buscar_s = filtro + "bottom_met_S" + selected_ports = { + name: port + for name, port in all_ports.items() + if buscar_w in name + or buscar_e in name + or buscar_n in name + or buscar_s in name + } # Ejemplo: solo los que tienen 'in' en su nombre + for name, port in selected_ports.items(): + new_name = filtro + name[-1] # Add prefix + component.add_port( + new_name, + port.center, + port.width, + port.orientation, + layer=port.layer, + port_type="electrical", + ) + if with_tie: + buscar = [ + "tie_N_top_met_W", + "tie_N_top_met_N", + "tie_N_top_met_E", + "tie_N_top_met_S", + "tie_S_top_met_W", + "tie_S_top_met_N", + "tie_S_top_met_E", + "tie_S_top_met_S", + "tie_E_top_met_W", + "tie_E_top_met_N", + "tie_E_top_met_E", + "tie_E_top_met_S", + "tie_W_top_met_W", + "tie_W_top_met_N", + "tie_W_top_met_E", + "tie_W_top_met_S", + ] + selected_ports = dict() + for busqueda in buscar: + new_port = { + name: port + for name, port in all_ports.items() + if busqueda in name and "row" not in name + } + selected_ports.update(new_port) + for name, port in selected_ports.items(): + posicion = {"N": "up", "S": "down", "E": "right", "W": "left"} + new_name = "bulk_" + posicion[name[4]] + "_" + name[-1] + component.add_port( + new_name, + port.center, + port.width, + port.orientation, + layer=port.layer, + port_type="electrical", + ) + if full_output_size: + if pdk_sky130: + ports_list = [ + L1.ports["bottom_layer_W"], + L1.ports["bottom_layer_N"], + L2.ports["bottom_layer_E"], + L2.ports["bottom_layer_S"], + L5.ports["bottom_layer_W"], + L5.ports["bottom_layer_N"], + L6.ports["bottom_layer_E"], + L6.ports["bottom_layer_S"], + ] + names = ["A_source_T_", "A_drain_T_"] + if enable_B: + ports_list += [ + L3.ports["bottom_layer_W"], + L3.ports["bottom_layer_N"], + L4.ports["bottom_layer_E"], + L4.ports["bottom_layer_S"], + L7.ports["bottom_layer_W"], + L7.ports["bottom_layer_N"], + L8.ports["bottom_layer_E"], + L8.ports["bottom_layer_S"], + ] + names += ["B_source_T_", "B_drain_T_"] + elif pdk_gf180: + ports_list = [ + L1.ports["bottom_lay_W"], + L1.ports["bottom_lay_N"], + L2.ports["bottom_lay_E"], + L2.ports["bottom_lay_S"], + L5.ports["bottom_lay_W"], + L5.ports["bottom_lay_N"], + L6.ports["bottom_lay_E"], + L6.ports["bottom_lay_S"], + ] + names = ["A_source_T_", "A_drain_T_"] + if enable_B: + ports_list += [ + L3.ports["bottom_lay_W"], + L3.ports["bottom_lay_N"], + L4.ports["bottom_lay_E"], + L4.ports["bottom_lay_S"], + L7.ports["bottom_lay_W"], + L7.ports["bottom_lay_N"], + L8.ports["bottom_lay_E"], + L8.ports["bottom_lay_S"], + ] + names += ["B_source_T_", "B_drain_T_"] + + for i in range(len(names)): + component.add_port( + names[i] + "W", + ports_list[4 * i].center, + ports_list[4 * i].width, + ports_list[4 * i].orientation, + layer=ports_list[4 * i].layer, + port_type="electrical", + ) + component.add_port( + names[i] + "N", + ports_list[4 * i + 1].center, + ports_list[4 * i + 1].width, + ports_list[4 * i + 1].orientation, + layer=ports_list[4 * i + 1].layer, + port_type="electrical", + ) + component.add_port( + names[i] + "E", + ports_list[4 * i + 2].center, + ports_list[4 * i + 2].width, + ports_list[4 * i + 2].orientation, + layer=ports_list[4 * i + 2].layer, + port_type="electrical", + ) + component.add_port( + names[i] + "S", + ports_list[4 * i + 3].center, + ports_list[4 * i + 3].width, + ports_list[4 * i + 3].orientation, + layer=ports_list[4 * i + 3].layer, + port_type="electrical", + ) + + return component.flatten() + + +def interdigitado_placement_Onchip( + pdk: MappedPDK, + deviceA_and_B: Literal["nfet", "pfet"], + output: Literal["metal", "via"] = "metal", + output_separation: tuple[Optional[float], Optional[float]] = (0, 0), + width: float = 1, + length: float = 2, + fingers: int = 1, + with_dummy: bool = False, + with_lvt_layer: bool = True, + with_tie: bool = True, + with_substrate_tap: bool = False, + gate_common: bool = True, + routed: bool = False, + common_route: Optional[Union[bool, tuple[Optional[bool], Optional[bool]]]] = ( + False, + False, + ), + array: list = [[1, 2, 3]], + **kwargs, +) -> Component: + interdigitado = Component() + array = copy.deepcopy(array) + max_output = max(array[0]) + # Add dummys to array + if with_dummy: + column = len(array[0]) + + horizontal = [0] * (column + 2) + array_column = [[0] + row + [0] for row in array] + + array = [horizontal] + array_column + [horizontal] + arrayT = [list(fila) for fila in zip(*array)] + # Multiplier's arguments + kwargs["sdlayer"] = "n+s/d" if deviceA_and_B == "nfet" else "p+s/d" + kwargs["pdk"] = pdk + kwargs["dummy"] = (False, False) + kwargs["routing"] = False + reference = multiplier( + width=width, length=length, fingers=fingers, gate_down=True, **kwargs + ) + gate_extension_ref = abs( + pdk.get_grule("met2")["min_separation"] + reference.ports["gate_W"].width + ) + if gate_common == False: + reference = list() + for i in range(max_output): + gate_extension = gate_extension_ref * i + kwargs["gate_route_extension"] = pdk.snap_to_2xgrid(gate_extension) + reference.append( + multiplier( + width=width, + length=length, + fingers=fingers, + gate_down=True, + **kwargs, + ) + ) + + # dummy reference + if with_dummy: + kwargs["gate_route_extension"] = 0 + dummy_single_up = multiplier( + width=width, length=length, fingers=1, gate_up=True, **kwargs + ) + dummy_single_down = multiplier( + width=width, length=length, fingers=1, gate_down=True, **kwargs + ) + dummy_up = multiplier( + width=width, length=length, fingers=fingers, gate_up=True, **kwargs + ) + dummy_down = multiplier( + width=width, length=length, fingers=fingers, gate_down=True, **kwargs + ) + # min separation + if pdk == sky130: + min_separation = pdk.get_grule("poly")["min_separation"] + elif pdk == gf180: + min_separation = pdk.get_grule("met2")["min_separation"] + # Create the array of transistors + transistors = list() + for i in range(len(array)): + transistors_in_row = list() + for j in range(len(array[i])): + if i == 0 or i == len(array) - 1: # first and last row + if j == 0 or j == len(array[i]) - 1: # first and last column + # corner transistors + if array[i][j] == 0 and i == 0: + # small dummy + transistors_in_row.append(interdigitado << dummy_single_down) + elif array[i][j] == 0 and i == len(array) - 1: + # small dummy + transistors_in_row.append(interdigitado << dummy_single_up) + else: + if gate_common: + transistors_in_row.append(interdigitado << reference) + else: + transistors_in_row.append( + interdigitado << reference[array[i][j] - 1] + ) + elif i == 0: # first row + # first row transistors + if array[i][j] == 0: + # dummy + transistors_in_row.append(interdigitado << dummy_down) + else: + if gate_common: + transistors_in_row.append(interdigitado << reference) + else: + transistors_in_row.append( + interdigitado << reference[array[i][j] - 1] + ) + else: # last row + # last row transistors + if array[i][j] == 0: + # dummy + transistors_in_row.append(interdigitado << dummy_up) + else: + if gate_common: + transistors_in_row.append(interdigitado << reference) + else: + transistors_in_row.append( + interdigitado << reference[array[i][j] - 1] + ) + else: # middle rows + if array[i][j] == 0: + # small dummy + transistors_in_row.append(interdigitado << dummy_single_up) + else: + if gate_common: + transistors_in_row.append(interdigitado << reference) + else: + transistors_in_row.append( + interdigitado << reference[array[i][j] - 1] + ) + # Add the transistors in the row + transistors.append(transistors_in_row) + min_separation_x = pdk.get_grule("p+s/d")["min_separation"] + 0.01 + # [0][1] = distance center to bottom + # [1][1] = distance center to top + # Move the transistors + for i in range(len(transistors)): + # Move the transistors in y direction + if i == 0: + # first row dont move + ymove = 0 + else: # find max y size in the row + distance_center2bottom_ref = transistors[i][0].bbox[0][1] # Temporal + distance_center2top_pre_ref = ( + transistors[i - 1][0].bbox[1][1] - ymove + ) # Temporal // Minus the ymove because this one was already moved + ymove_temp = ( + abs(distance_center2bottom_ref) + + abs(distance_center2top_pre_ref) + + min_separation + ) + for k in range(len(transistors[i])): + distance_center2bottom_temp = transistors[i][k].bbox[0][ + 1 + ] # distance center to bottom of the transistor that will be moved + distance_center2top_pre_temp = ( + transistors[i - 1][k].bbox[1][1] - ymove + ) # distance center to top of the transistor above the one that will be moved + ymove_temp_2 = ( + abs(distance_center2bottom_temp) + + abs(distance_center2top_pre_temp) + + min_separation + ) + if ymove_temp_2 > ymove_temp: + ymove_temp = ymove_temp_2 + ymove += ( + ymove_temp + if i == 1 or i == len(transistors) - 1 + else ymove_temp + 3 * evaluate_bbox(via_stack(pdk, "met1", "met2"))[1] + ) + for j in range(len(transistors[i])): + size_transistor = evaluate_bbox(transistors[i][j]) + # Move the transistors in x direction + if j == 0: + # first transistor dont move + xmove = 0 + else: + pre_last_size = evaluate_bbox(transistors[i][j - 1]) + # rest of transistors + xmove += (size_transistor[0] + pre_last_size[0]) / 2 + min_separation_x + transistors[i][j].movex(pdk.snap_to_2xgrid(xmove)) + transistors[i][j].movey(pdk.snap_to_2xgrid(ymove)) + interdigitado.add_ports( + transistors[i][j].get_ports_list(), + prefix=str(i) + str(j) + "_" + str(array[i][j]) + "_", + ) + + # Center the component + interdigitado = center_component_with_ports(interdigitado) + ##RINGS + # Define configurations according to transistor type + device_config = { + "nfet": { + "sdlayer": "p+s/d", + "well_layer": "pwell", + "tap_enclosure_rule": "p+s/d", + }, + "pfet": { + "sdlayer": "n+s/d", + "well_layer": "nwell", + "tap_enclosure_rule": "n+s/d", + "substrate_tap_layer": "p+s/d", + }, + } + + # Obtaining the correct configuration + config = device_config.get(deviceA_and_B) + # Add tie if necessary + if with_tie: + tie_layers = ["met2", "met1"] + + tap_separation = max( + pdk.get_grule("met2")["min_separation"], + pdk.get_grule("met1")["min_separation"], + pdk.get_grule("active_diff", "active_tap")["min_separation"], + ) + tap_separation += pdk.get_grule(config["tap_enclosure_rule"], "active_tap")[ + "min_enclosure" + ] + + tap_encloses = ( + 2 * (tap_separation + interdigitado.xmax), + 2 * (tap_separation + interdigitado.ymax), + ) + tapring_ref = interdigitado << create_tapring_onchip( + pdk, + enclosed_rectangle=tap_encloses, + sdlayer=config["sdlayer"], + horizontal_glayer=tie_layers[0], + vertical_glayer=tie_layers[1], + with_lvt_layer=with_lvt_layer, + ) + interdigitado.add_ports(tapring_ref.get_ports_list(), prefix="tie_") + if with_dummy: + first_mos_ds = interdigitado.ports[ + "00_0_leftsd_met_array_row0_col0_top_met_W" + ] + first_mos_gate = interdigitado.ports["00_0_gate_W"] + first_mos_ds_R = interdigitado.ports[ + "0" + + str(len(arrayT) - 1) + + "_0_" + + "row0_col0_rightsd_met_array_row0_col0_top_met_E" + ] + first_mos_gate_R = interdigitado.ports[ + "0" + str(len(arrayT) - 1) + "_0_gate_E" + ] + last_mos_ds = interdigitado.ports[ + str(len(array) - 1) + "0_0_leftsd_met_array_row0_col0_top_met_W" + ] + last_mos_gate = interdigitado.ports[str(len(array) - 1) + "0_0_gate_W"] + last_mos_ds_R = interdigitado.ports[ + str(len(array) - 1) + + str(len(arrayT) - 1) + + "_0_row0_col0_rightsd_met_array_row0_col0_top_met_E" + ] + last_mos_gate_R = interdigitado.ports[ + str(len(array) - 1) + str(len(arrayT) - 1) + "_0_gate_E" + ] + tie_left_W = interdigitado.ports["tie_W_array_row0_col0_top_met_W"] + tie_right = interdigitado.ports["tie_E_array_row0_col0_top_met_E"] + width_route_dummy = 1 if width >= 1 else width + for i in range(len(array)): + if i == 0: + # First Dummys + interdigitado << straight_route( + pdk, first_mos_ds_R, tie_left_W, width=width_route_dummy + ) + interdigitado << straight_route( + pdk, first_mos_ds, tie_right, width=width_route_dummy + ) + interdigitado << straight_route(pdk, first_mos_gate_R, tie_left_W) + interdigitado << straight_route(pdk, first_mos_gate, tie_right) + elif i == len(array) - 1: + # Last Dummys + interdigitado << straight_route( + pdk, last_mos_ds_R, tie_left_W, width=width_route_dummy + ) + interdigitado << straight_route( + pdk, last_mos_ds, tie_right, width=width_route_dummy + ) + interdigitado << straight_route(pdk, last_mos_gate_R, tie_left_W) + interdigitado << straight_route(pdk, last_mos_gate, tie_right) + else: + interdigitado << straight_route( + pdk, + interdigitado.ports[ + str(i) + + "0_0_row0_col0_rightsd_met_array_row0_col0_top_met_E" + ], + tie_left_W, + width=width_route_dummy, + ) + interdigitado << straight_route( + pdk, + interdigitado.ports[ + str(i) + + str(len(array[0]) - 1) + + "_0_leftsd_met_array_row0_col0_top_met_W" + ], + tie_right, + width=width_route_dummy, + ) + interdigitado << straight_route( + pdk, interdigitado.ports[str(i) + "0_0_gate_E"], tie_left_W + ) + interdigitado << straight_route( + pdk, + interdigitado.ports[ + str(i) + str(len(array[0]) - 1) + "_0_gate_W" + ], + tie_right, + ) + + # Add well + interdigitado.add_padding( + layers=(pdk.get_glayer(config["well_layer"]),), + default=pdk.get_grule(config["well_layer"], "active_tap")["min_enclosure"], + ) + + # Adding taps on the perimeter + interdigitado = add_ports_perimeter( + interdigitado, layer=pdk.get_glayer(config["well_layer"]), prefix="well_" + ) + dims_post_tie = evaluate_bbox(interdigitado) + + # Add substrate tap if necessary + if deviceA_and_B == "pfet": + if with_substrate_tap: + substrate_tap_separation = pdk.get_grule("dnwell", "active_tap")[ + "min_separation" + ] + substrate_tap_encloses = ( + 2 * (substrate_tap_separation + interdigitado.xmax), + 2 * (substrate_tap_separation + interdigitado.ymax), + ) + ringtoadd = create_tapring_onchip( + pdk, + enclosed_rectangle=substrate_tap_encloses, + sdlayer=config["substrate_tap_layer"], + horizontal_glayer="met2", + vertical_glayer="met1", + with_lvt_layer=False, + ) + tapring_ref = interdigitado << ringtoadd + interdigitado.add_ports( + tapring_ref.get_ports_list(), prefix="substratetap_" + ) + # Output port + T_not_dummy = 0 + size_interdigitado = evaluate_bbox(interdigitado) + min_separation_met3 = pdk.get_grule("met3")["min_separation"] + size_transistor = ( + evaluate_bbox(reference) if gate_common else evaluate_bbox(reference[0]) + ) + + for i in range(len(array)): + for j in range(len(array[i])): + if array[i][j] == 0: + continue + else: + T_not_dummy += 1 + port_reference_top = interdigitado.ports[ + str(i) + str(j) + "_" + str(array[i][j]) + "_leftsd_top_met_N" + ] + port_reference_bottom = interdigitado.ports[ + str(i) + str(j) + "_" + str(array[i][j]) + "_leftsd_top_met_S" + ] + port_referenceg_left = ( + interdigitado.ports["11_" + str(array[1][1]) + "_gate_W"] + if with_dummy + else interdigitado.ports["00_" + str(array[0][0]) + "_gate_W"] + ) + port_referenceg_right = interdigitado.ports[ + str(i) + str(j) + "_" + str(array[i][j]) + "_gate_E" + ] + # port_reference_top.width = port_reference_bottom.width + rect = rectangle( + (port_reference_top.width, port_reference_bottom.width), + layer=pdk.get_glayer("met3"), + ) + via = via_stack(pdk, "met2", "met3") + output_port = rect if output == "metal" else via + rectg = rectangle( + (port_referenceg_left.width, port_referenceg_right.width), + layer=pdk.get_glayer("met2"), + ) + size_rect = evaluate_bbox(rect) + size_rectg = evaluate_bbox(rectg) + size_via = evaluate_bbox(via) + size_output = size_rect if output == "metal" else size_via + salidas_row = list() + drain = 0 + source = 0 + for k in range(fingers + 1): + salidas_row.append(interdigitado << output_port) + reference = ( + port_reference_top if k % 2 == 0 else port_reference_bottom + ) + separation = ( + min_separation_met3 + size_output[1] + output_separation[0] + if k % 2 == 0 + else min_separation_met3 + size_output[1] + output_separation[1] + ) + if gate_common: + distance_out_ring = ( + size_interdigitado[1] / 2 - size_transistor[1] / 2 + if k % 2 == 0 + else size_interdigitado[1] / 2 + - size_transistor[1] / 2 + + gate_extension_ref + ) + else: + distance_out_ring = ( + size_interdigitado[1] / 2 - size_transistor[1] / 2 + if k % 2 == 0 + else size_interdigitado[1] / 2 + - size_transistor[1] / 2 + + gate_extension_ref * max_output + ) + ymove = ( + distance_out_ring + separation * (array[i][j]) + if k % 2 == 0 + else -1 * (distance_out_ring + separation * (array[i][j])) + ) + align_comp_to_port(salidas_row[-1], reference) + if common_route[0] and k % 2 == 0: + ymove -= separation * (array[i][j] - 1) + elif common_route[1] and k % 2 == 1: + ymove += separation * (array[i][j] - 1) + salidas_row[-1].movey(pdk.snap_to_2xgrid(ymove)) + output_port_name = "e2" if output == "metal" else "top_met_S" + # print(salidas_row[-1].get_ports_list()) + interdigitado << straight_route( + pdk, + salidas_row[-1].ports[output_port_name], + reference, + glayer1="met3", + glayer2="met2", + ) + prefix = ( + "drain_" + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(drain) + + "_" + if k % 2 == 0 + else "source_" + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(source) + + "_" + ) + interdigitado.add_ports( + salidas_row[-1].get_ports_list(), prefix=prefix + ) + if k == fingers: + break + drain += 1 if k % 2 == 0 else 0 + source += 1 if k % 2 == 1 else 0 + port_reference_top = interdigitado.ports[ + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_row0_col" + + str(k) + + "_rightsd_top_met_N" + ] + port_reference_bottom = interdigitado.ports[ + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_row0_col" + + str(k) + + "_rightsd_top_met_S" + ] + if gate_common: + salidas_gate = list() + for i in range(2): + salidas_gate.append(interdigitado << output_port) + referenceg = port_referenceg_left if i == 0 else port_referenceg_right + align_comp_to_port(salidas_gate[-1], referenceg) + separationg = min_separation_met3 + size_rectg[0] + if with_dummy: + distance_out_ring = ( + size_interdigitado[0] / 2 + - ((len(array[0])) / 2 - 1) * size_transistor[0] + ) + else: + distance_out_ring = 2 * separationg + xmove = ( + -distance_out_ring - separationg + if i == 0 + else distance_out_ring + separationg + ) + salidas_gate[-1].movex(pdk.snap_to_2xgrid(xmove)) + prefix = "gate1_" if i == 0 else "gate2_" + interdigitado.add_ports(salidas_gate[-1].get_ports_list(), prefix=prefix) + interdigitado = rename_ports_by_orientation(interdigitado) + ports_gate = ( + ["gate2_E", "gate1_W"] + if output == "metal" + else ["gate2_bottom_met_E", "gate1_bottom_met_W"] + ) + interdigitado << straight_route( + pdk, + interdigitado.ports[ports_gate[0]], + interdigitado.ports[ports_gate[1]], + glayer1="met2", + glayer2="met2", + ) + + # Save ports + component = Component() + component << interdigitado + all_ports = interdigitado.ports + + ports = list() + + if with_tie: + buscar = [ + "tie_N_top_met_W", + "tie_N_top_met_N", + "tie_N_top_met_E", + "tie_N_top_met_S", + "tie_S_top_met_W", + "tie_S_top_met_N", + "tie_S_top_met_E", + "tie_S_top_met_S", + "tie_E_top_met_W", + "tie_E_top_met_N", + "tie_E_top_met_E", + "tie_E_top_met_S", + "tie_W_top_met_W", + "tie_W_top_met_N", + "tie_W_top_met_E", + "tie_W_top_met_S", + ] + selected_ports = dict() + for busqueda in buscar: + new_port = { + name: port + for name, port in all_ports.items() + if busqueda in name and "row" not in name + } + selected_ports.update(new_port) + for name, port in selected_ports.items(): + posicion = {"N": "up", "S": "down", "E": "right", "W": "left"} + new_name = "bulk_" + posicion[name[4]] + "_" + name[-1] + component.add_port( + new_name, + port.center, + port.width, + port.orientation, + layer=port.layer, + port_type="electrical", + ) + + ports = list() + name = list() + for i in range(len(array)): + for j in range(len(array[i])): + if array[i][j] == 0: + continue + else: + drain = 0 + source = 0 + for k in range(fingers + 1): + if k % 2 == 0: + if output == "metal": + ports.append( + "drain_" + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(drain) + + "_" + ) + name.append( + "drain_" + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(drain) + + "_" + ) + elif output == "via": + ports.append( + "drain_" + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(drain) + + "_top_met_" + ) + name.append( + "drain_" + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(drain) + + "_" + ) + drain += 1 + else: + if output == "metal": + ports.append( + "source_" + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(source) + + "_" + ) + name.append( + "source_" + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(source) + + "_" + ) + elif output == "via": + ports.append( + "source_" + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(source) + + "_top_met_" + ) + name.append( + "source_" + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(source) + + "_" + ) + source += 1 + if gate_common: + gate_names = ( + ["gate1_", "gate2_"] + if output == "metal" + else ["gate1_top_met_", "gate2_top_met_"] + ) + ports.append(gate_names[0]) + ports.append(gate_names[1]) + name.append("gate1_") + name.append("gate2_") + else: + all_ports = interdigitado.ports + selected_ports = { + name: port + for name, port in all_ports.items() + if "gate" in name and "row" not in name and "_0_" not in name + } + for name_original, port in selected_ports.items(): + new_name = name_original[1:] + component.add_port( + new_name, + port.center, + port.width, + port.orientation, + layer=port.layer, + port_type="electrical", + ) + + # ports.append + # Add ports to component + for i in range(len(ports)): + filtrar_puertos(interdigitado, component, ports[i], name[i]) + # port name format metal output + # source/drain + position + type transistor + output number(if there are more than one finger) + # port name format via output + # source/drain + position + type transistor + output number(if there are more than one finger) + top_met_ + # port name format common gate + # gate1_ left gate_2 right + # port name format not common gate + # postion + type transistor + gate + direction + # center component + # component = center_component_with_ports(component) + return component # return interdigitado + + +def interdigitado_cascode_placement_Onchip( + pdk: MappedPDK, + deviceA_and_B: Literal["nfet", "pfet"], + output: Literal["metal", "via"] = "metal", + output_separation: float = 0, + width: float = 1, + length: float = 2, + fingers: int = 1, + with_dummy: bool = False, + with_lvt_layer: bool = True, + with_tie: bool = True, + with_substrate_tap: bool = False, + common_route: Optional[Union[bool, tuple[Optional[bool], Optional[bool]]]] = ( + False, + False, + ), + array: list = [[1, 2, 3]], + **kwargs, +) -> Component: + interdigitado = Component() + max_array = max(array[0]) + array = copy.deepcopy(array) + if output != "metal" and output != "via": + raise ValueError("Output must be metal or via") + # Duplicate the array + array = array * 2 + # Add dummys to array + if with_dummy: + column = len(array[0]) + + horizontal = [0] * (column + 2) + array_column = [[0] + row + [0] for row in array] + + array = [horizontal] + array_column + [horizontal] + arrayT = [list(fila) for fila in zip(*array)] + # Multiplier's arguments + kwargs["sdlayer"] = "n+s/d" if deviceA_and_B == "nfet" else "p+s/d" + kwargs["pdk"] = pdk + kwargs["dummy"] = (False, False) + kwargs["routing"] = False + reference = multiplier( + width=width, length=length, fingers=fingers, gate_down=True, **kwargs + ) + # dummy reference + if with_dummy: + dummy_single_up = multiplier( + width=width, length=length, fingers=1, gate_up=True, **kwargs + ) + dummy_single_down = multiplier( + width=width, length=length, fingers=1, gate_down=True, **kwargs + ) + dummy_up = multiplier( + width=width, length=length, fingers=fingers, gate_up=True, **kwargs + ) + dummy_down = multiplier( + width=width, length=length, fingers=fingers, gate_down=True, **kwargs + ) + # min separation + if pdk == sky130: + min_separation = pdk.get_grule("poly")["min_separation"] + elif pdk == gf180: + min_separation = pdk.get_grule("met2")["min_separation"] + # Create the array of transistors + transistors = list() + for i in range(len(array)): + transistors_in_row = list() + for j in range(len(array[i])): + if i == 0 or i == len(array) - 1: # first and last row + if j == 0 or j == len(array[i]) - 1: # first and last column + # corner transistors + if array[i][j] == 0 and i == 0: + # small dummy + transistors_in_row.append(interdigitado << dummy_single_down) + elif array[i][j] == 0 and i == len(array) - 1: + # small dummy + transistors_in_row.append(interdigitado << dummy_single_up) + else: + transistors_in_row.append(interdigitado << reference) + elif i == 0: # first row + # first row transistors + if array[i][j] == 0: + # dummy + transistors_in_row.append(interdigitado << dummy_down) + else: + transistors_in_row.append(interdigitado << reference) + else: # last row + # last row transistors + if array[i][j] == 0: + # dummy + transistors_in_row.append(interdigitado << dummy_up) + else: + transistors_in_row.append(interdigitado << reference) + else: # middle rows + if array[i][j] == 0: + # small dummy + transistors_in_row.append(interdigitado << dummy_single_up) + else: + transistors_in_row.append(interdigitado << reference) + # Add the transistors in the row + transistors.append(transistors_in_row) + min_separation_x = pdk.get_grule("p+s/d")["min_separation"] + 0.01 + # [0][1] = distance center to bottom + # [1][1] = distance center to top + # Move the transistors + for i in range(len(transistors)): + # Move the transistors in y direction + if i == 0: + # first row dont move + ymove = 0 + else: # find max y size in the row + distance_center2bottom_ref = transistors[i][0].bbox[0][1] # Temporal + distance_center2top_pre_ref = ( + transistors[i - 1][0].bbox[1][1] - ymove + ) # Temporal // Minus the ymove because this one was already moved + ymove_temp = ( + abs(distance_center2bottom_ref) + + abs(distance_center2top_pre_ref) + + min_separation + ) + for k in range(len(transistors[i])): + distance_center2bottom_temp = transistors[i][k].bbox[0][ + 1 + ] # distance center to bottom of the transistor that will be moved + distance_center2top_pre_temp = ( + transistors[i - 1][k].bbox[1][1] - ymove + ) # distance center to top of the transistor above the one that will be moved + ymove_temp_2 = ( + abs(distance_center2bottom_temp) + + abs(distance_center2top_pre_temp) + + min_separation + ) + if ymove_temp_2 > ymove_temp: + ymove_temp = ymove_temp_2 + ymove += ( + ymove_temp + if i == 1 or i == len(transistors) - 1 + else ymove_temp + + 3 * evaluate_bbox(via_stack(pdk, "met1", "met2"))[1] + + (evaluate_bbox(via_stack(pdk, "met1", "met2"))[1] * (max_array - 1)) + ) + for j in range(len(transistors[i])): + size_transistor = evaluate_bbox(transistors[i][j]) + # Move the transistors in x direction + if j == 0: + # first transistor dont move + xmove = 0 + else: + pre_last_size = evaluate_bbox(transistors[i][j - 1]) + # rest of transistors + xmove += (size_transistor[0] + pre_last_size[0]) / 2 + min_separation_x + transistors[i][j].movex(pdk.snap_to_2xgrid(xmove)) + transistors[i][j].movey(pdk.snap_to_2xgrid(ymove)) + + interdigitado.add_ports( + transistors[i][j].get_ports_list(), + prefix=str(i) + str(j) + "_" + str(array[i][j]) + "_", + ) + # Center the component + interdigitado = center_component_with_ports(interdigitado) + ##RINGS + # Define configurations according to transistor type + device_config = { + "nfet": { + "sdlayer": "p+s/d", + "well_layer": "pwell", + "tap_enclosure_rule": "p+s/d", + }, + "pfet": { + "sdlayer": "n+s/d", + "well_layer": "nwell", + "tap_enclosure_rule": "n+s/d", + "substrate_tap_layer": "p+s/d", + }, + } + + # Obtaining the correct configuration + config = device_config.get(deviceA_and_B) + # Add tie if necessary + if with_tie: + tie_layers = ["met2", "met1"] + + tap_separation = max( + pdk.get_grule("met2")["min_separation"], + pdk.get_grule("met1")["min_separation"], + pdk.get_grule("active_diff", "active_tap")["min_separation"], + ) + tap_separation += pdk.get_grule(config["tap_enclosure_rule"], "active_tap")[ + "min_enclosure" + ] + + tap_encloses = ( + 2 * (tap_separation + interdigitado.xmax), + 2 * (tap_separation + interdigitado.ymax), + ) + tapring_ref = interdigitado << create_tapring_onchip( + pdk, + enclosed_rectangle=tap_encloses, + sdlayer=config["sdlayer"], + horizontal_glayer=tie_layers[0], + vertical_glayer=tie_layers[1], + with_lvt_layer=with_lvt_layer, + ) + interdigitado.add_ports(tapring_ref.get_ports_list(), prefix="tie_") + if with_dummy: + first_mos_ds = interdigitado.ports[ + "00_0_leftsd_met_array_row0_col0_top_met_W" + ] + first_mos_gate = interdigitado.ports["00_0_gate_W"] + first_mos_ds_R = interdigitado.ports[ + "0" + + str(len(arrayT) - 1) + + "_0_" + + "row0_col0_rightsd_met_array_row0_col0_top_met_E" + ] + first_mos_gate_R = interdigitado.ports[ + "0" + str(len(arrayT) - 1) + "_0_gate_E" + ] + last_mos_ds = interdigitado.ports[ + str(len(array) - 1) + "0_0_leftsd_met_array_row0_col0_top_met_W" + ] + last_mos_gate = interdigitado.ports[str(len(array) - 1) + "0_0_gate_W"] + last_mos_ds_R = interdigitado.ports[ + str(len(array) - 1) + + str(len(arrayT) - 1) + + "_0_row0_col0_rightsd_met_array_row0_col0_top_met_E" + ] + last_mos_gate_R = interdigitado.ports[ + str(len(array) - 1) + str(len(arrayT) - 1) + "_0_gate_E" + ] + tie_left_W = interdigitado.ports["tie_W_array_row0_col0_top_met_W"] + tie_right = interdigitado.ports["tie_E_array_row0_col0_top_met_E"] + width_route_dummy = 1 if width >= 1 else width + for i in range(len(array)): + if i == 0: + # First Dummys + interdigitado << straight_route( + pdk, first_mos_ds_R, tie_left_W, width=width_route_dummy + ) + interdigitado << straight_route( + pdk, first_mos_ds, tie_right, width=width_route_dummy + ) + interdigitado << straight_route(pdk, first_mos_gate_R, tie_left_W) + interdigitado << straight_route(pdk, first_mos_gate, tie_right) + elif i == len(array) - 1: + # Last Dummys + interdigitado << straight_route( + pdk, last_mos_ds_R, tie_left_W, width=width_route_dummy + ) + interdigitado << straight_route( + pdk, last_mos_ds, tie_right, width=width_route_dummy + ) + interdigitado << straight_route(pdk, last_mos_gate_R, tie_left_W) + interdigitado << straight_route(pdk, last_mos_gate, tie_right) + else: + interdigitado << straight_route( + pdk, + interdigitado.ports[ + str(i) + + "0_0_row0_col0_rightsd_met_array_row0_col0_top_met_E" + ], + tie_left_W, + width=width_route_dummy, + ) + interdigitado << straight_route( + pdk, + interdigitado.ports[ + str(i) + + str(len(array[0]) - 1) + + "_0_leftsd_met_array_row0_col0_top_met_W" + ], + tie_right, + width=width_route_dummy, + ) + interdigitado << straight_route( + pdk, interdigitado.ports[str(i) + "0_0_gate_E"], tie_left_W + ) + interdigitado << straight_route( + pdk, + interdigitado.ports[ + str(i) + str(len(array[0]) - 1) + "_0_gate_W" + ], + tie_right, + ) + + # Add well + interdigitado.add_padding( + layers=(pdk.get_glayer(config["well_layer"]),), + default=pdk.get_grule(config["well_layer"], "active_tap")["min_enclosure"], + ) + + # Adding taps on the perimeter + interdigitado = add_ports_perimeter( + interdigitado, layer=pdk.get_glayer(config["well_layer"]), prefix="well_" + ) + dims_post_tie = evaluate_bbox(interdigitado) + + # Add substrate tap if necessary + if deviceA_and_B == "pfet": + if with_substrate_tap: + substrate_tap_separation = pdk.get_grule("dnwell", "active_tap")[ + "min_separation" + ] + substrate_tap_encloses = ( + 2 * (substrate_tap_separation + interdigitado.xmax), + 2 * (substrate_tap_separation + interdigitado.ymax), + ) + ringtoadd = create_tapring_onchip( + pdk, + enclosed_rectangle=substrate_tap_encloses, + sdlayer=config["substrate_tap_layer"], + horizontal_glayer="met2", + vertical_glayer="met1", + with_lvt_layer=False, + ) + tapring_ref = interdigitado << ringtoadd + interdigitado.add_ports( + tapring_ref.get_ports_list(), prefix="substratetap_" + ) + + # Outputs and routing + size_interdigitado = evaluate_bbox(interdigitado) + min_separation_met3 = pdk.get_grule("met3")["min_separation"] + min_separation_met2 = pdk.get_grule("met2")["min_separation"] + T_not_dummy = 0 + up = False + down = False + salidas_gate = list() + + for i in range(len(array)): + for j in range(len(array[i])): + if (i == 1 and with_dummy) or (i == 0 and with_dummy == False): + # print('down') + down = True + up = False + elif (i == len(array) - 2 and with_dummy) or ( + i == len(array) - 1 and with_dummy == False + ): + up = True + down = False + # print('up') + else: + up = False + down = False + + if array[i][j] == 0: + continue + else: + T_not_dummy += 1 + size_transistor = evaluate_bbox(transistors[i][j]) + port_reference_top = interdigitado.ports[ + str(i) + str(j) + "_" + str(array[i][j]) + "_leftsd_top_met_N" + ] + port_reference_bottom = interdigitado.ports[ + str(i) + str(j) + "_" + str(array[i][j]) + "_leftsd_top_met_S" + ] + port_referenceg_left = ( + interdigitado.ports["11_" + str(array[1][1]) + "_gate_W"] + if with_dummy + else interdigitado.ports["00_" + str(array[0][0]) + "_gate_W"] + ) + port_referenceg_right = interdigitado.ports[ + str(i) + str(j) + "_" + str(array[i][j]) + "_gate_E" + ] + # port_reference_top.width = port_reference_bottom.width + rect = rectangle( + (port_reference_top.width, port_reference_bottom.width), + layer=pdk.get_glayer("met3"), + ) + rect_hor = rectangle( + (port_reference_top.width, port_reference_bottom.width), + layer=pdk.get_glayer("met2"), + ) + via = via_stack(pdk, "met2", "met3") + via_hor = via_stack(pdk, "met1", "met2") + output_port = rect if output == "metal" else via + rectg = rectangle( + (port_referenceg_left.width, port_referenceg_right.width), + layer=pdk.get_glayer("met2"), + ) + size_rect = evaluate_bbox(rect) + size_rectg = evaluate_bbox(rectg) + size_via = evaluate_bbox(via) + size_output = size_rect if output == "metal" else size_via + size_via_hor = evaluate_bbox(via_hor) + salidas_row = list() + middle_port = list() + drain = 0 + source = 0 + for k in range(fingers + 1): + if up and k % 2 == 0: + # print('placement up') + salidas_row.append(interdigitado << output_port) + reference = port_reference_top + separation = ( + min_separation_met3 + size_output[1] + output_separation + ) + distance_out_ring = ( + size_interdigitado[1] / 2 - size_transistor[1] + ) + ymove = distance_out_ring + separation * (array[i][j]) + align_comp_to_port(salidas_row[-1], reference) + if common_route[0] and k % 2 == 0: + ymove -= separation * (array[i][j] - 1) + salidas_row[-1].movey(pdk.snap_to_2xgrid(ymove)) + output_port_name = "e2" if output == "metal" else "top_met_S" + # print(salidas_row[-1].get_ports_list()) + interdigitado << straight_route( + pdk, + salidas_row[-1].ports[output_port_name], + reference, + glayer1="met3", + glayer2="met2", + ) + prefix = ( + "drain_" + + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(drain) + + "_" + ) + interdigitado.add_ports( + salidas_row[-1].get_ports_list(), prefix=prefix + ) + drain += 1 + elif up and k % 2 == 1: + # print(k,'ruteo') + # print('no break') + middle_port.append(interdigitado << via_hor) + move_middle_port = [ + port_ruteo_top.center[0], + port_gate_top.center[1] + - (size_output[1] + size_via_hor[1]) / 2 + - min_separation_met2, + ] + middle_port[-1].movex( + pdk.snap_to_2xgrid(move_middle_port[0]) + ).movey(pdk.snap_to_2xgrid(move_middle_port[1])) + extra_movey = (min_separation_met2 + size_via_hor[1]) * ( + array[i][j] - 1 + ) + middle_port[-1].movey(pdk.snap_to_2xgrid(-extra_movey)) + interdigitado << straight_route( + pdk, port_ruteo_top, port_ruteo_bot + ) + interdigitado.add_ports( + middle_port[-1].get_ports_list(), + prefix="middle_" + + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(k) + + "_", + ) + + elif down and k % 2 == 0: + # print('placement down') + salidas_row.append(interdigitado << output_port) + reference = port_reference_bottom + separation = ( + min_separation_met3 + size_output[1] + output_separation + ) + distance_out_ring = ( + size_interdigitado[1] / 2 - size_transistor[1] / 2 + ) + ymove = -1 * (distance_out_ring + separation * (array[i][j])) + align_comp_to_port(salidas_row[-1], reference) + if common_route[1] and k % 2 == 0: + ymove += separation * (array[i][j]) + salidas_row[-1].movey( + pdk.snap_to_2xgrid(ymove - output_separation) + ) + output_port_name = "e2" if output == "metal" else "top_met_S" + # print(salidas_row[-1].get_ports_list()) + interdigitado << straight_route( + pdk, + salidas_row[-1].ports[output_port_name], + reference, + glayer1="met3", + glayer2="met2", + ) + prefix = ( + "source_" + + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(source) + + "_" + ) + interdigitado.add_ports( + salidas_row[-1].get_ports_list(), prefix=prefix + ) + source += 1 + if k == fingers: + break + port_reference_top = interdigitado.ports[ + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_row0_col" + + str(k) + + "_rightsd_top_met_N" + ] + port_reference_bottom = interdigitado.ports[ + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_row0_col" + + str(k) + + "_rightsd_top_met_S" + ] + if up: + port_ruteo_top = interdigitado.ports[ + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_row0_col" + + str(k) + + "_rightsd_top_met_S" + ] + port_gate_top = interdigitado.ports[ + str(i) + str(j) + "_" + str(array[i][j]) + "_gate_E" + ] + port_ruteo_bot = interdigitado.ports[ + str(i - 1) + + str(j) + + "_" + + str(array[i][j]) + + "_row0_col" + + str(k) + + "_rightsd_top_met_S" + ] + rows = len(array) + cols = len(array[0]) + output_port = rect_hor if output == "metal" else via + # Ruteo intermedio + ports_name = [name for name in interdigitado.ports if "middle" in name] + # print(ports_name) + for i in range(max_array + 1): + port_inicial = [ + name + for name in interdigitado.ports + if "middle_" in name + and "_" + str(i) + "_1_" in name + and "top_met_E" in name + ] + if len(port_inicial) > 1: + interdigitado << straight_route( + pdk, + interdigitado.ports[port_inicial[0]], + interdigitado.ports[port_inicial[-1]], + ) + # print(port_inicial) + + # Ruteo gate + for i in range(rows): + if ((i > 0 and i < rows - 1) and with_dummy) or with_dummy == False: + port_referenceg_left = ( + interdigitado.ports[str(i) + "1_" + str(array[1][1]) + "_gate_W"] + if with_dummy + else interdigitado.ports[str(i) + "0_" + str(array[0][0]) + "_gate_W"] + ) + port_referenceg_right = ( + interdigitado.ports[ + str(i) + str(cols - 2) + "_" + str(array[i][cols - 2]) + "_gate_E" + ] + if with_dummy + else interdigitado.ports[ + str(i) + str(cols - 1) + "_" + str(array[i][cols - 1]) + "_gate_E" + ] + ) + salidas_gate.append(interdigitado << output_port) + salidas_gate.append(interdigitado << output_port) + # referenceg = port_referenceg_left if l == 0 else port_referenceg_right + align_comp_to_port(salidas_gate[-1], port_referenceg_left) + align_comp_to_port(salidas_gate[-2], port_referenceg_right) + separationg = min_separation_met3 + size_rectg[0] + if with_dummy: + distance_out_ring = ( + size_interdigitado[0] / 2 + - ((len(array[0])) / 2 - 1) * size_transistor[0] + ) + else: + distance_out_ring = 2 * separationg + # xmove = -distance_out_ring -separationg if l==0 else distance_out_ring+separationg + xmove_left = -distance_out_ring - separation + xmove_right = distance_out_ring + separation + salidas_gate[-1].movex(pdk.snap_to_2xgrid(xmove_left)) + salidas_gate[-2].movex(pdk.snap_to_2xgrid(xmove_right)) + # prefix = 'gate1_' if i==0 else 'gate2_' + prefix_left = "gate_" + str(i) + "_l_" + prefix_right = "gate_" + str(i) + "_r_" + interdigitado.add_ports( + salidas_gate[-1].get_ports_list(), prefix=prefix_left + ) + interdigitado.add_ports( + salidas_gate[-2].get_ports_list(), prefix=prefix_right + ) + interdigitado = rename_ports_by_orientation(interdigitado) + ports_gate = ( + ["gate_" + str(i) + "_l_E", "gate_" + str(i) + "_r_W"] + if output == "metal" + else [ + "gate_" + str(i) + "_l_bottom_met_E", + "gate_" + str(i) + "_r_bottom_met_W", + ] + ) + interdigitado << straight_route( + pdk, + interdigitado.ports[ports_gate[0]], + interdigitado.ports[ports_gate[1]], + glayer1="met2", + glayer2="met2", + ) + + # Save ports + component = Component() + component << interdigitado + all_ports = interdigitado.ports + + ports = list() + + if with_tie: + buscar = [ + "tie_N_top_met_W", + "tie_N_top_met_N", + "tie_N_top_met_E", + "tie_N_top_met_S", + "tie_S_top_met_W", + "tie_S_top_met_N", + "tie_S_top_met_E", + "tie_S_top_met_S", + "tie_E_top_met_W", + "tie_E_top_met_N", + "tie_E_top_met_E", + "tie_E_top_met_S", + "tie_W_top_met_W", + "tie_W_top_met_N", + "tie_W_top_met_E", + "tie_W_top_met_S", + ] + selected_ports = dict() + for busqueda in buscar: + new_port = { + name: port + for name, port in all_ports.items() + if busqueda in name and "row" not in name + } + selected_ports.update(new_port) + for name, port in selected_ports.items(): + posicion = {"N": "up", "S": "down", "E": "right", "W": "left"} + new_name = "bulk_" + posicion[name[4]] + "_" + name[-1] + component.add_port( + new_name, + port.center, + port.width, + port.orientation, + layer=port.layer, + port_type="electrical", + ) + + ports = list() + name = list() + for i in range(len(array)): + for j in range(len(array[i])): + if array[i][j] == 0: + continue + else: + out_source = 0 + out_drain = 0 + if (i == 1 and with_dummy) or ( + i == 0 and with_dummy == False + ): # or i==rows-1) + for k in range(fingers + 1): + if k % 2 == 0: + if output == "metal": + ports.append( + "source_" + + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(out_source) + + "_" + ) + name.append( + "source_" + + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(out_source) + + "_" + ) + elif output == "via": + ports.append( + "source_" + + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(out_source) + + "_top_met_" + ) + name.append( + "source_" + + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(out_source) + + "_" + ) + out_source += 1 + if (i == rows - 2 and with_dummy) or ( + i == rows - 1 and with_dummy == False + ): + for k in range(fingers + 1): + if k % 2 == 0: + if output == "metal": + ports.append( + "drain_" + + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(out_drain) + + "_" + ) + name.append( + "drain_" + + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(out_drain) + + "_" + ) + elif output == "via": + ports.append( + "drain_" + + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(out_drain) + + "_top_met_" + ) + name.append( + "drain_" + + str(i) + + str(j) + + "_" + + str(array[i][j]) + + "_" + + str(out_drain) + + "_" + ) + out_drain += 1 + + for i in range(rows): + if ((i > 0 and i < rows - 1) and with_dummy) or with_dummy == False: + name_gate = ( + ["gate_" + str(i) + "_l_", "gate_" + str(i) + "_r_"] + if output == "metal" + else [ + "gate_" + str(i) + "_l_top_met_", + "gate_" + str(i) + "_r_top_met_", + ] + ) + ports.append(name_gate[0]) + ports.append(name_gate[1]) + name.append("gate_" + str(i) + "_l_") + name.append("gate_" + str(i) + "_r_") + + for i in range(len(ports)): + filtrar_puertos(interdigitado, component, ports[i], name[i]) + # port name format metal output + # source/drain + position + type transistor + output number(if there are more than one finger) + # port name format via output + # source/drain + position + type transistor + output number(if there are more than one finger) + top_met_ + # center component + component = center_component_with_ports(component) + return component # return interdigitado + + +def create_tapring_onchip( + pdk: MappedPDK, + enclosed_rectangle=(2.0, 4.0), + sdlayer: str = "p+s/d", + horizontal_glayer: str = "met2", + vertical_glayer: str = "met1", + sides: tuple[bool, bool, bool, bool] = (True, True, True, True), + with_lvt_layer=False, # New input variable +) -> Component: + """ptapring produce a p substrate / pwell tap rectanglular ring + This ring will legally enclose a rectangular shape + args: + pdk: MappedPDK is the pdk to use + enclosed_rectangle: tuple is the (width, hieght) of the area to enclose + ****NOTE: the enclosed_rectangle will be the enclosed dimensions of active_tap + horizontal_glayer: string=met2, layer used over the ring horizontally + vertical_glayer: string=met1, layer used over the ring vertically + sides: instead of creating the ring on all sides, only create it on the specified sides (W,N,E,S) + ports: + Narr_... all ports in top via array + Sarr_... all ports in bottom via array + Earr_... all ports in right via array + Warr_... all ports in left via array + bl_corner_...all ports in bottom left L route + """ + enclosed_rectangle = pdk.snap_to_2xgrid(enclosed_rectangle, return_type="float") + # check layers, activate pdk, create top cell + pdk.has_required_glayers( + [sdlayer, "active_tap", "mcon", horizontal_glayer, vertical_glayer] + ) + pdk.activate() + ptapring = Component() + if not "met" in horizontal_glayer or not "met" in vertical_glayer: + raise ValueError("both horizontal and vertical glayers should be metals") + # check that ring is not too small + min_gap_tap = pdk.get_grule("active_tap")["min_separation"] + if enclosed_rectangle[0] < min_gap_tap: + raise ValueError("ptapring must be larger than " + str(min_gap_tap)) + # create active tap + tap_width = max( + pdk.get_grule("active_tap")["min_width"], + 2 * pdk.get_grule("active_tap", "mcon")["min_enclosure"] + + pdk.get_grule("mcon")["width"], + ) + ptapring << rectangular_ring( + enclosed_size=enclosed_rectangle, + width=tap_width, + centered=True, + layer=pdk.get_glayer("active_tap"), + ) + # create p plus area + pp_enclosure = pdk.get_grule("active_tap", sdlayer)["min_enclosure"] + pp_width = 2 * pp_enclosure + tap_width + pp_enclosed_rectangle = [dim - 2 * pp_enclosure for dim in enclosed_rectangle] + ptapring << rectangular_ring( + enclosed_size=pp_enclosed_rectangle, + width=pp_width, + centered=True, + layer=pdk.get_glayer(sdlayer), + ) + + ########################################################################################################################################################### + # Create a LVT layer for LVT transistors from schematic design + if pdk is sky130: + # create 65/44 area + con = (65, 44) + ptapring << rectangular_ring( + enclosed_size=enclosed_rectangle, + width=tap_width, + centered=True, + layer=con, + ) + + if with_lvt_layer: + # create lvt area for nmos + lvt_layer = (125, 44) + ptapring << rectangle( + size=enclosed_rectangle, + centered=True, + layer=lvt_layer, + ) + ########################################################################################################################################################### + + # create via arrs + via_width_horizontal = evaluate_bbox( + via_stack(pdk, "active_tap", horizontal_glayer) + )[0] + arr_size_horizontal = enclosed_rectangle[0] + horizontal_arr = via_array( + pdk, + "active_tap", + horizontal_glayer, + (arr_size_horizontal, via_width_horizontal), + minus1=True, + lay_every_layer=True, + ) + # Create via vertical + via_width_vertical = evaluate_bbox(via_stack(pdk, "active_tap", vertical_glayer))[1] + arr_size_vertical = enclosed_rectangle[1] + vertical_arr = via_array( + pdk, + "active_tap", + vertical_glayer, + (via_width_vertical, arr_size_vertical), + minus1=True, + lay_every_layer=True, + ) + + # add via arrs + refs_prefixes = list() + if sides[1]: + metal_ref_n = ptapring << horizontal_arr + metal_ref_n.movey(round(0.5 * (enclosed_rectangle[1] + tap_width), 4)) + refs_prefixes.append((metal_ref_n, "N_")) + if sides[2]: + metal_ref_e = ptapring << vertical_arr + metal_ref_e.movex(round(0.5 * (enclosed_rectangle[0] + tap_width), 4)) + refs_prefixes.append((metal_ref_e, "E_")) + if sides[3]: + metal_ref_s = ptapring << horizontal_arr + metal_ref_s.movey(round(-0.5 * (enclosed_rectangle[1] + tap_width), 4)) + refs_prefixes.append((metal_ref_s, "S_")) + if sides[0]: + metal_ref_w = ptapring << vertical_arr + metal_ref_w.movex(round(-0.5 * (enclosed_rectangle[0] + tap_width), 4)) + refs_prefixes.append((metal_ref_w, "W_")) + # connect vertices + if sides[1] and sides[0]: + tlvia = ptapring << L_route( + pdk, metal_ref_n.ports["top_met_W"], metal_ref_w.ports["top_met_N"] + ) + refs_prefixes += [(tlvia, "tl_")] + if sides[1] and sides[2]: + trvia = ptapring << L_route( + pdk, metal_ref_n.ports["top_met_E"], metal_ref_e.ports["top_met_N"] + ) + refs_prefixes += [(trvia, "tr_")] + if sides[3] and sides[0]: + blvia = ptapring << L_route( + pdk, metal_ref_s.ports["top_met_W"], metal_ref_w.ports["top_met_S"] + ) + refs_prefixes += [(blvia, "bl_")] + if sides[3] and sides[2]: + brvia = ptapring << L_route( + pdk, metal_ref_s.ports["top_met_E"], metal_ref_e.ports["top_met_S"] + ) + refs_prefixes += [(brvia, "br_")] + # add ports, flatten and return + for ref_, prefix in refs_prefixes: + ptapring.add_ports(ref_.get_ports_list(), prefix=prefix) + return component_snap_to_grid(ptapring) + + +def __gen_fingers_macro( + pdk: MappedPDK, + rmult: int, + fingers: int, + length: float, + width: float, + poly_height: float, + sdlayer: str, + inter_finger_topmet: str, +) -> Component: + """internal use: returns an array of fingers""" + length = pdk.snap_to_2xgrid(length) + width = pdk.snap_to_2xgrid(width) + poly_height = pdk.snap_to_2xgrid(poly_height) + # sizing_ref_viastack = via_stack(pdk, "active_diff", "met1") This variable is not used + # figure out poly (gate) spacing: s/d metal doesnt overlap transistor, s/d min seperation criteria is met + sd_viaxdim = rmult * evaluate_bbox(via_stack(pdk, "active_diff", "met1"))[0] + poly_spacing = ( + 2 * pdk.get_grule("poly", "mcon")["min_separation"] + + pdk.get_grule("mcon")["width"] + ) + poly_spacing = max(sd_viaxdim, poly_spacing) + met1_minsep = pdk.get_grule("met1")["min_separation"] + poly_spacing += met1_minsep if length < met1_minsep else 0 + # create a single finger + finger = Component("finger") + gate = finger << rectangle( + size=(length, poly_height), layer=pdk.get_glayer("poly"), centered=True + ) + sd_viaarr = via_array( + pdk, + "active_diff", + "met1", + size=(sd_viaxdim, width), + minus1=True, + lay_bottom=False, + ).copy() + interfinger_correction = via_array( + pdk, + "met1", + inter_finger_topmet, + size=(None, width), + lay_every_layer=True, + num_vias=(1, None), + ) + + ########################################################################################################################################################### + sd_viaarr_ref = finger << sd_viaarr + sd_viaarr_ref_met_top = ( + finger << interfinger_correction + ) # Separate vias are added to save the ports of the inter_finger_topmetal metals. + sd_viaarr_ref_met_top.movex((poly_spacing + length) / 2) + sd_viaarr_ref.movex((poly_spacing + length) / 2) + finger.add_ports(gate.get_ports_list(), prefix="gate_") + finger.add_ports(sd_viaarr_ref.get_ports_list(), prefix="rightsd_") + finger.add_ports( + sd_viaarr_ref_met_top.get_ports_list(), prefix="rightsd_met_" + ) # Right inter_finger_topmet metal ports are saved + ########################################################################################################################################################### + + # create finger array + fingerarray = prec_array( + finger, + columns=fingers, + rows=1, + spacing=(poly_spacing + length, 1), + absolute_spacing=True, + ) + sd_via_ref_left = fingerarray << sd_viaarr + sd_via_ref_left_met_top = ( + fingerarray << interfinger_correction + ) # A separate via array is added to store the ports of the inter_finger_topmet metals. + sd_via_ref_left.movex(0 - (poly_spacing + length) / 2) + sd_via_ref_left_met_top.movex(0 - (poly_spacing + length) / 2) + fingerarray.add_ports(sd_via_ref_left.get_ports_list(), prefix="leftsd_") + fingerarray.add_ports( + sd_via_ref_left_met_top.get_ports_list(), prefix="leftsd_met_" + ) # Left inter_finger_topmet metal ports are saved + # center finger array and add ports + centered_farray = Component() + fingerarray_ref_center = prec_ref_center(fingerarray) + centered_farray.add(fingerarray_ref_center) + centered_farray.add_ports(fingerarray_ref_center.get_ports_list()) + # create diffusion and +doped region + multiplier = rename_ports_by_orientation(centered_farray) + diff_extra_enc = 2 * pdk.get_grule("mcon", "active_diff")["min_enclosure"] + diff_dims = (diff_extra_enc + evaluate_bbox(multiplier)[0], width) + diff = multiplier << rectangle( + size=diff_dims, layer=pdk.get_glayer("active_diff"), centered=True + ) + sd_diff_ovhg = pdk.get_grule(sdlayer, "active_diff")["min_enclosure"] + sdlayer_dims = [dim + 2 * sd_diff_ovhg for dim in diff_dims] + sdlayer_ref = multiplier << rectangle( + size=sdlayer_dims, layer=pdk.get_glayer(sdlayer), centered=True + ) + multiplier.add_ports(sdlayer_ref.get_ports_list(), prefix="plusdoped_") + multiplier.add_ports(diff.get_ports_list(), prefix="diff_") + + return component_snap_to_grid(rename_ports_by_orientation(multiplier)) + + +# drain is above source +def multiplier( + pdk: MappedPDK, + sdlayer: str, + width: Optional[float] = 3, + length: Optional[float] = None, + fingers: int = 1, + routing: bool = True, + inter_finger_topmet: str = "met2", + dummy: Union[bool, tuple[bool, bool]] = True, + sd_route_topmet: str = "met2", + gate_route_topmet: str = "met2", + rmult: Optional[int] = None, + sd_rmult: int = 1, + gate_rmult: int = 1, + interfinger_rmult: int = 1, + sd_route_extension: float = 0, + gate_route_extension: float = 0, + dummy_routes: bool = True, + gate_up: Optional[bool] = False, + gate_down: Optional[bool] = False, +) -> Component: + """Generic poly/sd vias generator + args: + pdk = pdk to use + sdlayer = either p+s/d for pmos or n+s/d for nmos + width = expands the transistor in the y direction + length = transitor length (if left None defaults to min length) + fingers = introduces additional fingers (sharing s/d) of width=width + routing = true or false, specfies if sd should be connected + inter_finger_topmet = top metal of the via array laid on the source/drain regions + ****NOTE: routing metal is layed over the source drain regions regardless of routing option + dummy = true or false add dummy active/plus doped regions + sd_rmult = multiplies thickness of sd metal (int only) + gate_rmult = multiplies gate by adding rows to the gate via array (int only) + interfinger_rmult = multiplies thickness of source/drain routes between the gates (int only) + sd_route_extension = float, how far extra to extend the source/drain connections (default=0) + gate_route_extension = float, how far extra to extend the gate connection (default=0) + dummy_routes: bool default=True, if true add add vias and short dummy poly,source,drain + + ports (one port for each edge), + ****NOTE: source is below drain: + gate_... all edges (top met route of gate connection) + source_...all edges (top met route of source connections) + drain_...all edges (top met route of drain connections) + plusdoped_...all edges (area of p+s/d or n+s/d layer) + diff_...all edges (diffusion region) + rowx_coly_...all ports associated with finger array include gate_... and array_ (array includes all ports of the viastacks in the array) + leftsd_...all ports associated with the left most via array + dummy_L,R_N,E,S,W ports if dummy_routes=True + """ + # error checking + if "+s/d" not in sdlayer: + raise ValueError("specify + doped region for multiplier") + if not "met" in sd_route_topmet or not "met" in gate_route_topmet: + raise ValueError("topmet specified must be metal layer") + if rmult: + if rmult < 1: + raise ValueError("rmult must be positive int") + sd_rmult = rmult + gate_rmult = 1 + interfinger_rmult = (rmult - 1) or 1 + if sd_rmult < 1 or interfinger_rmult < 1 or gate_rmult < 1: + raise ValueError("routing multipliers must be positive int") + if fingers < 1: + raise ValueError("number of fingers must be positive int") + + ########################################################################################################################################################### + # Conditions to avoid double overlapping or duplication of gates in dummies + if gate_up and gate_down: + raise ValueError("Gate up and Down can't be at the same time") + if routing and (gate_down or gate_up): + raise ValueError("Gate up and Down can't be used with routing") + ########################################################################################################################################################### + + # argument parsing and rule setup + min_length = pdk.get_grule("poly")["min_width"] + length = min_length if (length or min_length) <= min_length else length + length = pdk.snap_to_2xgrid(length) + min_width = max(min_length, pdk.get_grule("active_diff")["min_width"]) + width = min_width if (width or min_width) <= min_width else width + width = pdk.snap_to_2xgrid(width) + poly_height = width + 2 * pdk.get_grule("poly", "active_diff")["overhang"] + # call finger array + multiplier = __gen_fingers_macro( + pdk, + interfinger_rmult, + fingers, + length, + width, + poly_height, + sdlayer, + inter_finger_topmet, + ) + # route all drains/ gates/ sources + if routing: + # place vias, then straight route from top port to via-botmet_N + sd_N_port = multiplier.ports["leftsd_top_met_N"] + sdvia = via_stack(pdk, "met1", sd_route_topmet) + sdmet_hieght = sd_rmult * evaluate_bbox(sdvia)[1] + sdroute_minsep = pdk.get_grule(sd_route_topmet)["min_separation"] + sdvia_ports = list() + for finger in range(fingers + 1): + diff_top_port = movey(sd_N_port, destination=width / 2) + # place sdvia such that metal does not overlap diffusion + big_extension = sdroute_minsep + sdmet_hieght / 2 + sdmet_hieght + sdvia_extension = big_extension if finger % 2 else sdmet_hieght / 2 + sdvia_ref = align_comp_to_port(sdvia, diff_top_port, alignment=("c", "t")) + multiplier.add( + sdvia_ref.movey( + sdvia_extension + pdk.snap_to_2xgrid(sd_route_extension) + ) + ) + multiplier << straight_route( + pdk, diff_top_port, sdvia_ref.ports["bottom_met_N"] + ) + sdvia_ports += [sdvia_ref.ports["top_met_W"], sdvia_ref.ports["top_met_E"]] + # get the next port (break before this if last iteration because port D.N.E. and num gates=fingers) + if finger == fingers: + break + sd_N_port = multiplier.ports[f"row0_col{finger}_rightsd_top_met_N"] + # route gates + gate_S_port = multiplier.ports[f"row0_col{finger}_gate_S"] + metal_seperation = pdk.util_max_metal_seperation() + psuedo_Ngateroute = movey( + gate_S_port.copy(), 0 - metal_seperation - gate_route_extension + ) + psuedo_Ngateroute.y = pdk.snap_to_2xgrid(psuedo_Ngateroute.y) + multiplier << straight_route(pdk, gate_S_port, psuedo_Ngateroute) + # place route met: gate + gate_width = ( + gate_S_port.center[0] + - multiplier.ports["row0_col0_gate_S"].center[0] + + gate_S_port.width + ) + gate = rename_ports_by_list( + via_array( + pdk, + "poly", + gate_route_topmet, + size=(gate_width, None), + num_vias=(None, gate_rmult), + no_exception=True, + fullbottom=True, + ), + [("top_met_", "gate_")], + ) + gate_ref = align_comp_to_port( + gate.copy(), + psuedo_Ngateroute, + alignment=(None, "b"), + layer=pdk.get_glayer("poly"), + ) + multiplier.add(gate_ref) + # place route met: source, drain + sd_width = sdvia_ports[-1].center[0] - sdvia_ports[0].center[0] + sd_route = rectangle( + size=(sd_width, sdmet_hieght), + layer=pdk.get_glayer(sd_route_topmet), + centered=True, + ) + source = align_comp_to_port( + sd_route.copy(), sdvia_ports[0], alignment=(None, "c") + ) + drain = align_comp_to_port( + sd_route.copy(), sdvia_ports[2], alignment=(None, "c") + ) + multiplier.add(source) + multiplier.add(drain) + # add ports + multiplier.add_ports(drain.get_ports_list(), prefix="drain_") + multiplier.add_ports(source.get_ports_list(), prefix="source_") + multiplier.add_ports(gate_ref.get_ports_list(prefix="gate_")) + + ########################################################################################################################################################### + # Added the option to place the gate above or below the component along with its connection ports as long as routing = False. + if gate_down: + for finger in range(fingers): + gate_S_port = multiplier.ports[f"row0_col{finger}_gate_S"] + metal_seperation = pdk.util_max_metal_seperation() + psuedo_Ngateroute = movey( + gate_S_port.copy(), 0 - metal_seperation - gate_route_extension + ) + psuedo_Ngateroute.y = pdk.snap_to_2xgrid(psuedo_Ngateroute.y) + multiplier << straight_route(pdk, gate_S_port, psuedo_Ngateroute) + gate_width = ( + gate_S_port.center[0] + - multiplier.ports["row0_col0_gate_S"].center[0] + + gate_S_port.width + ) + gate = rename_ports_by_list( + via_array( + pdk, + "poly", + gate_route_topmet, + size=(gate_width, None), + num_vias=(None, gate_rmult), + no_exception=True, + fullbottom=True, + ), + [("top_met_", "gate_")], + ) + gate_ref = align_comp_to_port( + gate.copy(), + psuedo_Ngateroute, + alignment=(None, "b"), + layer=pdk.get_glayer("poly"), + ) + multiplier.add(gate_ref) + multiplier.add_ports(gate_ref.get_ports_list(prefix="gate_")) + elif gate_up: + for finger in range(fingers): + gate_N_port = multiplier.ports[f"row0_col{finger}_gate_N"] + metal_seperation = pdk.util_max_metal_seperation() + psuedo_Ngateroute = movey( + gate_N_port.copy(), 0 + metal_seperation + gate_route_extension + ) + psuedo_Ngateroute.y = pdk.snap_to_2xgrid(psuedo_Ngateroute.y) + multiplier << straight_route(pdk, gate_N_port, psuedo_Ngateroute) + gate_width = ( + gate_N_port.center[0] + - multiplier.ports["row0_col0_gate_N"].center[0] + + gate_N_port.width + ) + gate = rename_ports_by_list( + via_array( + pdk, + "poly", + gate_route_topmet, + size=(gate_width, None), + num_vias=(None, gate_rmult), + no_exception=True, + fullbottom=True, + ), + [("top_met_", "gate_")], + ) + gate_ref = align_comp_to_port( + gate.copy(), + psuedo_Ngateroute, + alignment=(None, "t"), + layer=pdk.get_glayer("poly"), + ) + multiplier.add(gate_ref) + multiplier.add_ports(gate_ref.get_ports_list(prefix="gate_")) + ########################################################################################################################################################### + + # create dummy regions + if isinstance(dummy, bool): + dummyl = dummyr = dummy + else: + dummyl, dummyr = dummy + if dummyl or dummyr: + dummy = __gen_fingers_macro( + pdk, + rmult=interfinger_rmult, + fingers=1, + length=length, + width=width, + poly_height=poly_height, + sdlayer=sdlayer, + inter_finger_topmet="met1", + ) + dummyvia = dummy << via_stack(pdk, "poly", "met1", fullbottom=True) + align_comp_to_port( + dummyvia, dummy.ports["row0_col0_gate_S"], layer=pdk.get_glayer("poly") + ) + dummy << L_route( + pdk, dummyvia.ports["top_met_W"], dummy.ports["leftsd_top_met_S"] + ) + dummy << L_route( + pdk, dummyvia.ports["top_met_E"], dummy.ports["row0_col0_rightsd_top_met_S"] + ) + dummy.add_ports(dummyvia.get_ports_list(), prefix="gsdcon_") + dummy_space = pdk.get_grule(sdlayer)["min_separation"] + dummy.xmax + sides = list() + if dummyl: + sides.append((-1, "dummy_L_")) + if dummyr: + sides.append((1, "dummy_R_")) + for side, name in sides: + dummy_ref = multiplier << dummy + dummy_ref.movex(side * (dummy_space + multiplier.xmax)) + multiplier.add_ports(dummy_ref.get_ports_list(), prefix=name) + return component_snap_to_grid(rename_ports_by_orientation(multiplier)) + + +def layer_pin_and_label(pdk:MappedPDK, metal: str, label_or_pin: str): + if not "met" in metal: + raise ValueError("layer must be a metal") + if label_or_pin not in ["label", "pin"]: + raise ValueError("label_or_pin must be 'label' or 'pin'") + + if pdk is sky130: + diccionario_label = { + "met1": (67, 5), + "met2": (68, 5), + "met3": (69, 5), + "met4": (70, 5), + "met5": (71, 5), + } + diccionario_pin = { + "met1": (67, 16), + "met2": (68, 16), + "met3": (69, 16), + "met4": (70, 16), + "met5": (71, 16), + } + + elif pdk is gf180: + diccionario_label = { + "met1": (34, 10), + "met2": (36, 10), + "met3": (42, 10), + "met4": (46, 10), + "met5": (81, 10), + } + diccionario_pin = { + "met1": (67, 16), + "met2": (68, 16), + "met3": (69, 16), + "met4": (70, 16), + "met5": (71, 16), + } + if label_or_pin == "label": + layer = diccionario_label[metal] + else: + layer = diccionario_pin[metal] + return layer + + +def pin_label_creation(pdk:MappedPDK, pin, label, met, componente, signal: bool = False): + # Obtengo el ancho del port en x e y + x_size = componente.ports[pin + "_N"].width + y_size = componente.ports[pin + "_W"].width + label_met = layer_pin_and_label(pdk, met, "label") + pin_met = layer_pin_and_label(pdk, met, "pin") + # Obtengo la posicion central del port + pos = [ + componente.ports[pin + "_N"].center[0], + componente.ports[pin + "_E"].center[1], + ] + # Calculo el centro del rectangulo con la layer del pian a agregar + center = [pos[0] - y_size / 2, pos[1] - y_size / 2] + # Creo el rectangulo para pin + if pdk is sky130: + pin_rectangle = rectangle(size=(y_size, y_size), layer=pin_met) + # Agrego el pin y lo centro + pin_t = componente << pin_rectangle + pl = pin_t.bbox + offset = -pl[0] + pin_t.move(destination=offset) + # Lo ubico a la posicion final calculada + pin_t.movey(center[1]).movex(center[0]) + # Agrego los ports al componente + componente.add_ports(pin_t.get_ports_list(), prefix=label + "_") + # Agrego el label segun el metal + componente.add_label(label, position=(pos[0], pos[1]), layer=label_met) + if signal: + print(f"Pin {pin} and label {label} created on component with metal {met}.") + + +def filtrar_puertos( + componente_original, + componente_filtrado, + filtro, + port_name: Optional[str] = None, + signal: bool = False, +): + if port_name is None: + port_name = filtro + all_ports = componente_original.ports + buscar_w = filtro + "W" + buscar_e = filtro + "E" + buscar_n = filtro + "N" + buscar_s = filtro + "S" + if buscar_w not in all_ports: + raise ValueError(f"Port not found") + selected_ports = { + name: port + for name, port in all_ports.items() + if buscar_w in name or buscar_e in name or buscar_n in name or buscar_s in name + } # Ejemplo: solo los que tienen 'in' en su nombre + for name_original, port in selected_ports.items(): + new_name = port_name + name_original[-1] # Add prefix + componente_filtrado.add_port( + new_name, + port.center, + port.width, + port.orientation, + layer=port.layer, + port_type="electrical", + ) + if signal: + print(f"Port {port_name} filtered and added to the component.") + + +def center_component_with_ports(component: Component) -> Component: + centered = Component() + ref = centered << component + + # Calcular el desplazamiento necesario para centrar + dx, dy = -component.center[0], -component.center[1] + ref.move((dx, dy)) # Mueve la referencia al centro + + # Transformar y añadir los puertos + for port in component.get_ports_list(): + new_port = port.copy() + new_port.center = (port.center[0] + dx, port.center[1] + dy) + centered.add_port(name=port.name, port=new_port) + + return centered + + +def Boundary_layer(pdk:MappedPDK, componente=Component(), layer=(235, 4)) -> Component: + if pdk is sky130: + layer=(235, 4) + elif pdk is gf180: + layer=(63,0) + dimension = evaluate_bbox(componente) + rectangle_boundary = rectangle( + (dimension[0], dimension[1]), layer=layer, centered=True + ) + rect_ref = componente << rectangle_boundary + return rect_ref + + +def rails( + pdk, + component: Component, + width: float, + route_list: Optional[list] = None, + specific_rail: Optional[list] = None, +) -> Component: + + if specific_rail != None: + for info in specific_rail: + if len(info) > 2: + raise ValueError( + "Each component must be conformed by rail label and rail number (left to right)" + ) + size_component = evaluate_bbox(component) + rectangle_ref = rectangle( + (width, size_component[1]), layer=pdk.get_glayer("met5"), centered=True + ) + min_separation_met5 = pdk.get_grule("met5")["min_separation"] + L = size_component[0] + W = width + s_min = min_separation_met5 if W < min_separation_met5 else W / 2 + separation = W + n = 1 + while True: + s_n = (L - (2 * n + 1) * W) / (2 * n) + if s_n < s_min: + n -= 1 + break + if s_n < separation: + separation = s_n + n += 1 + n_rectangles = n * 2 + 1 + space = separation + width + carril = list() + rail_list = list() + prefix_list = list() + Available_space = dict() + if specific_rail is not None: + Available_space = {item[0]: [] for item in specific_rail} + Available_space["VSS"] = [] + Available_space["VDD"] = [] + for i in range(n_rectangles): + carril.append(component << rectangle_ref) + carril[-1].movex(pdk.snap_to_2xgrid(-size_component[0] / 2 + width / 2)) + carril[-1].movex(pdk.snap_to_2xgrid(space * i)) + prefijo = None + if specific_rail != None: + for rail_info in specific_rail: + for rail in rail_info[1]: + if i + 1 == rail: + prefijo = rail_info[0] + "_" + str(i + 1) + "_" + prefijo_label = rail_info[0] + rail_list.append(rail_info[0]) + break + if prefijo is None: + if i % 2 == 0: + prefijo = "VSS_" + str(i + 1) + "_" + prefijo_label = 'VSS' + rail_list.append("VSS") + else: + prefijo = "VDD_" + str(i + 1) + "_" + prefijo_label = 'VDD' + rail_list.append("VDD") + prefix_list.append(prefijo) + component.add_ports(carril[-1].ports, prefix=prefijo) + component = rename_ports_by_orientation(component) + pin_label_creation(pdk, prefijo[0:-1], prefijo_label, 'met5', component) + + ports = [ + name + for name in component.ports + if "Ref1_B_drain_T" in name or "Ref1_B_source_T" in name + ] + #print(ports) + # Available spaces + for i in range(len(rail_list)): + Available_space[rail_list[i]].append( + [ + component.ports[prefix_list[i] + "W"].center[0], + component.ports[prefix_list[i] + "E"].center[0], + ] + ) + + # Via conection + via_ref = via_stack(pdk, "met4", "met5") + min_separation_via5 = pdk.get_grule("via4")["min_separation"] + separation = evaluate_bbox(via_ref)[0] + min_separation_via5 + for route in route_list: + if (len(route)) != 2: + raise ValueError( + "Each route must be conformed by a port name and a rail name" + ) + if route[1] not in Available_space: + raise ValueError("The rail name must be in the specific rail list") + port_E = route[0] + "E" + port_W = route[0] + "W" + # ports = [name for name in component.ports if 'Ref1_A_drain_T' in name] + # print(ports) + range_ports_available = [ + component.ports[port_W].center[0], + component.ports[port_E].center[0], + ] + space_available = abs(range_ports_available[1] - range_ports_available[0]) + if space_available < separation: + raise ValueError("There is not enough space to add the via") + n_vias = int(space_available // separation) + vias = list() + for i in range(n_vias): + movement_x = range_ports_available[0] + separation / 2 + separation * i + movement_y = component.ports[port_W].center[1] + for j in range(len(Available_space[route[1]])): + if ( + Available_space[route[1]][j][0] + evaluate_bbox(via_ref)[0] / 2 + < movement_x + < Available_space[route[1]][j][1] - evaluate_bbox(via_ref)[0] / 2 + ): + vias.append(component << via_ref) + vias[-1].movex(movement_x).movey(movement_y) + # component.add_ports(vias[-1].ports, prefix=route[0]+'_via_') + break diff --git a/blocks/composite/folded_cascode/glayout/primitives.py b/blocks/composite/folded_cascode/glayout/primitives.py new file mode 100644 index 00000000..d44dadad --- /dev/null +++ b/blocks/composite/folded_cascode/glayout/primitives.py @@ -0,0 +1,719 @@ +# Numerical functions +from decimal import Decimal +from typing import Literal, Optional, Union + +# PDK functions + +from glayout import MappedPDK, sky130, gf180 + + +from gdsfactory.component import Component, copy + +# Import custom functions (Matrix generator) +from custom_functions import macro_two_transistor_placement_Onchip +from custom_functions import pin_label_creation +from custom_functions import filtrar_puertos +from custom_functions import center_component_with_ports + +# Glayout tools + +from glayout.util.comp_utils import ( + align_comp_to_port, + evaluate_bbox, + movex, + movey, + prec_ref_center, + prec_array, +) + +from glayout.util.port_utils import ( + add_ports_perimeter, + get_orientation, + print_ports, + rename_ports_by_list, + rename_ports_by_orientation, + set_port_orientation, +) + +from glayout.util.snap_to_grid import component_snap_to_grid + +# Routing functions +from glayout import via_stack +from glayout.routing import c_route, L_route, straight_route + +# Porting functions +from gdsfactory.functions import transformed + + +#### 1ST LEVEL PRIMITIVES #### + +### Mirror primitive ### + +def mirror(pdk: MappedPDK, devices_info, matrix, with_pin: int = 0) -> Component: + mirror = Component() + """" + pdk = pdk to use + devices_info = the devices to place, usually formed as an array with all the information + matrix = A full matrix with the placement organization + with_pin = Makes the primitive have pins which don't have any electrical purpose + + Mirror primitive, can be used in its NMOS version or PMOS + """ + # Matrix placement + + config = macro_two_transistor_placement_Onchip(pdk=pdk, deviceA_and_B=devices_info['type'], with_substrate_tap=devices_info['with_substrate_tap'], + with_tie=devices_info['with_tie'], width1=devices_info['width'], length1=devices_info['length'], + fingers1=devices_info['fingers'], matriz=matrix, with_dummy=devices_info['with_dummy'], + width_route_mult=devices_info['width_route_mult'], with_lvt_layer=devices_info['lvt']) + + matrix = mirror << config + mirror.add_ports(matrix.get_ports_list()) + + # Evaluate the dimensions + ################################ + size_component = evaluate_bbox(matrix) + + # Routing + ##################### + + # Gate to Gate (A -> B) + route_Gate = mirror << straight_route(pdk, matrix.ports['A_gate_E'], matrix.ports['B_gate_W']) + + # Source to Source (A -> B) + route_Src = mirror << L_route(pdk, matrix.ports['A_source_N'], matrix.ports['B_source_E']) + + # Gate to Drain (A -> A (B)) + route_gate_drain_A = mirror << L_route(pdk, matrix.ports['A_gate_S'], matrix.ports['A_drain_W']) + + # Bulk routing (Neglecting Body Effect) + route_bulk_1 = mirror << straight_route(pdk, matrix.ports['A_source_N'], matrix.ports['bulk_down_S'], glayer1='met3', glayer2='met3') + route_bulk_2 = mirror << straight_route(pdk, matrix.ports['B_source_N'], matrix.ports['bulk_down_S'], glayer1='met3', glayer2='met3') + + ## External o Internal device + + if with_pin == 1: + # Pin creation + pin_label_creation('A_drain', 'V_REF', 'met3', mirror) + pin_label_creation('B_drain', 'V_OUT', 'met3', mirror) + pin_label_creation('B_source', 'VS', 'met3', mirror) + pin_label_creation('A_gate', 'VB', 'met3', mirror) + + + + component = Component() + component << mirror + + filtrar_puertos(mirror, component, 'A_drain_', 'V_REF_') + filtrar_puertos(mirror, component, 'B_drain_', 'V_OUT_') + filtrar_puertos(mirror, component, 'B_source_', 'VS_') + filtrar_puertos(mirror, component, 'A_gate_', 'VB_') + + return component + +### Single transistor primitive ### + +def transistor(pdk, devices_info, matrix, with_pin: int = 0, with_b_effect: int = 0) -> Component: + transistor = Component() + """" + pdk = pdk to use + devices_info = The devices to place, usually formed as an array with all the information + matrix = A full matrix with the placement organization + with_pin = Makes the primitive have pins which don't have any electrical purpose + with_b_effect = Allows to have or not to have a bulk port + + Transistor primitive, can be used in its NMOS version or PMOS, it already neglects the body effect + """ + #Matrix placement + + config = macro_two_transistor_placement_Onchip(pdk=pdk, deviceA_and_B=devices_info['type'], with_substrate_tap=devices_info['with_substrate_tap'], + with_tie=devices_info['with_tie'], width1=devices_info['width'], length1=devices_info['length'], + fingers1=devices_info['fingers'], matriz=matrix, with_dummy=devices_info['with_dummy'], + width_route_mult=devices_info['width_route_mult'], with_lvt_layer=devices_info['lvt']) + + matrix = transistor << config + transistor.add_ports(matrix.get_ports_list()) + + # Evaluate the dimensions + ################################ + size_component = evaluate_bbox(matrix) + + # Routing + ##################### + + if with_b_effect == 0: + + # Bulk routing (Neglecting Body Effect) + via_ref = via_stack(pdk, 'met2', 'met3') + + via_bulk = transistor << via_ref + via_bulk.movex(matrix.ports['A_source_N'].center[0]).movey(matrix.ports['bulk_down_E'].center[1]) + + route_bulk_1 = transistor << straight_route(pdk, matrix.ports['A_source_S'], via_bulk.ports['top_met_N']) + + ## External o Internal device + + if with_pin == 1: + + #Pin creation + pin_label_creation('A_drain', 'VD', 'met3', transistor) + pin_label_creation('A_gate', 'VG', 'met3', transistor) + pin_label_creation('A_source', 'VS', 'met3', transistor) + + + + component = Component() + component << transistor + + filtrar_puertos(transistor, component, 'A_drain_', 'VD_') + filtrar_puertos(transistor, component, 'A_gate_', 'VG_') + filtrar_puertos(transistor, component, 'A_source_', 'VS_') + filtrar_puertos(transistor, component, 'bulk_down_', 'VBC_D_') + filtrar_puertos(transistor, component, 'bulk_up_', 'VBC_U_') + + if with_b_effect == 1: + if with_pin == 1: + + ## External o Internal device + + #Pin creation + pin_label_creation('A_drain', 'VD', 'met3', transistor) + pin_label_creation('A_gate', 'VG', 'met3', transistor) + pin_label_creation('A_source', 'VS', 'met3', transistor) + pin_label_creation('bulk_down', 'VB', 'met3', transistor) + + + + component = Component() + component << transistor + + filtrar_puertos(transistor, component, 'A_drain_', 'VD_') + filtrar_puertos(transistor, component, 'A_gate_', 'VG_') + filtrar_puertos(transistor, component, 'A_source_', 'VS_') + filtrar_puertos(transistor, component, 'bulk_down_', 'VBC_D_') + filtrar_puertos(transistor, component, 'bulk_up_', 'VBC_U_') + + return component + +### Single transistor diode primitive ### + +def diode(pdk, devices_info, matrix, with_pin: int = 0) -> Component: + diode = Component() + """" + pdk = pdk to use + devices_info = The devices to place, usually formed as an array with all the information + matrix = A full matrix with the placement organization + with_pin = Makes the primitive have pins which don't have any electrical purpose + + Diode primitive, can be used in its NMOS version or PMOS + """ + #Matrix placement + + config = macro_two_transistor_placement_Onchip(pdk=pdk, deviceA_and_B=devices_info['type'], with_substrate_tap=devices_info['with_substrate_tap'], + with_tie=devices_info['with_tie'], width1=devices_info['width'], length1=devices_info['length'], + fingers1=devices_info['fingers'], matriz=matrix, with_dummy=devices_info['with_dummy'], + width_route_mult=devices_info['width_route_mult'], with_lvt_layer=devices_info['lvt']) + matrix = diode << config + diode.add_ports(matrix.get_ports_list()) + + # Evaluate the dimensions + ################################ + size_component = evaluate_bbox(matrix) + + # Routing + ##################### + + # Gate to Drain (A -> A) + route_gate_drain_A = diode << L_route(pdk, matrix.ports['A_gate_S'], matrix.ports['A_drain_W']) + + # Bulk routing (Neglecting Body Effect) + route_bulk_1 = diode << straight_route(pdk, matrix.ports['A_source_N'], matrix.ports['bulk_down_S'], glayer1='met3', glayer2='met3') + + if with_pin == 1: + #Pin creation + pin_label_creation('A_drain', 'VD', 'met3', diode) + pin_label_creation('A_source', 'VS', 'met3', diode) + + + component = Component() + component << diode + + filtrar_puertos(diode, component, 'A_drain_', 'VD_') + filtrar_puertos(diode, component, 'A_source_', 'VS_') + + return component + +### Current source primitive ### + +def current_source(pdk,devices_info,matrix, with_pin: int = 0, with_b_effect: int = 0) -> Component: + """" + pdk = pdk to use + devices_info = The devices to place, usually formed as an array with all the information + matrix = A full matrix with the placement organization + with_pin = Makes the primitive have pins which don't have any electrical purpose + with_b_effect = Allows to have or not to have a bulk port + + Current source primitive, can be used in its NMOS version or PMOS + """ + current_source = Component() + + #Matrix placement + config = macro_two_transistor_placement_Onchip(pdk=pdk, deviceA_and_B=devices_info['type'], with_substrate_tap=devices_info['with_substrate_tap'], + with_tie=devices_info['with_tie'], width1=devices_info['width'], length1=devices_info['length'], + fingers1=devices_info['fingers'], matriz=matrix, with_dummy=devices_info['with_dummy'], + width_route_mult=devices_info['width_route_mult'], with_lvt_layer=devices_info['lvt']) + matrix = current_source << config + current_source.add_ports(matrix.get_ports_list()) + + # Evaluate the dimensions + ################################ + size_component = evaluate_bbox(matrix) + + # Routing + ##################### + + #Gate routing (Gate (A) -> Gate (B)) + route_Gate = current_source << straight_route(pdk, matrix.ports['A_gate_E'], matrix.ports['B_gate_W']) + + if with_b_effect == 0: + + # Bulk routing (Neglecting Body Effect) + via_ref = via_stack(pdk, 'met2', 'met3') + + via_A_bulk = current_source << via_ref + via_A_bulk.movex(matrix.ports['A_source_N'].center[0]).movey(matrix.ports['bulk_down_E'].center[1]) + + via_B_bulk = current_source << via_ref + via_B_bulk.movex(matrix.ports['B_source_N'].center[0]).movey(matrix.ports['bulk_down_E'].center[1]) + + Route_bulk_1 = current_source << straight_route(pdk, matrix.ports['A_source_N'], via_A_bulk.ports['top_met_N']) + Route_bulk_2 = current_source << straight_route(pdk, matrix.ports['B_source_N'], via_B_bulk.ports['top_met_N']) + + ## External o Internal device + + if with_pin == 1: + #Pin creation + pin_label_creation('A_gate', 'VBIAS', 'met3', current_source) + pin_label_creation('B_gate', 'VBIAS2', 'met3', current_source) + pin_label_creation('A_source', 'VS1', 'met3', current_source) + pin_label_creation('B_source', 'VS2', 'met3', current_source) + pin_label_creation('A_drain', 'VD1', 'met3', current_source) + pin_label_creation('B_drain', 'VD2', 'met3', current_source) + pin_label_creation('bulk_up', 'VBC_U', 'met3',current_source) + pin_label_creation('bulk_down', 'VBC_D', 'met3',current_source) + + + component = Component() + component << current_source + + filtrar_puertos(current_source, component, 'A_gate_', 'VBIAS_') + filtrar_puertos(current_source, component, 'B_gate_', 'VBIAS2_') + filtrar_puertos(current_source, component, 'A_source_', 'VS1_') + filtrar_puertos(current_source, component, 'B_source_', 'VS2_') + filtrar_puertos(current_source, component, 'A_drain_', 'VD1_') + filtrar_puertos(current_source, component, 'B_drain_', 'VD2_') + filtrar_puertos(current_source, component, 'bulk_up_', 'VBC_U_') + filtrar_puertos(current_source, component, 'bulk_down_', 'VBC_D_') + + if with_b_effect == 1: + + ## External o Internal device + + if with_pin == 1: + #Pin creation + pin_label_creation('A_gate', 'VBIAS', 'met3', current_source) + pin_label_creation('B_gate', 'VBIAS2', 'met3', current_source) + pin_label_creation('A_source', 'VS1', 'met3', current_source) + pin_label_creation('B_source', 'VS2', 'met3', current_source) + pin_label_creation('A_drain', 'VD1', 'met3', current_source) + pin_label_creation('B_drain', 'VD2', 'met3', current_source) + pin_label_creation('bulk_down', 'VB', 'met3', current_source) + + + component = Component() + component << current_source + + filtrar_puertos(current_source, component, 'A_gate_', 'VBIAS_') + filtrar_puertos(current_source, component, 'B_gate_', 'VBIAS2_') + filtrar_puertos(current_source, component, 'A_source_', 'VS1_') + filtrar_puertos(current_source, component, 'B_source_', 'VS2_') + filtrar_puertos(current_source, component, 'A_drain_', 'VD1_') + filtrar_puertos(current_source, component, 'B_drain_', 'VD2_') + filtrar_puertos(current_source, component, 'bulk_down_', 'VBC_D_') + filtrar_puertos(current_source, component, 'bulk_up_', 'VBC_U_') + + return component + +### Differential pair ### + +def differential_pair(pdk,devices_info,matrix, with_pin: int = 0, with_b_effect: int = 0) -> Component: + """" + pdk = pdk to use + devices_info = The devices to place, usually formed as an array with all the information + matrix = A full matrix with the placement organization + with_pin = Makes the primitive have pins which don't have any electrical purpose + with_b_effect = Allows to have or not to have a bulk port + + Differential pair primitive, can be used in its NMOS version or PMOS + """ + differential_pair = Component() + + #Matrix placement + config = macro_two_transistor_placement_Onchip(pdk=pdk, deviceA_and_B=devices_info['type'], with_substrate_tap=devices_info['with_substrate_tap'], + with_tie=devices_info['with_tie'], width1=devices_info['width'], length1=devices_info['length'], + fingers1=devices_info['fingers'], matriz=matrix, with_dummy=devices_info['with_dummy'], + width_route_mult=devices_info['width_route_mult'], with_lvt_layer=devices_info['lvt']) + matrix = differential_pair << config + differential_pair.add_ports(matrix.get_ports_list()) + + # Evaluate the dimensions + ################################ + size_component = evaluate_bbox(matrix) + + # Routing + ##################### + + #Routing from Source(A -> B) + route_source_A_source_B = differential_pair << L_route(pdk, matrix.ports['A_source_N'], matrix.ports['B_source_E']) + + if with_b_effect == 0: + # Bulk routing (Neglecting Body Effect) + via_ref = via_stack(pdk, 'met2', 'met3') + + via_A_bulk = differential_pair << via_ref + via_A_bulk.movex(matrix.ports['A_source_N'].center[0]).movey(matrix.ports['bulk_down_E'].center[1]) + + via_B_bulk = differential_pair << via_ref + via_B_bulk.movex(matrix.ports['B_source_N'].center[0]).movey(matrix.ports['bulk_down_E'].center[1]) + + ruta_bulk_1 = differential_pair << straight_route(pdk, matrix.ports['A_source_S'], via_A_bulk.ports['top_met_N']) + ruta_bulk_2 = differential_pair << straight_route(pdk, matrix.ports['B_source_S'], via_B_bulk.ports['top_met_N']) + + ## External o Internal device + + if with_pin == 1: + #Pin creation + pin_label_creation('A_gate', 'VGP', 'met3', differential_pair) + pin_label_creation('B_gate', 'VGN', 'met3', differential_pair) + pin_label_creation('A_source', 'VS', 'met3', differential_pair) + pin_label_creation('A_drain', 'VD1', 'met3', differential_pair) + pin_label_creation('B_drain', 'VD2', 'met3', differential_pair) + + + + component = Component() + component << differential_pair + filtrar_puertos(differential_pair, component, 'A_gate_', 'VGP_') + filtrar_puertos(differential_pair, component, 'B_gate_', 'VGN_') + filtrar_puertos(differential_pair, component, 'B_source_', 'VS_') + filtrar_puertos(differential_pair, component, 'A_drain_', 'VD1_') + filtrar_puertos(differential_pair, component, 'B_drain_', 'VD2_') + filtrar_puertos(differential_pair, component, 'bulk_down_', 'VBC_D_') + filtrar_puertos(differential_pair, component, 'bulk_up_', 'VBC_U_') + + if with_b_effect == 1: + + ## External o Internal device + + if with_pin == 1: + #Pin creation + pin_label_creation('A_gate', 'VGP', 'met3', differential_pair) + pin_label_creation('B_gate', 'VGN', 'met3', differential_pair) + pin_label_creation('A_source', 'VS', 'met3', differential_pair) + pin_label_creation('A_drain', 'VD1', 'met3', differential_pair) + pin_label_creation('B_drain', 'VD2', 'met3', differential_pair) + pin_label_creation('bulk_down', 'VB', 'met3', differential_pair) + + + + component = Component() + component << differential_pair + filtrar_puertos(differential_pair, component, 'A_gate_', 'VGP_') + filtrar_puertos(differential_pair, component, 'B_gate_', 'VGN_') + filtrar_puertos(differential_pair, component, 'B_source_', 'VS_') + filtrar_puertos(differential_pair, component, 'A_drain_', 'VD1_') + filtrar_puertos(differential_pair, component, 'B_drain_', 'VD2_') + filtrar_puertos(differential_pair, component, 'bulk_down_', 'VBC_D_') + filtrar_puertos(differential_pair, component, 'bulk_up_', 'VBC_U_') + + + return component + +#### 2ND LEVEL PRIMITIVES #### + +### Cascode ### + +def Cascode(pdk, devices_info, array, with_pin: int = 0) -> Component: + """" + pdk = pdk to use + devices_info = The devices to place, usually formed as an array with all the information + array = A full matrix with the placement organization + with_pin = Makes the primitive have pins which don't have any electrical purpose + + Cascode primitive, can be used in its NMOS version or PMOS + """ + Cascode = Component() + + # Use of 1st order primitive + + CS1 = current_source(pdk, devices_info[0], array[0], 0, 1) + CS2 = current_source(pdk, devices_info[1], array[1], 0, 0) + + Current_Source_1 = Cascode << CS1 + Current_Source_2 = Cascode << CS2 + + + # Placement and size of the current source + #################### + + size_CS_2 = evaluate_bbox(Current_Source_2) + size_CS_1 = evaluate_bbox(Current_Source_1) + max_size = pdk.snap_to_2xgrid(pdk.get_grule('met4')['min_separation'] + (size_CS_1[1]+size_CS_2[1])/2) + Current_Source_1.movey(sky130.get_grule('met4')['min_separation']+max_size) + + Current_Source_1.mirror(p1=(0, 0), p2=(1, 0)) + Current_Source_2.mirror(p1=(0, 0), p2=(1, 0)) + + # Centering + + ### Porting ### + + Cascode.add_ports(Current_Source_1.get_ports_list(),prefix='CS1_') + Cascode.add_ports(Current_Source_2.get_ports_list(),prefix='CS2_') + + # Routing + ################### + + ### Diode routing ### + diode_route = Cascode << c_route(pdk, Current_Source_1.ports['VD1_W'], Current_Source_2.ports['VBIAS_W'], cglayer = 'met3', cwidth = (Current_Source_2.ports['VS2_E'].width)/2) + + ### Between transistors routing ### + Route_DS1 = Cascode << straight_route(pdk, Current_Source_1.ports['VS1_N'], Current_Source_2.ports['VD1_S']) + Route_DS2 = Cascode << straight_route(pdk, Current_Source_1.ports['VS2_N'], Current_Source_2.ports['VD2_S']) + + ### Source connections ### + + Route_Ref = Cascode << L_route(pdk, Current_Source_2.ports['VS1_N'], Current_Source_2.ports['VS2_E']) + + ### Bulk connection ### + + via_ref = via_stack(pdk, 'met2', 'met3') + via_cs1 = Cascode << via_ref + via_cs1.movex(Current_Source_1.ports['VBC_D_N'].center[0]).movey(Current_Source_1.ports['VBC_D_E'].center[1]) + + via_cs2 = Cascode << via_ref + via_cs2.movex(Current_Source_2.ports['VBC_U_N'].center[0]).movey(Current_Source_2.ports['VBC_U_E'].center[1]) + Route_bulk = Cascode << straight_route(pdk, via_cs1.ports['top_met_N'], via_cs2.ports['top_met_S']) + ## External o Internal device + + if with_pin == 1: + + pin_label_creation('CS2_VS1', 'VREF', 'met3', Cascode) + pin_label_creation('CS2_VD1', 'VIP', 'met3', Cascode) + pin_label_creation('CS2_VD2', 'VIN', 'met3', Cascode) + pin_label_creation('CS1_VBIAS', 'VB1', 'met3', Cascode) + pin_label_creation('CS1_VD1', 'VD1', 'met3', Cascode) + pin_label_creation('CS1_VD2', 'VOUT', 'met3', Cascode) + + component = Component() + component << Cascode + + filtrar_puertos(Cascode, component, 'CS2_VS2_', 'VREF_') + filtrar_puertos(Cascode, component, 'CS2_VD1_', 'VIP_') + filtrar_puertos(Cascode, component, 'CS2_VD2_', 'VIN_') + filtrar_puertos(Cascode, component, 'CS1_VBIAS2_', 'VB1_') + filtrar_puertos(Cascode, component, 'CS2_VBIAS2_', 'VB2_') + filtrar_puertos(Cascode, component, 'CS1_VD1_', 'VD1_') + filtrar_puertos(Cascode, component, 'CS1_VD2_', 'VOUT_') + + component_centered = center_component_with_ports(component) + + return component_centered + +### Bi current source ### + +def Bi_current_source(pdk, devices_info, array, with_pin: int = 0) -> Component: + """" + pdk = pdk to use + devices_info = The devices to place, usually formed as an array with all the information + array = A full matrix with the placement organization + with_pin = Makes the primitive have pins which don't have any electrical purpose + + Bi_current_source primitive, can be used in its NMOS version or PMOS + """ + Bi_current_source = Component() + + # Use of 1st order primitive + + CS1 = current_source(pdk, devices_info[0], array[0], 0, 0) + CS2 = current_source(pdk, devices_info[1], array[1], 0, 1) + + Current_Source_1 = Bi_current_source << CS1 + Current_Source_2 = Bi_current_source << CS2 + + + # Placement and size of the current source + #################### + + size_CS_2 = evaluate_bbox(Current_Source_2) + size_CS_1 = evaluate_bbox(Current_Source_1) + max_size = (size_CS_1[1]+size_CS_2[1])/2 + + Current_Source_2.movey(sky130.get_grule('met4')['min_separation']+max_size) + + ### Porting ### + + Bi_current_source.add_ports(Current_Source_1.get_ports_list(),prefix='CS1_') + Bi_current_source.add_ports(Current_Source_2.get_ports_list(),prefix='CS2_') + + # Routing + ################### + + ### Between transistors routing ### + Route_DS1 = Bi_current_source << straight_route(pdk, Current_Source_1.ports['VD1_N'], Current_Source_2.ports['VS1_S']) + Route_DS2 = Bi_current_source << straight_route(pdk, Current_Source_1.ports['VD2_N'], Current_Source_2.ports['VS2_S']) + + ### Source connections ### + + Route_Ref = Bi_current_source << L_route(pdk, Current_Source_1.ports['VS1_N'], Current_Source_1.ports['VS2_E']) + + ### Bulk connection ### + via_ref = via_stack(pdk, 'met2', 'met3') + via_cs1 = Bi_current_source << via_ref + via_cs1.movex(Current_Source_1.ports['VBC_U_N'].center[0]).movey(Current_Source_1.ports['VBC_U_E'].center[1]) + + via_cs2 = Bi_current_source << via_ref + via_cs2.movex(Current_Source_2.ports['VBC_D_N'].center[0]).movey(Current_Source_2.ports['VBC_D_E'].center[1]) + Route_bulk = Bi_current_source << straight_route(pdk, via_cs1.ports['top_met_N'], via_cs2.ports['top_met_S']) + + #Route_bulk = Bi_current_source << L_route(pdk, Current_Source_1.ports['VS2_E'], Current_Source_2.ports['VB_S'], + # vglayer = 'met3', hwidth = (Current_Source_1.ports['VS2_N'].width)/2) + ## External o Internal device + + if with_pin == 1: + + pin_label_creation('CS1_VD2', 'VOUT', 'met3', Bi_current_source) + pin_label_creation('CS1_VD1', 'VD1', 'met3', Bi_current_source) + pin_label_creation('CS2_VD2', 'VCOMM', 'met3', Bi_current_source) + pin_label_creation('CS1_VBIAS', 'VB2', 'met3', Bi_current_source) + pin_label_creation('CS2_VBIAS2', 'VB3', 'met3', Bi_current_source) + pin_label_creation('CS2_VS2', 'VREF', 'met3', Bi_current_source) + + component = Component() + component << Bi_current_source + + filtrar_puertos(Bi_current_source, component, 'CS2_VD2_', 'VOUT_') + filtrar_puertos(Bi_current_source, component, 'CS2_VD1_', 'VD1_') + filtrar_puertos(Bi_current_source, component, 'CS1_VBIAS_', 'VB2_') + filtrar_puertos(Bi_current_source, component, 'CS1_VBIAS2_', 'VB2R_') + filtrar_puertos(Bi_current_source, component, 'CS2_VBIAS2_', 'VB3_') + filtrar_puertos(Bi_current_source, component, 'CS1_VS2_', 'VREF_') + filtrar_puertos(Bi_current_source, component, 'CS1_VD2_', 'VCOMM_') + + + component_centered = center_component_with_ports(component) + + return component_centered + +### Pair bias ### + +def Pair_bias(pdk, devices_info, array, with_pin: int = 0) -> Component: + """" + pdk = pdk to use + devices_info = The devices to place, usually formed as an array with all the information + array = A full matrix with the placement organization + with_pin = Makes the primitive have pins which don't have any electrical purpose + + Pair_bias primitive, can be used in its NMOS version or PMOS + """ + Pair_bias = Component() + + # Use of 1st order primitive + + P1 = differential_pair(pdk, devices_info[0], array[0], 0, 1) + T1 = transistor(pdk, devices_info[1], array[1], 0, 0) + + Pair = Pair_bias << P1 + Tail = Pair_bias << T1 + + # Placement and size of pair and tail + #################### + + size_P1 = evaluate_bbox(Pair) + size_T1 = evaluate_bbox(Tail) + max_size = (size_P1[1] + size_T1[1])/2 + + Pair.movey(sky130.get_grule('met4')['min_separation']+max_size) + + ### Porting ### + + Pair_bias.add_ports(Pair.get_ports_list(),prefix='P1_') + Pair_bias.add_ports(Tail.get_ports_list(),prefix='T1_') + + # Routing + ################### + + ### Source to drain + + Route_SD = Pair_bias << L_route(pdk, Pair.ports['VS_S'], Tail.ports['VD_E']) + + if with_pin == 1: + + pin_label_creation('P1_VGP', 'VGP', 'met3', Pair_bias) + pin_label_creation('P1_VGN', 'VGN', 'met3', Pair_bias) + pin_label_creation('P1_VD1', 'VDP', 'met3', Pair_bias) + pin_label_creation('P1_VD2', 'VDN', 'met3', Pair_bias) + pin_label_creation('T1_VG', 'VBIAS', 'met3', Pair_bias) + pin_label_creation('T1_VS', 'VREF', 'met3', Pair_bias) + + + + component = Component() + component << Pair_bias + + filtrar_puertos(Pair_bias, component, 'P1_VGP_', 'VGP_') + filtrar_puertos(Pair_bias, component, 'P1_VGN_', 'VGN_') + filtrar_puertos(Pair_bias, component, 'P1_VD1_', 'VDP_') + filtrar_puertos(Pair_bias, component, 'P1_VD2_', 'VDN_') + filtrar_puertos(Pair_bias, component, 'P1_VBC_D_', 'P_VBC_D_') + filtrar_puertos(Pair_bias, component, 'P1_VBC_U_', 'P_VBC_U_') + filtrar_puertos(Pair_bias, component, 'T1_VG_', 'VBIAS_') + filtrar_puertos(Pair_bias, component, 'T1_VS_', 'VREF_') + filtrar_puertos(Pair_bias, component, 'T1_VBC_D_', 'T_VBC_D_') + filtrar_puertos(Pair_bias, component, 'T1_VBC_U_', 'T_VBC_U_') + + component_centered = center_component_with_ports(component) + return component_centered + +def moscap(pdk,devices_info, matrix): + moscap = Component() + """" + description + """ + + #Matrix placement + config = macro_two_transistor_placement_Onchip(pdk=pdk, deviceA_and_B=devices_info['type'], with_substrate_tap=devices_info['with_substrate_tap'], + with_tie=devices_info['with_tie'], width1=devices_info['width'], length1=devices_info['length'], + fingers1=devices_info['fingers'], matriz=matrix, with_dummy=devices_info['with_dummy'], + width_route_mult=devices_info['width_route_mult'], with_lvt_layer=devices_info['lvt']) + + matrix = moscap << config + moscap.add_ports(matrix.get_ports_list()) + + # Routing + ##################### + + # Bulk to source connection + + # route_bulk_1 = moscap << L_route(pdk, matrix.ports['A_source_N'], matrix.ports['bulk_down_E']) + route_drain_source = moscap << straight_route(pdk, matrix.ports['A_drain_N'], matrix.ports['A_source_S']) + + component = Component() + component << moscap + + filtrar_puertos(moscap, component, 'A_drain_', 'VD_') + filtrar_puertos(moscap, component, 'A_source_', 'VS_') + filtrar_puertos(moscap, component, 'A_gate_', 'VG_') + + return component + + ## External o Internal device \ No newline at end of file