HELP Contents
この章ではサンプルプログラムを作るために作ってしまった汎用に使えそうなマクロおよびサブルーチンの解説をします。
このサブルーチン集は前にも述べたとおり、新装版を出すにあたってサンプルプログラムを追加しようと思ったところかけ算割り算が必要になって、さらにマップ上に歩数を表示するのに文字列処理などが必要になって、さらに疑似乱数を作っていたら1ワードの数では満足いく乱数がでなかったので結局マルチワードのかけ算割り算までが必要になって、結局それに付随してマルチワード計算用の各種ルーチンまで作らざるを得なくなって作ってしまった物です。その途中でツールの使いにくさにキレていろいろ改造を加えていたら今回のようなバージョンアップになってしまいましたが、できてしまった物はしかたありません。隠していても仕方ないのでこうして公開することにしました。
このサブルーチンは、シングルワードのかけ算、割り算、マルチワード各種演算、文字列処理、モニタの操作など。必要最低限のものです。汎用サブルーチンは以下の3つのファイルに分割して収められています。
ファイル名 | ユニット名 | 内容 |
---|---|---|
GeneralSub.pasm | GENERAL | 条件判断マクロ、サブルーチン呼び出しマクロなどの定義 |
CalcSub.pasm | CALC | 乗除算、マルチワード演算用の各種サブルーチン・マクロ定義 |
StrSub.pasm | STRINGS | 文字列処理やモニタへの描画用サブルーチン・マクロ定義 |
これらを使いたい場合はプログラムの最初に
USES GENERAL, CALC, STRINGS
と記述して、プログラムの最後に
INCLUDE "GeneralSub.pasm"
と記述します。そうすれば以下のサブルーチンの全機能が使えるようになります。
サブルーチンには原則パラメータを渡さなければなりません。そのためここで利用できるサブルーチンは例えばかけ算の場合は
LD ^X_ @A LD ^Y_ @B CALL >ML_
というように、サブルーチンで定義されているポインタ型変数にアドレスを渡すという呼び出し方をします。しかしたかがかけ算のルーチンを呼ぶのに3行も費やすのはムダなので、さらに呼び出し用のマクロが用意してあります。それを使うとかけ算ならば以下のように書くだけで呼び出せます。
&ML_ @A @B
サブルーチンで計算が行われた場合、機械語命令同様にその結果は第1パラメータの変数に格納されます。またその結果に従って各種フラグが設定されるのも同様です。すなわち上記のマクロ呼び出しを使っていれば、あたかも機械語命令にかけ算が増えたような気分でプログラムを組んでいくことができるわけです。
マルチワード数とは複数のワードによって一つの数を表したもの。2ワードなら32ビット整数、4ワードなら64ビット整数を表します。
ここでマルチワード演算を行う場合、ワードの並びはビッグエンディアンとします。ビッグエンディアンとは複数のワードからなる値を扱う際に、上位の桁から順番にメモリに格納していく方式です。例えば 214A35F2h という2ワード数の場合、メモリに 214Ah, 35F2h の順で格納します。
逆に 35F2h, 214Ah と下の桁から格納する方式もあって、これをリトルエンディアンといいます。Windowsのパソコンなどは実はこちらの方式です。そしてこのどちらの軍門に下るかでコンピューター界はキリスト教とイスラム教のごとくに二分されているのです。
実はPMLとはその宗教戦争とはまさに無縁な自由な存在です。というのはPML仮想コンピュータは扱える値もメモリアドレス空間も、そしてメモリに格納できる値もみんな同じ16ビット、すなわち0〜65535がという類い希な特徴があるからです。このためマルチワード演算を行う場合にメモリに上の桁から収めるか下の桁から収めるなんてことはもう完全にプログラマーの趣味の領域です(ただし一度どちらかに決めたら、後はずっとそれを踏襲しないと死を見ますが)
ところが通常のCPUでは一般的に扱える数の範囲とアクセス可能なメモリアドレスの範囲は異なっていますし、そもそもメモリというのが1バイトしか書き込めないため、必然的に「マルチバイト」のデータ処理が発生します。そのときメモリに値をビッグエンディアンで格納しておくか、リトルエンディアンで格納しておくかはそのCPUの設計に完全に依存します。すなわちリトルエンディアン設計のCPUではリトルエンディアンの数でないと扱うことができないのです。
そしてここでなぜ作者がビッグエンディアンにしたかというと―――単にいままで使っていたのがリトルエンディアンばかりで飽きていたという理由です。
マルチワードルーチンでは数のワード幅、すなわち何ワードで一つの数を表すかということについて、2ワードとか4ワードと決め打ちになっていることが普通です。しかしこのライブラリでは任意のワード幅の整数が使えます。
CALCユニットにWRDWX_という変数が定義されていて、そこに以下のようなワード幅を表す定数を設定すればそのワード幅の計算ができるようになっています。
#WRDW1_ EQU 0 ;1ワード(16ビット)の整数 #WRDW2_ EQU 1 ;2ワード(32ビット)の整数 #WRDW3_ EQU 2 ;3ワード(48ビット)の整数 #WRDW4_ EQU 3 ;4ワード(64ビット)の整数 #WRDW5_ EQU 4 ;5ワード(80ビット)の整数 #WRDW6_ EQU 5 ;6ワード(96ビット)の整数 #WRDW7_ EQU 6 ;7ワード(110ビット)の整数 #WRDW8_ EQU 7 ;8ワード(128ビット)の整数
文字列とはメモリのある領域に文字、すなわち文字コードがずらっと入っている物ですが、このライブラリでは以下のように、最初のワードに文字列の長さが入っていて、次のメモリから実際の文字列が並んでいるものだとします。
アドレス | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 |
文字 | 10 | 今 | 日 | は | 朝 | か | ら | 夜 | だ | っ | た |
以下はGENERALユニット内にある条件判断マクロです。
ある条件を満たしたらラベルLにジャンプする、というのはとても頻繁に現れる処理ですが、PMLに限らず機械語では書き方がとても分かりにくいので、もう少しユーザーフレンドリーにマクロ化したものです。そのためマクロの内容も付記しています。
&IFXZ_: Macro %X, %L JPF %L %X ;%Xが0なら%Lへ EndMacro
&IFXNZ_:MACRO %X, %L JPT %L %X ;%Xが0でなければ%L_へ ENDMACRO
&IFZ_: MACRO %L JPT %L ZF ;結果が0なら%Lへ ENDMACRO
&IFNZ_: MACRO %L JPF %L ZF ;結果が0でなければ%Lへ ENDMACRO
&IFM_: MACRO %L JPT %L SF ;結果 < 0だったら%Lへ ENDMACRO
&IFMZ_: MACRO %L JPT %L ZF ;結果 <= 0なら%Lへ JPT %L SF ENDMACRO
&IFP_: MACRO %L, ?L0 JPT ?L0 ZF ;結果 > 0なら%Lへ JPT ?L0 SF JP %L ?L0: ENDMACRO
&IFPZ_: MACRO %L JPF %L SF ;結果 >= 0なら%Lへ ENDMACRO
&IFC_: MACRO %L JPT %L CF ;結果が桁あふれしていたら%Lへ ENDMACRO
&IFNC_: MACRO %L JPF %L CF ;結果が桁あふれしていなければ%Lへ ENDMACRO
&IFV_: MACRO %L JPT %L VF ;結果がオーバーフローしていたら%Lへ ENDMACRO
&IFNV_: MACRO %L JPF %L VF ;結果がオーバーフローしていなければ%Lへ ENDMACRO
&IFEQ_: MACRO %X, %Y, %L CMP %X %Y ;%Xと%Yが等しければ%L_へ JPT %L ZF ENDMACRO
&IFNEQ_:MACRO %X, %Y, %L CMP %X %Y ;%Xと%Yが等しくなければ%Lへ JPF %L ZF ENDMACRO
&IFLT_: MACRO %X, %Y, %L CMP %X %Y ;%X < %Y (符号なし)なら%Lへ JPT %L CF ENDMACRO
&IFLE_: MACRO %X, %Y, %L CMP %X %Y ;%X <= %Y (符号なし)なら%L_へ JPT %L ZF JPT %L CF ENDMACRO
&IFMT_: MACRO %X, %Y, %L, ?L0 CMP %X %Y ;%X > %Y (符号なし)なら%Lへ JPT ?L0 ZF JPT ?L0 CF JP %L ?L0: ENDMACRO
&IFME_: MACRO %X, %Y, %L CMP %X %Y ;%X >= %Y (符号なし)なら%Lへ JPF %L CF ENDMACRO
&IFSLT_:MACRO %X, %Y, %L CMP %X %Y ;%X < %Y (符号あり)なら%L_へ JPT %L SF ENDMACRO
&IFSLE_:MACRO %X, %Y, %L CMP %X %Y JPT %L ZF ;%X <= %Y (符号あり)なら%Lへ JPT %L SF ENDMACRO
&IFSMT_:MACRO %X, %Y, %L, ?L0 CMP %X %Y ;%X > %Y (符号あり)なら%Lへ JPT ?L0 ZF JPT ?L0 SF JP %L ?L0: ENDMACRO
&IFSME_:MACRO %X, %Y, %L CMP %X %Y ;%X >= %Y(符号あり)なら%Lへ JPF %L SF ENDMACRO
CALL >MWAIT_
WS_にミリ秒単位で待ち時間をセットしてサブルーチンを呼び出す
LD WS_ waittime CALL >TWAIT_
CALL >SWAIT_
以下はCALCユニット内のサブルーチン・マクロです。
以下は1ワードの乗除算のサブルーチンです。
マクロ呼び出し | 機能 |
---|---|
&ML_ @X,@Y | 1ワードの符合なし乗算 |
&MLS_ @X,@Y | 1ワードの符合付き乗算 |
&DV_ @X,@Y | 1ワードの符合なし除算 |
&DVS_ @X,@Y | 1ワードの符合付き除算 |
以下はマルチワード乗除算のサブルーチンです。
マクロ呼び出し | 機能 |
---|---|
&NULX_ @X | Xを0で初期化する |
&SETXN_ @X,@Y | Xに1ワードの値を代入する |
&LDXY_ @X,@Y | XにYを代入する |
&CSTXY_ @X, WX, @Y, WY | ワード幅WXのXにワード幅WYのYを代入する(WX≠WY) |
&CSSXY_ @X, WX, @Y, WY | 符合付きでワード幅WXのXにワード幅WYのYを代入する(WX≠WY) |
&PUSHX_ @X | XをスタックにPUSHする |
&POPX_ @X | スタックからXにPOPする |
マクロ呼び出し | 機能 |
---|---|
&ISXZ_ @X | Xが0かどうか比較する |
&ISXN_ @X,@Y | Xと1ワード数を比較する |
&CMPXY_ @X,@Y | マルチワード数同士を比較する |
マクロ呼び出し | 機能 |
---|---|
&NOTX_ @X | Xの論理否定を計算する |
&ANDXY_ @X,@Y | XとYの論理積を計算する |
&ORXY_ @X,@Y | XとYの論理和を計算する |
&XORXY_ @X,@Y | XとYの排他的論理和を計算する |
&BITXY_ @X,@Y | XとYのビット比較を行う |
マクロ呼び出し | 機能 |
---|---|
&ADDXY_ @X,@Y | マルチワード加算を行う |
&SUBXY_ @X,@Y | マルチワード減算を行う |
&INCX_ @X | マルチワード数に1を加算する |
&DECX_ @X | マルチワード数から1を減算する |
&INCNX_ @X,@Y | マルチワード数に1ワード数を加算する |
&DECNX_ @X,@Y | マルチワード数から1ワード数を減算する |
マクロ呼び出し | 機能 |
---|---|
&NEGX_ @X | マルチワード数の符合を反転する |
&SRX_ @X | マルチワード数の右シフトを行う |
&SLX_ @X | マルチワード数の左シフトを行う |
マクロ呼び出し | 機能 |
---|---|
&MLXY_ @X,@Y | マルチワード数の符合なし乗算を行う |
&MLSXY_ @X,@Y | マルチワード数の符合付き乗算を行う |
&DVXY_ @X,@Y | マルチワード数の符合なし除算を行う |
&DVSXY_ @X,@Y | マルチワード数の符合付き除算を行う |
最初に1回、RNDX_にシード(0〜9999の数)を入れて呼び出すと、RNDX_に次々に乱数(0〜9999)が戻る。
CALL >RAND_
以下はSTRINGSユニット内のサブルーチン・マクロです。
Sは文字列を保持しているメモリのアドレス、LやCは1ワード数です。
マクロ呼び出し | 機能 |
---|---|
&SCLR_ @S, L, C | 文字列Sの長さをLに設定して文字Cで埋め尽くす |
&SLEN_ @S, L | 文字列Sの長さをLに変更する。短くなった場合余った分は切り捨てて、長くなった場合は半角スペースで埋める。 |
&SLD_ @S1, @S2 | 文字列S2をS1にコピーする |
&SADD_ @S1, @S2 | 二つの文字列を結合する |
&SCMP_ @S1, @S2 | 二つの文字列を比較する |
&STR_ @S, X | 符合なし1ワードの数値Xを文字列Sに変換する |
&MSTR_ @S, X | 符合なしマルチワードの数値Xを文字列Sに変換する |
&SCONV_ @S
文字列データを作る際にいちいち文字数をカウントして設定するのは面倒なので、以下のようなデータを作っておいて、そのアドレス@Sをこのサブルーチンに渡すと、文字数をカウントして長さをセットしてくれる。
S: DW 0,'今日は朝から夜だった生まれたばかりの……',0
マクロ呼び出し | 機能 |
---|---|
&PRTCHR_ C | 1文字Cをモニタに表示する |
&PRTSTR_ @S | 文字列をモニタに表示する |
&SETFRC_:MACRO %R, %G, %B OUT #23h %R ;モニタ文字色の設定 OUT #24h %G OUT #25h %B ENDMACRO
&SETBKC_:MACRO %R, %G, %B OUT #26h %R ;モニタ背景色の設定 OUT #27h %G OUT #28h %B ENDMACRO
&LOCATE_:MACRO %L, %C OUT #21h %L ;文字表示位置指定 OUT #22h %C ENDMACRO