Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testbenches #329

Merged
merged 2 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions openfasoc/generators/glayout/glayout/flow/testbench/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# NGSpice Testbenches

This directory contains testbenches to evaluate components generated from the glayout flow using NGSpice.

Currently, the following testbenches are available:

- `diffpair_tb.sp`: Testbench for the differential pair
- `opamp_tb.sp` : Testbench for a 2 stage Operational Amplifier
- `currmirror_tb.sp` : Testbench for the current mirror

To run the testbenches, you need to have NGSpice installed and the python script `process_tb.py` must be run

It can be run as follows -

```
python3 process_tb.py \
--temperature <temp> \
--mode <stp/cryo/custom> \
--pdkroot <path to pdkroot> \
--testbench <opamp/currmirror/diffpair> \
--pexpath <path to extracted netlist> \
--modulename <Name of the module in the netlist>
```

The first four arguments are not mandatory. Their default values are as follows -

- `temperature` : 27
- `mode` : stp
- `pdkroot` : /usr/bin/miniconda3/share/pdk/
- `testbench` : opamp


**The placeholders in the testbenches with `@@__` can be filled in manually as well, if the user so choses. Take care of the following if you use the script:**
1. Temperature must be an integer
- Temperature less than 0 is automatically treated as a cryo sim if the python script is used
- Temperature equal to 27 degrees is treated as STP
2. The PDK_ROOT must be a valid and accessible path
3. The pex script path (can be a post or pre-pex netlist) must exist
4. The module name must be the exact same as in the netlist
- Pin orders:
- Differential Pair
`XDUT minus drain_right drain_left source plus @@MODULE_NAME`
- Current Mirror
`XDUT mirr_drain ref_drain GND @@MODULE_NAME`
- Opamp
`XDUT GND csoutputnetNC vo VDD vip vin biascsn biason biasdpn @@MODULE_NAME`
- `csoutputnetNC` is the 2nd stage Amplifier's output
- `vo` is the output from the NMOS driver circuit
- the current bias components are connected to the mirror drains of the corresponding current mirrors

***The results are written to the directory that the script is run in.***
106 changes: 106 additions & 0 deletions openfasoc/generators/glayout/glayout/flow/testbench/currmirror_tb.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
* currmirr_perf_eval.sp
** OpenFASOC Team, Chetanya Goyal 2024, As a part of GSoC
.temp 25

.param bref = 5u
.param rbias = 10k
.param cbias = 1p
* input voltages
Vsup VDD GND 1.8

* measure current through ref_drain and mirr_drain
V1 ref_drain GND DC 0
V2 mirr_drain GND DC 0

* source bias
Iref VDD ref_drain {bref}

* bias resistors
R1 ref_drain VDD {rbias}

.lib /usr/bin/miniconda3/share/pdk/sky130A/libs.tech/ngspice/sky130.lib.spice tt
.include @@PEX_PATH
XDUT mirr_drain ref_drain GND @@MODULE_NAME
* .ac dec 10 10 10G
.control

echo "Starting simulation"
set filetype = ascii
let maxBiasRef = -1
let minCurrDiff = 987654321
let maxBiasR = -1

* init biases
let linear_step_until = 0u
let linear_step_default = 1.1u
let bias_ref_Min = 0.5u
let bias_ref_Max = 50u
let bias_ref_logStep = 1.1
let bias_rbias_Min = 1k
let bias_rbias_Max = 1Meg
let bias_rbias_logStep = 1.1

let bias_ref = bias_ref_Min
let bias_rbias = bias_rbias_Min

let index = 0

while bias_ref le bias_ref_Max
while bias_rbias le bias_rbias_Max

* this way because matching is necessary
* place
alter R1 = $&bias_rbias
alter iref = $&bias_ref

echo "~~~~ Run #$&index ~~~~"
echo "Bias Current: $&bias_ref"
echo "Bias Resistor: $&bias_rbias"

op
save mirr_drain ref_drain
let mirr_curr = bias_ref
let ref_curr = (1.8 - v(ref_drain))/bias_rbias
let currdiff = (( abs( abs(mirr_curr) - abs(ref_curr) ) ) / abs(mirr_curr)) * 100

echo "mirr_curr = $&mirr_curr"
echo "ref_curr = $&ref_curr"
echo "currdiff = $&currdiff %"

* update max values
if ( currdiff le minCurrDiff )
let minCurrDiff = currdiff
let maxBiasRef = bias_ref
let maxBiasR = bias_rbias
end
let index = index + 1
let bias_rbias = bias_rbias * bias_rbias_logStep
end
let bias_rbias = bias_rbias_Min
if ( linear_step_until ge bias_ref )
let bias_ref = bias_ref + linear_step_default
else
let bias_ref = bias_ref * bias_ref_logStep
end
end

echo "Simulation complete"
echo "Best Bias Current: $&maxBiasRef"
echo "Min Curr Diff: $&minCurrDiff %"
echo "Best Bias Resistance: $&maxBiasR"

wrdata result_ac.txt maxBiasRef minCurrDiff maxBiasR
alterparam bref = $&maxBiasRef
alterparam rbias = $&maxBiasR
reset

op
let ptotal_exact = i(Vsup) * 1.8
wrdata result_power.txt ptotal_exact
echo "Best power usage: $&ptotal_exact"


