公開日:2025/04/19
title.png

34th Season


#34-6 真乱数発生器(PLL方式)

 Cmod A7ボード(FPGA)を使って、オリジナル16ビットCPUコアMoscoviumの開発を進めています。合わせて、ソフトウェアの開発環境として、Blockly for Moscoviumも整備してきました。

 Blocklyで乱数を発生するカスタムブロックを作ったのですが、応用プログラムを作っていた時に、ハタと困ったのは乱数の種をどうするか?でした。乱数の種……、いつも、ちょっと困るんだぁ。

真乱数と擬似乱数

擬似乱数

 普段ソフトウェアで使う乱数発生関数などは、擬似乱数と言って、一見ランダムに見える数列を使っています。規則的な数列なので、以下の様な特徴があります。

 C言語の標準rand()関数は、線形合同法と言うアルゴリズムを使って、疑似的に乱数に見える数列を返しています。int型のビット幅に寄りますが、16ビットintなら65,536(=216)周期で同じ数列が返ってきます。

 毎回使い始める前に、ユニークな「乱数の種」を設定してやる必要があります。それが課題です。

真乱数

 現実世界でサイコロ🎲を振ると、出た目は真にランダムな値を示します。サイコロを投げた時の微妙な力加減、サイコロが手から離れる時間の微妙な違い、等々、様々な不確定要素があるため、出る目を制御したり予想したりする事は非常に困難だからです。
 この様に、擬似乱数列の様な特徴を持たず、自然界の雑音によって発生する乱数を「真の乱数」と言う意味で、真乱数と呼びます。
 真乱数の生成速度次第では、そのまま「乱数」として使っても良いし、もし、生成に時間を要するならば、疑似「乱数の種」として使う事も可能です。


 過去記事では、Arduino UNOのソフトウェアで作ったことがありました(以下記事)。

  「#6-10 真の乱数を生成する

 上の記事では、フローティングアナログ端子の雑音を使って、真乱数を生成しました。


 Arduino DUEには、真乱数を発生するTRNGユニットが搭載されています(以下記事)。

  「#13-5 DUEのTRNGを使ってみよう

 DUEに搭載されたマイコンSAM3X8Eデータシートには、TRNGユニットのアルゴリズム(動作原理)に言及が無いので、アルゴリズムは不明です。

FPGAで真乱数を発生する

 今回はMoscoviumの応用で使いたいので、Cmod A7ボード(FPGA)で真乱数を発生させたいと思います。

フローティングアナログ端子の雑音

 UNOの時に実施したのと同様に、フローティングアナログ端子の雑音を使う方法で真乱数を発生できるか検討してみましょう。
 Cmod A7ボードのアナログ入力端子は、1V定格の差動入力です。ここに、3.3Vアナログ信号を接続可能とするため、抵抗分圧回路がボード上に形成されています。この回路のお陰で、Cmod A7ボードでは3.3Vアナログ信号のAD変換ができるのですが、副作用としてアナログ端子がGNDに高抵抗接地された状態となっています。
 つまり、アナログ端子はフローティング(開放)ではなく高抵抗接地なので、アナログ端子を開放してAD変換しても0しか読み出すことができず、雑音成分が含まれません。

 仮に雑音成分が含まれたとしても、2入力しかないCmod A7ボードの貴重なアナログ端子を真乱数発生に使うのは、否定的です。

 UNOで実施した真乱数の発生方式は、却下です。

調査

 では、DUEのTRNGユニット等の様に、ハードウェア(LSI)で真乱数を発生する方法には、他にどのような方式があるのでしょうか?

  真乱数を発生する方法を検索(別ウインドウが開きます)

 色々と調べた結果、大きく分類して、以下の2種類が実現できそうな感触を得ました。

 以下、詳細に検討してみます。

真乱数発生器のアルゴリズム検討

リングオシレータ方式

 リングオシレータを発振させ、その発振周波数やジッタなどに含まれる雑音を乱数として利用する方式です。
 FPGAで構築するためのブロック図を以下に示します。

