0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ngspiceとSKY130を使ってみる(2) Flip Flop(1)  Tpd,Setup,Hold

Last updated at Posted at 2025-08-27

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
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?