Skip to content

Commit

Permalink
Merge pull request #329 from chetanya-goyal/main
Browse files Browse the repository at this point in the history
Testbenches
  • Loading branch information
msaligane authored Jul 24, 2024
2 parents f0677e8 + 333547a commit c11ceb1
Show file tree
Hide file tree
Showing 5 changed files with 644 additions and 0 deletions.
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

0 comments on commit c11ceb1

Please sign in to comment.