a346_trngosc.png

 リングオシレータは、ゲートループあるいはタイミングループと呼ばれる種類の回路であり、STAはじめ論理合成、論理シミュレータなどのツールでエラーとして報告される事象です。従って、FPGA内にリングオシレータを作り込む事はできません。
 そこで、上図の様にI/Oポートを2本使い、Cmod A7ボードの外部で直結(短絡、ショート)して使う事により、リングオシレータを作ります。

 UNOで実施したフローティングアナログ端子のケースもそうだったのですが、LSIチップの外部端子を使って真乱数を生成するため、真乱数の発生に対して外部から干渉可能な恐れがあります。耐タンパ性が低下するという短所に繋がります。
 個人の趣味のレベルで生成する真乱数なので、耐タンパ性を無視したとしても、外部回路の接続忘れなどがあると真乱数の発生を妨げてしまう恐れもあります。
 そもそも、貴重なI/Oポートと言うリソースを2本も、真乱数の発生に使ってしまう事に抵抗があります。

 以上の理由により、この案は却下と致します。

PLL方式

 PLLのジッタと、FFに於けるメタステーブル状態を雑音源として、乱数を生成する方式です。
 FPGAで構築するためのブロック図を以下に示します。

a346_trngpll.png

 上図の通りFPGA内部で閉じて形成できる事は、1つの特長と言って良いでしょう。
 PLLによって、入力クロックclkと出力クロックpll_clkの位相が揃っています。初段のFFには、データとしてclk、クロックとしてpll_clkが接続されているため、データとクロックが同時に変化する回路を形成しています。

 この様な回路では、FFの出力が0/1に確定しない、メタステーブルと呼ばれる状態に陥る事が知られています。下図で解説します。

a346_metas.png

 上図には、FFに到達したクロックpll_cllkとデータclkの変化タイミングがぴったり重なってしまった場合の波形図を示しています。

 0/1と言う二値論理が前提となって成立している論理回路設計に於いては、0/1が確定できないメタステーブル状態を引き起こすような回路は有ってはなりません(禁止)。このため、この様な回路構成を作り込んだ場合、STAにてセットアップまたはホールド違反として報告される事になります。
 設計者は、STAのタイミング違反を修正しなくては、なりません。さもないと、0/1が確定しない論理動作によって回路が誤動作する為です。
 真乱数発生回路では、このメタステーブル状態(不確定状態)を雑音源として積極的に利用します。

 この方式の真乱数発生回路では、雑音源の1つはメタステーブル状態ですから、該当するFFに於いてクロックとデータの位相差を合わせ込めるかどうか?がポイントです。
 しかしながら、クロックとデータの到達時間をぴったり合わせ込んで(点と点の合わせ込み)、メタステーブル状態を作り出すのは、大変困難なのです。

  何故なら、そういう状態を作り出すことは論理設計としては「禁止」なのですから。

 普通はSTAにてタイミング違反(セットアップ/ホールド)が報告される案件だと申し上げました。禁止されている状態を作り出すような合わせ込み機能なんて、普通は用意されていないのです。


 上に示した回路を作り込んでCmod A7ボード(FPGA)へ書き込み、実際の動作で確認してみたところ、案の定、決まった値しか出力されませんでした。
 上図の回路例だと、規則的な0,1,0,1,0,1,……の繰り返しが出力されます。どこかでもう少し、メタステーブル状態が発生して、0,1,1,1,0,1,……など、不規則な値が出力されるのが期待でした。恐らく、クロックとデータの位相関係がぴったり同時に調整できておらず、少しずれたことで、確定値がラッチ出来てしまっているのでしょう。

 う〜ん、理論としては正だけど、実装としては否な回路構成ですね。

