Zero TypeをDOS1で使うとキーヒストリが効かなかった訳。
といっても、分かってみれば大したことでは無い。COMMAND.COMの常駐部がTPAの最後にあって、ここを破壊するとヒストリが使えなくなるのである。よくよく考えるとコマンドラインの処理はCOMMAND.COMの管轄なのだから、ヒストリを保存する領域がそこにあるのは、当然と言えば当然。
しかし、お役所仕事みたいで嫌だなぁ、と思う今日この頃。
ray-netでやったネタだけど、まぁいいや。
プログラマ五態
問題:
HLに0〜255が入っている。このとき、次のような変換を行うプログラムを書け。
HL=0 -> HL=256 HL=1〜255 -> HL=1〜255
INC L DEC L JR NZ,JUMP00 INC H JUMP00:
LD A,L SUB 1 RLC H
LD A,255 ADD A,L CCF LD A,H ADC A,A LD H,A
ADD HL,HL LD A,(HL) INC HL LD H,(HL) LD L,A
DEC L INC HL
VDPコマンドで転送幅に0を指定したときの内部動作ってどんなんかな。
DMAG/DBMPの3375色中16色表示は嘘でした。
はい、1/60秒毎にパレットを切り替えているのですが、インターレースモードだとただの2ラインディザ(何それ?)になっちゃいます。ノンインターレースなら嘘じゃ無いんだけどねぇ。理由は....分かる方には明白。
1/30秒毎にパレットを切り替える版も作ってみたけど、チラツキが耐え難いほど大きくなって、全然使えませんでした。
そうそう、1575色中256色の方は本当です。信じて下さい。巨大な亀が空を飛んで行ったんです。
DOS2でCOMMAND2.COM経由の子プロセス起動をする話。
基本的に以前書いたDOS1子プロセス起動と同じなのだが、LD_FLAG(0037H)や環境変数の%PROGRAM%と%PARAMETERS%を設定する必要があったりして、結構面倒である。
PATHを検索して実行ファイルを探したり、FCBを設定したりするのは更に面倒なので、通常はCOMMAND2.COM を経由して子プロ起動するのだが、TPA が大幅に減少する上にTPA上限をxx06Hに揃えなければならない。
Zero Typeでは、この事に気付かずバグに苦しんだのだが、自分でPATH検索やら何やらを行う今となっては、過去のことだったりする。
ビーバーさんが、BIOSのGTTRIG(00D8H)の破壊するレジスタが、テクハンに書いてある物と違うという事を書いています。で、私がBIOSを逆アセンブルしたところA=0(SPACEが押されたかを判定)でCALLした場合は、テクハン・Datapackにあった通りAFのみの変化でしたが、A=1〜4でCALLした場合はAF・BCが変化します。
それほど使い途のあるBIOSではないので、問題は少ないでしょうが参考までに。
VDPウェイトへの無意味なこだわり。
通常のI/O直いじりでVRAMにアクセスすると、最低でも24クロックかかる、というのは下に書いた通りで通常はこれが正しい。しかしV9958のオートウェイト機能をONにした場合に限り23クロック間隔でアクセスしても問題ないという結果が出ている。これはどういう事なのだろう。この機能はV9958とZ80のウェイト線がつながっていない為、MSXでは使えない筈なのである。
ふと、実はつながっているのだが1ウェイトしかかからない不完全仕様なのではないかという事を思い付いた。しかし、実験してみるとウェイトがかかった形跡は無い。謎は深まるばかりである。
VRAMアクセスはひょっとするとVDPコマンドの方が速いかも知れない。
通常のI/O直いじりでVRAMにアクセスすると、最低でも24クロック(OTIRの本来のステート数21+M1サイクルのウェイト2+I/Oアクセスにかかるウェイト1=24クロック)かかる。これは、約6.72μ秒に相当する。
一方、私の調べたところではHMMC(CPU−>VRAM高速転送)のアクセス間隔は約3.64μ秒で充分なようだ。つまり、VRAM書き込みに限ってはVDPコマンドを使った方が高速であると言える。勿論、ステータスレジスタをチェックする必要も無い。
VDPの役にたたない話
ステーテスレジスタS#6のbit1は本によってY9(スプライト衝突座標のbit9)とかEO(解説なし)と書いてある。でまぁどちらが正しいのかを調べてみたところ、どうもEOが正解らしい。そもそもスプライトのY座標はbit7からbit0までしかない(衝突座標のオフセットを入れてもbit8からbit0)なのだからY9はこの段で却下。
で、S#nのEOと言えば普通S#2のbit1(EO:表示フィールドの状態)を指すわけでこのS#2とS#6のbit1の相関をとってみたら見事に一致した。でもなんでS#6なんかにS#2(の一部)のコピーがあるんだろう。役にたたないと思うぞ。
3ヶ月以上更新していなかったのか・・・。
FCC5H以降の4bytesに各基本スロットの拡張スロット選択レジスタを保存するシステムワークがある。今までは特に意識する事も無かったのだが、昨日I/OのA8Hとmemory mappedI/OのFFFFHを保存して、必要なときに元に戻すSAVSLTとREVSLTというサブルーチンを使っていたらどうもうまく動かない。で、I/OだけでなくFCC5H以降の4bytesを保存するようにしたらうまくいった。
どうも、DOS2の割り込みルーチンがこのワークエリアを参照している為らしい。これだけの為に5時間近く悩んでしまった。
トリプル P
MGSDRVとATの相性が悪いと教えてもらい、原因を調べた。CTRL+ten keyで操作すると暴走するとのこと。H.TIMIを殺しているはずなのにおかしいなと思ったがバグを確認。
MGSDRVが、どこでキーを割り込ませているのか調べるのは結構大変だったが、システムの割り込みルーチンが、H.KEYI・H.TIMI以外のフックを呼んでいるのに気がついて、解決した。
で、R800では割り込みを生かしたままでも十分動作スピードを確保できることが分かったので、CPUモードを判定してR800ではMGSDRVが鳴るよう変更した。
ブラウザがMosaic viewからNetscape navigaterに変わって気づいたこと。
何故か、半角スペースが通らない。前は、スペースn個分は、sgn(n)個表示されたのに、今では一個も表示されない。
おかげでハンドルのAとtoの間、toとCの間の半角スペースはそのまま詰められてしまう。困ったものだ。
DAMG/DBMP ver1.16について
このバージョンを3/16から3/18に落とした方は現在改訂版がアップされていますのでこちらを利用して下さい。BMP loaderのバグを取り除いて有るほか手直しが加えられています。
Who killed interrupt?
誰が割り込みを殺したか
それは私、とmainが言った
hookとretで私が殺した
というわけで、ATを使用中、MGSDRV等の割り込みを乗っ取って常駐するプログラムが動作しないことについての言い訳です。
ATは走査線番号6もしくは14でまず第一の走査線割り込みを発生します。しかしタイマ割り込みルーチンが重い場合、タイマ割り込みルーチンを実行中に走査線割り込みがかかり最悪の場合暴走します。これを防ぐためにタイマ割り込みルーチンを実行する直前走査線割り込みを無効にしています。こうしたところで暴走しなくなるだけの話で、タイマ割り込みルーチンを軽くしない限り問題の解決にはなりません。そこでH.TIMIの1byte目にRETを書き込んでユーザーの割り込みを無効にし、ルーチンの軽量化を図っています。で、H.TIMIを乗っ取って動作するMGSDRVは乗っ取りを無効にされて沈黙するというワケです。
誰が割り込み死ぬのを見たか
それは私と私が言った
二つの目玉で私が見てた
AT.COM等で使っている小技を2つ。
LD A,(WORK) : : LD (WORK),A : : WORK: DS 1
といったワークエリアの取り方をしているプログラムは、
WORK@: LD A,0 : : LD (WORK@+1),A
とすると、2bytes節約でき実行速度もアップする。
値xxとyyを交互に変換したい場合、例えばAレジスタにxxが入っているとして
LD B,xx CP B LD A,B JR NZ,JUMP LD A,yy JUMP: : :
とするのが最もストレートで分かりやすいが、8bytesも使う上に遅くて汚い。
そこで、BASICでいうところのA=(xx+yy)-Aを使えば
LD B,A LD A,xx+yy SUB B
とすると4bytesで出来る。Bレジスタを破壊したくない場合には
SUB xx+yy NEG
でも同じ結果が得られる。しかしXORを使うと2bytesで出来てしまう。つまり、
XOR xx XOR yy
ここで左のXORはZ80の命令で、右のXORはアセンブラの疑似命令である。
因みに、xx XOR yyがFFHの場合は、
CPL
この1byteですんでしまう。
DMAG/DBMP ver1.15のウリ。
これまでの機能はそのままに、高忠実度色再生モードを搭載した。と、書くと何だかよく分からないが要は色の再現が幾らかマシになったという事。
16色モードではパレットを512色の中から選んでいたのが3375色から選べる様になった。つまりRGB各15段階。256色モードでは固定256色だったのが、1575色中256色となりグラデーションが細かくなった。SCREEN 8にパレットを付けた様に見えるが、実際は1575色同時表示できる。どちらもタイマー割り込みを使ってこれを実現しているが、その影響で画面がちらつくのは大きな副作用である。
DOS1で子プロ起動する方法。
まず、指定されたファイルをロードする常駐プログラムを作る。次に、0006H〜0007Hで示されるTPAの上限から常駐部の大きさを引いた場所に常駐部を転送する。そして0000Hのジャンプ先をこの常駐部の先頭に書き換える。つまり、プログラムが終了する度に常駐部にジャンプするようにする。
これだけだと、LD SP,(0006H) とされた時困るので常駐部の更に3bytes手前に0005Hからの3bytesを転送し0005Hには(常駐部の先頭-3)へのジャンプ命令を書き込む。
常駐部では子プロ起動するプログラムを0100H以降にロードした後0100Hにジャンプさせれば良い。子プロセスが終了して実行が返って来た時には、次のプロセスを実行するか0000Hと0005Hを元に戻してプログラム全体を終了させるかを選ぶ。この2つを戻せば常駐部は解放されるので後々邪魔になる事はない。
以上、DOS2での子プロ起動法が解らなかった為に編みだしたテクニックでした(常識だったら恥ずかしいな)。
sc0knj.lzhが2ヶ月ぶりにバージョンアップ。
今回から、乗っ取るフックをH.KEYIから0038Hに変更した。これは0038Hからジャンプする割り込みルーチンの内容が機種毎に違う事から前のバージョンがST以外では正常に動かなかったのを解消するためである。割り込みルーチンが実行される前に自分のルーチンを実行してしまえばどの機種でも同じ動作をするというわけだ。
おまけに、割り込みが走査線割り込みだった時、自分のルーチンだけを実行するようにしたため、その分高速になった。
これで安心してテキストビュアーとして完成させられるのだが、BASIC環境での実行が難しくなってしまった。まあ不可能ではないのだが。
MAPLIB.MACがリニューアル。
これまでは、各ルーチンがマッパテーブルに飛んでいたのだが、マッパテーブルが飛ぶ場所に直接飛ぶようになった。MAPLIBも、実はこの方がプログラムもシンプルで組みやすいのだが、長いこと気づかなかった。
で、簡単になってレジスタが余ったので自己書き換えを行うアドレスを記録しているテーブルを消して、その初期値だけを与えるようにした。つまり、書き換えるアドレスに次に書き換えるアドレスが書いてあって次々と連鎖していくようになっている。これだけで30bytes程の節約になった。
似たような改造をVDPLIBにも施してあるが、この方式の欠点はこれらのルーチンを1回しか呼べないことである。ま、初期化ルーチンを2回も呼ぶ物好きはいないだろうけど。
ここに書くのは久しぶり。
AtoC_lib.lzhの内容がちょっと変わった。VDP.MAC内のNWRVRM,CWRVRM,BIGFIL等がわずかな高速化と引き替えに長くなり、画面の許可・禁止ルーチンはBCレジスタを破壊しなくなった。他にも変更したのだが思い出せない。
実はマニュアルを読み返していてあまりの誤植の多さにいちいちチェックしていたらもっと速くなると気付いてこのように相成った。