論理回路を大局的に理解するにはverilog HDLをザクッと学ぶとよい

論理回路の基本を知ってたほうがいいかもしれない。どこから勉強したらいいのかわからなくて時間をつぶしたことがあるので書いときます。なんというか大局的理解、というのが結構大事だと思います。詳細は必要に応じて勉強すればいいんです。

* まずRTL(レジスタトランスファレベル,以下で説明）の回路を学ぶべき。回路と言ってもプログラムです。線を引いたりしません。pythonの基本プログラミングができるレベルの人になら〜５時間で大体のことは学べると思う。休みの日にゆっくりと学べるぐらいです。

* RTLの回路図を言語的に記述するにはverilog HDL(hardware discription language)が使われる。これをザクッと学ぶのがよい。それで簡単なテレビゲームの回路（と言ってもverilog HDLで書かれたプログラム）みたいなのがどうなってるかを雰囲気理解できることが目標。その後はCPUなどの理解に進むことができる。論理回路を勉強するのに物理的なデバイスの知識はほとんど必要ない。たとえばwikiにあるようなverilog HDLで書かれたプログラムを直接読んでも（以下ぐらいの素朴な知識だけで）結構理解できるんじゃないかと思う。機械や物理の人でも最低限レベルは学んだほうがいい思う。

* ただそうは言ってもそういうたぐいの本や文書を突然読み始めるとイラッとします。その本を読むための前提が、ある種の業界の大学３年ぐらいなら知ってるはず、というようなものだからです（想定読者の知識が自分の受けた教育経験をもとに想定されている）。なのでその常識を補うという意味で書いときます。出発点はpythonプログラミングがある程度わかる人、ぐらいです。

---

* まず知るべき点：論理回路は、
　１．クロック
　２．組み合わせ回路（LUT、ルックアップテーブルなどと言われる）
　３．メモリ
からなること。組み合わせ回路だけでは計算はできない。（大雑把には）メモリの組み込まれた回路を順序回路と言う。もちろん２進数の世界です。クロックに応じて、入力、出力、内部状態が変化していくのが論理回路。内部状態はメモリで保持されている。

１．クロック
はグラウンドレベルに対して０，１，０，１，。。。と変化する。
以下、その立ち下がりタイミング(1->0)を利用するとする（たち上がりでもよい）。クロックは1nsecとかで動作している。データを読んだり書いたりするのはこの立ち下がりタイミングにおいてのみ。そのタイミングの前後で例えば±0.1nsecとかは値が保持し続けられる必要がある。それ以外の時間は状態が定常状態になるのを待つのに必要な遷移時間である。

２．組み合わせ回路（LUT)
　入力wireN本と出力wire１本からなる。
これは２^N個の値に対して０か１の値を対応させるという計算であるが早見表を見れば済む（N=3なら入力値８個に対して出力値が１か０と書いてある早見表。これがLUT＝組み合わせ論理回路での計算である）。
入力wire複数本に０か１の値をあたえて保持して既定のクロック数だけ待てば（たとえば数クロック待てば）、出力wireには早見表の値が安定的に保持されている。
出力wireの値は入力wireの値の関数として決定される。純粋な組み合わせ回路では内部状態はない。LUTは基本的には加算とかの演算回路である。
　LUTはAND,OR,NOTがあれば作れるのだがそういうことについて細かく知る必要はないー（上の早見表のアイデアを知っていれば済む）。入力wireの値が保持され続ける限りにおいてのみ、出力wireの値が保持され続ける点に注意が必要である。
　注：現実には、純粋な組み合わせ回路、というのは理想化された考え方。なんらかの内部状態のスイッチ(メモリ、以下）を持ち、それに値を入れて組み合わせ回路の動作バターンを変える、というのはよくある。なので正確に言えば純粋な「組み合わせ回路」はちょっと特殊なもの。

  LUTだけだと計算は困難である。ステップを踏んで計算をすすめるには、入力値から、まず一旦Xを得て、それからYを得る、というような手順が必要になる。このときには以下のメモリ(reg)が必要になる。
  
  これに関して、ちょっと思考実験をしてみる。たとえば第１原理電子状態計算で金属か非金属化を決定する、という計算を想像してみる。入力は２^N個のデータ（Nは結晶構造を指定するだけの変数）として与えられるのでこの解を与えるLUTがあるのならそれを通すだけで答えが出る。ただしそのLUTは超巨大で実現不可能なものである。一方でこれを小さいサイズの多数のLUTとメモリを組み合わせることで実現が可能である（ただしメモリを使って細かくLUTを通していくことが必要になる）。代償としてかなりのクロック数が必要になる。要するに計算量は「ステップ数ｘLUTサイズ」で決まっているということ。

３．メモリ
上述のように過去結果を記憶しておかないと計算はできない。メモリをverilog HDLではregと書く。regは入力wire1本、出力wire1本と、タイミング端子1本を持っていて、タイミング端子が立ち下がりのタイミングでregの出力wireの値は入力wireの値にリフレッシュされる。もちろんこれを多数個束ねて用いることになる。

組み合わせ回路Aの出力wireに「reg(出力端の数だけ用意する）の入力wire」を接続しておくとどうなるか？組み合わせ回路Aの入力wireの値があるタイミングで変わったとするとregの入力wireの値（=回路Aの出力wireの値）も変わるのでその出力wire値も変わるが、regに「タイミング端子立ち下がり」を与えるまでは回路Aの過去出力wireの値がregの出力端に保持されている。「regのタイミング端子が立ち下がり」を起こさせてはじめて回路Aの新規出力である「regの入力wire値」をregの出力wire値に移送・保持できる。

これではじめて組み合わせ回路Aの入力に対して出力を得てregへ落とし(carry out)、それを組み合わせ回路Bへいれて(carry in)結果を得る,というような順序回路が可能になる。

--- 
<!---* 論理マシンを作るとは巨大なLUTを作ることだ、と言える。長い桁の加算器を単一の1桁加算器（繰り上がりあり）から作ろうとすると、どうしても繰り上がり(carryin carryout)を保持するメモリが必要。クロック数も必要になる。しかし、大きなLUTであればワンクロックで答えが出る。すなわち「入力値が2^N個で出力値が２個であれば、2^N->２となるLUTは2^{N+１}通り」。FPGAだとN=4かN=6となるLUTが基本となるらしい。
* ちゃんと動くかどうか？には実時間を想定し物理的な時間要件を考慮したタイミングシミュレータが必要になる。
--->

* 一般に普通のプログラムはメモリと条件分岐と繰り返しがあればどんな計算でも書ける。同様に、これらだけでどんな論理マシンでも書ける.
* CPUなどもこれらの応用。ARM,AMD,NVIDIAでもHDLを書いてるだけ（IPコア）。ソフトが物理的な実装に落としこんでくれる。
* 普通の意味のプログラミングとの違いを考える。verilog HDLではwireとregという２つのタイプの変数を考慮する必要がある(wireは中間的変数。regの値(出力値）は記憶されうるので普通のプログラムで使うような変数）。モジュール分割して設計するが、各モジュールには、wire入力,wire出力,reg出力,がある。また内部状態としてのregもある。
* 普通のpythonプログラミングにおいては計算手順だけが時間軸であるが、verilog HDLではクロック（たち下がりタイミング）を意識した計算手順を書く必要がある。クロックによって同期的に値が変更されていくということ。この点以外に違いはないです。

* 論理回路を大局的に理解するには「verilog HDLプログラミングをざくっと勉強する」というのが良いです。その上で、ゲートレベルのフリップフロップの簡単な場合も理解しておけばいいと思う。フリップフロップではNANDを双安定性を持つように結線するー結果を得るには入力値を与えて定常状態になるまで待つ必要がありますー論理としてのNANDを結線しただけでは理解できないです。

* verilogHDLで書けるRTL（レジスタートランスファーレベル）をまず理解しましょう、ということです。RTLの概念は1980ごろに打ち立てられたんだと思う。それ以前では、ゲートレベルの回路をブロックとして直接組み合わせて設計していたのかもしれない。多数のモジュールを階層的に組み合わせたCPUなどの巨大な論理回路、というのは結局（その入力はキーボードなどほんのわずかなもの）、レジスタに格納された内部情報をどう伝達し遷移させていくか？ということになります。なのでRTLと呼ぶわけです。RAMやHDDなどの外部装置は、CPU本体から見ると、外部バスに何かを書いてしばらく待つと何かが返ってくる（メモリを指定し、アドレス端子に値を書いて、読むか書くかのフラグも書いて、しばらく待つと、データ端子に値が戻る。読み書きできたかどうかのコンファメーションのフラグも戻る）、と言うだけのものです。

* FPGAがどうなってるのか？の雰囲気をだいたい理解する、のはそんなにむずかしくないです。たとえば機械の制御したいだけならRTLレベルで十分です。