-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #329 from chetanya-goyal/main
Testbenches
- Loading branch information
Showing
5 changed files
with
644 additions
and
0 deletions.
There are no files selected for viewing
51 changes: 51 additions & 0 deletions
51
openfasoc/generators/glayout/glayout/flow/testbench/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
106
openfasoc/generators/glayout/glayout/flow/testbench/currmirror_tb.sp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
160
openfasoc/generators/glayout/glayout/flow/testbench/diffpair_tb.sp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.