じょんのブログ -8ページ目

じょんのブログ

NEC PC-88VA2を修理(?)している記録です。

 

 

 

タイトルとは関係ないけど、↑の話の続きなので…

 

セグメント配置の話

 

前回、COM形式のファイルの中で、コードとデータが混在するような場合に、セグメントを分割してグループ化する話をしました。

 

そもそも、そんな面倒なことをしなければならなかったのは、コードセグメント(CSEG)の中にデータを配置すると、デフォルトセグメントがCSになるので、メモリをアクセスする時に、CS:のプリフィックスコードがついてしまうからでした。

 

ここで、コードセグメントではなく、データセグメントに入れたらいいんじゃない?

ということを思いつきました。

 

実際にやってみたら、うまくいきます。

プログラムコードをデータセグメントに入れても、ジャンプするたびにCS:プリフィックスを強制的につけられるということはないようです。

セグメントを分けずに、すべてDSEGの中に入れたらOKでした。

 

_TEXT   DSEG    'CODE'

 

という、「えっ、何か間違ってない?」と、思わずツッコミたくなるようなセグメント定義をするとよいようです。

以上、たぶん誰の役にも立たないであろう知識でした。

 

Watcomアセンブラの話

 

色々と調べていた中で、Watcomアセンブラが、Windows10上で動いて、かつ、MS-DOSコードを出力することができることを知りました。

当然、R86とは互換性がなく、MASM互換となっています。

 

32bitベースのソフトなので、PC-88VA上では動きませんが、アセンブルを88VA上でやる必然性はありません。

 

こちらのアセンブラは、

 

        AND     BX,3

 

のようなコードを AND reg16,imm8 のコードで出力します。

これで、DBを使ってコードを直接埋め込む必要はなくなるかな?と思っていたら、そうはいきませんでした。今度は、

 

        CMP     ax,1

 

というコードに、差異が出ました。

Watcomは、これもCMP reg16,imm8にするのですが、元のコードはCMP reg16,imm16のまま。

こちらの場合、どちらも3バイトで、imm8にしたところで、何もメリットが無いからです。

同様なことが、

 

        SUB    ax,12h 

 

というコードでもありました。

まあ、正直、どっちでもいいですが、やっぱりアセンブルした結果が、元と同じになってほしいので、ここはDBでコードを埋め込むことにしました。

 

なかなか素直に同じコードを出してくれないものですね。

 

 

↓この話の続きはこちら

 

 

↑この話の続き

 

ICM製Ethernet + SCSIちゃんぽんボードのIF-2771ETを使って、Ethernet接続する話の続きです。

 

とりあえず、それほど開発環境がそろっているわけでもないので、まずはそこからなのですが、さすがにこの文明開化の世の中に、MS-DOS(しかも似非)のプログラムをしようなどという酔狂な人はほとんどいないみたいで、とにかく情報がありません。

 

とりあえず、フリーのディスアセンブラをいくつかダウンロードしてみましたが、どれも割り込み駆動するプログラムはきちんと追えませんでした。

まあ、スタートアップから追っていっても割込みルーチンにはたどり着かないですから、仕方ないかもしれませんね。

 

そんなわけで、SYMDEBを使って、手作業でコードを追って、LSIC-C86に付属のR86アセンブラのソースコードに落としていきました。

プログラムサイズは4,836バイトです。

手作業でコードを追う気になるギリギリのラインですね。

 

1. 最適化コード

 

ところで、8086のインストラクションコードのなかで、以下のようなコードがあります。

 

        AND     BX,3

 

普通のコードっぽく見えますが、実はこのコード、R86は元通りにアセンブルしてくれませんでした。

元のコードは、

        83 E3 03

となっていて、これをSYMDEBで見ると、

        AND     BX,03

と表示されるわけですが、これを信じて上記のコードをアセンブルすると、その出力結果は

        81 E3 03 00

となってしまいます。

まあ、実行結果は同じなので、バグというわけではないのですが、1バイト大きくなります。

 

どういうことかというと、元のコードは、

        AND     reg16, imm8

で、R86が出力したコードは、

        AND     reg16, imm16

