初期にはNational Semiconductor社のMM57109のように、電卓用のLSIの入出力部をマイクロコンピュータのバスに接続できるように改造したようなチップもありました。比較的安価(1万円しないという意味で)ですが、中身が電卓用なので、四則演算でも0.1秒くらいかかってしまいます。
本格的な高速浮動小数点演算用周辺チップとして開発されたのがAMD社のAm9511です。AMD社はこのほかにもユニークで高性能な8080周辺チップを開発しています。DMAコントローラのAm9517なんかもAm9511と同じ時期の製品ですね。このAm9511も8080の周辺チップで、2
MHzクロックで8080バスにI/Oポートとしてそのまま接続できるようになっています。CPUからI/Oポートにアクセスする形で演算対象のデータやコマンドを書き込んで、結果を読み出します。
32 bit長の単精度浮動小数点演算と16 bit整数と32 bit整数の演算が行えます。四則演算の他、初等関数の計算もできます。浮動小数点の四則演算なら100
us程度で実行できます。sinやcos関数なら2 ms、logなら3 msで計算可能です。当時の8
bitのマイクロプロセッサを用いてソフトウェアで四則演算を行わせると、1 msから10
msくらい必要でしたから、一応は桁違いの性能を実現できます。逆にこれ以上高速でも、当時の8080Aの速度では浮動小数点数をAm9511とメモリ間で転送する時間が40
usくらいかかりますから、データをマイクロプロセッサが与えて演算指令を書き込み結果をメモリに戻すなんてのに必要な時間の方が長くなってしまい、トータルの計算時間を短縮できないので、無意味です。連続した計算なら、前回の計算結果はAm9511の中にありますから、次の数値をひとつとコマンドを与えるだけでよいのですが、それでも50
usくらいはCPUが消費するので、トータルの計算時間は約150 us。仮にAm9511が2倍の速度になっても100
usだし、1 usで計算を終えることができたとしても約50 usで、努力の程度ほどトータルの速度はあがりません。そのくらいに高速なLSIが実現できたとすれば、CPUを介さずにLSIの側でDMAを用いてデータと命令をメモリから勝手に読み込んで次々と演算を行っていくような形にしなくては効率があがらず、結局はそれって新しいCPUを開発するのと変わりませんから、8
bit CPU用の周辺LSIとしては大規模になりすぎて、労力をつぎ込まれなかったのでしょう。すでに次世代16
bit CPUの開発が行われつつありましたから。
姉妹品として倍精度浮動小数点の四則演算専用の(初等関数はできない)Am9512がありました。共に大変に高価なLSIでした。たとえば1979年4月ごろの秋葉原店頭での価格は79000円だったりしました。しかしCPUとデータをやり取りして、せいぜい演算終了時割り込みを発生させるだけですから、ピン数は少なくて済み、このように24ピンのコンパクトなパッケージです。
電源は+5 Vの他、+12 Vも必要。
では実際の使い方と性能について見ていきます。
CPUからAm9511を眺めると、読み書き可能なデータレジスタと書き込み専用のコマンドレジスタと読み出し専用のステータスレジスタだけがアドレス空間に割り当てられています。コマンドレジスタは演算命令を指示するのに使用します。ステータスレジスタは演算が完了したかとか符号やゼロや演算エラーなどのフラグ類を読み出すためのものです。
さて、データレジスタは実際には16 Byte分のスタックのへの読み書き窓口になります。浮動小数点数データや32
bit長整数データの場合には4レベルのスタック、16 bit長整数データの場合には8レベルのスタックにデータを配置できることになります。そうして、単項演算命令の場合にはスタックトップのデータに対して、2項演算命令の場合にはスタックトップとそのすぐ下のデータに対して、演算を行うのが原則です。
すると、ある程度の複雑さの数式ならば、逆ポーランド記法の順序でデータと命令を与えてやれば計算ができそうですが、実際にはそんなに簡単に行きません。後で詳細な命令表を掲載しますが、そこからわかるように関数の類の演算の作業領域として同じスタックが使われてしまうことがあるのです。たとえば逆三角関数のASIN命令の場合には、スタックトップのデータをポップしてからそのASINを求めて、その結果をスタックトップにプッシュしなおすのですが、他の3レベルのスタックのデータがすべて失われてしまいます。というわけで、内蔵スタック領域をCPUが活用するのは命令実行の細部まですべて理解する必要があり、結構面倒なことになります。
結果的に、一般的な使い方というと、1ないし2個のデータをプッシュしてから演算命令を発行し、演算結果が得られたらスタックからポップするということになります。せいぜい一連の演算を連続実行する場合に、結果をいちいちポップするのをやめて、追加のデータをひとつプッシュしてから2項演算命令を発行するのを繰り返すくらいの使い方しかできなさそうです。
具体的な命令については、浮動小数点数命令、32 bit整数命令、16 bit整数命令の順に説明します。
まずは浮動小数点数に対する命令です。
命令 Code スタック SZOCE クロック数 意味
ACOS 06 R U U U ** *
7734 Inverse Cosine of A
ASIN 05 R U U U ** *
7668 Inverse Sine of A
ATAN 07 R B U U **
6006 Inverse Tangent of A
CHSF 15 R B C D **
18 Sign Change of A
COS 03 R B U U **
4118 Cosine of A
EXP 0A R B U U ** * 3794-4878
Exp(A) function
FADD 10 R C D U ** * 54-368
Add A and B
FDIV 13 R C D U ** * 154-184
Divide B by A
FLTD 1C R B C U **
98-378 32 bit Integer to Floating point conversion
FLTS 1D R B C U **
98-186 16 bit Integer to Floating point conversion
FMUL 12 R C D U ** * 146-168
Multiply A and B
FSUB 11 R C D U ** * 70-370
Subtract A from B
LOG 08 R B U U ** * 4474-7132
Common Logarithm of A
LN 09 R B U U ** * 4298-6956
Natural Logarithm of A
POPF 18 B C D A **
12 Stack Pop
PTOF 17 A A B C **
20 Stack Push
PUPI 1A R A B C **
16 Push Pi onto Stack
PWR 0B R C U U ** * 8290-12032 B**A
power function
SIN 02 R B U U **
4464 Sine of A
SQRT 01 R B C U ** *
800 Square Root of A
TAN 04 R B U U ** *
5764 Tangent of A
XCHF 19 B A C D **
26 Exchange A and B
この表で、命令はニーモニック、Codeはコマンドレジスタに書き込むべき命令コードの下位7
bitを16進数表示したものです。命令コードはすべて1 Byteです。ただし最上位ビットに関しては終了割り込みの有無を指示するために使われているので、表ではすべてMSBを0にしてあります。
スタックの欄は、命令実行前にスタックトップのデータをA、そのすぐ下のデータをB、さらにその下のデータをC、底のデータをDとしたとき、命令実行後のスタックの状態がどうなっているかを表します。ただしRは演算結果のデータ、Uは不定データを意味します。たとえばFADDはAとBをポップして加算した結果をプッシュしますから、スタックトップから順にR
C Dとなりスタックの底には不定値のUが入ることになります。ただし前述の注意のようにたとえばACOS命令ではR以外はすべて不定値になったりしますので、APUへの命令を自分で最適化しようとする場合にはスタックの状態表を正確に把握する必要があります。
SZOCEはステータスレジスタへの影響を意味します。Sは符号フラグ、Zはゼロフラグ、Oはオーバーフロー、Cはキャリーフラグ、Eはエラー発生の可能性を意味します。影響を受ける欄には'*'を入れてあります。空白になっている場合は命令実行の影響を受けません。ただしOとCは整数演算にだけ関係するため、この浮動小数点演算命令ではすべて空白になっています。
クロック数は命令実行に必要なクロック数です。普通のAm9511ですと最高クロック周波数が2
MHzで、その場合にはたとえばACOS命令は3867 usの実行時間であることがわかります。EXP命令のように3794-4878と書かれている場合、データによって命令実行クロック数が変化し、その最小値が3794で最大値が4878であることを意味します。
FADD, FSUB, FMUL, FDIV命令はそれぞれ加減乗除の四則演算です。SQRT命令は平方根を求めます。
ACOS, ASIN, ATAN命令は逆三角関数で、COS, SIN, TAN命令は一般の三角関数です。ともに角度はラジアン単位です。
EXP命令は指数関数で、LN命令とLOG命令が対数関数になります。LOG命令のほうは常用対数でLN命令が自然対数ですね。PWR命令はBのA乗を求めるための命令です。
CHSF命令は浮動小数点数の符号を反転させるものです。
FLTD命令とFLTS命令はそれぞれ32 bit整数と16 bit整数を浮動小数点数に変換する命令です。一般に入出力に伴って文字列で表現された数値を浮動小数点数に変換したり、浮動小数点数を文字列表現に変換したりする必要がありますが、その作業の一部にこれらの命令を利用できます。
POPF, PTOF, PUPI, XCHFの各命令はスタック操作のための命令です。POPF命令はスタックトップの浮動小数点データを読み捨てるもので、PTOF命令はスタックトップを複製してプッシュする命令です。PUPIは円周率の定数値をスタックにプッシュするもので、XCHF命令はスタックトップとその直下のデータを入れ換えるものです。たとえばFDIV命令はB/Aを求める命令ですが、すでにスタックに納められているAとBに対してA/Bを求めたい場合、まずXCHF命令でAとBを入れ換えてからFDIV命令を発行するのが効率的です。このほか、CPUがAm9511のデータレジスタを読み書きすることによって、データをプッシュしたりポップしたりすることができます。
次は32 bit長整数演算命令です。
命令 Code スタック SZOCE クロック数 意味
CHSD 34 R B C D ***
27 Sign Change of A
DADD 2C R C D A ** **
21 Add A and B
DDIV 2F R C D U ** *
208 Divide B by A
DMUL 2E R C D U *** 194-210
Multiply A and B (R = lower 32 bit)
DMUU 36 R C D U *** 182-218
Multiply A and B (R = upper 32 bit)
DSUB 2D R C D A ****
38 Subtract A from B
FIXD 1E R B C U *** 100-346
Floating point to Integer conversion
POPD 38 B C D A **
12 Stack Pop
PTOD 27 A A B C **
20 Stack Push
XCHD 39 B A C D **
26 Exchang A and B
DADD, DSUB, DMUL, DMUU, DDIV命令が四則演算です。ただし乗算だけは演算結果が64
bitになってしまいますから、結果の上位32 bitを得るか下位32 bitを得るかで別々の命令が用意されています。
FIXD命令は浮動小数点数から32 bit整数への変換命令です。
CHSD命令は符号の反転命令で、POPD, PTOD, XCHD命令はスタック操作命令になります。
16 bit長整数演算命令は次のようなものが用意されています。
命令 Code スタック SZOCE クロック数 意味
CHSS 74 RBCDEFGH ***
23 Sign Change of A
FIXS 1F RCDEFUUU *** 92-216
Floating point to Integer conversion
POPS 78 BCDEFGHA **
10 Stack Pop
PTOS 77 AABCDEFG **
16 Stack Push
SADD 6C RCDEFGHA ** ** 17
Add A and B
SDIV 6F RCDEFGHU ** * 84-94
Divide B by A
SMUL 6E RCDEFGHU ** * 84-94
Multiply A and B (R = lower 16 bit)
SMUU 76 RCDEFGHU ** * 80-98
Multiply A and B (R = upper 16 bit)
SSUB 6D RCDEFGHA ** ** 30
Subtract A from B
XCHS 79 BACDEFGH **
18 Exchang A and B
NOP 00 ABCDEFGH
4 No Operation
だいたい32 bit整数演算命令と同じですね。ただ、スタックが8レベルとなるので、そこだけに注意してください。スタックの初期値はABCDEFGHとしてあります。
それとNOP命令は例によって何もしない命令ということで。
総じて、演算に必要なクロック数が、現在では考えられないくらい多いことに気づくと思います。浮動小数点数の四則演算で100クロックとか200クロックくらい必要で、関数計算にいたっては10000クロックを越える場合すら存在します。これらは、当時のコンピュータでアセンブリ言語で浮動小数点演算ルーチンを作成したことのある人なら納得できる程度のクロック数だと思いますが、最近の1
- 2クロックで浮動小数点演算をこなすマイクロプロセッサからすれば、大変な違いですね。
このAm9511は標準的な8 bitマイクロプロセッサが数千トランジスタ程度で実装され、最先端の16
bitマイクロプロセッサが数万トランジスタ規模で開発されつつあった時代に開発されました。つまり、浮動小数点演算専用LSIといっても、Z-80
CPUとかMC6809と大差ない規模のLSIだということです。実際、Intel社はAm9511のセカンドソースとして8231という名前で同等品を販売していましたが、その資料によると、内部データパスは16
bit幅であり、算術演算ユニット(ALU)も入出力とも16 bit幅となっています。しかも、整数乗除算のクロック数から類推して、このALUは乗除算を直接実行する能力はなく、加算程度しかできないもののようです。乗算は、多桁の乗算を筆算で行うときのように、一桁ずつ1か0を掛けて桁をずらしながら加えていく方式で、数クロックで1桁分の積和を行っていくために多数のクロックが必要となるのでしょう。浮動小数点数の加算は、仮数部の加算に先立って仮数部の小数点位置桁合わせでシフト操作が必要となり、現在の高性能プロセッサで行われているように任意のビット数シフトを1クロックで実行する回路ではなく、1
bitずつシフトする操作を繰り返しているため、必要クロック数が多くなり、しかも入力数値によって必要クロック数が変化すると考えられます。
結局、加算やシフト演算しか内蔵していない16 bitマイクロプロセッサでソフトウェアで浮動小数点演算を行うのと同じことを、内部マイクロプログラムで一般のマイクロプロセッサよりは高速に実行しているわけです。
このAm9511はIntel社から8086用の浮動小数点演算コプロセッサ8087が発売されるまで、特に数値計算を高速に実行するために必要なLSIとして有名でした。しかし、演算速度では8087に負け、コスト面ではソフトウェアによる浮動小数点演算にかなわなくなると(ROMなどプログラムを格納するメモリは急激に安くなりますから)、使われなくなっていきます。意外なほど旬が短かったLSIでもありました。
Return to IC Collection