So-net無料ブログ作成

BSAVE / SAVEM 前史 #3 [プログラム]

2010/03/19 プログラム解説部分を加筆修正しました

この記事は「BSAVE / SAVEM 前史 #2」の続きです。


セーブしたいデータ個数分だけループを回す方法だと、データ量が多くなればなるほど時間が掛かります。
しかも、ループ内でやっている事と言えば、メモリ上にあるデータをバッファ内に、そっくりそのままコピーするだけです。

バッファへデータをコピーするなら、マシン語を使用してブロック転送をする方法もあるのですが、BSAVE をするプログラムが BLOAD を必要とするというのも…。
かと言って、プログラム内にデータ文でマシン語を格納するとプログラムが肥大化してしまいます。

そこで、ちょっとトリッキーな方法ですが VARPTR() を使用した方法にトライしてみます。




N-BASIC には VARPTR() という関数があり、変数の値が保存されているアドレスを調べることができます。
数値変数では、そのアドレスに整数型/単精度型/倍精度型それぞれが2/4/8バイトで保存されています。
文字列変数だけは特別で、VARPTR() で返されるアドレス AD に文字数、AD+1, AD+2 に実際に値が保存されているアドレス(ポインタですね)が保存されています (この 3 bytes をまとめてストリングディスクリプタと呼んでいます)。

このストリングディスクリプタを操作すれば、コピーを繰り返すことなくバッファにデータセットできるはずです。

DEFINT A-Z
T1$="":T2$=""
FIELD #1, 128 AS D1$, 128 AS D2$
    |
FOR AD!=BA! TO EA! STEP 256
    |
  POKE VARPTR(T1$)  ,128
  POKE VARPTR(T1$)+1,PEEK(VATPTR(A1))
  POKE VARPTR(T1$)+2,PEEK(VATPTR(A1)+1)
  POKE VARPTR(T2$)  ,128
  POKE VARPTR(T2$)+1,PEEK(VATPTR(A2))
  POKE VARPTR(T2$)+2,PEEK(VATPTR(A2)+1)
  LSET D1$=T1$:LSET D2$=T2$
  PUT #1,RC:RC=RC+1
    |
NEXT
CLOSE #1

1レコードは 256 bytes なのですが、文字列変数には 255 bytes までしか入れられないので、仕方なく2つの変数に分割してあり、似たような処理が二つありますが、メインとなる処理はこれだけです。
A1, A2 の二つの整数変数にはセーブしたい領域の先頭アドレスが入っていて、T1$, T2$ の二つのストリングディスクリプタに文字数とアドレスを強制的に代入しています。
その後、LSET D1$=T1$:LSET D2$=T2$ とすることで、バッファ内へデータをコピーしています。

前回のプログラムではデータ個数分だけループを回していましたが、今回はレコード数分だけ回せばいいので結果的に処理速度は向上します。

Binary data saving sample program #2 (N-BASIC)
バイナリデータセーブ サンプルプログラム #2 (N-BASIC)


ただでさえ少ない Disk-BASIC のメモリをバイナリセーバー自身が浪費してしまわないように注力した結果出来上がったのがこのプログラムです。

前回のモノに比べるとプログラムが大きくなってしまっているのが難点ですが、配列変数を使用しなくなったので全体としてのメモリ使用量は減っています。
前回のように文字列型の配列変数を 256 個定義すると、ストリングディスクリプタだけで 768 bytes もメモリを消費してしまいますから。
N-BASIC に unsigned int 変数型が用意されていれば、もう少しプログラムサイズも小さくなるのでしょうがね…。

ちなみに、掲載した N-BASIC のプログラムはデバッグ済みですので問題なく利用していただけるはずですが、ご使用は自己責任でお願いします。

おわり

タグ:PC-8001 N-BASIC

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。