.endc
.GLOBAL VDD
.GLOBAL GND
.end
160 changes: 160 additions & 0 deletions openfasoc/generators/glayout/glayout/flow/testbench/diffpair_tb.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
* diffpair_perf_eval.sp
** OpenFASOC Team, Chetanya Goyal 2024, As a part of GSoC
.temp {@@TEMP}
.param bdp = 5u
.param r1p = 10k
.param r2p = 10k
.param vbias = 0.8

* input voltages
Vsup VDD GND 1.8
Vbias net1 GND {Vbias}
Vp plus net1 AC 0.5
Vn minus net1 AC -0.5

* source bias
Ibiasdp source GND {bdp}

* bias resistors
R1 drain_left VDD {r1p}
R2 drain_right VDD {r2p}

.lib @@PDK_ROOT/sky130A/libs.tech/ngspice/sky130.lib.spice tt

.include @@PEX_PATH
XDUT minus drain_right drain_left source plus @@MODULE_NAME

* .ac dec 10 10 10G
.control

echo "Starting simulation"
set filetype = ascii
let maxBiasDP = -1
let maxVinP = -1
let maxBiasR = -1
let minVinN = 1
let maxFOM = -1
let maxDiffGain = -1
let minCommonModeGain = 987654321
let maxCMRR = -1
let maxThreeDB = -1
let minNoiseFig = -1

* init biases
let linear_step_until = 0u
let linear_step_default = 1.1u
let bias_dp_Min = 0.1u
let bias_dp_Max = 5u
let bias_dp_logStep = 1.8
let bias_r2_Min = 0.85Meg
let bias_r2_Max = 10G
let bias_r2_logStep = 1.3
let bias_voltage_min = 0.7
let bias_voltage_max = 1.3
let bias_voltage_step = 0.15

let bias_dp = bias_dp_Min
let bias_r1 = bias_r1_Min
let bias_r2 = bias_r2_Min
let bias_voltage = bias_voltage_min
* let vinp_Min = 0.1
* let vinp_Max = 1.0
* let vinp_logStep = 1.2
* let vinn_Min = -0.1
* let vinn_Max = -1.0
* let vinn_logStep = 1.2
* let vinstep = 0.1
* let vinp = vinp_Min
* let vinn = vinn_Min

let index = 0
while bias_voltage le bias_voltage_max
while bias_dp le bias_dp_Max
while bias_r2 le bias_r2_Max

* this way because matching is necessary
alter R1 = $&bias_r2
alter ibiasdp = $&bias_dp
alter R2 = $&bias_r2
alter Vbias = $&bias_voltage

echo "~~~~ Run #$&index ~~~~"
echo "Bias Current DP: $&bias_dp"
echo "Bias Resistor R1: $&bias_r2"
echo "Bias Resistor R2: $&bias_r2"
echo "Bias Voltage: $&bias_voltage"

save drain_left drain_right
ac dec 10 10 1G
let vo = (v(drain_right) - v(drain_left))
let vadd = (v(drain_right))
meas ac diff_gain find vdb(vo) at=10
* meas ac common_mode_gain find vdb(vadd) at=10
alter Vn ac=0.5
meas ac common_mode_gain find vdb(vadd) at=10
alter Vn ac=-0.5
let threedbgain = diff_gain - 3
meas ac threedb when vd(vo) = threedbgain

* update max values
let FOM = diff_gain / bias_dp
if ( FOM ge maxFOM )
let maxFOM = FOM
let maxDiffGain = diff_gain
* let maxCommonModeGain = common_mode_gain
* let maxCMRR = cmrr
let maxThreeDB = threedb
let maxBiasDP = bias_dp
let maxBiasR = bias_r2
end
if ( common_mode_gain le minCommonModeGain )
if ( common_mode_gain ge 0 )
let minCommonModeGain = common_mode_gain
end
end
let index = index + 1
let bias_r2 = bias_r2 * bias_r2_logStep
end
let bias_r2 = bias_r2_Min
if ( linear_step_until ge bias_dp )
let bias_dp = bias_dp + linear_step_default
else
let bias_dp = bias_dp * bias_dp_logStep
end
end
let bias_dp = bias_dp_Min
let bias_voltage = bias_voltage + bias_voltage_step
end
let maxCMRR = maxDiffGain / minCommonModeGain
echo "Max Bias DP: $&maxBiasDP"
echo "Max Bias Resistance: $&maxBiasR"
echo "Max FOM: $&maxFOM"
echo "Max Diff Gain: $&maxDiffGain"
echo "Min Common Mode Gain: $&minCommonModeGain"
echo "Max CMRR: $&maxCMRR"
echo "Max 3dB: $&maxThreeDB"
echo "Max Bias R: $&maxBiasR"
wrdata result_ac.txt maxBiasDP maxFOM maxDiffGain minCommonModeGain maxCMRR maxThreeDB maxBiasR

alterparam bdp = $&maxBiasDP
alterparam r1p = $&maxBiasR
alterparam r2p = $&maxBiasR
reset

op
let ptotal_exact = i(Vsup) * -1.8
wrdata result_power.txt ptotal_exact
echo "Power usage: $&ptotal_exact"

reset
noise V(drain_left) Vp dec 100 1k 10G
setplot previous
let integ = integ(onoise_spectrum)
let total_noise = sqrt(integ[length(integ)-1])
wrdata result_noise.txt total_noise
echo "Total Noise: $&total_noise"

.endc
.GLOBAL VDD
.GLOBAL GND
.end
Loading