• 13 名前: [email protected] ID:2ZmNjY2Jj

    DEVICEHIGHは、デバイスドライバを1MB以下のUMB領域(0C0000h-0FFFFFh)に読み込む指定になります。
    プロテクトメモリには転送しません。
    この領域はDOSのメモリ管理下(MCBによる16byte単位)です。また、UMB領域はEMS(EMM386)によって16KB単位のバンクメモリ領域としても使用されます。

    ちなみにSETVERの常駐サイズを確認しましたが128byteのようです。またEXEは64KBの壁を超えるためセグメント分割されていて、ファイル内容がそのままメモリに展開されるわけではありません。
    参考までにDOSメモリ確認ツール https://www.vector.co.jp/soft/dos/hardware/se002492.html

    2020-07-28 13:11:21

  • 14 名前: 山川機長 ID:2ZmNjY2Jj

    とりあえずここまで調べた点なのですが、DEVICEHIGH=SETVER.EXEで、SETVER.EXEはいったん E126 セグメントに展開されて実行されているようです。
    このとき、INT 21HはEMM386経由で FF10 セグメントにフォワードされるようになっていて、この中で、

    FF10:00007B0B 8BC3 MOV AX,BX ; AX=BX=WholeSize-1stBatchSize,299BH for SETVER.EXE
    FF10:00007B0D 33D2 XOR DX,DX
    FF10:00007B0F 26F77602 DIV WORD PTR ES:[BP+02H] ; ES:[BP+02H]=800H
    FF10:00007B13 A3D605 MOV [05D6H],AX ; [05D6H]=CopySize/800H
    FF10:00007B16 8916D405 MOV [05D4H],DX ; [05D4H]=CopySize%800H

    なんの単位かわからないですが2KB単位で処理しているようです。
    ページングが有効になっているのでページ単位かとも思ったのですがだったら4KB単位にしそうですし。
    ひょっとして80286のページングって2KB単位だったりしますか?その名残でしょうか?

    なお、ES:[BP+02H]は起動の初期のうちにセットされていて、KEYSET.TBL読み込み前に既に0800Hと決まっていたようです。

    他にわかっていることで現在重要と考えているポイントは、以下の通りです。

    [032EH] コピー先セグメント (E126H)
    [05B8H] コピー先オフセット
    [05D2H] 最初総バイト数で、途中から一度のバッチでコピーされるバイト数。
    [05D6H] 800Hバイトフルにコピーする単位数。
    [05E2H] ソース情報(多分)

    FF10:7B48 FF10:9080の転送ルーチンを複数回に分けて呼び出してバイナリを転送。なぜか最初と最後しか転送してくれない。
    FF10:9080 転送ルーチン (MOVSWとMOVSB実行)
    FF10:9044 転送ルーチンから呼び出されてコピー元、コピー先、バイト数を返す

    FF19:914E 転送先ポインタを 0600H から 2E00H に書き換えている。この中で中間部分の転送が発生するべき?

    SETVER.EXE読み込み 9CB9:0014
    SETVER.EXE転送元 9CB9:0214
    SETVER.EXEファイル情報とか(多分) 9CB9:0000から14Hバイト
    SETVER.EXE転送先 E126:0000
    SETVER.EXE Strategy CS:IP E126:001E
    SETVER.EXE Interrupt CS:IP E126:0029 -> E126:0038 E95208 JMP 088D で飛び先に何もない(全部ゼロ)
    転送元の場合 9C9B:023D -> 9CB9:024C E95208 JMP 0AA1 とび先に意味のあるコードあり

    多分、Virtual86モードの実装が不完全なため、なぜか途中をすっ飛ばしてしまっているのではないかと思います。
    FF10:7B48内で、[05D6H]コピーする単位数を参照している箇所も既にわかっているので、その付近で中間部分をE126セグメントに転送するべきだと思うのですが、というところで今止まってます。

    2020-07-28 13:13:00

  • 15 名前: [email protected] ID:2ZmNjY2Jj

    80286はds等のセレクタによるリニアアドレス拡張(Max16MB)が主で、ページング機構はなかったはずです。
    よって2KB単位の意味はちょっとわからないです。
    お話を読む限りだと、転送ルーチンがうまく動いないように思えますが、あまりお役に立てなそう……。

    ネットワークドライブ(windrv.sysもどき)関連ですが、DOS側の必要な仕組みは概ね分かりました。
    特定のI/Oを叩くとエミュ側に処理引き継ぐ(APIコール的な)形の実装を考えています。エミュ側のソースぜんぜん読めていないので、まだ先には長いですが。

    2020-07-28 13:14:11

  • 16 名前: 山川機長 ID:2ZmNjY2Jj

    EMM386をインストールすると、以後INT 21HはEMM386がTake overするようですね。
    それまで1456セグメントに飛んでいたのがプロテクトモード経由でFF10に飛ぶようになります。
    また、SETVER.EXEコピー先のE126セグメントですが、Pagingによってプロテクトモードメモリが割り当てられているようです。
    (なおデバッガのADTRコマンドでリニアアドレス、物理アドレスが見れます)

    ADTR E126:0000
    0000E126:00000000
    LINE:000E1260
    PHYS:00149260

    また、2KB単位のコピーですが、コピー先はE126:0000で、しかも、物理の149260Hなので、コピー先の2KB境界は気にしていないようで、しかもコピー元も、最初の14Hバイトは何かのEXEに関する情報が書いてあるようなので、元も先もページ境界をばっちりまたいでます。800Hバイト単位にする意味がますます謎ですね。

    EMM386を使わなければDOS6も普通に動くみたいなんですけどね。
    WINDRV.SYSもどきですが、I/Oを開ける必要があったら言っていただければなんとでもしますので。例えば、ドライバにする前でもディレクトリ情報を受け渡すI/Oのプロトコルを決めてEXEで実験とかできると思いますので。よろしくお願いします!

    2KバイトREP MOVSWしている箇所を見つけたのですが、直前の条件分岐で回避されてしまいました。残念。

    2020-07-28 13:15:27

  • 17 名前: 山川機長 ID:jOGY1OGM2

    とにかくHIMEMとEMM386だけ組み込んでCOMMAND.COMが動けばいろいろできるようになるだろうと思って、それを目指しているのですが、VM86モードに入ってしまうとFM音源割り込み内でテキスト領域に変更があった場合VRAMにテキストを描画するためにプロテクテドモードに移行しようとするもののVM86モードだから失敗してクラッシュ、という現象が起きてました。が、TSSのI/O Mapをよくよく見たら058CH (TVRAM MD flag)は禁止になっていて、VM86モニタが迎撃するべきであることがわかって、これで動くか!?と一瞬希望を持ってGeneral Protection Faultを出すようにしてみたところ、VM86モニタが代わりに058CHを読むところまでは確認できて良かったのですが、なぜかその直後に CALLF 0138:0000 、しかも0138はリニアの00000148Hを指していて、ページ変換してもそのまま物理の00000148Hなので、リアルモードのIDTに突入してクラッシュ、という状況になっています。0138のデスクリプタはハードコードされていて、用途不明ですね。本来実行セグメントでは無いので、CALLFがExceptionを出すべきところですが、しかし、既にException Handler内なのに再帰的にExceptionを出すべきかどうか。

    ただ、一応ハンドラ内でI/Oの058CHを読んでるし、直前に0140Hセグメントを参照していて、ここには"FM-TOWNS TEXT EMULATOR"と書いてあるのでかなり近い気がしてます。

    2020-08-02 04:59:57

  • 18 名前: 山川機長 ID:5NmI3Y2Nk

    DOS6ですが、Exception Handlerの中でGeneral Protection Faultが、何のインストラクションでExceptionが発生したのか判定して分岐する箇所まで特定しました。その部分では、Exception発生箇所のCS:[IP]の値(IN AL,DXは0CDH)を正しく読んでいるので、正しいアドレスに分岐しているようです。が、その後の CALLF 0138H:0000H はとんでもない場所にジャンプするので、ここに至るまでにGDTを書き換えて0138Hセグメントを意味のある場所をポイントするようにするか、あるいは、CALLFに入らないようにフラグを調整するか、どちらかを実行するべきのように見えます。

    Exception Handlerの最初の方で発生箇所のバイトを取るためにGDTの値を更新していますが、セレクタ0138Hに関しては何も手がついていませんでした。セレクタ0138Hは、EMM386.EXE最初の方が固定した値を書き込んだままです。しかも、指しているのが物理アドレス 0148H でリアルモードIDTを指しているので用途不明ですね。0138Hが特別なゲートか何かかとも思ったのですが、リアルモードのIDTを指しているのでは、意味のある情報は無さそうです。

    インストラクションごとのジャンプテーブルがわかったのでCALLF(9AH)でExceptionを出したらどうなるかも見てみたのですが、CALLFでExceptionが出ていた場合は他の一般的な命令と同じアドレス(多分不正な割り込みが発生しましたとか表示するだけかも)にジャンプするだけだったので、CALLFでExceptionを出しても結果は変わらないように思います。

    しかし、そもそもEMM386はINT 4DをTakeoverしているのに、なぜわざわざ元のリアルモードのハンドラにVM86フラグを立てたまま処理を渡しているのか、というのが大きな問題ですね。雰囲気としてはEMM386のINT 4DハンドラはTVRAM MDフラグをチェックして書き換えがあったなら再描画してその後他の処理のためにリアルモードハンドラに処理を渡す、INT 4Dのハンドラ内ではTVRAMには何も書かないはずだからTVRAM MDフラグは変化しないはずだからリアルモードハンドラはあたかもTVRAMには何も変化が無かったように処理する、というのならわかるのですが。あるいは、リアルモードのハンドラなんだからリアルモードに戻してハンドオフして、戻ってきたところで再度VM86モードにするというのでもわかるのですが。せっかくわざわざINT 4Dをプロテクテドモードで受けたのに、何もしないままリアルモードハンドラにVM86フラグ立てたままハンドオフして、そして再度INT AL,DXをプロテクテドモードのException Handlerで受けるのは何か間違ってる気がしますね。

    あるいはもっと早い時点で違うExceptionが発生している可能性も考えていますが、リアルモードハンドラにハンドオフされてから、そんなに大したことをしないうちに IN AL,DX に至っているので、それらしいインストラクションもまだ発見できてません。

    とりあえず、現状報告でした。うんづにせめてブレークポイント機能だけでもあってくれたらと思うんですがね。最後の手段はディスクイメージ上のEMM386を書き換えて果たしてその場所に飛んでいるかを確認するという手がまだ残ってますが。年末、実機SCSI CD用パッチを開発するときはこの手をよく使いました。しかし、春のレトロゲーミングナイトで走らせようと思ってたのにコロナの影響でイベントが無くなってしまいましたが。

    2020-08-04 05:49:29

  • 19 名前: 山川機長 ID:5NmI3Y2Nk

    CALLF 0138:0000については、光明が見えてきました。まだ実装済んでませんが、どうやら0138HはCall Gateで、Segment Descriptorではなかったようです。その後、EMM386.EXEをインストールしない状態ではINT 4Dの割り込みはどこを呼び出しているのだろう?と思って調べたら、0008:0B1Aに飛んでいて、0008セグメントのリニアベースは0000D7F0、EMM386のINTハンドラ内で同じベースを持つのは 0148H。そういえば0138Hのリニアベースが0148Hだったな、と、思って、Descriptor 0138Hのダンプを取ったら、

    001882E8 0F 0B 48 01 00 84 00 00

    0B0F? 偶然にしては0B1Aに近すぎる、と、思って0148:0B0Fから逆アセンブルしたらALのビット7をチェックして立ってたらその先に飛ぶように書いて合って、偶然では無いとほぼ確信してOSDevとi486 Programmer's Reference Manualで確認しました。それで、今朝ゲートへのジャンプを検出してAbortするように書き換えたので、中身を書くのは今晩になりますね。せめてEMM386を入れた状態でCOMMAND.COMが立ち上がってくれればいろいろ調べられるようになると思うのですが、しかし、COMMAND.COMの前にこれが最後の壁かどうかは今晩(アメリカ東部時間)やってみてになります。

    TownsのエミュレータなのでWindows 95を動かすつもりはなかったのですが、ここまでやったら動かせるようにしたいと思う反面、DOS6だけでこの苦労では先が長いですね。でも、Namco Histroy Vol1, Vol2は走らせたい。僕は今まで一体Xeviousを何本買ったんだろう?ってぐらい各プラットフォーム用に買ってしまっているので、とりあえず当分動き続けるXeviousが一本あると次に見かけても買わなくて済みます。ちなみに、プレステ1はNamco Museumシリーズのためだけに買いました。

    2020-08-04 22:50:58

  • 20 名前: [email protected] ID:1YWVhMjFl

    >>19
    進展すてきです。将来Win95動いたらすごいですね。Win95インストールディスク発掘してこないと(気が早い
    KEYMAPの実装のおかげで、DOSが実用的に操作できてとても助かってます。SHIFT押しながら等の操作で、うんづよりキーエミュレーションがしっかりしてて使いやすいです。あと、もともとのキーマップはTOWNSキーボードの物理位置準拠だったと今更気づきました。

    2020-08-05 00:38:50

  • 21 名前: 山川機長 ID:5ODVjY2Ew

    キーボードは、実はホスト側のリピートのタイミングでリピートコードを出しているので、いろいろ違っているのですが、タイプしようと思ったらこの方が良いかと思ってます。実はESCと~はいい加減だったのですが、[email protected]さんにESCキーの件にコメントをいただいたとき真面目に直しました。

    DOS6, 一応EMM386がインストールされた状態でCOMMAND.COMまで出るようになりました!が、相変わらずDEVICEHIGH=SETVER.EXE するとプログラムの中間部分がコピーされない現象でクラッシュが続いてます。

    が、同じ転送ルーチンをEMM386がVM86モードに入る前に使っているので調べたところ、自信のコピーをメモリ→メモリ転送していのかと、思ったら転送先に中間部分を書き込んでいたのはDMAのようだということがわかり、CPUじゃなくてSCSIの問題の可能性が浮上しています。たしかに、当時のメモリ容量でわざわざバイナリをいったんバッファに読み込んでから最終目的地に転送というのはありえないかもしれないですね。だとすると、200H単位だったのはセクタサイズから来ていたのだとすると納得できますね。また、200H単位がページ境界を普通にまたいでいたのも、SCSI側の都合だったとすると理解できますね。

    あとは、COMMAND.COMが立ち上がってもときどきクラッシュしますが割り込みの影響かもしれません。SETVERの中間部分が抜けるのと同じ原因鴨しれませんね。PICのSFNM=1になっていたので、Rotationを使っているとするとPICのエミュレーションが違っている可能性大です。

    2020-08-05 09:06:09

  • 22 名前: 山川機長 ID:kZWE3NDJm

    DOS6、SETVER.EXE突破しました!一応、EMM386.EXEインストール状態で、SETVER.EXEを読み込んで、COMMAND.COMが立ち上がります!

    問題は、なんと!DMAのStatusでした。FM Townsテクニカルデータブックによると、DMA StatusのTC0-3ビットは、Terminal Countに達した、と、ありますが、71071のデータシートによると、Terminal CountまたはENDとあります。

    問題の中抜け部分は、割り込みハンドラの中でTCビットを見て、読み込みバッファから本来の転送先にコピーされるべきものでした。ところが、なぜかSCSI読み書きのときTownsOSもDOS6も、多めのカウントを書き込んで、実際読み込むバイト数はコマンドに指定するセクタ数に依存だったため、カウントがTerminalに達することがなく、TCビットが立っていませんでした。

    DMAの問題とわかったので、既にI/OアクセスのException Handling箇所は特定してあったので、DMA Address書き込みをどのように処理しているか見たところ、ハイメモリ領域に読み込む場合はEMM386がページングをかけている場合があるので、いったん物理150000H~に読み込んで、それを何かのタイミングで最終目的地に転送していることを特定しました。そして、どうやらトリガになるのはTCビットということがわかったのですが、カウント数を見るとぜんぜんTerminalに達する気配が無く、ここまでCPUがうまく動いているのにカウントの計算を間違うのもおかしいと思ったものの、一応確認したところどう見ても間違っていなくて、そうであればTCフラグの方の問題かと思って71071データシートを見て、"Terminal Count OR END"と書いてあることがわかったので、そのように修正して、無事起動しました!

    多分まだ完全に安定はしてないと思うのですが、起動したときはガッツポーズが出ましたね。これだからプログラミングはやめられません。

    なお、この修正の前にリリースを出してしまったので、今日のリリースには入ってません。あと、CDROMとFDCにも同様の修正 (読み終わったらカウントに関係なくTCを上げる)を加えたので、例によってユニットテストを流してます。

    2020-08-06 10:07:05

  • 23 名前: 山川機長 ID:kZWE3NDJm

    すみません、↑の修正を入れたらTownsOSがハードディスクから起動しなくなったので、フラグを立てる条件とタイミングは検討が必要のようです。が、多分、それはなんとかなるでしょう。

    2020-08-06 10:35:11

  • 24 名前: 山川機長 ID:kZWE3NDJm

    多分、解決しました。TownsOSはINT 93HでterminalCountフラグが立っていたら転送終了と判定しているようなのですが、BIOSの中でフラグが立ったまま後始末をしていなかったようで、セクタを読み始めた途端に読み終わったと思ってクラッシュしていたようです。データシートには、terminalCountフラグを下げる条件はStatusを読むこと以外は書いていないように見えるのですが(ざっとしか読んで無いのでどこかにあるの鴨しれない)、terminalCountというぐらいだから、新しいカウント値が入ってきたらフラグを下げるようにしたらTownsOSも起動するようになりました。今は、DOS6で起動後にEDITを立ち上げようとしたとき、ときどきクラッシュする問題の原因を探してます。が、大きく前進しました。

    2020-08-06 13:03:41

  • 25 名前: WINDY ID:xMmM1NWRm

    DMACについては、情報が少なくTC0-3ビットの変化に関してデータシート上では、(1)イニシャライズコマンドによる初期化時にステータスレジスタの全ビットクリア,(2)ステータスレジスタリードコマンドによる読出後にクリアされると書かれているのみです。
    気になるオートイニシャライズ動作時(=新しいカウント値がベースカウントレジスタからカレントカウントレジスタに転送される)にTC0-3ビットの状態変化についての記載は有りませんでした。
    あとは、「END入力またはターミナルカウントの発生でDMAサービスが終了した場合には、サービスの終了したチャネルに該当するマスクレジスタのビットがセットされ(オートイニシャライズが設定されていない場合),そのチャネルのDMARQ入力はマスクされます。」とあるくらいです。

    2020-08-06 13:45:32

  • 26 名前: 山川機長 ID:kZWE3NDJm

    たしかに、IO.SYSがいちどInitializeコマンドを出してる鴨しれないですね。とりあえず、今のところカウントレジスタに書き込みでTCビットもクリアで動いているようなので、当面これで行ってみます。

    AUTOIがクリア状態の記述は僕も見ました。ひょっとするとmaskビットはReadもできるようなので影響を受けるものがそのうちあるかもしれないので、一応気に留めておこうと思いました。

    2020-08-06 21:36:09

  • 27 名前: 山川機長 ID:iOTlmMmI0

    DOS6でランダムにクラッシュする問題、解決したようです。これまではEMM386.EXEをインストールした状態だとEDITコマンドが5回に1回ぐらいの割合で謎のクラッシュを起こしていたのですが、少なくとも40連続で起動と終了を繰り返してもクラッシュしませんでした。他のデバイスドライバは、今日は疲れたので僕の体力が回復してからのテストになります。問題は、DMAでした。VM86モードの影響でいろんなことに多く時間がかかるらしく、ときどきSCSIがData Readyになるタイミングで、まだDMAの設定が終わっていないという状況が発生して、ゼロバイト転送して例のTerminalCountフラグを立ててしまっていました。それでBIOSはTerminalCountフラグを見てcurrent addressを進めてしまって、本来読み込まれる場所にセクタが読み込まれなくてクラッシュということになってました。だんだん簡単に取れる問題は取ってしまった感じで難しい問題が残りつつありますね(^_^;)

    2020-08-08 07:27:55

  • 28 名前: [email protected] ID:0Y2JhMTQ0

    おつかれさまです。
    >VM86モードの影響でいろんなことに多く時間がかかるらしく、
    実際「V86←→プロテクトモード」のスイッチ回数が増えますし、そのスイッチ自体もEMM386を組み込むとやや遅くりそうです(仕組み上)。

    2020-08-08 14:00:22

  • 29 名前: [email protected] ID:iMDFmZDA0

    ネットワークドライバ(仮称:vndrv)用のAPIのテスト案置きました。
    ttps://nabe.adiary.jp/0619
    もしよければ、ご意見願います。
    ・I/Oの番地はどのへんがよいのか。
    ・仕様の良くないところ。

    2020-08-10 00:02:38

  • 30 名前: 山川機長 ID:3YTc5ZmQ2

    (あれ、さっき書き込んだつもりが、多分スクリプトブロッカーの影響で書けてなかった。)仕様ありうがとうございます!とりあえず、FindFirst, FindNextのリターンに、BX|DXにファイルサイズを返しますか?それと、Linux、mac、および非Shift-JISのWindows環境では日本語のファイル名は化けると思いますが、日本語ファイル名はとりあえず考えないという方向でよいでしょうか?I/Oですが、2000番台は富士通内部でテストに使っていたという話をどこかで見た気がします。そうであればプロダクションモデルでは未使用ではないかと思うので、2000H番台は大丈夫なのではないでしょうか?既に僕は2386H, 2387Hを勝手に使ってしまっています。INT 2Fを使うのであれば、ちなんで 2F00H~というのでどうでしょうか?4000H番台はときどきBIOSが使ってるの見かけますね。一応、こちらでもディレクトリを返す準備しておきます!

    2020-08-10 08:55:53

  • 31 名前: [email protected] ID:hYWQ4YmI4

    >>30
    ファイルサイズとかファイル更新日時とか必要なの抜けてましたね……。仕様更新しました。
    2F00H、良いと思います。日本語は当面考えないことにしましょう。

    あと、I/Oの結果でレジスタを変更すると、後々CPUコアを最適化していくときに問題が起きるのかなとか心配になってしまったのですが、どうですか。発行にはレジスタを使ったとしても結果はすべてメモリに書き込むような仕様のほうが安全かなと寝ながら思いましたが、ご意見いただければ嬉しいです。

    2020-08-10 13:26:08

  • 全部読む/ 最新50/ 1-100/ 掲示板トップ