SSブログ

孤独へ向って突っ走れ(10) [  PC-98x1(補完計画)]

前回の記事の翌日、私の左足は腫れ上がって歩けなくなった。それからPCの前に座れなかったのは言うまでもない。それでも久しぶりにアセンブラのニーモニックに接した私の衝動は抑えようがなく、私は逆アセンブルの結果をPCからスマホに移して、歩けないながらも安楽椅子の上だろうと布団の上だろうと狂ったようにスマホ画面上で指だけ動かした。

今もまだ私は外出できずに家で寝ていなければならない。せめてもの楽しみに、今まで解析した分をスマホからUPしたい。そういう状況だから今回は無駄口なしで、つまり最近の記事にあったウルトラマンがどうのというつまらん冗談はなしで、ただひたすら解析結果だけを出す。

でもこれはこれで、昔PC-98用ゲームをプログラミングした人間には懐かしい初期設定ルーチンのオンパレードだ。

では前回の記事に出したコードの続きから。

MOV AH,41
INT 18
グラフィック画面を非表示にする

MOV AL,01
OUT 6A,AL
標準グラフィックスモード(EGCでない)16色にする

XOR AX,AX
OUT A4,AL
グラフィックVRAM表示画面0を選択する

XOR AX,AX
OUT A6,AL
グラフィックVRAM描画画面0を選択する

MOV AX,2916
MOV DS,AX
MOV BYTE PTR [024A],00
MOV AL,01
MOV CL,20
SHR AL,CL
JZ 4347
MOV BYTE PTR [024A],01
MOV AX,1D7C
MOV DS,AX
データセグメントを2916Hに
(今までは1D7CHだった。)
データセグメントのアドレス024AHに00Hを入れる
01Hを右へ20H回ビットシフトし
ゼロフラグが立っていれば4347Hへ行け
(SHRには何の意味があるのか。ゼロフラグの状態はいつ決定するのか。)
データセグメントのアドレス024AHに01Hを入れる
データセグメントを1D7CHに
(一時的に2916Hにしていたのを元に戻した。)

MOV AH,0A
MOV AL,00
INT 18
CRTモードを縦25行、横80文字、VLモード、コードアクセスモードに設定する
(ようするに当時の一般的なモードと思われる。)

XOR AX,AX
INT 33
マウスを初期化する

CALL 67B3
67B3Hへ行ってこい




コードセグメントのアドレス67B3Hから6819Hまでの命令
サブルーチン4306Hから飛んできたサブルーチン。最終的にサブルーチン4306Hに戻るまで。

MOV AX,0000
MOV ES,AX
MOV AX,ES:[0014]
MOV CS:[67A7],AX
MOV AX,ES:[0016]
MOV CS:[67A9],AX
セグメント0000Hのオフセット0014Hから4バイト(COPYキーの割り込みベクタアドレス)を取り出し、それをコードセグメントのアドレス67A7H以降に入れる

MOV AX,6843
MOV BX,2C70
CLI
MOV ES:[0014],AX
MOV ES:[0016],BX
STI
セグメント0000Hのオフセット0014Hから4バイト(COPYキーの割り込みベクタアドレス)を2C70H:6843Hに変更する(変更中の割り込み禁止)

MOV AX,ES:[0018]
MOV CS:[67AB]AX
MOV AX,ES:[001A]
MOV CS:[67AD],AX
セグメント0000Hのオフセット0018Hから4バイト(STOPキーの割り込みベクタアドレス)を取り出し、それをコードセグメントのアドレス67ABH以降に入れる

MOV AX,6843
MOV BX,2C70
CLI
MOV ES:[0018],AX
MOV ES:[001A],BX
STI
セグメント0000Hのオフセット0018Hから4バイト(STOPキーの割り込みベクタアドレス)を2C70H:6843Hに変更する(変更中の割り込み禁止)
(COPYキーとSTOPキーの割り込みアドレスを同じにした。COPYキーとSTOPキーの無効化かもしれない。)

MOV AX,3523
INT 21
MOV AX,ES
MOV CS:[67AF],AX
MOV CS:[67B1],BX
割り込み番号23H(Ctrl-C割り込み)の割り込みベクタアドレスを求め、それをコードセグメントのアドレス67AFH以降に入れる

MOV DX,6846
MOV AX,2C70
PUSH DS
MOV DS,AX
MOV AX,2523
INT 21
POP DS
割り込み番号23H(Ctrl-C割り込み)の割り込みベクタアドレスを2C70H:6846Hに変更する

RET
サブルーチン4306Hへ戻る




コードセグメントのアドレス4359Hから4362Hまでの命令
サブルーチン67B3Hから戻ってきた。サブルーチン4306Hの続き。
すぐにまたサブルーチンへ441CH飛ぶ。

LEA SI,[374B]
MOV CX,0010
ソースインデックスレジスタにアドレスとして374BHを入れる(ここにはパレット情報が格納されている)
CXには0010Hを入れておく(これはパレットの数16を意味する)

CALL 441C
441CHへ行ってこい




コードセグメントのアドレス441CHから4441Hまでの命令
サブルーチン4306Hから飛んできたサブルーチン。最終的にサブルーチン4306Hに戻るまで。
このサブルーチンに来る前に、SIには374BHが、CXには0010Hが入っている。

