Common Lispの系譜を継ぐuLispをラズパイPico2マイコン上で練習中。前回はregister関数を練習。メモリマップされた周辺回路のレジスタども(メモリでも)を読み書きできる関数でした。これがあれば何でもできそ~。今回はラズパイPico2(RP2350)特有の周辺、TRNGを使って真性乱数をゲットだぜ。
※Lispと一緒 投稿順 index はこちら
※実機確認は Raspberry Pi Pico2で行ってます。
※使用させていただいとります uLisp のバージョンは 4.6b (Arm用)です。
TRNG(True Random Number Generator)
uLispにも random という乱数を発生する関数がありますが、これは「算術的」に乱数を生成するもので、出来の良しあしはともかく、予測可能で計算可能なアルゴリズムで乱数を振り出しているものの筈。一方、ラズパイPico2搭載のRP2350チップにはTrue Random Number Generator という「予想できない自然現象」から乱数(エントロピーとも唱えるみたい。そういわれると学生時代、熱力学に苦しんだのを思い出すんだが)を生成できる機構を備えております。セキュリティの上からモダンなマイコンでは必須になりつつある装備。
TRNGについては以下の別シリーズ回で調べてます。
Pico三昧(46) ラズパイPico2:RP2350、Pico:RP2040、TRNG
今回はregister関数を「駆使」して(ホントか?)、TRNGを試用してみたいと思います。
TRNGアクセス用の自前関数ども
以下は uLisp上でTRNG使うために作成した関数どもです。
(defun sw-trng (onoff) (let ((trng-base #x400f0000) (rnd-src-en #x12c)) (register (+ trng-base rnd-src-en) onoff))) (defun check-trng () (let ((trng-base #x400f0000) (rng-isr #x104) (rng-icr #x108) (retval 0)) (register (+ trng-base rng-icr) 1) (loop (setq retval (register (+ trng-base rng-isr))) (if (/= retval 0) (return retval))))) (defun read-ehr () (let ((trng-base #x400f0000) (ehr-data0 #x114) (res '())) (dotimes (x 6 res) (setq res (cons (register (+ trng-base ehr-data0 (* x 4))) res))))) (defun read-trng () (sw-trng 1) (check-trng) (sw-trng 0) (read-ehr))
TRNGをイネーブルにしたり、ディセーブルにしたりするON/OFFを行うのが sw-trng関数です。1でON、0でOFFです。
TRNGは一度に192ビットの「エントロピー」を発生できるのですが、それには物理的な時間が掛かる上、ときどきエラーも起こるみたいです。そのエラーのなかにはフォン・ノイマン大先生のお名前を冠するものもあり、恐ろし気です。check-trng関数は、滅多に起こらないであろうエラーの時は除き、乱数生成に必要な期間「待つ」ための関数です。生成成功すれば1を返してきますが、万が一エラーの場合は2以上の値が返ります(といってエラーフラグを消していないので、その場合はよしなに。手抜きだよ。)
生成した192ビットの乱数はEHR-DATA[0]から[5]の6個の32ビットレジスタに格納されます。なおEHR-DATA[5]を読み出すと乱数値はクリアされます。よって読み出しの順番大事だな。この読み出しを行うのが read-ehr関数です。
上記の3関数を使役してTRNGから32ビット整数x6個の乱数をとりだす関数が、とっても手抜きな(エラーのことなとかんがえてない) read-trng関数です。こいつが32ビット整数x6個のリストを返してきます。
実機実験結果
上記のread-trng関数を使って ラズパイPico2上のuLispで「真性乱数」を振り出してみた結果が以下に。
評価などしておらんので、素人老人は「真性乱数」なんだかどうか分からんのだが。ま、ハードウエアは動いておるみたいです。