アドレスバスとデータバス

アドレスバスとデータバス

 アドレスは「住所」に訳される事が多いのですが、日本語にしてもあまりよく理解できない。という方が多いようです。

 アドレスはデータの場所を示す番号です。そして、アドレスはバスで構成されます。つまり、数本の信号線を束ねて「アドレスバス」と呼んでいます。

 アドレスバスは(例外がありますが)、通常は一方通行です。CPUなどの何らかのホストがアドレスを生成します。

アドレスバスとデータバスの構成を上図に示しました。

 上図ではアドレスバスを4ビット。データバスを8ビットにしました。アドレスバスには、必ずアドレスデコーダ(address decorder)が必要になります。アドレスデコーダは、アドレスバスの信号内容を読み取り、何番を指示しているのかを判別します。この「何番」というのを通常は「何番地」というように住所に似せて言います。「アドレスの2番地」という呼び方です。

 上図ではアドレスデコーダを2進数で記載しています。通常はアドレスデコーダーは16進数で指示します。「アドレスの2番地」は16進数での2番地になります。なので、「アドレスのa番地」という事もあり得ます。アドレスの”0010″番地という言い方はありませんし、10進数で言う事もありません。アドレスは必ず16進数で言います。

 上図の右半分にあるDFFに着目してください。DFFはデータバスに接続されていて、DFF(7)ならDFF(7)どうしが接続されています。同じようにすべてのDFFは同じ番号が接続されます。この場合8ビットなので、ビットの重みがすべて同じDFFに接続されていることになります。これがデータバスです。そして、DFFのイネーブル(有効)端子にアドレスデコーダが接続されています。このような構成にすることで、指定したアドレスのDFFだけが有効になります。

 アドレス2番地(=”0010″)の時にどうなるのかを図示したのが下の図です。

 アドレスバスは”0010″になって、2番地を指示しますので、アドレスデコーダは”0010″のアドレスデコーダだけが動作してイネーブル信号を出します。このイネーブル信号に接続されている2番地のDFFは8ビットすべてが有効になり、アドレスバスからアクセスすることができます。他のDFFは無効なので、アドレスバスには影響しません。

 一般に、指定された番地にDFFが接続されていれば、メモリと呼び、定数などが接続されていれば、ROMと呼びます。そして、直接FPGAの足に接続されることもあります。その時にはレジスタやIOと呼ぶことが多いです。

 このようにして、データバスは8本だけなのですが、アドレスバスと組み合わせることで多くのメモリやレジスタなどにアクセスすることができます。

 上の図では0番地~F番地までの16個の番地でした。よって、アドレスも4ビットで足りました。もっと多くの番地数が必要であれば、アドレスバスの数を増やせば良いのです。256番地必要であれば8ビットのアドレス信号が必要という事になります。

 また、データバスも上図では8ビットでしたが、16ビット、32ビット等に増やすことも可能です。ちなみに、データバスのビット数はCPUでいう所の”ビット数”と同じ意味です。8ビットCPUであれば、データバスのビット数は8ビットですし、windows10等のOSで使われている64ビットというのはデータバスが64ビットのCPUをターゲットにしています。

 8ビットより、16ビットの方が高性能なCPUというのは、同じデータの数を動かす時に、16ビットバスは1回で済むところを、8ビットバスであれば、2回動作しなくては、16ビット分の処理ができないからです。なので、64ビットCPUは一気に64ビット処理してしまうので、高性能なCPUという事になります。

 ここまでは、アドレスとデータの関係なので、そう難しい事はないのですが、アドレスの示す先がバイトである。という概念が出てくるところから混乱するようになります。

 アドレスは、先に示したようにアドレスデコーダでメモリやIOの番地を示すものです。アドレスの信号線は番地の分だけ用意されます。

 ところが、データバスはある単位で用意することが多く、8ビットバスや16ビットバス、32ビットバスなど、8ビット単位で用意される事が多いようです。

 この8ビット単位が曲者で、8ビット単位=バイトと定義することが多く、バイト単位での番地付けというのが定説になっています。番地を示すのは8ビット=バイト単位で、16ビットでも32ビットでもないのです。これは決まり事なので、FPGAの内部を自由に設計して良いという理由で、16ビットをまとめて1番地にできるのですが、一般論としては1つの番地に与えられるのは8ビットの1バイトになっています。

 16ビットバスを例として、図で示すと上図のようになります。16ビットのデータバスを8ビットで区切って、1バイトに1つの番地を割り当てます。このときに、16ビットバスの上半分(D15~D8)と下半分(D7~D0)のバイトデータに分けますが、上図のように下から番地を割り当てる方式をリトルエンディアンといいます。

 逆に上から番地を割り当てる方式をビックエンディアンと呼びます。
 この時、どちらの場合でもデータバスの最下位ビットをLSBといい、最上位ビットをMSBといいます。

 次に、16ビット以上のデータバスの場合、ワードやダブルワードなどの定義がありますが、ワードが16ビットで、2バイト。ダブルワードが64ビットで8バイトなどの定義付けをされる事が多いようですが、これらの定義に決まりというのはありません。32ビットをワードと言っても間違いではありませんし、32ビットをダブルワードと言っても間違いではありません。したがって、ワードやダブルワードを使用する場合には、お互いに定期付けをはっきりする必要があります。

 1バイト単位でアドレス(番地)が割り当てられるのは理解できたと思います。しかし、このままではせっかく16ビットや32ビットのバス幅があるのに、意味が無いのが理解できるでしょうか? いちいちアドレスを1番地単位でデコードしていては、16ビットバスの意味がないのです。

 上図の16ビットバスの使い方が意味のない使い方です。アドレスデコーダがアドレス1番地毎にデコードしており、16ビットバスの下位バイトをアクセスするとき、上位バイトをアクセスするとき、の2回アドレスを発生しなくては16ビットにアクセスできないからです。

 では、どのようにアクセスするのが効率的かといえば、偶数アドレスにだけアクセスするようにします。このようにアクセスすることで、偶数アドレスは16ビットデータの下位8ビット分。奇数アドレスは上位8ビット分に割り当てる事ができ、アドレスの生成も1度で2バイトアクセスできるようになります。

 ハードウェア的には、偶数と奇数を判別する必要がありますが、実はこれは簡単なことで、アドレスの最下位ビットであるAdd(0)のビットを読むだけで偶数と奇数が判別できます。また、どうせ偶数アドレスにしかアクセスしないので、Add(0)を無視する(接続しない)というのが一般的な設計方法になります。