3.1.3 加算器の設計
こんどは、自分で1 ビットの加算器から作ってみます、論理設計では、入力と出力の対応がどうなっているかがわかっていれば、論理設計は終わったも同然です。入力と出力の関係の意味するところは、論理設計の問題ではありません。
◆言語による真理値表の表記
1 ビットの足し算は、次のようになります。
0 + 0 = 0 0 + 1 = 1 1 + 0 = 1 1 + 1 = 0 で桁上がり
これは、このまま真理値表にできそうです。リスト5 が言語で書いた真理値表で、リスト6 がコンパイルで得られたVHDL の論理式です。
リスト5 1ビットの加算器no.1 真理値表
entity main
input a,b;
output c;
switch(a,b)
case 0,0: c=0;
case 0,1: c=1;
case 1,0: c=1;
case 1,1: c=0;
endswitch
ende
リスト6 1 ビットの加算器no.1 論理式
library IEEE;
use IEEE.std_logic_1164.all;
entity main is
port(c0 : out std_logic;
a0 : in std_logic;
b0 : in std_logic);
end main;
architecture RTL of main is
begin
c0 <= (not a0 and b0)
or (a0 and not b0) ;
end RTL;
◆真理値表の構造と論理式
1ビットの加算器の真理値表を使って、真理値表の構造を説明します。真理値表の列は、入力と出力で構成されます。
a とb が入力でc が出力です。入力が2 個ですので、4 行あれば完全な真理値表になります。
図3.3 論理積の取り出し
図3.4 論理和の取り出し
真理値表には、出力が0になる場合と1になる場合の両方が示されています。真理値表の行の意味は、図3.3 のように論理積を示しています。各行の論理積を論理和すると1 になります。真理値表から論理を取り出すには、図3.4のように0 になる論理を取り出したいときには出力が0 になる行の論理積を集めて論理和します。1 になる論理を取り出したいときには、出力が1 になる行の論理積を集めて論理和します。
論理積と論理和は、シンボルによる設計においても言語による設計においても基本になるものですが、真理値表を構成するものを部分的に切り出したもので、結局はこれらを組み合わせることは真理値表を作っていることになります。
論理を作るという作業は、入力に対応する出力が自分が求める機能においてどうであるべきか決めていくことです。それが真理値表の出力値を埋めていく作業になっています。
今回のように完全な真理値表から論理を取り出した場合は、論理的な検証は不要です。論理が大きくなっていって自分が求める機能に対応する完全な真理値表がわからないので、作り上げた真理値表が自分が求める機能に完全に満足するものかどうかを検証で確かめているわけです。
◆桁上がりを考慮した1 ビットの加算器
前回作った1 ビットの加算器に、下の桁からの桁上がりも加算した加算器を作ります。この加算器ができると、必要な個数をつなげて、8 ビットや16 ビットなどの加算器を作ることができます。
<下位の桁上がりがない場合>a b c ci 0 + 0 -> 0 + 0 = 0 0 + 1 -> 1 + 0 = 1 1 + 0 -> 1 + 0 = 1 1 + 1 -> 0 + 0 = 0 で桁上がり |
<下位の桁上がりがある場合>a b c ci 0 + 0 -> 0 + 1 = 1 0 + 1 -> 1 + 1 = 0 で桁上がり 1 + 0 -> 1 + 1 = 0 で桁上がり 1 + 1 -> 0 + 1 = 1 で桁上がり |
| ↓ | ↓ |
a b ci c 0 + 0 + 0 = 0 0 + 1 + 0 = 1 1 + 0 + 0 = 1 1 + 1 + 0 = 0 で桁上がり |
a b ci c 0 + 0 + 1 = 1 0 + 1 + 1 = 0 で桁上がり 1 + 0 + 1 = 0 で桁上がり 1 + 1 + 1 = 1 で桁上がり |
前回作った加算器の出力のc に、さらに下位の桁上がりのci を足します。ci が0 のときの結果を左上に示します。これを新たなc の出力にしたものを左下に示します。ci が1 のときの結果を右上に示します。これを新たなc の出力にしたものを右下に示します。
リスト7 が言語で書いた真理値表で、リスト8 がコンパイルで得られたVHDL の論理式です。
◆8 ビットの加算器を作る
この加算器を図3.5 のように8 個連結すると、8 ビットの加算器になります。1 ビットの論理を作ってから求めるビット数まで拡張する方法です。このように、1 ビット分を作ってしまえば後は単純な作業なので、手作業で設計するのに便利な方法ですが、欠点は1 ビット分の論理が確定する時間のビットの数の総計が動作時間になることです。
これを、8 ビットの真理値表で考えることもできます。その場合は、a が0~255 の256 個でb が0~255 の256 個なので、両方の組み合わせで65536 行の真理値表になります。この大きな真理値表から作った論理が1 ビットの論理をつなぎ合わせた論理よりも速くなるかどうかは、大きな論理がいくつのマクロセルをつなぎ合わせるのかどうかが影響するので、チップの構造により変わってくると思います。
論理は、単純にすればするほど速く動作する可能性が大きくなりますが、単純にしたことの代償に大きくなってしまう場合もあります。このことが、チップ化したときにマクロセルをいくつもつなぎ合わせることになり速度を上げられない原因になりそうです。
開発ツールやチップの種類によって性能が大きく違ってくると思いますが、論理設計の段階では見極めがつかないこのような問題もあります。
リスト7 1 ビットの加算器no.2 真理値表
entity main
input a,b,ci;
output c,co;
switch(a,b,ci)
case 0,0,0: c=0; co=0;
case 0,1,0: c=1; co=0;
case 1,0,0: c=1; co=0;
case 1,1,0: c=0; co=1;
endswitch
switch(a,b,ci)
case 0,0,1: c=1; co=0;
case 0,1,1: c=0; co=1;
case 1,0,1: c=0; co=1;
case 1,1,1: c=1; co=1;
endswitch
ende
リスト8 1 ビットの加算器no.2 論理式
library IEEE;
use IEEE.std_logic_1164.all;
entity main is
port(c0 : out std_logic;
a0 : in std_logic;
b0 : in std_logic;
ci0 : in std_logic;
co0 : out std_logic);
end main;
architecture RTL of main is
begin
c0 <= (not a0 and b0 and not ci0)
or (a0 and not b0 and not ci0)
or (not a0 and not b0 and ci0)
or (a0 and b0 and ci0) ;
co0 <= (a0 and b0)
or (b0 and ci0)
or (a0 and ci0) ;
end RTL;
桁上がりを考慮した加算器を、手続きに書いて図3.5 のようにつないだのがリスト9 です。リスト2 とほぼ同じような論理式に展開されて、図3.1 の1 個分の8 ビット加算器と同じように動きます。
加算器は、言語の演算子によって提供されているので真理値表から設計することはありませんが、言語の上で真理値表を使うときは論理式への変換や論理圧縮などはコンパイラが実施しますので、取り扱いが容易になっています。
図3.5 8 ビットの加算器構成
リスト9 の論理も言語の演算子を使えば10 文字も使わずに書けてしまいますが、演算子によっては大きな論理にもなるので、演算子の表す機能がどの程度の論理になるものかを自分で作ってみて知っておくことは重要なこと
だと思います。
◆減算器
減算器は加算器で作ることができます。A-B は算数ではA+(-B) です。-B は論理的には!B+1 です。mb=!B+1 とするなら、図3.5 のb7~b0 をmb7~mb0 に変えてやれば減算器になります。
リスト9 8 ビットの加算器no.4
{ --------------------------------- }
{ }
{ --------------------------------- }
procedure add
input a,b,ci;
output q[2];
bitn c,co;
q.0=c;
q.1=co;
switch(a,b,ci)
case 0,0,0: c=0; co=0;
case 0,1,0: c=1; co=0;
case 1,0,0: c=1; co=0;
case 1,1,0: c=0; co=1;
endswitch
switch(a,b,ci)
case 0,0,1: c=1; co=0;
case 0,1,1: c=0; co=1;
case 1,0,1: c=0; co=1;
case 1,1,1: c=1; co=1;
endswitch
endp
{ --------------------------------- }
{ }
{ --------------------------------- }
entity main
input a[8],b[8];
output c[8];
bitn int0add[2];
bitn int1add[2];
bitn int2add[2];
bitn int3add[2];
bitn int4add[2];
bitn int5add[2];
bitn int6add[2];
bitn int7add[2];
int0add=add(a.0,b.0,0);
int1add=add(a.1,b.1,int0add.1);
int2add=add(a.2,b.2,int1add.1);
int3add=add(a.3,b.3,int2add.1);
int4add=add(a.4,b.4,int3add.1);
int5add=add(a.5,b.5,int4add.1);
int6add=add(a.6,b.6,int5add.1);
int7add=add(a.7,b.7,int6add.1);
int0add.2=1;
int1add.2=1;
int2add.2=1;
int3add.2=1;
int4add.2=1;
int5add.2=1;
int6add.2=1;
int7add.2=1;
c.0=int0add.0;
c.1=int1add.0;
c.2=int2add.0;
c.3=int3add.0;
c.4=int4add.0;
c.5=int5add.0;
c.6=int6add.0;
c.7=int7add.0;
ende
◆負数減算器は負数を加算する加算器で作ることができるのは先に示したとおりです。負数の-5 は、8 ビットでいえば正数の5 の0000 0101 を否定した1111 1010に1 を足すと1111 1011 になりますが、これが-5 です。5 の0000 0101 を足すと0 になります。
-1 の場合は1 を足すと0 になるので、ビット数がどのようであってもすべてのビットが1 になります。
-5 の1111 1011 は負数でなければ251 ですが、負数を取り扱うときは、最上位のビットを符号を判断するビットに使って残りのビットで数値を表しますから、8ビットなら0~127,-1~-128 までの数値が取り扱える範囲です。
渕上賢二


コメントする