Flip Flopのタイミング定義
ここではFlip Flopには3つのPin:CLK(Clock input), D(Data input), Q(Data Output)があるものとする。
Flip Flopの主要なタイミングはClock To Data(Tpd), DataのSetup Time, DataのHold Timeである。(Set/Reset付ではそれ以外にもある、またMin-pulseなどもあるがそれらは別途)
それぞれの定義はベンダーによって違いがあるかもしれないが、以下とそれほど違わないはず。
- Tpd
DataがClockより十分前に確定した時のClock To Qの時間。 - Setup
DataがClockよりどれだけ前に確定していればラッチされるかを定義した時間。
DataをClockに近づけていくとDataが完全にラッチされなくなる前にTpdの値が徐々に伸びていくので、ここではDataがClockより十分前に確定した時のTpdをTpd0としたときに、TpdがTpd0より10%長くなる時のDataのClockの時間差とする。 - Hold
DataがClockよりどれだけ後まで値を維持していればラッチされるかを定義した時間。
SetupのようにTpdがTpd0の+10%になった点をHoldと定義するが、Tpdが+10%まで伸びる前にHoldできなくなる場合もあり、その場合はその時間をHoldとする。
SetupもHoldもマイナスの値をとることがあり、ライブラリによっては0にしている場合もある。
SetupもHold同様TpdがTpd0+10%にならない場合があるかもしれないが私は見たことがないので、今回はSetup算出は考慮していない。
Tpd
sky130のdfxtp_1を使ってSimする。
.option method=gear tnom=25
*.option autostop
.lib 'sky130.lib.spice' ss
.param vdd=1.8
.param vss=0
vcc vcc 0 dc vdd
vss vss 0 dc vss
.include 'dff.spi'
*.subckt dfxtp_1 CLK D VGND VNB VPB VPWR Q
xdff clk d vss vss vcc vcc q dfxtp_1
c1 q 0 0.1f
.param trf=100p
.param d_start=1n
.param clk_start=2n
vclk clk 0 pulse( 0 1.8 {clk_start} {trf} {trf} 10n 20n )
vdata d 0 pulse( 0 1.8 {d_start} {trf} {trf} 20n 40n )
.print tran v(clk) v(data) v(q)
.temp 25
.control
tran 10p 40n
plot all.v(d) all.v(clk) all.v(q)
write outputfile.raw all
.endc
.end
Setup
SetupはData=0時とData=1時で入力波形やMeasureが違うので、2つ(0測定用と1測定用)に分けた。
ngspiceは私が普段使っているhspiceにあるoptimizerが標準で実装されていないので、.control内にサーチを組み込むため結構なボリュームになってしまった。また、hspiceでは変数はmesure結果以外に.param(およびpar)しかないのだが、ngspiceは.param以外に.csparam,let,setなど種類があり、それぞれスコープが異なるため動くコードを書くのに少々苦労した。ngspiceの変数に関しては別途。
Setup(Data=0)
*
.option method=gear tnom=25
*.option autostop
.lib 'sky130.lib.spice' ss
.param vdd=1.8
.param vss=0
vcc vcc 0 dc vdd
vss vss 0 dc vss
.include 'dff.spi'
*.subckt dfxtp_1 CLK D VGND VNB VPB VPWR Q
xdff clk d vss vss vcc vcc q dfxtp_1
c1 q vss 0.1f
.param trf=100p
.param cycle=10n
.param clk_start=2n
.param setup=1n
.param d_start='cycle*2+clk_start-setup'
.csparam pds=d_start
.param cp2q0_para=100p
vclk clk vss pulse( {vss} {vdd} {clk_start} {trf} {trf} {cycle} {cycle*2} )
vdata d vss pulse( {vdd} {vss} {d_start} {trf} {trf} {cycle*2} {cycle*4} )
.print tran v(clk) v(data) v(q)
.temp 25
.measure tran p_setup param=setup
.measure tran p_dstart param=d_start
.control
* Accepted error ratio 0.1%
let serror=0.001
* Current Error = cp2q / cp2q0 - 1.1 ; setup time is the time when +10% cp2q than normal cp2q
let cerror=1
* Serch Step
let sdelta=500p
* Initial Setup Time in controll
let st=1n
* maximum loop
let maxloop=100
* valable for cp2q0
let pcp0=100p
echo cp2q0 "$&pcp0"
echo st0 "$&st"
* Exit switch
let esw=0
let loopnum=0
while esw < 1
echo first0 "$&loopnum"
if loopnum =0
tran 10p 40n
meas tran cp2q
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(q) val='0.5*vdd' fall=1
meas tran psetup
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(d) val='0.5*vdd' fall=1
let pcp0={cp2q}
let st=st-sdelta
else
alterparam setup=$&st
reset
tran 10p 40n
meas tran cp2q
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(q) val='0.5*vdd' fall=1
meas tran psetup
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(d) val='0.5*vdd' fall=1
let pcp={cp2q}
let pps={psetup}
let cpdiff=abs($&pcp - $&pcp0)
let cpdiff05=$&pcp0 * 0.5
let cpdiff01=$&pcp0 * 0.1
echo diff "$&cpdiff"
echo diff0.1 "$&cpdiff01"
echo diff0.5 "$&cpdiff05"
if cpdiff > cpdiff05
echo Failed
let sdelta=sdelta / 2
let st=st+sdelta
else
let cpd=$&pcp / $&pcp0
echo cp2q / cp2q0 "$&cpd"
if cpdiff > cpdiff01 and cpdiff < cpdiff05
echo Setup "$&pcp"
let sdelta=sdelta / 2
let st=st + sdelta
if abs(cerror) < serror
let esw=1
echo Cerror "$&cerror" Serror "$&serror"
end
else
if cpdiff > cpdiff01
echo Pass "$&pcp"
let sdelta=sdelta / 2
let st=st - sdelta
else
let sdelta=sdelta / 2
let st=st - sdelta
end
end
end
end
let cerror=cpd - 1.1
echo Num "$&loopnum" sdelta "$&sdelta" current_error "$&cerror"
let loopnum=loopnum+1
if loopnum > maxloop
let esw=1
end
end
plot all.v(d) all.v(clk) all.v(q)
write outputfile.raw all.v(d) all.v(clk) all.v(q)
.endc
.end
Setup(Data=1)
*
.option method=gear tnom=25
*.option autostop
.lib 'sky130.lib.spice' ss
.param vdd=1.8
.param vss=0
vcc vcc 0 dc vdd
vss vss 0 dc vss
.include 'dff.spi'
*.subckt dfxtp_1 CLK D VGND VNB VPB VPWR Q
xdff clk d vss vss vcc vcc q dfxtp_1
c1 q vss 0.1f
.param trf=100p
.param cycle=10n
.param clk_start=2n
.param setup=1n
.param d_start='cycle*2+clk_start-setup'
.csparam pds=d_start
.param cp2q0_para=100p
vclk clk vss pulse( {vss} {vdd} {clk_start} {trf} {trf} {cycle} {cycle*2} )
vdata d vss pulse( {vss} {vdd} {d_start} {trf} {trf} {cycle*2} {cycle*4} )
.print tran v(clk) v(data) v(q)
.temp 25
.measure tran p_setup param=setup
.measure tran p_dstart param=d_start
.control
* Accepted error ratio 0.1%
let serror=0.001
* Current Error = cp2q / cp2q0 - 1.1 ; setup time is the time when +10% cp2q than normal cp2q
let cerror=1
* Serch Step
let sdelta=500p
* Initial Setup Time in controll
let st=1n
* maximum loop
let maxloop=100
* valable for cp2q0
let pcp0=100p
echo cp2q0 "$&pcp0"
echo st0 "$&st"
* Exit switch
let esw=0
let loopnum=0
while esw < 1
echo first0 "$&loopnum"
if loopnum =0
tran 10p 40n
meas tran cp2q
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(q) val='0.5*vdd' rise=1
meas tran psetup
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(d) val='0.5*vdd' rise=1
let pcp0={cp2q}
let st=st-sdelta
else
alterparam setup=$&st
reset
tran 10p 40n
meas tran cp2q
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(q) val='0.5*vdd' rise=1
meas tran psetup
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(d) val='0.5*vdd' rise=1
let pcp={cp2q}
let pps={psetup}
let cpdiff=abs($&pcp - $&pcp0)
let cpdiff05=$&pcp0 * 0.5
let cpdiff01=$&pcp0 * 0.1
echo diff "$&cpdiff"
echo diff0.1 "$&cpdiff01"
echo diff0.5 "$&cpdiff05"
if cpdiff > cpdiff05
echo Failed
let sdelta=sdelta / 2
let st=st+sdelta
else
let cpd=$&pcp / $&pcp0
echo cp2q / cp2q0 "$&cpd"
if cpdiff > cpdiff01 and cpdiff < cpdiff05
echo Setup "$&pcp"
let sdelta=sdelta / 2
let st=st + sdelta
if abs(cerror) < serror
let esw=1
echo Cerror "$&cerror" Serror "$&serror"
end
else
if cpdiff > cpdiff01
echo Pass "$&pcp"
let sdelta=sdelta / 2
let st=st - sdelta
else
let sdelta=sdelta / 2
let st=st - sdelta
end
end
end
end
let cerror=cpd - 1.1
echo Num "$&loopnum" sdelta "$&sdelta" current_error "$&cerror"
let loopnum=loopnum+1
if loopnum > maxloop
let esw=1
end
end
plot all.v(d) all.v(clk) all.v(q)
write outputfile.raw all.v(d) all.v(clk) all.v(q)
.endc
.end
Hold
HoldもSetup同様Data=0とData=1に分けた。
Hold(Data=0)
*
.option method=gear tnom=25
*.option autostop
.lib 'sky130.lib.spice' ss
.param vdd=1.8
.param vss=0
vcc vcc 0 dc vdd
vss vss 0 dc vss
.include 'dff.spi'
*.subckt dfxtp_1 CLK D VGND VNB VPB VPWR Q
xdff clk d vss vss vcc vcc q dfxtp_1
c1 q vss 0.1f
.param trf=100p
.param cycle=10n
.param clk_start=2n
.param dsetup=500p
.param hold=1n
.param d_start='cycle*2+clk_start+hold'
.csparam pds=d_start
.param cp2q0_para=100p
vclk clk vss pulse( {vss} {vdd} {clk_start} {trf} {trf} {cycle} {cycle*2} )
vdata d vss pwl(0n vdd 'clk_start+cycle*2-dsetup' vdd
+ 'clk_start+cycle*2-dsetup+trf' vss 'clk_start+cycle*2+hold' vss 'clk_start+cycle*2+hold+trf' vdd 'cycle*10' vdd)
.print tran v(clk) v(data) v(q)
.temp 25
.measure tran p_hold param=hold
.measure tran p_dstart param=d_start
.control
* Accepted error ratio 0.1%
let serror=0.001
* Accepted error time
let terror=0.1p
* Current Error = cp2q / cp2q0 - 1.1 ; hold time is the time when +10% cp2q than normal cp2q
let cerror=1
* Serch Step
let sdelta=500p
* Initial Hold Time
let hld=1n
let hldmin=hld
* maximum loop
let maxloop=100
* valable for cp2q0
let pcp0=100p
echo cp2q0 "$&pcp0"
echo hld0 "$&hld"
* Exit switch
let esw=0
let loopnum=0
while esw < 1
*repeat 20
echo first0 "$&loopnum"
if loopnum =0
tran 1p 40n
meas tran cp2q
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(q) val='0.5*vdd' fall=1
meas tran phold
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(d) val='0.5*vdd' rise=1
let pcp0={cp2q}
let hld=hld-sdelta
else
alterparam hold=$&hld
reset
tran 1p 40n
meas tran cp2q
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(q) val='0.5*vdd' fall=1
meas tran phold
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(d) val='0.5*vdd' rise=1
let pcp={cp2q}
let pps={phold}
let cpdiff=abs($&pcp - $&pcp0)
let cpdiff05=$&pcp0 * 0.5
let cpdiff01=$&pcp0 * 0.1
echo diff "$&cpdiff"
echo diff0.1 "$&cpdiff01"
echo diff0.5 "$&cpdiff05"
if cpdiff > cpdiff05
echo Failed
let sdelta=sdelta / 2
let hld=hld+sdelta
else
let cpd=$&pcp / $&pcp0
echo cp2q / cp2q0 "$&cpd"
if cpdiff > cpdiff01 and cpdiff < cpdiff05
echo Hold "$&pps" cp2q "$&pcp"
let sdelta=sdelta / 2
let hld=hld + sdelta
if abs(cerror) < serror
let esw=1
echo Cerror "$&cerror" Serror "$&serror"
if hldmin > pps
let hldmin=pps
end
end
else
if cpdiff > cpdiff01
* echo Pass "$&pps" cp2q "$&pcp"
let sdelta=sdelta / 2
let hld=hld - sdelta
else
* echo Pass2 "$&pps" cp2q "$&pcp"
* let sdelta=sdelta / 2
let hld=hld - sdelta
end
if hldmin > pps
let hldmin=pps
end
end
end
end
let cerror=cpd - 1.1
echo Num "$&loopnum" Current Hold "$&hld" sdelta "$&sdelta" current_error "$&cerror" Hold "$&hldmin"
let loopnum=loopnum+1
if loopnum > maxloop
let esw=1
end
if sdelta < terror
let esw=1
end
end
plot all.v(d) all.v(clk) all.v(q)
write outputfile.raw all.v(d) all.v(clk) all.v(q)
.endc
.end
Hold(Data=1)
*
.option method=gear tnom=25
*.option autostop
.lib 'sky130.lib.spice' ss
.param vdd=1.8
.param vss=0
vcc vcc 0 dc vdd
vss vss 0 dc vss
.include 'dff.spi'
*.subckt dfxtp_1 CLK D VGND VNB VPB VPWR Q
xdff clk d vss vss vcc vcc q dfxtp_1
c1 q vss 0.1f
.param trf=100p
.param cycle=10n
.param clk_start=2n
.param dsetup=500p
.param hold=1n
.param d_start='cycle*2+clk_start+hold'
.csparam pds=d_start
.param cp2q0_para=100p
vclk clk vss pulse( {vss} {vdd} {clk_start} {trf} {trf} {cycle} {cycle*2} )
vdata d vss pwl(0n vss 'clk_start+cycle*2-dsetup' vss
+ 'clk_start+cycle*2-dsetup+trf' vdd 'clk_start+cycle*2+hold' vdd 'clk_start+cycle*2+hold+trf' vss 'cycle*10' vss)
.print tran v(clk) v(data) v(q)
.temp 25
.measure tran p_hold param=hold
.measure tran p_dstart param=d_start
.control
* Accepted error ratio 0.1%
let serror=0.001
* Accepted error time
let terror=0.1p
* Current Error = cp2q / cp2q0 - 1.1 ; hold time is the time when +10% cp2q than normal cp2q
let cerror=1
* Serch Step
let sdelta=500p
* Initial Hold Time
let hld=1n
let hldmin=hld
* maximum loop
let maxloop=100
* valable for cp2q0
let pcp0=100p
echo cp2q0 "$&pcp0"
echo hld0 "$&hld"
* Exit switch
let esw=0
let loopnum=0
while esw < 1
echo first0 "$&loopnum"
if loopnum =0
tran 1p 40n
meas tran cp2q
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(q) val='0.5*vdd' rise=1
meas tran phold
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(d) val='0.5*vdd' fall=1
let pcp0={cp2q}
let hld=hld-sdelta
else
alterparam hold=$&hld
reset
tran 1p 40n
meas tran cp2q
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(q) val='0.5*vdd' rise=1
meas tran phold
+ trig v(clk) val='0.5*vdd' rise=2
+ targ v(d) val='0.5*vdd' fall=1
let pcp={cp2q}
let pps={phold}
let cpdiff=abs($&pcp - $&pcp0)
let cpdiff05=$&pcp0 * 0.5
let cpdiff01=$&pcp0 * 0.1
echo diff "$&cpdiff"
echo diff0.1 "$&cpdiff01"
echo diff0.5 "$&cpdiff05"
if cpdiff > cpdiff05
echo Failed
let sdelta=sdelta / 2
let hld=hld+sdelta
else
let cpd=$&pcp / $&pcp0
echo cp2q / cp2q0 "$&cpd"
if cpdiff > cpdiff01 and cpdiff < cpdiff05
echo Hold "$&pps" cp2q "$&pcp"
let sdelta=sdelta / 2
let hld=hld + sdelta
if abs(cerror) < serror
let esw=1
echo Cerror "$&cerror" Serror "$&serror"
if hldmin > pps
let hldmin=pps
end
end
else
if cpdiff > cpdiff01
* echo Pass "$&pps" cp2q "$&pcp"
let sdelta=sdelta / 2
let hld=hld - sdelta
else
* echo Pass2 "$&pps" cp2q "$&pcp"
* let sdelta=sdelta / 2
let hld=hld - sdelta
end
if hldmin > pps
let hldmin=pps
end
end
end
end
let cerror=cpd - 1.1
echo Num "$&loopnum" Current Hold "$&hld" sdelta "$&sdelta" current_error "$&cerror" Hold "$&hldmin"
let loopnum=loopnum+1
if loopnum > maxloop
let esw=1
end
if sdelta < terror
let esw=1
end
end
plot all.v(d) all.v(clk) all.v(q)
write outputfile.raw all.v(d) all.v(clk) all.v(q)
.endc
.end