SSCG方式

 PLL方式は、理論としては正だと考えられるので、少し知恵を絞ってFPGAで実現容易な案を考えてみました。
 SSCG(Spread Spectrum Clock Generator)を使って、クロック周波数を意図的に変動させ、データとの到達時間を点と点ではなく、点と線にすることで、メタステーブル状態を作り出す案を検討してみたいと思います。

 Cmod A7ボードのXC7A35Tには、SSCGを適応可能なMMCM(Mixed-Mode Clock Manager)と言うクロック生成マクロ(機能的にはPLL)が搭載されていて、最大5個使用する事ができます。
 MMCMマクロにてSSCGを適応するには、入力クロック≧25MHzの条件があります。Moscoviumのシステムクロックclkの周波数=24MHzなので、入力クロック周波数の条件を満たしていません。そこで、前段にもう1個PLLを追加して、システムクロック24MHzを48MHzに逓倍して回避します。
 SSCGを使った真乱数発生回路のブロック図を以下の通りに考えてみました。

a346_trngsscg.png

 PLL1は、入力クロックを×2逓倍します。PLL2は、入力クロックを÷2逓倍(分周)した上でSSCGを適応します。その次段FFがメタステーブル状態となって雑音を発生する素子です。

PLLとSSCG

 ここで、PLLとSSCGについて解説しておきます。

a346_pllsscg.png

 PLLと言う回路は、

 位相比較や発振はアナログ回路なので、常にアナログ的に合わせ込みを実行する都合上、位相や周波数が変動します。この現象をジッタと呼びます。PLL方式ではジッタを雑音源の1つとして利用しています。

 これに対して、EMIノイズ低減などを目的としてクロック周波数を作為的に変動させる技術がSSCGです。恐らく、フィードバックするクロックの分周比を論理的に変動させて実現しているのだと思われます。結果、ジッタ特性とも相まって、出力クロックの周波数がジッタよりも広い範囲で変動します。

 SSCGには周波数の変動範囲によって、主にセンタスプレッドとダウンスプレッドが存在します。

 今回はSSCG(センタスプレッド)を、FFへのデータ入力側のPLL2に適用する事で、クロック入力側PLL1との位相差を変動させ、メタステーブル状態を意図的に発生させようと考えています。

 回路を作り込んだその一点では、うまくタイミングが合わず、メタステーブル状態を作り出せなかったとしても、SSCGによって周波数が変動する事で、変動した範囲内のどこかでタイミングが合い、メタステーブル状態を作り出すことが可能なはずです。

乱数ビットの織り込み(LFSR)

 ここまでに検討してきた、いずれの方式でも、発生するのは1ビットの乱数です。これがクロックサイクル毎に発生するので、すべて回収して複数ビットから成る真乱数にするためにLFSR(Linear Feedback Shift Register)を使います。
 LFSRの出力値(M系列)は、数値だけ見るとランダムな値の羅列に見えます(以下参考データ)。

  実験サンプル:シミュレーション結果ログ
  RDY:
  trngrand:
  c9425428
  1351f31c
  c0c5e5d2
  31aca0b8
  b14408f1
  9e20f16a
  7424d7d7
  973696a5
  16b3e345
  d951a91c
  7ec00b5f
  e93c6843
  d701be73
  cb6ca79a
  2399b36a
  8d42e518

 しかし、シミュレーションして波形として見てみると、以下図の様に見えます。

a346_lfsrwf.png

 時間軸の進行に伴って、上位ビットから下位ビット側へデータが移動して行く様な、規則的波形が観測されるのです。LFSRの基本構造はシフトレジスタなのですから当然です。
 これを乱数として使う時、ビット毎に何らかの動作を決定するパラメータとして使ってしまうと、時系列で関連のある、「規則的な数列」の様な振る舞い(※)となってしまう場合がある事に留意してください。

※例えば、各ビットをLEDの駆動信号として割り当て、LEDを順番通り左→右の順で一列に並べると、光が左から右へ流れて行く様な、規則的な点滅が観測されます。

 対策としては以下の様な案が考えられます。

 「物理的な雑音を使って真乱数を生成する」という本ページの趣旨とは無関係ですので、注意喚起に留め、対策はソフトウェアでの工夫にお任せ致します。


 真乱数を発生させるアルゴリズムの考案が完了しました。次回、具体的な回路を設計して完成まで漕ぎ着けようと思います。


btn_arduino.png

btn_prev.png btn_next.png

home