SCSIのPhaseのMESSAGE_INとSTATUSの順を入れ替えたら、とりあえずSCSIのエラーは出なくなりました。
が、HIMEM.SYSインストール中に割り込みハンドラを破壊という現象が起きていて原因を調査中です。
なお、デバッガで BRKON INT 21 AH=3D としておくとfile openで止まるので、pri cst するとどのファイルを開くとこかわかるようになってます。
2020-07-28 12:59:54
多分原因究明しました。
1086:0000A6C2 F36766A5 REP MOVSD
リアルモードで 67 をつけると32-bitオフセット使えるっぽいですね。
直前でどうみても物理アドレスを計算するルーチンがあったので、YSSCSICD.SYS書いたとき、リアルモードだとアドレシングは強制的に16ビットになるものと思っていたのですが、いろいろ新たな発見がありますね。CPUコア、どこかで矛盾出さずに簡単に直るかな?とりあえずやってみます。
2020-07-28 13:01:16
HIMEM.SYSやっぱ変ですね。Real ModeだとセグメントリミットがFFFFのはずなのに。
直前で↓になっているので、
1086:0000A67A 0F01E0 SMSW AX
1086:0000A67D D1E8 SHR AX,1
1086:0000A67F 0F82C901 JB 0000A84C
Unreal Modeでも無さそうなのですが。しかし67Hプレフィックスはついているし。HIMEM.SYSがちょっと難航しそうですね。
2020-07-28 13:02:37
連続ですみません。
https://wiki.osdev.org/Unreal_Mode
これによるとセグメントリミットってリアルモードに戻ってもリセットされないんですね!本当なのだろうか。
そんなことが可能ならDOS Extender無くても良さそうな。。。。
Unreal ModeはリアルモードでCR0のビット0を立てて使うもんだと思ってました。
これを実装すれば多分HIMEM.SYSも動くかも。とりあえず、やってみます。
2020-07-28 13:03:35
リリース出しました!
DOS6.2は動きますがEMM386.EXEがTask Registerを使っている影響で未対応です。
Task Registerの扱いは改めて勉強しないとわかりません。
Task Register対応は後回しということにさせてください。
なお、DOS6.2のHIMEM.SYSに対応したらFractal Engine Demoの画面の乱れも直ってしまいました。(やっぱりCPUだった)
2020-07-28 13:04:12
DOS6動きました、ありがとうございます。EMM386対応も期待してます(Free386のデバッグに使いたいらしい)。
うんづで言うところの windrv.sys みたいなのが欲しくなりますね。
幸いDOSプログラミングは多少慣れているので、DOSでネットワークドライブを作成するドライバ仕様と時間があればやりたいところですが、軽く検索してみても、今どきDOSの資料探すのは大変だった。
多分sysファイルだとブロックデバイスにするしかなくエミュレーションが大変そうなので、ネットワークドライブはMSCDEXよろしくEXEで作るんだと思いますが……。どなたか情報お持ちの方いませんか。
2020-07-28 13:04:56
Free386のデバッグにお役に立てるのであれば、なんとかしたいと思います!
知り合いのX68Kユーザ(カーネギーメロン大最強の卒業生)にXMODEM対応したと言ったら、X68KにはWINDRVというドライバがあって、と自慢されたので是非ほしいですね!
一応、勝手に空けたI/Oで高速にファイルを流し込む機能は既に入ってるのですが、ファイル共有できるとデモプログラミングが楽になりますね。
あとは、EthernetCardの仕様がわかれば実装したいとこなのですが。
2020-07-28 13:05:32
keymapの実装ありがとうございます。嬉しいです。
個人的にはNumLockは無反応(マップなし)で良いのではないかと思います(物理キー側のモードを切り替えるだけなので、何か入力したくて押すわけではない)。
仮想ドライブドライバですが、SHSUCDXというものを見つけたので昨日ずっとソースを読んでました。
まだ完全に理解したわけではないですが、そんなに複雑なことはしなさそうですのでなんとかなるかも。
http://adoxa.altervista.org/shsucdx/index.html
あと、DOS6の仮想86モードは、ほとんどすべての特権命令をEMM386がエミュレートするので、ユーザーランドからみるとリアルモードとほぼ変わりありません。
ですので、V86として真面目に実装しなくても(I/O他特権命令を素通りさせても)、DOSは問題なく動く気がします。
-HIMEM.SYS 1MB超えメモリの管理。CPUのリアル←→プロテクトモード切り替え機能。
-EMM386.EXE CPUをV86モードに切り替えてEMM機能(バンクメモリシステム)のエミュレート。
2020-07-28 13:06:29
とりあえずVM86に入ることはできてINTも出るようになったのですが、INT 97H(TimerBIOS)が出てる箇所があって、プロテクトモードのIDTに97Hが書いてなくて止まってます。
ここは本来97Hのエントリが書かれてあるべきなのか、それともNP faultを出すのが正しいのかで止まってます。
ごまかしてリアルモードのとび先に直接飛ばすという手でも動きそうな気がしますが一応正しく処理する方法を模索してます。
2020-07-28 13:08:16
>INT 97H(TimerBIOS)
V86モードでもプロテクトモードで割り込みを発生させる場合は、DOS-Extenderの機能を使ってリアルモード側のベクタを書き換えるのが正しい処理になります。
よって、V86モードで発生した割り込みでしたら、EMM386の機能としてはリアルモードベクタに飛ばすのが正しい処理だと思われます。
もしくは正しい例外処理をエミュレートできれば、EMM386がエミュレートしてリアルモード割り込みに引き継ぐと思われます。
※EMM386は、V86なDOS環境をリアルモードと極力同じにするよう動作します。
2020-07-28 13:08:51
IDTが存在しないINTはGP例外を出すとEMM386が処理をフォワードしてくれるようです。
が、次にDEVICEHIGH=SETVER.EXEで、なぜかヘッダを除いて最初の600Hバイトと最後の19BHバイトしかHIEH Memoryに転送しない現象が起きてます。
(SETVER.EXEのファイルサイズは319BH) 600Hバイトはヘッダ200Hを足すと800HになるのでEMM386のページサイズが800Hなのではないかと思うのですが、どうして途中を飛ばすのやら。
2020-07-28 13:09:36
削除済
2020-07-28 13:10:01
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
とりあえずここまで調べた点なのですが、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
80286はds等のセレクタによるリニアアドレス拡張(Max16MB)が主で、ページング機構はなかったはずです。
よって2KB単位の意味はちょっとわからないです。
お話を読む限りだと、転送ルーチンがうまく動いないように思えますが、あまりお役に立てなそう……。
ネットワークドライブ(windrv.sysもどき)関連ですが、DOS側の必要な仕組みは概ね分かりました。
特定のI/Oを叩くとエミュ側に処理引き継ぐ(APIコール的な)形の実装を考えています。エミュ側のソースぜんぜん読めていないので、まだ先には長いですが。
2020-07-28 13:14:11
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
とにかく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
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
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
>>19
進展すてきです。将来Win95動いたらすごいですね。Win95インストールディスク発掘してこないと(気が早い
KEYMAPの実装のおかげで、DOSが実用的に操作できてとても助かってます。SHIFT押しながら等の操作で、うんづよりキーエミュレーションがしっかりしてて使いやすいです。あと、もともとのキーマップはTOWNSキーボードの物理位置準拠だったと今更気づきました。
2020-08-05 00:38:50
キーボードは、実はホスト側のリピートのタイミングでリピートコードを出しているので、いろいろ違っているのですが、タイプしようと思ったらこの方が良いかと思ってます。実はESCと~はいい加減だったのですが、nabe@abkさんに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
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
すみません、↑の修正を入れたらTownsOSがハードディスクから起動しなくなったので、フラグを立てる条件とタイミングは検討が必要のようです。が、多分、それはなんとかなるでしょう。
2020-08-06 10:35:11
多分、解決しました。TownsOSはINT 93HでterminalCountフラグが立っていたら転送終了と判定しているようなのですが、BIOSの中でフラグが立ったまま後始末をしていなかったようで、セクタを読み始めた途端に読み終わったと思ってクラッシュしていたようです。データシートには、terminalCountフラグを下げる条件はStatusを読むこと以外は書いていないように見えるのですが(ざっとしか読んで無いのでどこかにあるの鴨しれない)、terminalCountというぐらいだから、新しいカウント値が入ってきたらフラグを下げるようにしたらTownsOSも起動するようになりました。今は、DOS6で起動後にEDITを立ち上げようとしたとき、ときどきクラッシュする問題の原因を探してます。が、大きく前進しました。
2020-08-06 13:03:41
DMACについては、情報が少なくTC0-3ビットの変化に関してデータシート上では、(1)イニシャライズコマンドによる初期化時にステータスレジスタの全ビットクリア,(2)ステータスレジスタリードコマンドによる読出後にクリアされると書かれているのみです。
気になるオートイニシャライズ動作時(=新しいカウント値がベースカウントレジスタからカレントカウントレジスタに転送される)にTC0-3ビットの状態変化についての記載は有りませんでした。
あとは、「END入力またはターミナルカウントの発生でDMAサービスが終了した場合には、サービスの終了したチャネルに該当するマスクレジスタのビットがセットされ(オートイニシャライズが設定されていない場合),そのチャネルのDMARQ入力はマスクされます。」とあるくらいです。
2020-08-06 13:45:32
たしかに、IO.SYSがいちどInitializeコマンドを出してる鴨しれないですね。とりあえず、今のところカウントレジスタに書き込みでTCビットもクリアで動いているようなので、当面これで行ってみます。
AUTOIがクリア状態の記述は僕も見ました。ひょっとするとmaskビットはReadもできるようなので影響を受けるものがそのうちあるかもしれないので、一応気に留めておこうと思いました。
2020-08-06 21:36:09
DOS6でランダムにクラッシュする問題、解決したようです。これまではEMM386.EXEをインストールした状態だとEDITコマンドが5回に1回ぐらいの割合で謎のクラッシュを起こしていたのですが、少なくとも40連続で起動と終了を繰り返してもクラッシュしませんでした。他のデバイスドライバは、今日は疲れたので僕の体力が回復してからのテストになります。問題は、DMAでした。VM86モードの影響でいろんなことに多く時間がかかるらしく、ときどきSCSIがData Readyになるタイミングで、まだDMAの設定が終わっていないという状況が発生して、ゼロバイト転送して例のTerminalCountフラグを立ててしまっていました。それでBIOSはTerminalCountフラグを見てcurrent addressを進めてしまって、本来読み込まれる場所にセクタが読み込まれなくてクラッシュということになってました。だんだん簡単に取れる問題は取ってしまった感じで難しい問題が残りつつありますね(^_^;)
2020-08-08 07:27:55
おつかれさまです。
>VM86モードの影響でいろんなことに多く時間がかかるらしく、
実際「V86←→プロテクトモード」のスイッチ回数が増えますし、そのスイッチ自体もEMM386を組み込むとやや遅くりそうです(仕組み上)。
2020-08-08 14:00:22
ネットワークドライバ(仮称:vndrv)用のAPIのテスト案置きました。
ttps://nabe.adiary.jp/0619
もしよければ、ご意見願います。
・I/Oの番地はどのへんがよいのか。
・仕様の良くないところ。
2020-08-10 00:02:38
(あれ、さっき書き込んだつもりが、多分スクリプトブロッカーの影響で書けてなかった。)仕様ありうがとうございます!とりあえず、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
>>30
ファイルサイズとかファイル更新日時とか必要なの抜けてましたね……。仕様更新しました。
2F00H、良いと思います。日本語は当面考えないことにしましょう。
あと、I/Oの結果でレジスタを変更すると、後々CPUコアを最適化していくときに問題が起きるのかなとか心配になってしまったのですが、どうですか。発行にはレジスタを使ったとしても結果はすべてメモリに書き込むような仕様のほうが安全かなと寝ながら思いましたが、ご意見いただければ嬉しいです。
2020-08-10 13:26:08
そうか。更新日時が抜けてましたね!CPUコアはデバッガなどに対応するために外部からのレジスタの変更は必要な機能なので、I/O書き込みでレジスタに値を返すのは問題ないと思います。心配といえば、もしも誰かが津軽のソースをForkして別のCPUコアに載せ替えたバージョンとか作る日が来たらなんらかの影響が出るかもしれないですが、その可能性はとりあえず小さいのではないでしょうか。あとは、アドレスをプロテクテドモードでVM=0の場合は32ビットオフセットにするか、必ず16ビットにするかも決めておいた方がいい鴨しれないですね。あとは、コマンド0AHでDLのフラグで、DS:[EBX], LINEAR:EBX, PHYSICAL:EBXを選べるようにしてもいい鴨しれません。
互換情報に書くべきかもしれないですが、昨日Brandishを見ていてPCMに大きな間違いを発見してしまいました。PCM全体のOn/OffフラグがOffのとき、Ch On/Offへの書き込みを無視してました。Brandishは先にCh On/Offを設定してから全体をOnにしているため、PCMが再生されず、そのため割り込みが発生せず、いつまでも割り込みを待ってました。これを直したところ、その後画面が乱れるのですが、ボタンを押すと次に進むものの、絶対に抜けられない無限ループ入りしてしまうので、コピープロテクトかなとちょっと疑ってますが引き続き解析してみます。Brandishはまだ動きませんが、動かなかったタイトルとかPCM再生が変だったタイトルのうちいくつかはこの影響を受けていたかもしれないですね。
ひょっとしてDual Targets, ZeroがPCM割り込みでちょっとずつキャラクタを描画してたりするかとちょっと期待したのですがそれは違ったようです。見てるとRGBがずれて飛んできて最後にまとまるかと思ったら消えてしまってますね。
2020-08-10 23:18:07
肝心のディレクトリ機能がまだですが、とりあえずPresence Check, Enable/Disable, AUX Commandを実装してみました。Break, Print, Dumpは一応386ASMとHigh-Cでテストしたので動くと思います。testcサブディレクトリのvndrv*.c, vndrvtst.asmがテストプログラムのソースです。今晩は残りは、Brandishの捜査に当たろうと思うので、ディレクトリ機能などは明日以降になりますね。実際使ってみたら別なやり方がよかったと思うようなことが出てくると思うので、仮の実装ということで。なお、VNDRVライブラリはsrc/towns/vndrv下です。Windows用、それ以外用のディレクトリ取ってくるライブラリも src/osdependent/filesys に書きかけてます。C++17になるとファイルシステムがstdライブラリに入るとか聞いたんですが、C++11の範囲で書こうと思ったらディレクトリ取ってくるのもOSに依存しますね。
2020-08-11 08:45:04
Presence Check, Enable/Disable, AUX Command動作確認しました(VM86モードにて)。ありがとうございます!
DOSで実装するので16bitしか考えていませんでしたが仕様として美しくないので必ず32bitがよさそう。
リニアアドレス、物理アドレスダンプは条件分岐よりコマンド増やすほうがスマートかなと思いますがいかがですか(共に仕様案に反映しました)。
仮実装で全く問題ないです。こちらも実装してみないとわからないところが多いので。そうかファイル検索って非標準なのですね……。C++17ならたしかにstd::filesystemでできそう(VS2019もC++17を有効化すれば対応してるっぽい)。
2020-08-11 19:05:08
とりあえず、Primary Commandも実装しました。ディレクトリ返せます。サブディレクトリはテストしていないですが。-SHAREDIR path オプションで共有ディレクトリを指定できます。とりあえず合計8個まで指定できて、以後は無視します。それで、今タイムスタンプはいい加減です。あと、フラグもディレクトリ以外立ててません。それから、8.3ファイル名ですが、現在単にC-Stringで "FILE.EXT"で残りは'\0'で埋めていますが、セクタ内風に"FILE EXT "、あるいは、"FILE .EXT"がいいですか?その辺はなんとでも対応しますので、一番楽な方法を指定してください。うまくいったら次はファイルアクセスですね。
VNDRVが実現したらTowns用アプリの開発が楽になりますね。DOSBoxを使えばHigh-Cも386ASMも走るので、Windows上のエディタでソースを編集して、DOSBoxでコンパイルして、VNDRV経由で津軽上で実行できます。僕は今年は津軽を開発しているし、今年のDemosplashは開催してもリモートになりそうなので一年休みますが、毎年一本、できればFM77AV用一本、FMTowns用一本デモを書こうと思ってます。よかったらTowns用デモを書いて、Demosceneに参戦しませんか?
なお、Brandishはマウスを使うんですね。マウスインテグレーションやってみます。Townsの市販ソフトの個数は有限なので、ひとつずつ撃破していけば有限の時間内にすべてのソフトのマウスインテグレーションが書けるはず。
2020-08-12 13:18:14
Primary Command実装ありかとうございます。暇を見ながらDOS側の実装がんばります。
>現在単にC-Stringで "FILE.EXT"で残りは'\0'で埋めています
たしかDOSはこの形式だったと記憶しているので問題ないと思います。Demosplash初めて知りました。
あとvndrvとは関係ないのですが、DOS6上でTOWNS-OSの稼働に必要な「TBIOSLD.SYS」や「TOWNS.SYS」を組み込むとVERR/VERWで Abort してしまうようです。もし気が向いたら見て頂ければ嬉しいです。
2020-08-13 16:51:44
よろしくお願いします!一応、お盆休みにコーディングされるかと思ったので、とりあえず大急ぎで実装しましたが、悠久の時間に存在する(?)Townsなので、お時間のあるときにお願いします。
VERR,VERW,BOUNDは実装しました。なんか間違ってないか不安ですが一応動いているようです。VERR,VERWはsegment descriptor作らないと本質的なテストができず、BOUNDはINT 5のハンドラを書かないと同じくテストできないので、ユニットテストに気楽に追加できないんですよね。
まもなくユニットテストが終わるのでソース上げます。
2020-08-14 11:01:08
VERR/VERWありがとうございます。VERRを通過して、CLTS(0Fh 06h)で死亡しました。T-OSはなぜタスク機能を使ってるのか……。
お盆あんまり関係ないんですよね。まとまった時間取れれば集中してドライバ書いてたいのですが。
2020-08-14 21:33:10
CLTS実装ありがとうございます。TBIOSLD.SYSとTOWNS.SYSを組み込んだ状態で起動するようになりました。
ですが、COCO で forrbios.nsd を組み込むとコードでない場所(V86モード)を実行して止まるようです。
(COCOを組み込まなくても適当なEXPを起動してると同じようなところで停止。同条件でEMM386を組み込まない場合は問題なし。)
なんとなく根が深そうなので、お時間あるときに見ていただけら嬉しいです。
2020-08-15 15:15:40
あらぬ場所にジャンプしてしまう現象は、考えられる可能性として高いのは、
(1) Exceptionを正しく出してない。
(2) Exceptionの出し方が正しくない。
(3) Task Gateを使ってジャンプしている。
(4) CPUコアに未発見のエラーがある。
と、このぐらいだと思います。多分、(1)だと思うんですね。なんとか環境を作って調べられないか検討してみます。
2020-08-16 02:51:32
>>40
TOWNS-OS on DOS6環境を作るには、DOS6をインストールしたHDD区画に対して、TOWNS-OS V2.1L40以降のシステムCDを起動して、アイコンから新規インストール先として指定すれば、DOS6上にTOWNS-OSがインストールされます。
これで128MB超えのHDD区画もバッチリ認識……じゃなかった。これで上に書いた問題も再現します(V2.1L50にて確認)。
2020-08-17 18:16:55
了解しました!詰まったら、多分実家から回収してきたFM Townsシステムセットアップガイドを見ながらなんとかできると思います。(一応共著者に名前入ってるけどDOS6の部分は全部武井先生が書いた)。やってみます!
2020-08-19 05:36:29
状況再現しました。クラッシュは↓ですね?
3FF8:000014E1 FFFF
この直前がIRETDで、NT=1となっているので、どうやらTask Returnというのを実装しなくてはならないらしいです。戻ってくるアドレス自体は正しいのですが、素直にStack ReturnsしてしまうとVMフラグをクリアしてしまって、3FF8をセレクタと解釈してとんでもないリニアアドレスだと思っているようです。
想像なのですが、ここはRUN386の中のようで、このTask Returnした先でVMフラグをクリアして3FF8:000014E1に戻してRUN386に続きをさせるということではないかと見ています。
どのぐらい簡単か難しいかまだわからないので、ちょっと勉強してみます。
2020-08-19 08:45:30
うーん、もはやどれを信じていいのかわからない。i486 Programmer's Reference ManualのPsuedo Codeによると、
(* Protected mode *)
IF VM=1
THEN #GP(0)
ELSE
IF NT=1
THEN GOTO TASK-RETURN
と、あるものの、下の説明では、
#GP(0) fault if the IOPL is less than 3, to permit emulation
しかし、VM86モードのIOPLは3のはずだから、'less than'にはあたらない。ので、Pseudo Codeとテキストの解説が矛盾してます。結構こういう誤記なのか手抜きなのかわからない表記多いんですよね。
ここの記述→では、https://www.felixcloutier.com/x86/iret:iretd
IF(EFLAGS.VM=1)
THEN GOTO RETURN-FROM-VIRTUAL-8086-MODE;
ELSE GOTO PROTECTED-MODE;
RETURN-FROM-VIRTUAL-8086-MODE:
(*Processor is in virtual-8086 mode when IRET is executed and stays in virtual-8086 mode*)
とあり、その説明では普通にNTフラグにかかわらずStack ReturnするがVMビットは影響を受けない。とのこと。しかし、そんなことはi486 Programmer's Reference Manualを見る限りまったく書いてません。POPFDではそういう記述があるんですけどね。VMフラグそのたいくつかのフラグはPOPFDによって変化しないそうです。
それで、Task Returnを調べたところ、TSSにReturn先のTRが書いてなければならないことになってますが、EMM386環境ではタスクはひとつしかなくて、ほかのタスクにリターンしたくてもそもそも戻り先タスクが存在しなさそうです。
一番都合のいい解釈は、VM86モード下のIRETではVMフラグが変わらない以外は基本的に普通のIRETと一緒、とする説なので、そのようにしてみたところ、DOS6上でTowns MENUが起動しました。例によって現在ctestを流しているので、全部通ったらソースをPUSHしますね。
2020-08-19 09:44:41
>44 山川機長さん
もうある意味解決しているのかもしれませんが、INTELのia32_arh_dev_man_vol2a_i.pdfの該当個所を見てみると、
RETURN-FROM-VIRTUAL-8086-MODE:
(* Processor is in virtual-8086 mode when IRET is executed and stays in virtual-8086mode *)
IF IOPL=3 (* Virtual mode: PE=1, VM=1, IOPL=3 *)
THEN IF OperandSize = 32
THEN
IF top 12 bytes of stack not within stack limits THEN #SS(0); FI;
IF instruction pointer not within code segment limits THEN #GP(0); FI;
EIP ← Pop();
CS ← Pop(); (* 32-bit pop, high-order 16 bits discarded *)
EFLAGS ← Pop();
(*VM,IOPL,VIP,and VIF EFLAGS bits are not modified by pop *)
とあります。
2020-09-02 14:39:35
そうですね。とりあえずDOS6を走らすレベルでは解決しましたが、ありがとうございます!一応、i486 Programmer's Reference Manualというのを参考にしていて、Intelの公式出版物のようなのですが、エラーが多いです。Intel公式のSoftware Development Manual (多分ia32_arch_dev_man_vol2a_i.pdfがそれかな?) を参考にする方が良い、と、とある知り合いの方から教えていただいたので今後はそのようにしようかと思ってます。
2020-09-03 05:33:45