Mathpack数値計算ライブラリについて

「Mathpack数値計算ライブラリについて」の編集履歴(バックアップ)一覧に戻る

Mathpack数値計算ライブラリについて - (2013/06/17 (月) 06:25:10) のソース

Mathpackは数値計算を扱うライブラリ。このライブラリはMAINROMにあり殆どのハードウエアに
ROMBASICと一緒に記録されている。
元々当時のマイクロソフト社BASICの機能が整数BASICのみであり、実数計算を実装する上で
ライブラリとして実装したものらしく、
基本的には外部には公開されていないものだがユーザーが使う事もできる機能である。
この数値計算ライブラリはROMBIOSに含まれる機能で、sdccなどのC言語のMath.hに定義されるもの
とは別である。

一般的な数値計算ライブラリがC関数として実装されているのに対し、これらの
数値計算ライブラリは今では珍しく仮想計算機として実装されている。
実装方法は浮動小数点演算を対象とした仮想計算機(VirtualMachine)そのものであり、
実数をレジスタにロードストアし、演算命令を実行するというもので、
現代的な関数ライブラリとは違いがある。これは時代的な背景もあるのだろう。

仮想計算機はソフトウエアで実装されており、BCD表現された浮動小数点数8byteを単位として、
演算サイズ(Float,64bit)の実数レジスタを2個搭載したレジスタマシンとして設計されている。
これらは当時のi8087のようなFPUと似ており、ソフトウエア実装されたFPUといえるものである。
浮動小数点の数値表現はBCDで現代的なIEEEフォーマットではない。(当時そのような仕様はなかった)
この仕様はROMBASICの実数表現の計算精度となる。
ライブラリはBCDであり8bitのマシンで動作するため速度は遅いが、演算精度は良い。

MAINROMBIOSには実数の数値計算のためのエントリアドレスがある。それら主要な機能は0x0-0x3FFFの
16KB以内に収まっている。その機能のうち数値型変換の幾つかはROMBASICがないと動作しない。
仮想計算機の実数レジスタはワークエリアRAM(0xF380-0xFFFF)に置かれている。
実数レジスタはDAC,ARGという二つのレジスタがある。実数計算はこれらのレジスタが中心となる。
実数レジスタの変数領域はRAM(ワークエリア)上に確保されており、数値はワークエリアのメモリに
直接値をロードストアしたり、仮想計算機の命令(BIOSのAPIとして実装)でロード可能。

MathpackのAPIには実数を対象とした加減乗除のほか、平方根、三角関数、数値レジスタへの
ロードストア、そして変数のタイプ変換機能などがある。
しかし数値変換機能など一部の機能はBASICコードを呼び出し利用しているらしくMathpack本体が
保存されているMAINROM単体だけでは動作しないものがある。
(元々ROMBASICインタプリタ内部で利用することを前提としているので、型変換部分については
BASICインタプリタのコードを用いているようである)




数値計算ライブラリの数値表現方式は、binaryではなくBCDを使った実数表現。
実数はsingle/doubleがあり、フォーマットは指数部(exp)1byte、仮数部(frac)があり、
仮数部はsingle/doubleそれぞれ3/7byteの長さを持つ。
(singleの場合仮数部が24bitの長さ、doubleが56bitの長さを持つ実数表現となる)
実数サイズはsingleは4byte,doubleは8byteとなる。

指数部は符号と指数部にわかれ、7bitのオフセットバイナリ、またはエクセス127で表現される。
(指数部7bitで表現される数値64が10^0を意味する。127が10^63を表現する。逆に指数部が1であれば
10^-63、62の時は10^-2となる)

指数部は1byteで表現され、1bit符号、7bit指数部というフォーマットを持つ。
しかし符号ビットはゼロ表現のみに用いられ実際の符号とはあまり関係がない。


仮想計算機としての実装はワークエリアに作られた二つのレジスタDAC,ARGで計算行なう仕組み。
ライブラリルーチンはこのレジスタに対する演算として機能する。

DAC/ARGはワークエリアの16byteを消費するメモリ区画で、演算対象の数値を置く。
DAC/ARGはそれぞれ0xF7F6,0xF847というアドレスが決められている。

このエリアはワークエリアでアドレスは直接参照しても良いので構造体で参照することが
できるだろう。

 typedef struct {
 	unsigned char exp;
 	unsigned char frac[7];
 } r_num;


 void main(void){
 	r_num *dac;
 	unsigned char *r_type;
 
 	dac=(r_num *)0xF7F6;
 	r_type=(unsigned char *)0xF663;
 }


dac->expで指数部、dac->frac[0]で仮数部を参照し、このコードで数値計算ライブラリが管理する
実数計算用仮想レジスタを読み書きすることができる。

数値表現はBCDなのでいずれもcharで扱い、必要に応じて数値変換する必要がある。
Cが扱っているfloatやintとは数値表現に互換性はないのでそのまま扱えない。

一例として3.316e-0と表現する場合は、

 dac->exp=0x40;
 dac->frac[0]=33;
 dac->frac[1]=16;
 dac->frac[2]=0;
 dac->frac[3]=0;
 dac->frac[4]=0;
 dac->frac[5]=0;
 dac->frac[6]=0;
 dac->frac[7]=0;

とする。
(指数部(dac->exp)が0x40の理由は上位ビットが符号を表現し、下位が指数部のため)



ライブラリはROMに記録されたルーチンなので
dosなどから利用する場合は内部スロットコール(インタースロットコール)を経由する必要がある。
MAINBIOSROMが見えるような環境ではそのままルーチンをコールすれば良い。
DOS環境では素直にsdccのCライブラリのfloatを使うのがよいだろう。

Mathpack数値計算ライブラリをC関数から呼ぶ場合は、適切にプロトタイプを用意する必要がある。
DOS環境では内部スロットコールを使うので、アセンブラでCとのインターフェースを書くことになる。
ページ0のBIOSROMを直ぐに呼び出せるような環境ではもっと単純だろう。

計算手順は
仮想レジスタに実数をストアし、計算し、結果を得るというサイクルで数値計算を行なうが、
このとき値の読み書き(ロードストア)はメモリー間、CPUスタック間、仮想レジスタ間の相互にMOVEが可能。
ライブラリ計算中はCPUのレジスタ群、ワークエリアは計算処理に用いられるのでスタックへの退避など
保護が必要である。

仮想レジスタは、DACがアキュミュレータ、ARGが汎用レジスタとなる。
すべての実数計算処理はこの二つのレジスタを使う。
機能によってはフラグとしてCPUのAレジスタに値が帰る、HLレジスタ間接メモリ参照で
実数の保存されているメモリからロードするなどの機能がある。
仮想計算機としてはレジスタマシンといえる。i8087のようなスタック構造ではないので8087FPU用の
レジスタ版ともいえるだろう。

ベクトル計算を行う場合は単純な演算を組み合わせる必要があるだろう。
(たった16KBしかないサイズで実数演算をしているが8bitなので計算速度は遅い)


演算以外の機能については仮想レジスタDAC/ARG内容に対して両者の値の移動、メモリ間の移動、
スタックポインタからの移動、メモリ間のコピーなどがある。


参考
[[MSX2 Technical Handbook Appendix A.2 Math-Pack >http://ngs.no.coocan.jp/doc/wiki.cgi/TechHan?page=Appendix+A.2+Math-Pack]]
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。