ADD SI,+04
SUB CX,+01
SIには4を足し、CXからは1を引く
(なぜ最初からその値を入れないかだが、おそらく下のコードでパレット番号0が(0,0,0)に固定されているので、そのぶんを差し引いているのだろう)

MOV AL,00
OUT A8,AL
OUT AA,AL
OUT AC,AL
OUT AE,AL
パレット番号0を(0,0,0)に設定

CMP WORD PTR[0002],+00
JNZ 4442
データセグメントのオフセット0002Hからの2バイトが0でなければ4442Hへ飛べ

4433: ;LOOPのラベルはここ
LODSB
OUT A8,AL
LODSB
OUT AA,AL
LODSB
OUT AC,AL
LODSB
OUT AE,AL
LOOP 4433
データセグメントのアドレスSIから1バイトずつ読みながら15個のパレットを設定する

RET
サブルーチン4306Hに戻る




コードセグメントのアドレス4363Hから4387Hまでの命令
サブルーチン441CHから戻ってきた。サブルーチン4306Hの続き。
最終的にサブルーチンF065Hに飛ぶまで。

MOV AX,0000
MOV ES,AX
OR BYTE PTR ES:[0500],20
セグメント0000Hオフセット0500Hの1バイトについて、ビット5を1にする(キーバッファオーバーフロー時にビープを鳴らさない設定)

TEST BYTE PTR ES:[0501],80
MOV AX,2FFD
JZ 437C
セグメント0000Hオフセット0501Hの1バイトについて、ビット7が1(システムクロック周波数が8MHz)でなければ、AXに2FFDHを入れておいて437Cへ飛べ

MOV AX,26FC
MOV CS:[F063],AH
MOV CS:[F064],AL
コードセグメントのアドレスF063Hに26Hを入れ、アドレスF064HにFCHを入れる
(この値は次のサブルーチンでタイマのカウンタ#0(インターバルタイマ用)に書き込む。)

CALL F065
F065Hへ行ってこい




コードセグメントのアドレスF065HからF0A7Hまでの命令
サブルーチン4306Hから飛んできたサブルーチン。最終的にサブルーチン4306Hに戻るまで。

MOV AX,0000
MOV ES,AX
MOV SI,0020
MOV AX,ES:[SI]
MOV BX,ES:[SI+02]
MOV CS:[F05F],AX
MOV CS:[F061],BX
セグメント0000Hのオフセット0020Hから4バイト(タイマ用の割り込みベクタアドレス)を取り出し、それをコードセグメントのアドレスF05FH以降に入れる

CLI
MOV AX,F0C9
MOV BX,2C70
MOV ES:[SI],AX
MOV ES:[SI+02],BX
STI
セグメント0000Hのオフセット0020Hから4バイト(タイマ用の割り込みベクタアドレス)を2C70H:F0C9Hに変更する(変更中の割り込み禁止)

MOV AL,36
OUT 77,AL
タイマのモード設定。カウンタ#0、LSB,MSBの順にリード/ライト 、モード3(方形波ジェネレータ)、バイナリカウント

MOV AL,CS:[F064]
OUT 71,AL
MOV AL,CS:[F063]
OUT 71,AL
タイマのカウンタ#0(インターバルタイマ用)に書き込む

JMP SHORT F09F
NOP
F09F: ;JMP SHORTはここへ飛ぶ

CLI
IN AL,02
AND AL,FE
OUT 02,AL
STI
割り込みマスクレジスタを書き換える

RET
サブルーチン4306Hに戻る




コードセグメントのアドレス4387Hから43B0Hまでの命令
サブルーチンF065Hから戻ってきた。サブルーチン4306Hの続き。
最終的にメインルーチンに戻るまで。

PUSH CS
POP ES
MOV BX,4300
XOR AX,AX
INT 1C
日付・時刻を読み出し、コードセグメントのオフセット4300H以降に格納する

MOV AX,CS:[4304]
MOV BX,AX
ROR AX,1
OR AX,6997
OR BH,AB
MUL BX
ADD AX,142B
ADD CS:[6C8B],AX
ROR AX,1
ADD CS:[6C1A],AX
時刻のうち分と秒の部分2バイトを取り出し(上位4ビット下位4ビットがそれぞれ10の位1の位を表す)
右へ1ビットシフトして出たビットを左端に入れ
0110 1001 1001 0111bとORをとり
それとは別個に秒の部分だけ
1010 1011bとORをとったものを作り
両方を掛け合わせ
その下位2バイト分だけを取り出して
142BHを足し
それをコードセグメントのオフセット6C8BHからの2バイトに足す
コードセグメントのオフセット6C8BHからの2バイトには右へ1ビットシフトして出たビットを左端に入れたものを足す
(結局それは何をやりたいんだ?時刻からランダムな数を作るというのがあったが、ひょっとして?)

RET
メインルーチンに戻れ




ここまで来てようやく、逆アセンブル結果の解析をしたいという衝動が収まった。

コメント(1) 

コメント 1

コメントの受付は締め切りました
blueclouds

この記事内にある下記コードについての記述訂正
MOV AL,01
MOV CL,20
SHR AL,CL
JZ 4347
調べたところ、ゼロフラグはSHRの結果によって決定される。また、CLの値は5ビットにマスクされ、最大で31回となる。つまり上記のCLの値20Hが5ビットにマスクされ、実際には0回のビットシフトとなる。0回のビットシフトの結果ALは01Hのままなので、ゼロフラグは立たない。

by blueclouds (2016-06-17 08:40)