回路シミュレータ without LoL

結局、LoL の alet や dlambda を使わずに再度書き直した。struct をつかった。これにより SICP の関数を返す関数であったり、クロージャーというのは使わなくなった。いいかどうかわからない。たぶん良い方向に舵を切ったと今の時点では思っている。インタフェースも簡素化され、make-xsignal になった。signal というキーワード自身は common lisp が使っているので使えなかった。

第一段階では完全に macro を排除した。その後、and-gate, or-gate が非常に良く似た構造であったためマクロを導入することにした。ここで結局 defmacro! を使う。そのおかげで各ゲートが2行出書けた。nor, nand, xor もさくっと完成。

(defun and-gate (a-input0 a-input1 a-output)
  (in2-out1-gate a-input0 a-input1 a-output and-gate-delay-time logic-and))

(defun nand-gate (a-input0 a-input1 a-output)
  (in2-out1-gate a-input0 a-input1 a-output nand-gate-delay-time logic-nand))

(defun or-gate (a-input0 a-input1 a-output)
  (in2-out1-gate a-input0 a-input1 a-output or-gate-delay-time logic-or))

(defun nor-gate (a-input0 a-input1 a-output)
  (in2-out1-gate a-input0 a-input1 a-output nor-gate-delay-time logic-nor))

(defun xor-gate (a-input0 a-input1 a-output)
  (in2-out1-gate a-input0 a-input1 a-output xor-gate-delay-time logic-xor))

気をよくして rs-ff, rs-clk-ff, latch をつくる。ついでに VHDL で学ぶディジタル回路設計にあった静的ハザードとハザードフリーの回路を作る。シミュレーションするのに時間の概念を小刻みにする必要があったので、propagate に引数を増やして任意の時間進められるようにした。

(defun propagate (delta)
  (if (empty-agenda-p the-agenda)
    (progn
      (set-current-time the-agenda (+ (get-current-time the-agenda) delta))
      'done)
    (let* ((cur-time (get-current-time the-agenda))
           (diff-time (- (caadr the-agenda) cur-time)))
      (if (> diff-time delta)
        (set-current-time the-agenda (+ cur-time delta))
        (let ((action (first-agenda-item the-agenda)))
          (funcall action)
          (remove-first-agenda-item the-agenda)
          (propagate (- delta diff-time)))))))

これにより、シミュレーション用の記述がかけるようになった。テストベンチがかけるようになったわけだ。テストベンチを自動的に読みながらすすめることが出来るようにツールをくみ、probe でも適当に一般的な情報を出せば簡易的な回路シミュレータが出来る。ff の中身の配線は今レキシカル変数として定義されているがパンドラの箱を開けるようにすれば、それも probe 出来るようになる。(かもしれない)

上のプログラムの caadr はださい。何をやっているのかわからない。LoL に tlist の説明にあったようにこれらの Lisp のプログラムは構造自体が API だ。だから SICP ではその構造をアクセスする為の関数に名前をつけている。car ではなく get-current-time と名前を付け替えている。つまり関数自身がデータ構造のコメントになっているのだ。だから、上の caadr はダサい。get-time-of-first-segment としなければならないだろう。まぁいいや。the-agenda つかっているのもださい。

xsignal (これも x はダサい。wired-signal か?)の登録された action はファンアウトの数だから、数が多ければ多いほど遅延をつけるという処理をすればより本物?に近づくかもしれない。あと遅延をゼロにすると暴走する。改良の余地は一杯ある。

しかし、これはここまでだな。いくらなんでもこの and や or で回路のプログラムを書いていくわけにはいかない。edif で回路かけないでしょ。このプログラムは and や or が即シミュレートできる。それは単純で原始的な要素だから。VHDL でも verilog でもいいのだが、そのレベルものを書こうとすると言語仕様を決めただけでは単純な原始的要素あるいはシミューレションに落ちない。コンパイルするという必要がでてくる。インタプリットしてもいいけどそれじゃ将来性がない。

コンパイルして枝を見て枝から必要な回路に落としてやればよい?gcc の md (だっけ?)見たいな記述だね。一回抽象的な言語に落としたほうがいいだろう。and or の抽象的な記述に落とし、そこで、X などがあれば論理圧縮できる。LUT に落とすことも出来るかもしれないな。

ということはまずは and or の抽象言語を作らないといけないということか。それって edif か?