なのです。

R86はメモリや即値に型を持たないので、基本的にはレジスタの指定によって、メモリや即値の型を推定します。オペランドがメモリと即値だった場合は、メモリに型指定をします。

つまり、オペランド1とオペランド2のサイズが違うことを想定していません。

 

即値の値を見て、8ビット範囲内だったらimm8のコードを生成してほしいという考え方もあるでしょうが(OPTASMとかはそうなっています。)、このコードは、imm8で指定された即値を符号拡張するので、なかなか見つけられないバグの原因になりがちです。(例えば、AXレジスタのbit7だけ残してマスクする場合を考えてみてください。)

1バイトをケチるために、わざわざこんなことをしているあたり、当時のメモリの貴重さというものが伺えますよね。

 

で、結局、R86にはこのコードを生成するアセンブリコードが無いようなので、そのまま

        DB      83h, E3h, 03h        ;AND BX,3

と書いておきました。

 

2. COM形式実行ファイル

 

今回の解析対象となるパケットドライバIF27PD.COMは、COM形式実行ファイルです。

COM形式実行ファイルは、コード・データが、すべて1セグメント(64kバイト)内に収まるように作成されています。

実行時は、実行メモリ上に100hバイトのヘッダが付きますので、一般的にはセグメントの先頭に

        ORG     100h

という疑似命令を入れて、コードやデータのアドレスが100hバイトずれて配置されることをアセンブラに知らせます。

しかし、困ったことに、R86にはこのORG疑似命令がありません。

リンカ(LLD)には、COM形式実行ファイルを作成するオプションがありますが、ORG 100hが指定されていないとエラーを出す仕様になっています。

 

その疑似命令、無いんですけど?

どういうことなんでしょうね?

基本的にR86は、LSI-C86のためのアセンブラで、ORG 100hは、C言語のスタートアップコード内に記述されているから不要という意味なのでしょうか?

R86だけでCOM形式の実行ファイルを記述することはできないの?

 

この答えは、まだわかっていません。

とりあえず、ORG 100hだけ記述したファイルをTASMでアセンブルして、そのオブジェクトをリンクしていますが、どなたか正解をご存じの方、教えてください。

 

3. セグメント配置

 

今回、解析しているのは、メモリに常駐して割込み処理で駆動するドライバです。

こういった常駐プログラムは、できるだけ常駐量を小さくするように工夫されています。

常駐する部分と、そうでない部分は明確に分けて、常駐完了時には非常駐部のメモリは解放します。

今回のIF27PD.COMの場合、メモリの配置は、

 

プロセスヘッダ(100hバイト)

        jmp    (非常駐部へ)

常駐部(データ、コード)

非常駐部(データ、コード)

 

のようになっています。

非常駐部の処理が終了すると非常駐部のデータやコードが配置されていたメモリは解放されます。

上記のように、常駐プログラムでは、必然的に、データ部とコード部が交互に現れる構造になります。

しかし、何も考えずにリンクすると、リンカのLLDは、コード部はコード部で、データ部はデータ部で、それぞれまとめてしまいます。

通常のプログラムでは特に問題ないのでしょうが、常駐プログラムの場合、勝手にそんなことをされては困ります。

 

最初は、

「だったらセグメントなんて分けずに、全部コードセグメント内に記述すればいいじゃん。」

と思って、セグメントを分けずに作っていたのですが、データをアクセスする全てのコードにCS:プリフィックスがついてしまうという残念な結果に…。

やっぱり、まじめにセグメントを配置をする必要があるようです。

 

R86では、セグメント定義時に、何も指定せずに

 

TEXT    CSEG

 

とだけ記述すると、暗黙のクラス名'CODE'が指定されることになっています。

このクラス名が同じセグメントは、リンク時にまとめられてしまうということのようです。

まとめられないようにするためには、

 

TEXT1   CSEG    'CODE1'

 

のように、明示的にクラス名を指定すればいいということのようです。

 

でも、これだけではダメです。

先ほどのORG問題があります。書いてあるコードがメモリに配置されるときは、100hずれて配置されるので、ORG 100hが書かれたセグメントと連続していることを示さなければなりません。

