第1章 レジスタとは ― CPUの手元の作業台
x0 がいつも 0 である理由、倉庫(メモリ)との違いも見ます。ここが土台になって、第2章でブロックを組む時、第3章で命令が流れる時の様子がイメージできるようになります。
1.1 そもそも「途中の値の置き場」が、なぜ要るのか
読み物で見たとおり、CPUは「計算する部品」でした。たとえば「3 と 5 を足して、その答えに 2 をかける」。手計算でやるなら、まず 3+5=8 を出し、その 8 をいったん覚えておいて、次に 8×2 を計算して 16 を出します。この「いったん覚えておく」場所がなければ、足し算の答えをかけ算に渡せず、計算は一歩も進みません。
CPUもまったく同じです。計算の途中の値を、ほんの一瞬、すぐ手の届くところに置いておく場所が要ります。その置き場がレジスタです。
1.2 置き場のレジスタ ― 厨房の「作業台の桝」
レジスタを厨房でたとえるなら、コックの手元にある 作業台の桝(ます)です。計算中の値を、遠い倉庫まで行かずに、ちょいと手元の桝に置いておく。すぐ取り出せて、すぐ書きかえられる――これがレジスタの役どころです。この章は、その作業台を、ていねいに分解していきます。
1.3 【核心】混同しやすい3つの数を、分けて理解する
ここが、いちばん大事で、いちばん混同しやすいところです。レジスタの話には「32」が二度出てきて、しかも別物です。あわてず、3つの層に分けます。
- 作業台は、1つ。 厨房に作業台はひとつだけ。これがCPU全体で レジスタファイルと呼ばれるものです。
- その上に、桝が32個。 作業台は仕切られていて、桝が32個ならんでいます。この桝ひとつが レジスタ。桝には名前があって、
x0, x1, …, x31。たとえば「x1」は「1番の桝」という名前で、0 や 1 ではありません。 - 桝1個の中は、升目が32個。 桝の中をさらにのぞくと、升目――小さなお皿のように、ひとつにつき 0 か 1 をのせる枠――が32個。この32個の並びで、ひとつの数を表します。これが「32ビット」で、升目が 0/1 なので2進法です。
x0〜x31)。桝1つがレジスタで、その名前が「どの桝か」を指す。x0 だけは中身が常に 0。x1)の中身。名前(x1)と、中身(0/1 が32個)と、進法(2進法)は、それぞれ別の話です。まとめると――作業台1つ・桝32個・升目32。「1・32・32」は、それぞれ別の階層の数です。x1 は名前、中身は 0/1 が32個、進法は2進法。混ざりやすいので、この三つは切り分けて覚えてください。
1.4 桝の名前は「アドレス」 ― どの桝か、を指す番号
x0〜x31 という桝の名前は、じつはアドレス(番地)です。命令が「x1 と x2 を足して x3 へ」と言うとき、x1・x2・x3 は「どの桝か」を指す番号。桝は32個しかないので、番号は 0〜31 で足ります(とても小さい数です)。だから命令は、ほんの数桁で「どの桝か」を名指せます。あとで倉庫(メモリ)の番地と比べると、この「小ささ」がレジスタの速さにつながっていることが見えてきます。
ここで、少し設計者の目で見てみます。なぜ桝は32個なのか。これは綱引きの結果です。少なすぎると、値の置き場が足りず、倉庫(メモリ)への往復が増えて遅くなる。多すぎると、桝の名前(番号)を表す桁が増えて命令が太り、回路も大きくなる。32個なら、番号は5桁ぶん(5ビット)でちょうど名指せて、置き場としても足りる――この“ちょうどいい”あたりに、RISC-Vは32個と定めています。設計とは、こうした綱引きのバランスを選ぶことなのです。
1.5 x0 は、いつもゼロ ― なぜ 0 固定が得なのか
桝32個のうち、x0 だけは特別です。中身が常に 0 に固定されていて、何を書こうとしても変わらず、読むと必ず 0。一見むだに見えますが、これがあると命令がすっきりするのです。たとえば――
- コピーが作れる。 「x3 = x5 + x0」は、x5 に 0 を足すだけ= x5 の写し。専用のコピー命令を作らずに済みます。
- 捨て場になる。 いらない結果は x0 に書く。x0 は変わらないので、そのまま消えます。
- 「何もしない」も作れる。 x0 に書き込む命令=実質なにも起きない(いわゆる NOP)。
ゼロ専用の桝が1つあるだけで、これだけ得をします。その代わり、自由に使えるのは 32個中 31個。升目のほう(桝の容量=32ビット)は、まるごと使えます。「桝の個数は32だが、使えるのは31」「升目(ビット幅)は32まるごと」――この二つを、混ぜないのがコツです。
1.6 倉庫(メモリ)との違い ― だから命令は「載せて・計算して・戻す」になる
「値を置くだけなら、メモリ(RAM)もあるのに、なぜ別に桝が要るのか」。速さと近さが、まるで違うからです。作業台の桝は、手元にあって一瞬で取れる――けれど数は32個きり。倉庫(メモリ)は、いくらでも置けるかわりに遠くて、取りに行くと何拍も待たされる。アドレスの面でも同じで、桝は32個だから番号が短くすぐ名指せる。倉庫は棚が膨大で、番地が長く、取りに行くのも遠い。
・レジスタ=作業台の桝。CPUのすぐ内側にある、ごく小さくて非常に高速な置き場。数は32個きり。
・メモリ(RAM)=倉庫。CPUの外にある、大きいけれど“遠い”置き場。いくらでも置けるが、取りに行くのは遅い。
CPUの計算は猛烈に速いので、そのつど倉庫まで往復していたら、肝心の計算する手(ALU)が手待ちになってしまう。だから、いま使う数個の値だけは、手元の桝に載せておく。ここから、計算は自然と次の三拍子になります。
- 載せる。 倉庫(メモリ)から、いま使う値を作業台(桝)に持ってくる。
- 計算する。 桝どうしの値を ALU に渡して計算し、結果をまた桝に戻す。
- 戻す。 用が済んだ値を、桝から倉庫へ片づける。
厨房でいえば、こんな具合です。 「x5 と x6 を合わせて、x7 に置く」という命令を、シチュー作りにたとえてみましょう。桝 x5 には下ごしらえした玉ねぎが、桝 x6 にはにんじんが、もう載っています(升目の 0/1 が「どの材料か・どれだけか」を書きとめています)。命令が指すとおり、コンロ(ALU)が x5 と x6 の中身を読み取って合わせ、ひと煮こみし、できあがりを行き先の桝 x7 に盛ります。このとき――
- 材料の桝は、減りません。 玉ねぎ桝(
x5)とにんじん桝(x6)は、読まれるだけ。料理に使ったあとも、中身はそのまま残ります。 - 戻し先は、名指しした桝ひとつだけ。 できあがりは、命令が指した桝
x7に盛ります。x7に前あった中身は捨てられ、升目32個がまるごと新しい値に置きかわります。 - 読むのは2つ、書くのは1つ。 「2つの桝を合わせたから、2つに分けて戻す」のではありません。桝を2つ読んで、結果を桝1つに書く――これが計算の基本の形です。
RISC(そしてRISC-V)の命令が、この「載せる(ロード)/計算する/戻す(ストア)」に役割をくっきり分けているのは、偶然ではありません。作業台が狭いという物理の事情が、命令の形そのものを決めているのです。このリズムは、第3章の「5つの手順」で、もう一度はっきり姿を現します。