これは、

 

IF27GROUP  GROUP  TEXT1,DATA1,TEXT2,DATA2

 

のようにすればいいようです。

 

書いてしまえばそれだけなんですけど、マニュアル読んでも、クラスとかグループっていうものの意味は最初から分かっている前提で、それをどのように記述するかだけが書いてあって、どうすれば自分が思ったように配置されるのか全然わかりません。

カットトライで色々コードを書いて調べていたので、これだけのことがわかるのに、けっこう時間がかかりました…。

(いや、これ、20数年前なら知っていた内容だったんでしょうけど、もう完全に忘れてしまって…)

 

まとめ

 

そんなこんなで、3日がかりぐらいでパケットドライバをすべてアセンブリコードに落とすことができました。

R86なんて使わないで、TASMを使えばよかったと、何度思ったことか…。

 

これで完了じゃなくて、スタート地点。

ドライバがハングアップする原因を調べるための前処理なんですよね。

(最初の目的を忘れてしまいそう…。)

 

もう、今日は疲れたので寝ます。

おやすみなさい。

 

↓続きはこちら

 

 

この話の続きです。

 

実はPC-9821Xa12という機種を持っていますが、ハードディスクが壊れてしまって御蔵入していました。

 

フロッピーディスクで起動すりゃいいって話なんですけどね。

人間って一度便利なものに慣れてしまうとなかなか元には戻れないものなんですよ。

 

さて、そうは言ってもこの98は3.5インチのFDDしかありません。

どうやってプログラムを98に持っていけばいいのか…

と、思っていたら、なんと!都合のいいことに、if27シリーズのドライバディスクが

何十年も放置されていたフロッピーディスクの山の中から見つかりました。

 

 

 

はいっ、これが今は亡きICM社謹製のLANボード設定プログラムです。

 

で、説明に従って、パケットドライバにPC-88VA用のパッチを当てましたが…、ダメでした。

IF27PDVA.COMを起動するとハングアップします。

pc88.gr.jpの掲示板でも同じ症状に悩んで質問している人がいましたが、解決しないまま放置されてしまったようです。

 

コマンドラインオプションで、割り込み番号やら、I/Oアドレスやら指定できるようになっているようなので、設定してみましたが、やっぱりダメでした。

(ちゃんと設定できていない気がします。)

 

ちょっと諦めかけていた時に、IF27PD.SYSという、説明には一切出てこないデバイスドライバらしきものがある事に気付きました。

PC-98用なので、まあ動かないのだろうなと思いつつも、物は試しで登録してみたところ、何事もなかったかのように動いているではありませんか!

 

おおっ、コレはいけるかも?

と、疑心暗鬼ながらも、TEENE.COMを常駐させると、「常駐しました」のメッセージ。

 

PINGしてみると…

やったー!

通った!

 

 

 

 

 

 

 

 

 

 

 

 

 

と、思ったのですが、世の中そんなに甘くない。

電源をOFF/ONすると、デバイスドライバ登録でハングアップします。

 

コメントアウトしてもう一度同じ操作をするとつながります。

でも電源を切ると立ち上がらなくなる。

 

デバイスドライバを登録する時にMS-DOSエミュレーションの何かがあるっぽい感じに見えるけど、だからどうしたらいいのかはわかりません。

 

とりあえず、動いたことでハードウェア的には問題ないことはわかりました。

デバイスドライバの線より、IF27PDVA.COMがハングアップする理由をデバッガで追った方が解決は早いんじゃないかなと思っています。

 

1つ気になった点があります。

IF27PDVA.COMのパッチのドキュメントの中に、削除しても問題なかったので、98のタイマを使ってウェイトを入れている部分をゴッソリ削除したとの記述があります。

当時はフロッピーディスクやハードディスクのアクセスが十分に遅かったので問題にならなかっただけで、CFカードやSDカード等のシリコンディスクが主流になった現在では、このウェイトが必要なのかもしれないという予想です。

すいません。間違いでした。この話はIF2771ETではなく、LGY98のVA用パッチの話でした。

 

 

この続きは↓こちら