/var/log/hdk.log

2022 年 9 月

prev, this, next


01 (木)

%1 もくようび

9 月。

『異世界おじさん』7 話。 異世界で勇者を捜す思い出。 魔物のハリネズミ。 メガドライブ。

%2 MS-DOS

異世界でなく現実の話。 この前書いた MEDIA CHECK 改造デバイスドライバーは作れるか? を検討した。 残念ながらデバイスドライバーの最初の INIT コールの際にはまだリンクがされていないため、リストをたどることが不可能だ。 ただしデバイスドライバーの先頭のリンクポインターは使われるらしいことがわかった。 オフセット分足して同じセグメントでまた INIT を呼び出してくれるらしい。 そのため 2 つのデバイスドライバーをひとつのファイルに埋め込めば、2 番目のデバイスドライバーは 1 番目のデバイスドライバーのリンクポインターを読むことができる。

デバイスドライバーの組み込みをキャンセルできるかどうか。 キャラクターデバイスについては方法はひとつしかない。 Break address にわざととても大きなセグメントアドレスを設定してしまうこと。 そうするとリンクはされないがエラーメッセージが出る。 ブロックデバイスについてはそれ以外にドライブ数を 0 と返す手がある。 おそらくデバイスが接続されていなかった場合が想定されているのだろう。 これはエラーメッセージは出ない。 ただしメモリーを巻き戻す処理がある。 なぜか Break address のオフセットアドレスを 0 とみなして次の処理を始めるようになっている。 シンプルにデバイスドライバーのセグメントのままでオフセットアドレスだけを設定しているデバイスドライバーなら、これでなかったことになるが、セグメントアドレスを進めてしまっている場合は、そのセグメントアドレスの手前までは残るってことだ。 そんな仕様なのか? はよくわからないが、一応これらを元に考えていたものは作れそうな気がする。

で、調べてみると GET_IN_VARS という内部用のシステムコールがあって、それが返すデータの中にデバイスドライバーのリンクの先頭アドレスもあるようだ。 しかしこれ、バージョンによって構造が全然違うみたいで、例えば PC DOS 3.20 でもずいぶん後ろのほうになっていた。 なのでこれはちょっと使いにくいかなと思う。

他に記憶になかった話、CONFIG.SYS には AVAILDEV という設定があり、デフォルト TRUE だが、これを FALSE にすると、デバイスファイルに /dev/ (\dev\) 形式でしかアクセスできなくなるんだそうな。 つまりデバイスファイルと同じ名前のファイルが作れる。 これがあるから \DEV\CON ってキーワードが出てくるんだ。 FALSE をデフォルトに変えていたなら後の Windows 95 の concon bug はなかったかも知れないのになぁw あと微妙に思うところがあるのは、ファイルオープンのたびに、デバイスファイルかどうかを調べるために線形探索で文字列比較をするので、8088 みたいな遅いプロセッサでたくさんデバイスドライバーを組み込んでいると、FALSE のほうがファイルオープンにかかる時間が速くなっていただろうと思った。 ただし COPY CONNUL へのリダイレクトは当たり前のように使われていたため、普及しなかったのかも知れない。

SWITCHAR はなんかあったような記憶もあるが誰も使わなかったというか...

他に記憶になかったのは COUNTRY かな。 PC DOS 2.11 にはなかったが、PC DOS 3.20 や JX の DOS にはあったようだ。 0 がアメリカ、1 がヨーロッパ、2 が日本だ。 日付の並び順などが変わる。

2022/09/01 のコメントを読む・書く


02 (金)

%1 きんようび

雨。 涼しい日。 湿度が高かったためエアコンは使った。

テレビでやってた映画『るろうに剣心 京都大火編』。 2014 年の邦画。 映画館で見た映画。 第 1 作の『るろうに剣心』には今話題の香川照之が出演しているが、第 2 作以降には出演していないためか普通に放送される。 なお執行猶予期間の伊勢谷友介は今作には出演しており普通に放送もされている。

%2 MS-DOS

詳しい皆様のコメントにより INT 2EH ってのがあった話を知る。 いや、昔は知っていたかも知れないが、使った記憶はない...

それとデバイスドライバーとして組み込むこともできるしコマンドラインで実行することもできるプログラム、あったなぁー。 JX/PCjr だとそういうのでなくなぜか拡張子が .COM になっている (けどコマンドラインで実行はできない) デバイスドライバーもあったが、あれ謎だったな。 MS-DOS 2.0 のソースコードでわかるが、next ポインターはリストにリンクされる時に読み取られるので、.COM 形式で先頭に JMP 命令を置いておき、デバイスドライバーで最初に呼び出される INIT の処理の間に -1 に書き換えてしまえば、どちらでも組み込めるプログラムが作れる。

PCJRMEM.COM っていうデバイスドライバーがあったが、これは何者だったのか、ちょっぴり分析してみると、ビデオ BIOS をフックして何かやっているようだ。 Google 検索で情報が見つかるが、ああー。

PCjr Memory Compatibility

そうそう、PCjr はなぜか VRAM 共用メモリーが低位アドレス (0) から始まっていたんだった。 0 からは割り込みベクターがあるので実質は先頭ページは使えない。 テキスト VRAM は容量が小さいので、ページで後ろのほうを選択すれば上位のアドレスになる。 が、飛び地になってしまうんだな。 DOS がそれを扱えないので、このデバイスドライバーがまとめて予約済みにしてしまおうってことみたいだ。 割り込みフックが何をしているのかはよくわからんけど。 この辺は JX の (日本語モードの) ほうがメモリー配置を変えて VRAM 共用が上位アドレスになっているのでまともだが (ハードウェア的にはどちらのメモリーマップも扱えるように一種のメモリー管理ユニットのようなものが付いている)、それでも画面モードによっては上位アドレスを破壊するんだよな? DOS から見たら面倒な存在だろうな。

んで PCJRMEM.COM ってオプションがあったらしくて、/E って指定すればより大きく予約済みにするってことなのかな、これ。 たぶん本当はこれを指定して使わなきゃいけなかったんだろうな。 ただし BASIC と互換性がない (笑) から BASIC を使うなら組み込んじゃだめ。

2022/09/02 のコメントを読む・書く


03 (土)

%1 どようび

昼以降は晴れていた気がする。

夜コストコ行ってみたらこんでいた... 日曜日の夜のほうが空いているだろうか。 それとも夏休みが終わったから...

CO2 モニター、きのう久しぶりにつけてみたら 1000 近い数字で少し高すぎる気がしたので、トイレの窓を少し開けて窓のところに置いて補正をした。 100〜200 ぐらい高い数字が出ていた感じかな。

%2 MS-DOS

ソースコードに出てくる IBMJAPVERIBMJAPAN の由来、もしかして IBM マルチステーション 5550 なのでは? 1983 年前半に発売され、「日本語 DOS」を採用したパソコン。 日本語 MS-DOS としては実はパソピア 16 が先だったとの Wikipedia 情報もあるが、5550 は IBM のビジネス機であり IBM から Microsoft に日本語対応を依頼していても何の不思議もない。 実際のところ MS-DOS の KANJI 対応というのはあまりたいしたことはしていなくて、文字コードが決まってしまえばあとは 2 バイト文字をちゃんと扱えるようにしようというレベルの話のよう。 2 バイト目に \ があってもディレクトリ区切りにしない、とか、コマンドライン行編集で 2 バイト文字が 1 バイトずつ削除されないようにする、とか。

んで 5550 は当時としては珍しい 24 ドットフォント採用の高解像度パソコンだが、なんと初期のモデルには漢字 ROM を搭載せずソフトウェア描画を行っていたそうなので、1982 年に文字コードが決まってからの開発が十分間に合ったんじゃないのかな。 想像だけど。 Wikipedia 情報によれば、5550 のワードプロセッサは DOS ベースでなく、文字コードも EBCDIC を使っていたらしい...

パソピア 16 は 1982 年発売なのかよーマジか。 いや、発表か。 1983 年の 2 月に出荷開始か。

公開されている MS-DOS のソースコードから日付を検索すると、v1.25 のほうの最終は 1982 年の 3 月っぽい。 ASM.ASM だけ 1983 年があるが、これは "Seattle Computer Products 8086 Assembler" って書いてあるからたぶんあんまり MS-DOS との関係はないだろう。 v2.0 のほうは 1982 年に多数のリビジョン更新のあとがあり、IBM PC 用の DOS が出たのもこの年か。 1983 年の日付も見られるが、特に 2.11 のコードが少し含まれるようなので、その関係でなのかな。 "International DOS" ってのが 1983 年 2 月 17 日で MSHEAD.ASM に書いてあるのだが、パソピア 16 関係のアップデートがきちんと反映された的なものだろうか。

とにかくこの 1983 年前後にめまぐるしく変化している感じがあって、いけいけどんどんで開発されていたのかなと思う。 1993 年前後になると Windows が熱々なわけだ。 ここ 10 年で言えば virtual machine とか container とか machine learning とかそういうのみたいに、あるいはオペレーティングシステムで言えば 10 年前頃の Android かな、そういう熱さを感じる。

%3 ANSI.SYS

んで、MS-DOS のソースコードにあった ANSI.txt (ANSI.DOC) を見ていたら、キーコード入れ替え的な話がある。 ESC [ 0 ; 6 8 ; " d i r " ; 1 3 p という例が載っていて、これで F10 キーで dir コマンドを実行するようにできるんだよと。 へぇ、そういえばそんな機能もあったような...

そうすると、Unix 的に、カーソルキーを ESC [ A みたいな入力にするのもできるんじゃないの? つまり例えば ESC [ 0 ; 72 ; 27 ; " [ A " ; p とだな... って試したら本当にできた。 へぇ。 そうだったんだ。

PC-98 はどうだったか? カーソルキーのキーコードはどうやら ^H ^J ^K ^L に割り当てられていた。 vi かよw そういえばこのおかげでローグクローンをカーソルキーでプレイできたんだっけな。 この方式の欠点は左カーソルキーとバックスペースの区別が付かないところだ。 上の p を使うエスケープシーケンスは標準じゃないので ANSI.SYS 以外では使えなかったんじゃないかな。

DOS 汎用アプリケーションでも日本では IBM 方式の NUL 文字を使用するカーソルキー表現に対応しているものは少なかったような気がする。 Unix では ESC [ A みたいなのが当たり前になっているから DOS もみんなそうしていたら良かったんだよね。 でも DOS には ESC 入力で行削除的な機能もあったから、難しかったのかもなぁ。

2022/09/03 のコメントを読む・書く


04 (日)

%1 にちようび

晴れ。 のんびり。

%2 MS-DOS

MS-DOS のソースコードの中から DEBUG.COM のビルドは先月やったが、他のプログラムもビルドしてみようと思った。 が、とにかくコマンドを手で入れるのは面倒くさい。 MAKE コマンドがあればいいんだが...

で、手抜きの簡易 MAKE 的なものを作った。 MAKEFILE を読むのではなくて、引数に出力ファイルとソースファイル群を並べて、アセンブル、リンクと、必要に応じて EXE2BIN をやるってわけ。 これがなかなか面倒くさい。 MASM で書くからなんだがw DOS の Exec システムコールって EXE ファイルからならメモリーサイズの縮小の必要はないのかと思っていたけど、いざ書いてみたらだめだったので必要らしいw それに Exec システムコールの後はスタックポインターすら保持されないってどういうことやねんw スタックポインターをグローバル変数に保存してから実行するしかないのかw デバッグにも手こずった。 まぁちゃちなデバッガーである DEBUG.COM でもあるとないとでは大違いだけどね!

あと、INCLUDE まで考慮していないので、これだけではだめパターンが結構ある。 うーん、何時間も掛けて作った割にはいまいちか?

作っている時に発覚したのが、当時の MASM (バージョン 1.10), なんと、エラーになっても ERRORLEVEL 0 で終了しやがるw しかもエラーでも出力ファイルが中途半端に作られているw これじゃあエラーになっても止められないじゃないか、なんて実装なんだw

んで DOSBox で試していたんだけど、いざいろいろ試してみると MASM が *Out Of Memory* エラーを出すケースが出てきた。 その独自 MAKE ツールが COMSPEC (COMMAND.COM) 経由で子プロセスを起動するせいでメモリーが足りないのか? 厳しいな! と思ってソースコードの一部を分割してエラーが出なくなったことを確認したが、何やらいろいろ面倒で... CHKDSK.COM をビルドするのに、DOSSYM.ASM には必要な定義が含まれておらず、DOSSYM_v211.ASM を使う必要がある。 んで、じゃあ DOSSYM.ASM を置き換えればいいかなと思ったら、今度は DEBUG.COM のビルドに失敗する... ウーン...

ふと、FreeDOS でやったらどうなるんだろうと思って試してみた。 FreeDOS のフロッピーディスクのイメージをダウンロードしてきて、QEMU で一枚目で起動して言語選択、Y/N のところを N にしたらプロンプトに落ちる。 ここで FDISK, FORMAT 等のコマンドは使えるので仮想 HDD にシステムを転送、それから mtools で仮想 HDD にファイルをまとめてぶち込んで、起動して実験してみたところ、MASM のエラーは出なかった。 フーン。

何より QEMU なら Linux KVM が使えるのでめちゃくちゃ速い。 DOSBox はスピード調整ができるけど、基本遅いプロセッサのエミュレーションなので遅いんだな。 ただし仮想 HDD になるのでファイルの編集なんかが面倒くさい。 お手軽 DOS 互換環境としては、昔は dosemu っていうのも使っていたんだけど、これは Debian 公式パッケージがなくなっちゃったんだよな。

2022/09/04 のコメントを読む・書く


05 (月)

%1 げつようび

午前中ちょっとお腹が緩かったので、お昼を自炊にした。 幸いお昼以降は特に問題なかった。 お昼も特にお腹に優しい食事にしたわけではない。

きのうの F1 はオランダ GP か。 観客がだいぶアレw 発煙筒を投げ込むんじゃない! フェラーリはいつも通りのやらかしっぷり。 何というかライコネンがいた時以上にひどくなっているような... やっぱりライコネンはフェラーリチャンピオンってのがスタッフの意識にも響いていたのかなw メルセデス勢の追い上げが見物だったが、角田が止まってバーチャルセーフティカー、さらにはボッタスがメインストレートで止まってしまってのセーフティカーは本当にタイミングが悪かった。 まぁーセーフティカー無くてもフェルスタッペンが鬼の追い上げを見せて優勝していただろうとは思うが、その鬼の追い上げすら見られなくなったのは本当に残念だった。 というか、ペレスはピットイン後にセーフティカーになっちゃったんだっけな? 運が悪ければフェルスタッペンもそういうタイミングになっていた可能性もあるんだよな。

%2 MS-DOS

QEMU 上の FreeDOS でもっといろいろアセンブルしてみようと思っていろいろやってみていたんだが、MASM が internal error を吐いたり、ハングしたりする... やっぱりメモリー不足か? FreeDOS の拡張メモリー系を組み込み空きメモリーをたっぷりにして試してもだめだった。 んんー!

CHKDSK はビルドできたが DOS 2.x 上じゃないと動かないようにチェックがあるみたいで動作確認ができていない。 DISKCOPY はビルドできたがコピーの確認はしていない。 EDLIN もビルドできたがファイルを開いてみてはいない。 EXE2BIN はビルドできて使えていそうな感じがする。

MASM がうまくいかないファイルもそんなに大きい感じには見えないんだけど、マクロを多用しているかも知れない。 まぁ、マクロかシンボルか、だよな、おそらくメモリー上にいろいろ積みすぎてあふれてしまっているんだろう。 たぶん新しいバージョンの MASM ならうまくいくんだろうけど、ここはこの 1.10 で何とか通るようにしてみたいよなぁ。 MASM は自分で作るにはだいぶやっかいな高級アセンブラーなので、なるべくそのまま使えたらうれしい。

2022/09/05 のコメントを読む・書く


06 (火)

%1 かようび

朝ちょっと雨降ったっけ? 少し生ぬるい強めの風が吹いていた。

先月ぽろりすの 2000 年問題対策みたいなことを書いたが、なぁんと、作者様が昨年対応済みとの情報を頂いた。

PC98版の☆ぽろりす☆のY2K問題対応版をリリースしました(Version 1.57) | KTKR雑記

当時の環境を捨ててしまっていると再コンパイルは苦労するだろうなぁ。 だからといって機械語で直接パッチを当てるのも限界ってもんがあるんだが...

%2 MS-DOS + MASM

MASM のエラー、internal error が出たり、変なぐしゃぐしゃが表示されて終了したり、仮想 8086 メモリードライバーが例外検知のメッセージを出したり、ハングしたりと、明らかに挙動がおかしいパターンについて調べていくと、IFIDN または IFDIF が使われているとそうなることがわかった。 これは文字列比較のディレクティブらしくてマクロに渡された引数を識別している部分だが、ディレクティブそのものがエラーになるのではなく、異常動作をするというのは MASM Version 1.10 にそういうバグがあったのかな。 対策として、このディレクティブを使うのをやめて、文字列連結 (& でマクロの引数とつなげることができた) でシンボル参照して IFDEFIF による比較に変更したところ、その異常動作はなくなった。

で、メモリー不足はかなり発生しやすく、単純にアセンブルしていくのは難しい。 何が問題か? Out of memory で終了後 QEMU の pmemsave コマンドを使ってメモリーの内容をファイルに書き出して、中身を眺めてみたところ、ソースコードのキーワードが出てくるような領域は 64KiB ぐらいしかない。 後ろにメモリーは余っているが、別セグメントまで使う実装はまだ MASM Version 1.10 には入っていなかったのかも知れない。 メモリーを見るとインクルードされている DOSSYM に含まれる各シンボル名が異様に長く、これがメモリーを圧迫している気配だ。 明らかにカーネルでしか使わないであろうシステムコール絡みの構造体の定義などもあり、40 年前の実装にしてはアセンブル環境に求められるリソースがなかなか富豪的である。

これの対策は不必要な部分を除外できるように書き換えることかなと思っているが、それで十分かは怪しい気もする。 どうしても通せないようであれば、インクルード (INCLUDE) を展開の上で、エクスポート (PUBLIC) しないシンボル類を短いシンボルに置き換えたり、不必要なシンボル定義を削除したり、簡単な EQU 定義は先に展開してしまったりするプリプロセッサが必要かも知れない。

2022/09/06 のコメントを読む・書く


07 (水)

%1 すいようび

昼はまだ晴れていたが蒸し暑かった。 夜は雨になったっぽい。

座骨神経痛は今でも出ることがあるが、ごまかしがうまくいっているのでこれはもう大丈夫そうかな。 腰付近をもんだりさすったりする感じで。 頸椎のほうもたまに調子悪いけど、肩の位置を意識するごまかしはうまくいっている。 肩こりがひどいときは葛根湯を飲む時もあるけど、痛み止めは飲んでいない。

%2 MASM

メモリーの中身をもう一度見直すと、STRUC (構造体) のメンバーがずいぶん容量を食っている感じがする。 メンバーひとつで 40 バイトぐらいの勢いだ。 EQU も数が多いし名前が長いのでアレだが、メモリー上では詰まっているところも結構ある。

手としては手作業か自動のプリプロセッサか。 手作業では不必要な STRUC 定義を排除するというのがひとつ、EQU も頻繁に使われるものとそうでないものがあるのは確かなので、うまく IF で分けてそれでアセンブルが通るならうれしい。 プリプロセッサとする場合は、INCLUDE を展開した上でシンボル名を短いものに振り替えるというのがひとつ、さらに EQU の分は完全に独自で置換してしまう手もある。 数が数百個あって多いので EQU の大部分がなくなるだけでもききそうではあるが、STRUC があれだけメモリーを食っていたことを考えるとな...

%3 MS-DOS

MS-DOS のファイルの更新日時を読み取るシステムコールは %cx と %dx のふたつのレジスターに日時を返す仕組み。 これは FAT の書式をそのまま持ってきている模様で、年は 1980 を引いて 7 ビット、月が 4 ビットで日が 5 ビットだ。 それに時が 5 ビット、分が 6 ビット、秒は 1/2 して 5 ビットという形。

それに対して現在の日時のアクセスは日付と時刻が別々のシステムコールになっており、8 ビットあるいは 16 ビットのレジスターを使ってシンプルに返してくれる。 1980 年以降の縛りもない。 返そうと思えば閏秒さえ返せてしまえそうな、ある意味現代的なインターフェイスになっている。 ただし、日付と時刻が別々というのは、日付の変わり目に取得したらどっちだよってことになり面倒である。 某 C のランタイムライブラリはどうやら日付の取得を 2 回呼び出すようだ。 詳しくは見ていないが、標準 C ライブラリの日時管理は 1970 年 1 月 1 日からの秒数なので、アプリケーションが日付を求めるかどうかにかかわらず、日付と時刻を取得して秒数に変換するしかないわけで、それが 1 日ズレたら致命的だから、対策をしてあるんだろう。

それ以外に CLOCK デバイスファイルも存在するが、こっちは 6 バイトで日付と時刻を表す。 それが、1980 年 1 月 1 日からの日数 (16 ビット), 分 (8 ビット), 時 (8 ビット), 1/100 秒 (8 ビット), 秒 (8 ビット) の 6 バイトとなっていて、どうしてここは日数にしたんだろうか。 まぁ日数でも 16 ビットあるので、Unix 時間が秒で 32 ビットだったのに比べればずいぶん未来まで表現できはするんだけど、PC/AT 互換機の RTC って年月日の BCD 仕様になっているから変換が必要だし、システムコールではこれをまた年月日に分解すると思うとちょっと微妙なインターフェイスである。

2022/09/07 のコメントを読む・書く


08 (木)

%1 もくようび

雨ちょっと降った? 涼しい日。

スマートフォン Android One S6 なんだけど、開発者オプションでタップ位置を表示にしていてわかったことがあって、スリープ状態から電源ボタンなり指紋認証なりで画面を表示させた後、一発目のタップ位置がめちゃくちゃな位置になっているみたいだ。 前からそうだったかわからないけど、今はそうなっている。 あと Android 12 になってから ZXing の QR コードスキャナーアプリでなぜかオートフォーカスが働かない。 あと画面の左上が変色していて、落っことした時か何かに液晶にダメージが入ったのかも知れないけど、変色部位が広がっていく様子はない。 ソフトウェアアップデートはもう来ないんだろうしー、と思ってチェックしたら 5.230BE が来ていた。 あれ?? そろそろ最後かな? いや、発売から 3 年はまだ経っていないからもう少しあるのか。

ZXing のオートフォーカス問題は、追従フォーカスしないという設定を外したらなおった。 オートフォーカスの設定は別にあってそっちは有効にしてあったんだけど。 いつの間にかこの設定がオンになっていたのか、それとも、以前のバージョンではオンのままでも問題なかったのか。 わからん。

bcc っていう C コンパイラー、Debian パッケージもあって DOS 用の C ライブラリ elks-libc もあり、.COM 形式のプログラムは簡単に作れる。 MASM のプリプロセッサを試しに作ってみるならこれがいいか。

この前の F2 オランダ戦を見たら、Feature Race で岩佐が 3 位! はともかく、セーフティカー開けにひどい多重クラッシュが発生していた。 加速を遅らせると後方が混乱するの、去年 F1 でもあったな... あそこまでひどい速度差があったわけではなかったが、別々の場所で 2 台が追突していたように見えた。

それで知ったけど今の F2 はセーフティカー中のタイヤ交換はタイヤ交換義務を消化した扱いにはならないらしい。 ハードタイヤスタートが不利だよな、それって... いや、ソフトタイヤスタートでもそろそろピットインって頃にセーフティカー入られるとつらいか。 セーフティカー中のピットインの扱いは本当にどのやり方も一長一短で難しいよなぁ。 バーチャルセーフティカーやフルコースイエローのやり方のほうが不公平さは少ない感じがするんだけど、スピードを何分の一に落とす的な制限のかけ方の場合は結局ストレートのスピードはそこそこ速いので、この前の F1 オランダ GP みたいにメインストレートで止まったマシンがあるとまず使えないし。

2022/09/08 のコメントを読む・書く


09 (金)

%1 きんようび

晴れ!

ニトリでこの前買った携帯扇風機 HF3103、扇風機そのものはいいんだけど、バッテリーからの出力を切ることができない仕様で、減りが早い気がする。 電源マークのボタンが付いているけど、押すと残量が光るのみ。 押しても扇風機を止めることはできないし、押さなくても扇風機が起動できるということは... そもそもは最初フル充電にして少し試した後何もつながずに放っておいたら 1 週間ちょっとぐらいでスッカラカンになっていたというところ。 再度充電して何度か扇風機で使っているが、やっぱり使っていない間に残量が減っているような気がする。 常時 5V をかけているんだとしたら、そりゃ減るよな... eneloop モバイルバッテリー KBC-L2A が全然減らないのとは対照的。

テレビでやってた映画『るろうに剣心 伝説の最期編』。 2014 年の邦画。 映画館で見た映画。 奥義を使って志々雄を... というところ、去年テレビアニメ版を見たこともあって、あまりの違いに驚きもある。 テレビアニメ版は 15 分のたたかいを何話もかけてやるのでその点は映画のほうが引き延ばしがなくすっきりしている。 あとテレビアニメ版では漫画っぽいあまりにも非現実的な技表現がそのまま持ち込まれていたが、実写映画はうまいこと普通の剣術のように見せているのは良い。 高く飛び上がったり刀が燃えたりといった漫画っぽさをちょこちょこ取り入れつつ、技名を叫んで画面がチカチカして決着とか目に見えぬ速さで移動とかみたいなテレビアニメ的表現は避けている感じでバランスがいいよね。 技名だけじゃなくて、全体的に説明調でないのもいいところかも知れない。

%2 MASM

bcc でプリプロセッサを書いてみた。 STRUCEQU のシンボルに関して、前者は 5 文字以上、後者は 8 文字以上に関して、4 文字のシンボルに置換するというもの。 何度かデバッグの後、bcc が struct の値渡しをうまく扱えないようだというバグっぽいのにも遭遇しつつも、動くようになったので MSDOS.ASM を食わせたら、やっぱり MASM は out of memory だと。 そもそもシンボル多すぎなんだろうなぁこれ。 EQU の展開までやるしかないかなぁ。 でも一部 EQU は微妙に IF の影響があってトリッキーだ。 STRUC も不要なものは削るようにすべきか。

2022/09/09 のコメントを読む・書く


10 (土)

%1 どようび

晴れ。 のんびり。

西九州新幹線の開業が近づいてきたとのことでニュースが増えている。 武雄温泉駅と長崎駅の間が約 66km で、最速 23 分らしい。 鹿児島中央駅と出水駅の間が 78.8km で 24 分なのと比べると、ずいぶん遅いなと思ったが、駅数が多いみたいだ。 あらためて地図を見ると、鳥栖駅ってところから西に向かって長崎本線が始まっている。 一駅で、新鳥栖駅という、今の九州新幹線鹿児島ルートの駅がある。 佐賀駅までは何駅かあるようだ。 佐賀駅を過ぎて少し行くと唐津線という路線との分岐がある。 唐津線は北部の海岸のほうまで出る路線だ。 長崎本線をさらに進めば数駅で武雄温泉駅... ではない、これはまた別の路線に分岐していて佐世保線という路線の駅だ。 西九州新幹線は武雄温泉駅からだから、長崎本線から佐世保線に乗り入れる列車を多く通すんだろう。 長崎本線は鹿島市というところに向かって南下し始めて、その後は海沿いを走って諫早市というところに行くようだ。

そんな感じで意外と路線が多いんだなというところ、以前使ったことがある佐賀県の駅は、鹿児島本線のけやき台駅で、佐賀県の端っこである。 博多駅からそこまで鹿児島本線で行って、途中下車して、乗り直して久留米駅まで鹿児島本線で行って、新幹線に乗った。 んで地図を見れば新鳥栖駅があるわけだ。 あれ? あの時ひょっとして久留米駅まで行かなくても良かった??

かというと、そうではない。 鳥栖駅から新鳥栖駅までは長崎本線であって鹿児島本線ではないため、新幹線の博多駅から久留米駅間を途中経路に含む乗車券を持っていても、使えないようだ。 別途鳥栖駅から新鳥栖駅までの乗車券を買った場合は新鳥栖駅に行けるだろうが、その場合、新幹線の博多駅から久留米駅間の経路を鳥栖駅まで消化したものを新鳥栖駅から使えるんだろうか? という疑問はある。 答えはよくわからない。 鹿児島本線で久留米駅まで行ったこと自体は全く問題なさそうだ。

んでまぁ地図を見れば西九州新幹線が佐賀県にメリットがなさすぎるというのもわかる。 鉄道網で見れば、鹿児島本線の鳥栖駅からわかれる長崎本線が佐賀県と長崎県の県庁所在地を通るメインルート。 佐賀県からすれば在来線の長崎本線を残せ & 金は出さねぇよってところか。

MASM の自作プリプロセッサ改造... いろいろ考えて、作って、試して... 定義をまるごととっておき、必要になったらその場で出す、これは EQUSTRUC について適用可能。 name STRUC の使い方として SIZE name というのがあるらしい。 シンボル名解決だから OK OK と思って書いていると、EQU の右辺にそれがあって、使ってもいないのに無駄に STRUC が出てしまう事案。 それで EQU はすべてとっておくにしたら TRUE FALSE みたいなのまで対象になってあんまりだ。 どこかに短縮対象シンボルが含まれる場合に限りとっておくとした。 しかし行まるごととっておくのはメモリーが厳しい。 簡易的にスペース除去の実装を入れて対処。 今度こそ OK と思って試していたら、なんと STRUC の中に別の STRUC のサイズを使うものがあった... それを STRUC の中に STRUC を出してしまったから MASM がエラーを出した。 そりゃそうだ。 ウーン! 大変だねこれは! いきなりアセンブリ言語で書いていなくてよかった。 C なのでいろいろと対処はしやすい。

%2 MS-DOS

昔の某ぷ... 市販ゲームをなんとフロッピーディスクじゃなくてファイル単位でしか持っていなかったらしく、まぁいいかと動かそうとしたらメモリー不足だと。 本来 MEGDOS だからな、DOS 6.2 はデカすぎか。 探すと某一... 市販ワードプロセッサのフロッピーディスクのイメージがあって MS-DOS 2.11 だ。 懐かしの MS.COM コマンドで見るとメモリーの空きはかなりある。 ふむふむ、とフロッピーディスクイメージにファイルを入れようとしたら入りきらない。 MEGDOS ってめっちゃ小さかったらしい。

あと DOS 6.2 は 1440KiB フロッピーディスクに対応しているが 2.11 では無理そうだ。 フーン... MEGDOS を無理やり起動できたらそれはそれでおもしろいんだがブートローダーを手作りしないと無理だな。

昔の DOS のブートローダーって IO.SYS やらを連続セクターに入れていないと動いてくれなくて、それを FAT を見て非連続でも動くようにしようという無茶な試みを一時期やったことがあったような気がする。 まぁ無茶っていうかいつ頃からか公式に実現していたような気もするんだけど。 今考えれば IO.SYS の先頭に何か必要情報を置いておいて連携して続きを読むぐらいで良かった気がするし、PC-98 で主流だった 1232KiB フォーマットなら 1024 バイト/セクターだったから最初から余裕があったはずではある。

2022/09/10 のコメントを読む・書く


11 (日)

%1 にちようび

昼はやや暑かったが涼しい日。 のんびり。

GNU Emacs のフォント設定、"Noto Sans Mono CJK JP" に変えた。 デフォルトで選択されるフォントではなぜか漢字が中国語か韓国語の形になっていた。 あんまり X11 で使わないから気にしていなかったけど、たまに X11 でも使うのでなおしておこうと。 なんでデフォルトがそうなるのかは知らない。 他のアプリケーションでは大丈夫なのにな。

F1 イタリア GP の週末。 DAZN まだ見られるんだけど、おかしいな、2 週前に買った povo トッピング (1 週間) だぞ? 1 日 2 日は誤差かと思ったが、1 週間はさすがに...

%2 例のプリプロセッサ

ずっと作っていたのは EQU やら STRUC やらの定義をためておき、必要になった時点で放出するというもの。 そのため IF で囲まれたブロック内にあったら困るから無視するとか、STRUC の中に STRUC を出してしまわないようにするとか、いろいろと対策が必要だった。 さらには EQU の右辺に $ (現在のアドレス) を入れているケースがあり ($ はシンボル名の文字として使えるが、1 文字だけの $ シンボルが特別扱いで現在のアドレスになっているよう)、それも場所が変わったら困るので、無視するようにして。 それでいい感じだなと片っ端からファイルを入力して試していたら、FORMAT.ASM で引っ掛かった。 なんと、EQU の定義が使っているところより後ろにある...

こうなると未知のシンボルをかき集めて把握するか、あるいは 2 pass にするかだ。 まぁ 2 pass のほうが話としてはシンプル。 IF 無視も $ 無視もいらなくなり、参照されていない不要な定義の除去だけすればいい。 というわけで書き直し始めたら 3 pass になったんだけど、まぁいいか。

%3 MS-DOS

ALTOS ACS-86C 用のコードなら公開されている分でビルドできるのかと思っていたけど、IO.ASM が不足している。 これにはシステムコールの 1〜12 の実装が必要らしい。 10 だけは STRIN.ASM に実装があり、これを INCLUDE する形で他のシステムコールを実装して IO.ASM を完成させないといけないのか。 まぁ面倒そうなのはなさそうには見えるけど。 バージョン 1.25 のほうには IO.ASM があるけど、これは全然実装が違っていそうだなぁ。

んでもそういえばどうやって実装するんだ? リダイレクトができるってことはファイル I/O を使う? でも 1〜12 ってデバイスドライバーからでも使えるんだか何かじゃなかったっけか。 スタックの消費量が少ない的な、そんなような話があったような... お、6 の実装もあるな。 RAW_CON_IO ってなっている。 7 の RAW_CON_INPUT もある。 このへんを参考にして実装するのか。

いまいち DOS のデバイスドライバーの作りがわかっていないんだけど、CON デバイスの実装 (SKELIO.ASM) を見る限り、単に BIOS を呼び出している風に見える。 CON の読み取り (COPY CON 等) で行編集機能が使えるのは何つながりだ? って探すと DISK.ASM の中で STRIN.ASM にあるルーチンを呼び出す部分がある。 DEV.ASM から LOAD ってので来るのかなー、いや、これはファイル I/O 用だな? 意味わからん!w DISK.ASM にキャラクターデバイスの実装入れるの何とも思わなかったんだろうかw

2022/09/11 のコメントを読む・書く


12 (月)

%1 夏休み 1 日目

泌尿器科。 土曜日よりこんでいた気がする。 今日は残尿少なかった。

1 か月以上ぶりぐらいに原付を動かしたんだが、エンジンは一発始動で好調だった。 やっぱりたまにフューエルワンを投入するぐらいがちょうどいいのかな、これには。 バッテリーもまだ無事なよう...

車もそろそろバッテリーがやばいなと思って動かした。 始動直後に 11.4V 台の激やば電圧が見えた気がするがちゃんと小一時間走行したから大丈夫に違いない。 久しぶりにイオンモールに行った。 5 年ぐらい行っていなかったんじゃね? と思ったが実際 4 年半以上前に行ったのが最後かも知れない。 調布にイオンシネマができたので行く機会が本当になくなった。 それ以上にここ 2 年はパンデミックの影響で無駄に寄り道しなくなったのも大きいが。 で、たまに行くと楽しい。 うっかり絵文字クッションを買ってしまったw

久しぶりだったので途中の景色も新鮮だった。 昭和記念公園の近くの道が太くなって南北に突き抜けたのは知っていたが、その道に沿ってドラッグストアやマンションか何かがぽこぽこと生えていた。 それでも半分は何もない感じだけど、以前とはだいぶ景色が違う。 それから... イオンモール。 テナントに「ガチャガチャの森」なるカプセルトイ専門店が入っていて、明らかに前はこんなのなかったなという感じが。 ゲームコーナーは今やクレーンゲームや類似の景品ものが大部分を埋め尽くし、その他のゲームを追いやっている感じ。 他にも以前と違うテナントがあるような気もするが、ここに来ていたのは映画を見に来ることが多かったから、あまりわからない。

%2 きのうの F1

イタリア GP。 フェルスタッペンが異次元の速さで優勝。 チームメイトのペレスと比べてもまさに異次元の速さで最後尾からでも勝っていたんじゃないのかなこの人。 フェラーリは地元で精一杯対抗した感じだったがルクレール 2 位。 セーフティカーのまま終了となってしまったが、そうならなくてもルクレールが優勝できる余地はなかったように見えた。 終盤のソフトタイヤのルクレールがタイム差をほとんど詰められなかったからねぇ。

アルボンが虫垂炎のため欠場となり、代役の新人デ・フリースが注目だった。 新人といってももう 27 歳なのだが、2019 F2 チャンピオン、さらには 2020-2021 シーズンのフォーミュラ E チャンピオンだそうで実績十分。 なんと予選からチームメイトを上回り、決勝ではポイント獲得。 直線がやたら速い今年のウィリアムズのマシンには、この人は今年スペイン GP の free practice で一度乗っただけのはずだが、今回の free practice 3 から乗ってこの結果とは... (今回の free practice 1 ではアストンマーチンをドライブしたそうなんだけど、マシン特性全然違うだろうからなぁ...) 新人にも負けるラティフィの遅さが際だってしまっている。

2022/09/12 のコメントを読む・書く


13 (火)

%1 夏休み 2 日目

平日 4 時台の高速はトラックだらけであり、平日 5 時台の空港はガラガラであった。 少し雨が降った。

初パッソ。 コンパクトカーとして 20 年前レベルの品質を感じる。 サイズも初代ヴィッツ並みだし。 特にステアリングの手応えがないのは何と言ったらいいんだろう... 軽すぎるというより、どこかに緩みがあるんじゃないのと言いたくなるほど、タイヤからの情報が届かない。 ゲーム機みたいな感覚だ。 トヨタが iQ の頃からとてもしっとりとしたステアリングの操作性を実現していたのとは大違いだ。 パッソもブランドはトヨタだけど。 ヤリスとは比較にならないし、2 代目スイフトだって電動パワーステアリングの違和感はあったものの、こんなひどさはなかったな。

MASM のプリプロセッサを MASM で書こうとしている件は、バージョン 1.10 の難しさもあって、プリプロセッサのプリプロセッサがほしくなって、文法を考えていた。 MASM に @@: @F みたいな表記が導入されたのは画期的だったし、GNU as だって 1: 1f みたいなのがあるわけで、それが何もない時代のアセンブリ言語は label の名前付けがかなり大変である。 それと一時変数や引数用のスタック参照、さらには if while などの構造も書き間違えそうになるわけで、そのへんの補助がほしい。 昔 PASM っていうのがあったが根本的なアイディアとしては同じだな。 演算子まで処理する気はないのと、解釈が簡単な文法にしたいくらいで。 まぁマクロでもそこそこ凝ったことができるはずだけどね。

2022/09/13 のコメントを読む・書く


14 (水)

%1 夏休み 3 日目

同級生の店でランチ。 たまには違うのをとてんこ盛り丼メニューの小盛版を頼んでみたものの量的には BIG 丼普通盛りみたいなもので、食べ過ぎて気持ち悪くなってしまったがそれは宿便の影響もあったか。

図書館に少し寄った。

Mugiuda Base っていうところの電動レンタルカート。 先月オープンしたばかりらしい。 カートといっても普通のフレームとは別物で、たぶんホイールベースが短いし駆動軸の幅も狭い。 最高速 37km/h 版はタイヤが減りすぎたらしく一時休止中。 28km/h 版だったかな、走らせてみるとおそろしく不安定で最初はこわかったがなれるとアクセル全開で周回できた。 S 字区間の切り返しでふらつくしひっくり返りそうな感覚になるが大丈夫だw アクセルオフでもある程度減速できる。 ブレーキも感触としては完全に電気仕様のようだ。 停止してブレーキ 2 回踏み込むと後退もできるらしい。 ふらつきっぷりからするともしかして駆動軸は直結でなくディファレンシャルが組み込まれているだろうか?

パッソはコストダウンを隠さない感じの車だ。 スマートキーにはなっているがドアに解錠・施錠用のボタンがついているタイプで、解錠したか施錠したかはハザードランプの点滅回数を見て判断するしかないようだ。 室内灯のスイッチが ON/OFF だけかと思ったらドア連動と OFF だけのようでつまり走行中に ON にできないっぽい。 方向指示器はダイハツお得意の中立位置に戻る使いにくい電子スイッチで、これも自動解除をソフトウェアでするためのコストダウン策であろう。 レーン逸脱警告など一応ついているみたいだったが右側のスタートストップボタンの下あたりにごちゃっとスイッチが並べられているだけでわかりにくい。 さらにはフォグランプのスイッチっぽいのもあったのにフォグランプはそもそも装備していなかったんじゃないかな? メーターにはタコメーターがないのは当然で、平均燃費はあるのに瞬間燃費がない。 ヤリスより軽いのか加速はそこそこな感じもしたが、ヤリスは明らかに 1.5L をつめる余裕のあるボディに 1.0L だったから遅く感じたのかも知れない。 燃費はエアコンの影響が大きいのか 17km/l いかない感じで悪そうだ。 アイドリングストップは再始動はそこそこ速いが、ブレーキをわずかに踏み込んだり緩めたりするだけで再始動する感じ。 エアコンの関係で再始動した時はブレーキを緩めていないのに少し前進しだして、ブレーキをもうちょっと踏み込んでいる時じゃないとエンジン停止しちゃだめなのでは...? 一時停止等でエンジン停止してほしくない時にマツダみたいにブレーキを強く踏み込まないという手が有効でないため、セレクトレバーを N か S に入れておく必要がありそう。

とまぁパッソのいまいちなところが目立つのは 3 月にヤリスに乗ったせいだ。 ヤリスは iQ 同様まともに設計されている感じだが、パッソは街乗り用だからこんなのでいいよねという雰囲気を至る所から感じる。 まぁ、そうね、自分が大型二輪と小型スクーターを持っているように、でかい車を持っている人の 2 台目用としては売れるのかも知れない。 軽ターボくらいのパワーはあって軽ターボ車より安くてちょっと広い、みたいな、そんな感じじゃないだろうか。

2022/09/14 のコメントを読む・書く


15 (木)

%1 夏休み 4 日目

朝の溝辺はパラッと雨が降ったりやんだり。 飛行機は揺れも少なく東京着。 おとといの宮崎上空あたり (たぶん) のほうが揺れた。 駐車料金 4500 円強を支払い、案内板を頼りに一般道で帰宅。

東京国際空港の駐車場を出て、環八通りの案内に沿って来たつもりがなんかぐるぐる回らされたような... 駐車場の周回道路から一発では出られないのかな、あそこ。 それから環八通りが途中で渋滞するだろうと見込んで、適当に川崎方面に出てみようと思っていたところ、第一京浜というところで出てみたら、けっこうこんでいてなかなか国道 246 号線までたどり着かなかった。 2 時間ぐらいは掛かった。

車のバッテリーはだいぶ弱っているだろうに車の充電制御は容赦なく機能しており、もしやと思ってスタートストップシステムをオンにしたらちゃんとエンジン停止もしていた。 再始動の時にコンピューターが電圧降下を見ているだろうから、それでエンジン停止しなくなるかなと思っていたが、そうでもなかった。 南武線を越えるぐらいまでオンのまま来て、そこから先はまたオフにした。

%2 朝一便

今回は朝一便の飛行機を使っての 2 泊 3 日の帰省、実質 2 日だった。 ANA/SNA で東京発が 6:45, 鹿児島発が 7:15。

5 時台の東京国際空港はさすがに空いていて快適。 P4 駐車場もどのフロアも空車の表示。 空港の店はコンビニぐらいしか開いていない。 ラウンジでさえも 6:00 オープンで、実質 15 分ぐらいしかいられないから、使うまでもないかという感じだった。 到着した時の 8:30 過ぎの鹿児島空港は出発の人達がそこそこいる感じ。

6 時台の鹿児島空港も空いていたが、店は山形屋なども 6:30 頃には開けていたのだろうか、おみやげなどにも比較的アクセスしやすい感じになっていた。 到着した時の 9:00 前ぐらいの東京国際空港はやはりそれなりに人がいる感じ。

パンデミックになってからやっているこの空港駐車場利用の弾丸帰省 (?) も 4 回目になるが、朝一便は空いているという点では一番快適。 空港や機内でマスクすらまともに付けられない頭のおかしい大人はどこにでもいるので避けられないけど、純粋に人が少ないのがうれしい。 保安検査場はオープンしているレーンが少なくてアレだけど、それでも人が少ないし。 レンタカーの返却が前日になってしまうのが面倒とか、宿泊施設の選択肢がほぼないとか、そういうのはある。 ちなみに往復の飛行機とホテル 2 泊 3 日を楽天のパック旅行で手配して 29,900 円 (クーポン 500 円分の値引き後) だった。 2 年前はこの不人気な朝イチの便は欠航になっていて予約もできなかったが、今はこの繁忙期でない平日でも普通に運行されているのでありがたい。

えっ、PCR 検査を受けたかって? 去年の 4 月以降一度もないね!

%3 MASM

アセンブリ言語のプログラムを書きやすくするためのプリプロセッサをアセンブリ言語で作った。 できるだけ実装を手抜きできるような文法として、めちゃくちゃ手抜きして書いたので用途は限られている。 PROC 定義:

{(PROC(NAME))
...
}

これで ENDP まで自動。 cdecl の引数参照:

{(ARG(ARG1,ARG2))
...
}

これで PUSH BP MOV BP,SP POP BP が投入される他、%ARG1% %ARG2% がそれぞれ [BP+4] [BP+6] に置き換えられる。 (数字部分は固定桁数 16 進数になる。) ローカル変数:

{(LOCAL(I,J))
...
}

これで SUB SP,...MOV SP,BP が投入される他、%I% %J% がそれぞれ [BP-2] [BP-4] に置き換えられる。 (数字部分は固定桁数 16 進数になる。) Label の自動割り当て:

{((FOO,BAR))
...
}

これで %FOO%%BAR% が連番ベースの label 名に置き換えられる。 置き換えるだけなので %FOO%: のようにして好きなところで使う。 ブロックを抜ければ名前が無効になり、同じ名前を再利用できるのがポイント。 Label の自動割り当ての登録:

{(HOGE(FOO,BAR))}

これが一番悩んだ機能だったが削りに削ってこうなった。 こうしておくと {((FOO,BAR)) の代わりに {(HOGE) と書けるよ、という代物だ。 何を目指しているかというと、例えば以下のような IF 文の記述:

{(IF(THEN,ELSE,ENDIF))}
{(IF)
 CMP AX,1
 JE %THEN%
 CMP AX,2
 JNE %ELSE%
%THEN%:
 ...
 JMP %ENDIF%
%ELSE%:
 ...
%ENDIF%:
}

みたいなのを定型文として使えたらいいなという発想。 めちゃくちゃ簡易的なんだが結構使いやすくなるんじゃないかな。

MASM Version 1.10 はめっちゃ古いのにリスト出力機能なるものがついていて、どのアドレスにどの命令が割り当てられたか見えるようになっている。 何に使うかって言ったらこれをデバッグに使っていたんだな。 SYMDEB はシンボルを扱えたが DEBUG.COM は扱えなかったから、これを印刷して見ながらデバッグしていたんだろう。 ここまで実行、とか、この変数の中身を確認、とか、そういうのを手作業でアドレスに変換してやっていたわけだ。 自分はこれを印刷した記憶はないが、今は現代的に DOS をウインドウの中で動かしながらリストファイルを別のウインドウに出して作業すると案外便利だった。

MASM は 2 pass 仕様で、手前で定義されたシンボルはすぐに解決できるが後ろで定義される未知のシンボルはメモリーを想定して展開されている模様。 最終的にそれが定数だった場合 1 バイト余り、そこには NOP が入る。 JMP も同様で、手前については SHORT が自動的に適用されるが後ろは結果として短かったなら NOP になる。

2022/09/15 のコメントを読む・書く


16 (金)

%1 夏休み 5 日目

晴れ。 のんびりゴロゴロ。

パッソのエンジンは 1KR-FE で、型式的には iQ の 1L モデルやヤリスに積まれているものも同じだ。 しかしいろいろとマイナーチェンジがあるようだ。 ヤリスはスタートストップ機能が廃止されているが燃費はよく、パッソともさらに違うものなのかも知れない。 借りたパッソは平成 31 年 4 月登録だった。

テレビでやってた映画『マスク』(原題: The Mask)。 1994 年のアメリカ映画。 ヒロイン役はキャメロン・ディアス。 美人。

%2 MS-DOS

GitHub - hdk1983/HIDOS

とりあえずいろいろビルドできるようになったので GitHub においてみた。 プリプロセッサが 1 バイト単位の入力をするので DOSBox では非常に遅く、QEMU+FreeDOS でもちょっとファイルが大きいと 1 秒前後の時間が掛かる。

COMMAND.COM が既存の MS-DOS 上でも動かなくて残念な思いをしているが、調べてみるとひとつは international support がある DOS でないと NULL ポインター呼び出しになってしまうようだということと (case map routine を使うため)、もうひとつは環境変数 COMSPEC をあてにして自分自身をオープンして読み込む処理があるようで、それが別の COMMAND.COM になっているとだめなようだ。 しかし、それをクリアしても EXEC failure になるなどの不可思議事象が起きていてなんだろうなこれ。 内蔵コマンド系はちゃんと動いていそう。

2022/09/16 のコメントを読む・書く


17 (土)

%1 どようび

のんびりゴロゴロ。 夕方まで晴れていたと思う。

%2 MS-DOS ハック

さて。 COMMAND.COM は IBM DOS (PC DOS) で試すと EXEC failure になる疑惑。 NEC の MS-DOS バージョン 2.11 上であれば問題なく動いているみたい。 今回 MSVER でビルドしており、ソースコードにあった IF IBM が影響しているんだな。 なんか知らないけどいろいろと IBM 版は実装が違うみたいなんだよな。 NEC 版は COMMAND.COM を差し替えての起動もでき、英語バージョンだが日付等の国別設定は反映されている。

COMMAND.COM ではまだおもしろみがないので、次は MSDOS.SYS にチャレンジした。 問題はシステムコールの 1〜12 で、うち 6, 7, 11 は実装があるので残りを自分で作る。 他に不足するのが BUFOUT, OUTTAB の 3 つ。 それぞれ caller を見て入出力仕様を推測して実装するしかない。 まぁこの 3 つは幸いどれも簡単な文字出力のようで、制御文字を ^A スタイルにして出力するもの、単に 1 バイト出力するものと、タブ文字を出力するもののようだ。 システムコールも見よう見まねで実装し、^C のチェックをどうするのかと思ったら STATCHK というのがエクスポートされているのにどこからも参照されていないことが発覚したので、それを適当に呼び出すように書いた。

で、それを NEC の MSDOS.SYS と差し替えて起動すると、画面がぐしゃっとなって... さすがにだめか... でも、ソースコードがあるんだ! まずもって自分が書いたあたりが怪しいのは間違いないわけだが、軽く追うと起動時のメッセージを出すところがあるらしい。 ...というかまだ IBM 定義になっているのを変え忘れていたのが発覚したので修正した。 それでメッセージ出力の前後に無限ループを仕込んで起動して、メッセージが出ないところからスタート、いろいろ見ていくとアレだな、レジスターの保存が足りていない感じがしてきた。 いくつか加えると起動はしたが、COMMAND.COM にコマンドを入れるとハング。 わざと SHELL を DEBUG.COM に変えて、システムコールを試そうとしたが、どんなコマンドを入力しても完全に無視されるw 行入力ルーチンを確認したらこれもまたレジスターか。 レジスターの保存をさらに増やして、COMMAND.COM も起動するようになったが行編集機能がおかしい。 行編集機能の実装を見たらまたレジスターかw 何でもかんでも PUSH しようかとも思ったが、少しコードを追ってみたらファイルハンドルの参照に DS:SI を使うのとファイルハンドルの指定に BX を使うのでそこだけ保存すれば、他はすでに保存処理があるみたいだ。

MS-DOS

そんなこんなで動くようになった。 NEC 版 IO.SYS に、自分でビルドした MSDOS.SYS と COMMAND.COM の組み合わせ。 これは楽しい。

残るは IO.SYS といきたいところだが、ここはもう機種依存の実装から避けることはできない。 さらにはセグメントが何か面倒なことになっていそうな疑惑もあり、どのように作ろうか。

2022/09/17 のコメントを読む・書く


18 (日)

%1 にちようび

雨。 時々曇ったり晴れたり。

とんでもねぇ強さの台風が鹿児島市に上陸した。 935hPa! 八代市付近まで来ても 940hPa というのだから本当にとんでもない。 今年は鹿児島の気温が 20 年前の奄美大島並だねーなんていって笑っていたが、まさか台風まで奄美大島並とは... アメダスのデータを見れば鹿児島市は上陸直前あたりの 19 時頃にすげぇ雨が降ったのと、午前中に最大瞬間風速 43.5m/s が記録されているが、その後は落ち着いていそうだ。 進行方向右側になってしまった牧之原や志布志は風も降水量も強いデータが残っている。 まぁ、それを言ったら宮崎のほうが雨続きでかなりやばいらしい。 暴風域もデカいのでとにかくやばい。

鹿児島と言えば、こないだは Mugiuda Base からの帰りに姶良 IC を使ったんだけど、その一般道、制限速度いっぱいぐらいで割とのんびり走っていたら後ろの車は追い越したそうにしていたけど、追い越したのは登坂車線みたいになっていたところで 1 台だけだったか、なんだかとにかくついてきていた。 こっちはレンタカーなのにw まぁいいかとのんびり走っていたら、信号のところでさっき追い越された前の車に追いつき... んで信号が変わる、というパターンを数回やって、まるで走り慣れた道みたいになっていて不思議だった。

%2 IO.SYS

MS-DOS の IO.SYS 部分の作業に取りかかり始めたんだが... 難しいなこれ... ブートローダーのことも考えなきゃいけないのに、SKELIO.ASM ってなんかいろいろバグがあるように見えるんだよな...

他にもディスクのデバイスドライバーで初期化時に BPB array を指すポインターを指定するってのがあり、てっきり struct bpb hoge[n] 的な array の先頭アドレスのことだと思ったんだが SKELIO.ASM を見ると struct bpb *hoge[n] 相当になっていて、はてなと首をかしげつつ DOS の他のソースコードをチラチラ読んでみたら後者で合っていたので、これはドキュメントが説明不足だったか。

無理やり既存の DOS 環境の DEBUG.COM から立ち上げる手段でテストしようとしているんだが、なぜか \DEV\CON が見つからないエラーとコマンドインタープリターが見つからないエラーが出ている。 ディスクアクセスができていないのかなと思ったがよくわからない。 エラーメッセージが出ているんだから CON は大丈夫そうな気もするし... (INT 29H は未実装)

最初のスタックってどこにするのがいいんだろうな。 100 バイト程度でいいのなら別に割り込みベクターテーブルだってそのぐらいはあいている。 400H バイトもあるからね、1/4 でも 256 バイトは使える。 一時的にそれ用に使って用が済んだらクリア (IRET のアドレスに設定) しておくという手はなくはないのかも知れない。

2022/09/18 のコメントを読む・書く


19 (月)

%1 敬老の日

強い雨が降ったり、晴れたり、晴れているのに雨が降ったり、いろいろ。 夜になると風が強まってきた。 九州をガリガリと痛めつけた台風が今度は日本列島を横断するやつだ。

%2 MS-DOS

IO.SYS 起動チャレンジ。 ちょっと文字表示を足して試してみたところディスク I/O がうまくいっていない気配だ。 ディスクに問題があると \DEV\CON がなんちゃらみたいなエラーが出るのか。 へぇ。

ブートローダーを書くために FAT12 を見てファイルを読み込むコードを作った。 まずは IO.SYS から MSDOS.SYS を読み込むように作って先に DOS 上から IO.SYS を立ち上げる方法でテストし、うまくいったら今度はブートローダーの実装だ。 案外簡単に 512 バイトに収まった。 昔の苦労は何だったのか? PC-98 の面倒なのがあったかな。 いや、ここ 20 年何度もコードゴルフ的な遊びをやってきたせいで、コードサイズが無駄に大きい部分がすぐに気になって削ってしまうせいかも知れない。

それでいろいろとデバッグをして、案の定たくさんのバグを仕込んでしまっていて、手直しして何とか動くようになってきた。 そしてタブ文字が IBM の変な記号になる問題が発覚。 BIOS は水平タブを解釈しないんだな。 そのへん実装して、ついでに CARPOS を適当に設定するようにしてとりあえず使いやすくなるようにはした。 適当過ぎるのでいろいろ問題はあると思う。

CON のタブ対応と INT 29H を実装し気持ち高速になったか? AUX もうまく動いていなかったのでバグを直し、CLOCK もめちゃくちゃだったので修正をした。 IBM PC 互換の 40 年ものの古〜いインターフェイスを使ったのでまともに動くのは時刻のみだ。 それを 0x1800b0 と 8640000 でかけたり割ったりしなければならず、かけるのはともかく割り算はつらいなぁと思っていた。 ら、factor コマンドに突っ込んだらめちゃくちゃ因数あるじゃないか。 16 ビットで表せる数字の組み合わせにすれば、かけ算も割り算も 2 回ずつすれば良いのでどうってことはない。 多倍長演算にはなるが、プログラムは簡単だ。 実装して試したら四捨五入をしたほうが良さそうな感じがしてきた。 それもまぁ適当に実装。

いろいろ動くようになると JX ではどうなのかと気になり出す。 調べると JX は日本語処理用に BIOS が使う領域が広く先頭の 8KiB は使えないようだ。 英文モードのゲームが、なぜかブートセクターに IBMJ って入っていたせいで基本モードで起動できたものの画面表示がおかしかったというのがあったがこのへんが理由なのか。 ロードアドレスを調整すれば問題なく起動するようだ。 拡張表示モードでも基本モードでも英文モードでも起動する DOS。 良い。

ちなみに JX の英文モードは片面フォーマット (360KiB) で使っていたがこれは PCjr が 5.25 インチの片面ディスケットドライブを搭載していたことに由来するらしい。 PC DOS 3.2 のディスケットがあって、実はそれだと両面アクセスもできた疑惑がある。 (実機では未確認。) PC DOS 2.11 ではだめだったが、おそらく今回の自前ビルド MS-DOS ならアクセス可能なんじゃないか。

複数ドライブ対応も入れたがハードドライブには対応していない。

とまぁ 2 日がかりだったが何とか少しは使えそうなところまで来た。 DOS とはいえデバイスドライバーやブートプログラムといったところに来るとやっぱり手こずるんだな。 特にブロックデバイスは、FAT のパラメーターブロックと密接に関係していながら実質は LBA を使っているという、今思えば不思議な構成でだいぶ頭を使った。 でも、今時のコンピューターで仮想環境はあるしアセンブルは速いしリソースは有り余っているしという状況でやったからこんなもんだが、これを 40 年前にやっていた人達は本当にすごいし、時間も掛かっただろうなぁ。 そして意外と変なバグが残ったままリリースされていたものも多々あったんだろう。 この自分でビルドしたやつも、セクター数の違うディスクを交互にアクセスすると何かおかしい気がする。

2022/09/19 のコメントを読む・書く


20 (火)

%1 かようび

休み明け。 在宅勤務。 今日は休みの人が多かったみたいだ。

%2 MS-DOS

きのう動いたやつにはいろいろバグがあり急に動かなくなって何かと思えばレジスタークリア忘れていたし (訳わかんなくて DEBUG.COM で開いて CLI HLT を書き込んで保存しては QEMU で実行して QEMU monitor でレジスターを観察するなどしていた)、CLOCK デバイス実装もバグっていて四捨五入を書いたせいで上限を超えておかしなことになっていたし、たいした機能もつけていないのにバグだらけである。 なお時間の計算処理は見直していたら 64 ビットやる必要なくて 48 ビットでいけるので処理を減らすことができたし、他にも無駄な PUSH POP があったり、無駄に長い命令があったりといろいろ削ることができた。

んでついでなので最後のディスクアクセスから一定時間はディスクを交換していないと返すというやつを実装した。 時刻取得の INT 1AH は最後に呼び出してから日付が変わったかのフラグがあり、いろんなところで使うと日付のインクリメントをしそこねる可能性があるので注意が必要だ。

さて QEMU で試していると時々ディスクエラーになることがあり、なんでだろうと思っていたが、DMA の 64KiB boundary 問題であることがわかった。 エラーコード 9 が返される。 PC-98 と同じ制約、PC 互換機にもあったんだな。 PCjr と JX は DMA を搭載していなかったから、この制約は存在しなかったのである。 なおこの制約が生まれたのは、8 ビットプロセッサ向けの DMA を使っていて、アドレスが 16 ビットしか指定できず、20 ビットの 8088 で使うために残りの 4 ビットを DMA コントローラーとは別のレジスターで指定するようにした、というのが原因のひとつらしい。 もうひとつは、ケチって DMA からの割り込み線をつながなかったか何からしくて、本当なら途中で切り替えて続きをやれば良かったところ、それもできなくなってしまったらしい。 IBM PC と同時期に登場しバス幅 16 ビットの 8086 を搭載していた PC-98 まで同じ DMA コントローラーを使ったというんだから笑い話である。 いやこれ本当に面倒くさかったんだよ... まさか 2022 年にもなってあの面倒くささにハマるとは思わなかったがw

2022/09/20 のコメントを読む・書く


21 (水)

%1 すいようび

今日は午前中出社した。 急に気温が下がって肌寒い日。 特に朝は原付を走らせていたらフリースを着ていても寒かったな。

%2 DOS

DMA の 64KiB 境界問題の対策を実装していたら、あることを思い出した。 PC-98 でディスクコピーだったかファイルコピーだったかファイル読み取りだったか忘れたが、フロッピーディスクからたくさんのデータを読み取っている時、シーク音が 4 回ごとのサイクルになるのだ。 4 回ごとにちょっと間隔が開く。 これは、1232KiB フォーマットが 1 トラックあたり 8KiB, 両面で 16KiB, 4 回シークすれば 64KiB 分で、8086 でひとつのセグメントで扱える最大サイズと一致するから何となくそのせいかと思って深く考えていなかった。

しかしこれ、もしかして DMA のせいなのか、と。 フロッピーディスクドライブのコマンド的に、あるトラックのセクターを最後まで読んだら続けて違うヘッドに進むとか、次のシリンダーにシークするとか、そういうのはなかったはずで、最大でも 8KiB ずつ読み取りコマンドを発行していたに違いない。 なので 64KiB ごとに CPU が何か余計な仕事でもしない限りは、きっちり 64KiB ごとに時間が掛かる理屈は出てこない。 ...そうだ、DMA の境界問題だ。 8KiB 単位でコマンドを発行していたなら、8KiB 単位のアラインメントのアドレスでない限り、64KiB 以内に必ず境界問題が訪れるんだ。 で、自分で対策を実装してみてわかったけど、一時領域に転送してから正しいアドレスに CPU で転送をすることになり、一時領域を 8KiB もは確保したくないから、ギリギリまで普通に読み取り、またぐところだけ一時領域との間を CPU で転送し、残りはまた普通に読み取る、って形になりそう。 例えば最悪は 8KiB を 4KiB+1KiB+3KiB みたいな 3 回のコマンドに分けることになり、目的のセクターが通り過ぎてしまうからそこだけディスクが余計に 1, 2 周回ることになる。 360rpm だから 1 周は 1/6 秒、2 周で 1/3 秒はちょうどあの時の間隔分ぐらいな気がする。

for i in 1 2 3 4 5 6 7; do
for j in 1 2 3 4; do echo -n a; sleep 0.45; done; sleep 0.33; done

うん、イメージとしてはこんな感じだな。 これ書いていて思ったけど、4KiB+1KiB+3KiB の読み取りをするにしても、4KiB と 3KiB を先に読み取り、次に 1KiB の読み取りをしたほうがたぶん速い... 実はあの待ち時間はもう少し短縮できたのかも知れない。

そして Windows がどうだったかは忘れてしまったが、FreeBSD(98) ではその現象がまったく発生せず連続してアクセスできていたことも覚えている。 プリエンプティブマルチタスクのオペレーティングシステムではフロッピーディスクの転送をしながらハードドライブの転送もできるんだから強いよなーなんて思っていたけど、そこじゃない。 カーネルに DMA の制約に応じたアドレス割り当てをする機能があったからなんだな。 まぁ、DOS 時代は最後まで RAM 容量が厳しかったから、8KiB ものアラインメントで (セグメントアドレスで 200H 単位) メモリーを割り当てるというのはあまりにももったいなくて考えられなかったけどね。 でも RAM の空き領域を全部使うディスクコピーぐらいは、できるだけ 64KiB 境界をまたがない方法でアクセスしてもよかったよね。

2022/09/21 のコメントを読む・書く


22 (木)

%1 もくようび

在宅勤務。 昼は晴れていた。

%2 フロッピーディスク

きのうのコマンド適当すぎたな。 たぶんこっちのほうが適切だ:

for i in 1 2 3 4 5 6 7; do
for j in 1 2 3 4; do echo -n a; sleep 0.5; done; sleep 0.33; done

違いは 0.5 のところ。 ポイントはこうだ。 表面 8 セクターにアクセスして、続けて裏面 8 セクターにアクセスする時は、シークがいらないし、8 セクターの後に少し隙間があるので、裏面の 1 セクター目に間に合う。 なので表面と裏面は 2 回転の間にアクセスできる。 その次はシリンダーが変わるのでシークの必要があり、シーク後にコマンドを出した時にはもう 1 セクター目を過ぎているから、1 回転待ちになる。 つまり連続アクセスでは 16 セクターごとに 3 回転、3/6 秒必要になる。 んで、64KiB 境界のところで 8 セクターを 3 回に分けて読み取ったら、追加で 2 回転必要になる、と。

で。 きのうのアイディアを実装しようとしていたら、自分の実装もいい加減過ぎた。 読み取り前提になっていたw 当たり前だけど、書き込みの場合は先にメモリーコピーをしてからコマンド発行だ。 それをしていなかった。 あまりにもレジスターのやりくりがごちゃごちゃするので、スタック上にローカル変数を確保した。 LES DI,[BP-4] みたいな書き方をする時は DWORD PTR がいるらしいw 違和感あるw

そういえば、オーシャノグラフィ II というバックアップツールがあって、これは 8KiB セクターを使用していた。 確か特にずらしてはいなかったんじゃないかな。 8KiB セクターで 1 セクター/トラックのフォーマットにすると、通常 8 セクター時に必要なセクター間のギャップ 7 個分が不要になるので、だいぶぎゅっと詰まった感じになる。 んで、シークしてもセクターの先頭に間に合う、って仕掛けだったと思う。 一度に 8KiB ずつのアクセスになるので通常のファイルシステムには向かないが、バックアップツールはどちらかというとテープ的なシーケンシャルアクセス用途だから向いていたというわけ。 今考えてもなかなか賢い仕組みだったが、容量の大きなハードドライブに対応していなかったか何かが理由で早々に引退となった。

%3 libx86emu

GitHub - wfeldt/libx86emu: x86 emulation library

MS-DOS 独自ビルドで夢が広がっているので、このへんのライブラリを使って、超広大なメモリーが使える仮想マシンとその上で動く MS-DOS というのを作りたい。 超広大ったって 1MiB なんだけど、仮想マシンだから ROM も VRAM も不要で、普通なら ROM がある領域までまるまる MS-DOS 用に使える。 MS-DOS 的にはタイマー割り込みすら不要で、データのやりとり用に I/O ポートひとつ用意すれば十分かと。 動くアプリケーションは DOS 汎用のものに限られるからかなり少ないが、フロッピーディスクより大きめのディスクイメージを準備して、そこで MS-DOS セルフビルドができます、っていうのは楽しそうじゃない?

%4 MS-DOS

COMMAND.COM の CLS コマンドは ESC [ 2 J を出力する。 IBM 版は ANSI.SYS を組み込まないとどうなるかというと、ビデオ BIOS を呼び出す専用コードが実装されている。 しかしちゃんとチェックが入っていて、CON じゃなかったり (リダイレクトや AUX 等)、ANSI.SYS が組み込まれていると判断したりした時には、エスケープシーケンスを使うようになっている。 IOCTL で SPECIAL ビットもチェックしているようだ。

...えっ、この IOCTL ってセットもできるのか! Cooked mode/raw mode を変えられるのはわかるけど、他のビットも変えられそうな雰囲気だ。 JX の日本語 DOS で、わざと SPECIAL ビットをクリアしてみたところ、COMMAND.COM の CLS がエスケープシーケンスをそのまま出すようになった。 へぇ。 なお SPECIAL ビットをクリアしても INT 29H は引き続き使われているようだ。 試しに console input/output のビットもクリアしたら、何も出なくなった...

自分のビルドしたものは、console input/output のビットをクリアしても引き続き動いている。 これは IBM 版じゃないからというよりは、旧システムコールを自分で実装した部分の影響だろうな。

DIR /P や MORE の実装を見ると、画面行数は 24 行か 25 行の想定のよう。 MORE が IBMVER では桁数をビデオ BIOS から取得しているのに加え、漢字の時に 24 行としているのを見つけた。 これは時期を考えると完全に 5550 向け実装と言えるのではないか。 JX は 11+1 行しか使えない基本モードがあったから、JX の日本語 DOS はそのあたりも改造されていたんだと思う。

デバッガーにも謎の IBMJAPVER 実装があったけど、あれも 5550 ってことだろうな。 5550 は PC 互換ではないと言われているけど、意外と BIOS なんかには PC 互換な部分があったってことなのかもな。

後は DOS/V 互換的なものも実装できると楽しいだろうけど... フォントに 128KiB は必要だろうから、拡張メモリー無しで考えるとメモリーがめっちゃ厳しいなw

2022/09/22 のコメントを読む・書く


23 (金)

%1 秋分の日

昼過ぎぐらいまでは晴れていたような気がする。

テレビでやってた映画『竜とそばかすの姫』。 2021 年のアニメーション邦画。 細田守監督。 同じ監督の『サマーウォーズ』に出てくるようなオンライン世界が出てくる。 世界観として非常に似たものを感じる。 どうして鍵もかからないのか、どうしてすぐ暴力沙汰なのか、どうして文字でなくいちいち話しているのか、どうにも理解しがたい。 そして、繰り返される「あなたは誰」は違和感の塊だった。 お前こそ誰だよ状態だ。 結末はいい感じにまとまっているが、なんかどうにももにょもにょする映画だった。

%2 MS-DOS 専用仮想マシン

説明が足りなくてとっつきにくい libx86emu を使い、RAM を FFFF0H まで割り当てて、超いい感じな仮想マシンをつくったんだが、仮想ディスクの挙動がおかしい。 1 クラスターに満たないファイルを作ると、なぜかディレクトリエントリだけが作られて、FAT もデータも書き込まれない。 PC 用に実装したほうではその問題は起きないので、仮想マシン用に書いた実装に問題があるようだがさっぱりわからない。 まさか libx86emu のせいってこともあるのかと、RAM ディスクドライバーを組み込んでみたらそっちは動いているからやっぱり自分の実装のせいだ。 でもなんだろうな、やっていることは PC の ROM BIOS を呼び出すより遙かに簡単なんだけど...

なお読み取りに関しては普通に動いているようで、CHKDSK は以下のように空きメモリーを報告する:

  1048560 bytes total memory
   959568 bytes free

いぇーいw

2022/09/23 のコメントを読む・書く


24 (土)

%1 どようび

雨。 夜はあがった。 涼しい日。 湿度は高かった。

%2 MS-DOS

きのう作った仮想マシンのやつで、デカいディスクが使えるぞと試していたらファイルを書き込むと壊れる事象が発生。 いろいろ試していると 1 クラスター未満のサイズのファイルを作るとディレクトリエントリだけ書き込まれて FAT もデータも書き込まれない。 なんだこれー?

というののデバッグに時間を要した。 結論はディスクのデバイスドライバーの実装をミスっていて media change のステータスをレジスターに入れて満足してメモリーに書き込んでいなかった。 まさかこんな挙動になるとはね!

そのデバッグの際に libx86emu が trap flag (TF) を無視していることが発覚した。 少しコードを確認したところ非常に簡単な回避策で対処ができ、デバッグがスムーズになった。

そんなに動くとだんだん調子をこいて、CPU 負荷低減策も導入した上に Linux KVM 用のものも作った。 負荷は DOS の仕様上プリントスプーラー用の割り込みを生成しながらポーリングする処理になっているので、その割り込みのタイミングでモニターを呼び出して 1/100 秒待つっていう対策にした。 タイマー割り込みはないからね。 Linux KVM 用は前に自分で書いたコードがあったので簡単。 何しろこの独自仮想マシンはエミュレーションが何もいらないからね。 それでコードを整理していって push.

さぁて、セルフビルドを試みよう。 バッチファイルの CALL に MSDOS 2.11 は対応していないので、何とかする。 COMMAND /C なら動くのに \COMMAND /C だと動かない謎の事象... まぁいいや、ごまかして何とかしようとしていたら MASM が時々 out of memory を出してきた。 はて? まだ問題ありか?

とまぁこっからが泥沼である。 とりあえず理由がわからないけど、MASM がロードされる時に前のメモリーが 64KiB 単位プラスアルファぐらいの割り当てになっていると動くっぽいことを発見した。 そうじゃないと out of memory どころか何もメッセージを出さずにいきなりハングすることもある。 それで対策プログラムを作り、セルフビルドが通せるようにはなった。 そして DOSBox では行入力のリダイレクトをするときはファイルに改行コード LF を入れているとだめなようだ。 CR だけにしていないと動かない。 そういえば MS-DOS は最初に LF が来たら捨てるみたいな処理があったな。

とまぁ DOSBox でもビルドが通せるようになり (遅いけど)、いいかなーと思って整えていた時に、そういえば FreeDOS でもわざと変なアドレスにロードさせれば MASM がうまく動かなくなるんだろうなと思って、対策プログラムを改造して試したら、なぜか動くのだった... はぁー? DOSBox と MS-DOS 2.11 でだめで、FreeDOS で大丈夫ってどういうことだ?? しかも Linux KVM 版と libx86emu 版でも微妙に条件が違うんだよな... まぁ両者はメモリーサイズが微妙に違うんだけど...

2022/09/24 のコメントを読む・書く


25 (日)

%1 にちようび

晴れ。 のんびり。

バイクしばらく動かしていないなと思って、メインスイッチを入れると 12.3V の表示, たぶん 4 週間経っているのでさすがに 12.4V より下がるのか。 充電をかねて南多摩から若葉台やら稲城のジョイフルやらのあたりを回ってきた。 途中、よみうりランド行きの小田急バスを見かけて、おそらく新百合ヶ丘からの路線ではないかと思うが、どこを通るんだろうと思ってついていったら、いったん坂をのぼったところからまた下る感じになるんだな。 住宅地を通る道のようで、結構たくさんのバス停でお客さんを降ろしていた。 バイクだと、バス停で止まっているバスの後ろで左端にいたら、コイツ行く気ないなってのが一発で後続車に伝わって良い感じ。

%2 DAA

8086 の packed BCD の補正命令 DAA。 16 進数の変換に使われている ADD AL,90H; DAA; ADD AL,40H; DAA は有名だし、引き算バージョンで類似の DAS 命令を用いた CMP AL,10; SBB AL,69H; DAS もあるが、それ以外にごく普通の 10 進数演算にも使える (笑) んだけど、最近その使われかたを MS-DOS のソースコードで発見してしまった。

それは CHKDSK だった。 いや他にも COMMAND や RECOVER なんかにも同じものがあるんだけど、32 ビットの整数値を 10 進数の文字列に変換する部分で使われている。 これ、昔からディスク容量で出てくる話で、ディスクの容量や空き容量は、FAT のクラスター数で表されており、クラスター当たりのセクター数とセクターサイズなんかをかけ算していくと 32 ビットが必要になる。 (4GiB 以上になるともっとだが、DOS が主流だった時代は 4GiB 以上は本当に想定外だったな。) 10 で割って余りを出すには 16 ビットずつ 2 回の割り算をしなければならず、一桁ごとにそれをやっていては 8086 では時間もかかる。 CHKDSK の方法は、ぱっとみは上の 16 進数変換みたいな魔法のコードに見えた。 しかし良く読むとごく普通の方法だった。

MS-DOS/CHKDSK.ASM at master - microsoft/MS-DOS - GitHub

もし誰かに、正の整数を 2 進数にして上から 1 桁ずつ送るから、それを受け取って 10 進数で表してくれと言われたら、目の前の電卓をクリアして、数字を受け取るごとに、かける 2、1 をもらったら 1 足す、を繰り返していくと答えは出る。 例えば 1 0 1 0 と来たら、0*2+1=1 1*2+0=2 2*2+1=5 5*2+0=10 といった具合。 それを、送る側はビットシフトとローテート、受ける側は、かける 2 を同じ数字同士の足し算にして packed BCD 補正をかけて実現したのが CHKDSK にあったコードである。 4004 由来なのか 8086 では BCD でも桁上がりを素直に扱える仕組みがあるので、実にシンプルである。 16 ビットずつ別々に取り出すならビットシフトとローテートを組み合わせる必要もないしさらに速くなるだろう。 そして、32 ビット符号無し整数の最大値は 4294967295 で 10 桁なので、packed BCD であれば 40 ビットあれば表現でき、16 ビットの汎用レジスター 3 つで足りる。 つまり RAM をごちゃごちゃ触ることもなく、レジスターをこねくり回していれば完了する。 マジかぁ!

これは 32 ビットだと 32 回のループになる。 10 で割る方法では 10 回のループになるので比較しづらいが、8086 の割り算命令は 100 クロックサイクルを軽く突破するような命令なので、それを 1 桁あたり 2 回ずつ使わざるを得ない方法と比べれば、まぁ速いのではないか。 極めて単純なアイディアだけど、思いつかなかったな... 昔の人はすごい。

でまぁ、今時のコンピューターでは AMD64 の long mode を含め BCD 演算命令は排除される傾向にあり、この技は使えない。 専用命令なしで手で BCD 演算の処理を書くとさすがにシンプルにならない気がする。 16 進数のアレも、BCD 演算無しで条件ジャンプも無しだと結構つらいんだよな。 ADD AL,F6H; SBB AH,AH; AND AX,473FH; SUB AL,6; ADD AL,AH みたいに思いつきで書いても 11 バイトだ。 まぁ条件ジャンプは使えよって話か。 今時なら conditional move もあるし。

%3 MS-DOS

MASM が不安定な謎ははっきり解決はしていないんだけど、ひとつは空きメモリーが影響していることはわかった。 システムコールを見るとメモリー割り当て関連のものは一切使われておらず、謎のソフトウェア割り込み設定の他は、普通の入出力のみ。 どうやらメモリーに関しては Program Segment Prefix (PSP) のオフセット 2 に 16 ビットで書き込まれている上限アドレスを見て使っているようだ。 デバッガーでわざとそこを別の値に書き換えて実行すると、値によって out of memory になったりならなかったりする挙動が観察できた。

んで、どうやら、少なくとも明らかに問題があるのは、この連続空きメモリーが 512KiB を超えている場合だ。 中で引き算をした結果を符号付きの値として比較してしまっているようで、空きメモリーが少ないというほうの処理に入ってしまっておかしなことになるようだ。 FreeDOS については最初からセグメントが 2000H を超えており、また QEMU の 1MiB 未満の RAM 容量が 640KiB のためこの問題が起きない。 DOSBox はめちゃくちゃ下位のアドレスを使っている上に A49BH まであるというから、658KiB か? そして自分がこしらえた専用仮想マシン上では DOS のくせに 1MB も空きメモリーがあるんだからお察し。

そうするとやり方としては、わざと上位アドレスを先に割り当てて、メモリー空間に穴が開いた状態にして MASM を呼べば、空きメモリーが 512KiB を超えるなんてことにはならなくなってうまくいく。 まぁ、うまくいくのはいったんだが... 他のアドレスでも動くのかなと余計な試行錯誤をしたら、アドレス B9000H 前後 (?) でなぜか挙動がおかしくなるところを発見した。 アドレス D0000H ぐらいまで進んでいれば OK だし、もっと下位のアドレスでも問題ない。 これが本当に変で、MASM がロードされるアドレスをどこに調整しても関係なく、どうやら DOS 自身がぶっ壊れているようだ。 MASM は通常通りシステムコールを使っているのに、途中から標準エラー出力が出なくなり、その後に異常動作である。 はぁー。 DOS のバグか? さすがにもう知らん。

全部ビルドについては、libx86emu 版の専用仮想マシンは異様に遅くて、Ryzen 7 2700 のパワーをもってしても 35 分ぐらいかかる。 DOSBox は Ctrl+F12 で速くしてやるとそこまで遅くなく、8 分ほどだ。 Linux KVM 版の専用仮想マシンはなかなかな速さで、1 分以内だ。 QEMU + Linux KVM + FreeDOS も速いことは速いんだけど、コンソールが遅いし、シリアルポートに切り替えてもここまで速くはなさそうだ。

そんな感じで、PC-98 版 IO.SYS (DOS 流に呼ぶとこれが BIOS) も作ってみたいところではあるんだが、INT DCH まではさすがに面倒見切れないなと思うので、とりあえず動くだけといったところになるかな。 PC 版は文字入力でカーソルキー等を IBM 形式で期待されているっぽいところ以外は不思議なほど普通に使えそうな感じで動いているけど、PC-98 版はそうはいかないだろうな。 とにかくこの専用仮想マシン上でめちゃ速いビルドができるので作業がやりやすくはなる。

2022/09/25 のコメントを読む・書く


26 (月)

%1 げつようび

晴れ。 暑い。

%2 16bit code

この時に Linux の modify_ldt システムコールで遊んでいた。 この時は 32 ビットセグメントの実験で、64 ビットバイナリで使えないコードを書いたのは単に手抜きだ。 このシステムコールによる 16 ビットセグメントの使用も未だに許されている。 Wine が Win16 アプリケーションを動かす時に使うらしい。 2014 年頃に廃止されかけたけど、Wine ユーザーのおかげで助かったようだ。

で。 これを使って MS-DOS 用の MASM Version 1.10 を Linux 上で簡単に動かせないかというアホなことを思いついてやってみた。 本来仮想 8086 モードが必要だが、セグメントレジスターを最初の再配置だけですませているのなら、意外と動くのでは? EXE ファイルの MZ ヘッダーは極めて単純で、16 バイト単位のヘッダーサイズ分をスキップするとそこからが本体、アドレス 0000H:0000H から始まっているとみなしたコードとデータが含まれるらしい。 再配置データはポインターの配列構造で、ひとつのエントリは 32 ビットでセグメントとオフセットを並べたもの。 それが指す 16 ビットのセグメントアドレスに開始位置を足せば再配置完了。 あとはスタックポインターがヘッダーにあるので同様に足し、開始アドレスもヘッダーにあるので同様に足して使う。 それだけ! テキストセクションもデータセクションも一切区別無し!

今回は仮想 8086 モードじゃないセグメントにマップする必要があるので、足すんじゃなくてその位置のセグメントを作って割り当てるようにした。 おっと、データとコードの区別があるんだった。 困った。 よし、全部コードにしておいて、書き込みがあったら例外が発生するからそこでセグメントを切り替えよう。 %ds%es にコードセグメントが入っていたらデータセグメントに切り替えるだけだ。 スタックポインターにだけはコードセグメントはセットできないので、機械語解釈が必要になるが、そう難しくはないだろう。 あと割り込み禁止なんかも機械語解釈で進める。 ってな感じで適当にやると意外と動きそうな感じでシステムコールをとらえ始めたんだが、致命的な問題が発生した。 どうやら、おそらく、たぶん、なんだけど、LES 命令をダブルワードのメモリーコピーにおける読み取り用に使ってやがるw なんてことをしやがるんだw それは protected mode では virtual 8086 mode を使わないと動かしようがないw あぁーw

まぁ残念な結果ではあったが、その機械語解釈処理をシグナルハンドラーとして書いた時に、ucontext_t 構造体の中身を見ていたらなんと、64 ビット用ではセグメントセレクターの要素が一部しかないことが発覚した。 modify_ldt は 64 ビットでも使えるんだが、セレクターがないので、こういう例外をとらえて云々という処理は不可能なのか。 いや、もしかしたら、シグナルハンドラーに入っても %ds%es は変更せずにそのまま来ちゃうということなのかも知れない。 賢いけど 32 ビット用と共用するコードはとても書きづらいな。

2022/09/26 のコメントを読む・書く


27 (火)

%1 かようび

晴れ。

%2 MASM

何とか MASM をフルの DOS 環境なしで動かせないか? libx86emu を使う手もあり、それでも Unix と直接つなぐなら並列実行ができるから、30 倍遅くても 15 並列で 2 倍の時間で済むみたいなことはできる。 けど、考えていると x86 で x86 を実行するのをやってみたくなってきた。

エミュレーターは何度か書いたがフラグの扱いがとても面倒だ。 どの命令はフラグを壊す、どれは壊さない、それに補助キャリーフラグやらオーバーフローフラグやら、既存の高級言語で表現困難なものが多数ある。 しかし、x86 上で x86 なら、実際のフラグレジスターを流用できる。 ただし pushf popf でなければとっておけないフラグがあり、毎回 pushf popf をやっているとさすがにパフォーマンスが厳しいのではないか? (試したことはないけどね) それで、フラグをできるだけ壊さなければいいんだ、っていう謎の結論に達したw

BCD 命令関連の都合により i386 アセンブリで書く。 フラグレジスター無しでも結構やれることは多くて、lea 命令で足し算ができるし、4 倍までかけ算ができるし、jecxz で条件ジャンプもできる。 そして 8 ビットレジスターの存在のおかげでビットの取り出しまで行える。 なかなかつよい。 ちなみに not 命令はフラグを壊さないので、not 命令併用で引き算もできる。 こんなに何命令もフラグを壊さずに進むプログラムなんて書いたことがない。 見慣れた x86 とはちょっと違う世界が広がっている。

あとはまぁ勢いだ、ずばばばー、っと書かないとなかなか難しいんだけど、フラグレジスターの苦労がないのと、BCD 命令含めほとんどの命令はそのまま使っちゃえばいいということで勢いが落ちない。 デバッグは大変なんだけどとりあえず、システムコールまでたどり着けた。 さてこれが動くようになるかな。 性能はどれぐらいになるかな。

2022/09/27 のコメントを読む・書く


28 (水)

%1 休暇

「坂本冬美特別公演 中村雅俊特別出演」っていう公演を見に行った。 農業協同組合から招待券が届いていたため。 貸し切りと書いてあったが本当に貸し切りだった。 農業協同組合の役員紹介もあったし。 農業協同組合で 3 日間貸し切っているらしい。 自分の招待券はどうやら 2 日目、夜の部のほうだ。 東京都中央区日本橋浜町にある明治座というところで行われている公演で、舞台 (演劇) と、歌のコンサートがセットになっている。

学園祭レベルならともかく、有名人が複数出ている舞台を生で見るのは間違いなく初めてだった。 劇場という場所そのものが映画館ぐらいしかなじみがなく、舞台に本格的なセットが組まれて役者が演じるのを見たのはテレビで昔やっていたお笑い番組ぐらいのもんだろう。 まぁ、実際に見ると、予想の範囲内でもあったし、百聞は一見にしかず的なところもあった。 テレビドラマなどとは異なり、舞台の場合は目の前の舞台がすべてであり、幕がおりるか照明が消されない限り場面は大きくは切り替わらない。 舞台の床にはターンテーブルが仕込まれていて、セットごと回転させることで短時間で場面が切り替えられるようになっていたが、それにしたってテレビみたいにはかえられない。 それで、場面全体が見渡せるんだな。 テレビだと演出が見せたい絵になるというか、役者の顔がどアップになったり、逆に小さくなったりなんだけど、舞台は観客が見たいところを見るスタイルなんだな。 真ん中でかけあいをしている間に、端っこで別の役者が何か話をしている風な、そういうのがあった時に、テレビドラマだとこういう表現ないな、って思った。 まぁ、情報量の違いとも言える。 テレビの解像度が 4K, 8K になったところで、舞台の全体を固定カメラで映したままで、まるで実際に見に行ったみたいな体験がー、ってレベルにはまだ情報量が足りていない。

役者からしたら、テレビで言えばめちゃ長いワンカットで生放送、みたいな演じ方をしなきゃいけないんだから、難しさがあるんだろうと思う。 ライブなんだよな。 そういう意味で音楽のライブとも通ずるところがあるんだなと思ったし、坂本冬美のように歌手から俳優活動を始める人や、中村雅俊のように演劇の世界から歌を出す人もいるってことなんだろう。 中村雅俊、歌番組に初めて出演した頃の話をしていて、下駄にジーンズでいったんだとか、演劇の人間で音楽関係の知り合いいなかったしとか、そういうことを言っていた。

第二部の歌は坂本冬美だけなのかと思いきや、中村雅俊も何曲も歌ったし、もう一人、森山愛子という人も歌っていた。 大村健二って人かな、この人は舞台に出ていただけだけど、水戸黄門に出ていた人だって話をしていた。 演歌のことはわからないけど、楽器は意外と普通にポップスと同じなんだなと、演歌の間は演奏の人達を見るのが楽しかった。 スポットライトを無視して奥の人達を観察、こういうのも、ライブって感じがする。

%2 行き帰り

きのうの国葬の影響で今日も一部交通規制ありみたいな表示があって、でもどこが規制されるのかまったく情報がなく、不安があったので身軽なスクーターで行った。 結果としては交通規制はなかったが、数回道がわからなくなり路肩でチェックしたのと、あと目的地に近づいてきたら、一方通行の罠と、公園の駐車場の入口がわからずうろうろする羽目になり、まぁ結果としては邪魔にならない & 押せば歩行者になれるスクーターで正解だったな。 時間に余裕があったので (駐車場が満車だったら秋葉原にでもとめて列車で行くことも考えていた)、あえて地図を見ずにうろうろしたら、地下駐車場はなぜかかなり遠いほうから出てしまったし、明治座の裏手のほうに着いて、表はどこだ? とマジでわからなかった。

14 時 30 分前後に着き、16 時開始で 20 時になる前ぐらいに終わったので、6 時間の駐車でバイクだったから 600 円。 車だったら 2400 円か? 帰りは道が空いていて快適。 腹が減っていたので途中でごはんを食べようかと思っていたが、微妙に雨粒がバイザーについてきたのでコンビニで弁当を買って帰った。

%3 MASM のやつ

システムコールは作ってそれからまぁバグが出るわ出るわ... 間違いだらけだ。 そもそも命令を根本的に勘違いしていたものなどあり、自分のプログラムもまともに動かなかったのでそこをまずはなおして、何とか MASM もアセンブルが始まるようにはなったが、エラーだらけ。 なんだそりゃー。 まだ何か間違っているのかよとコード整理と目視確認、疑わしいのは CMPSB か? とそのあたりを徹底的に調べていたら、なんと REPE と REPNE を逆にしていたことが発覚したww 自分で書いた JX のエミュレーターのコードを参考にしていたら、それが間違ってやがるw いや、動作はあっていたんだが名前が間違っていて、間違っている名前を参考に書いたから間違っていたw

それでアセンブルが通るようになり、LINK と EXE2BIN のシステムコールにも簡単に対応してみた。 LINK はなんとカレントドライブを勝手に出力ファイル名につけるというおせっかいをしてくれる... どうしてそうなった...

いろいろデバッグ中に発覚したけど、MASM にはなぜか命令コード 82H が使われているらしい。 これは命令コード 80H とまったく同じで、通常は 80H しか使われない。 どうしてこうなったんだろうか。

あと自分のプログラム、1 バイト単位で入力するのが致命的に遅い。 Linux のシステムコールを 1 バイト単位で呼ぶのがさすがに厳しいか。 DOSBox なんかで遅いのにも関係があるかも知れない。 改良するのがよさそう。 MS-DOS はその点 1 バイト単位でも意外と高速動作かも知れない。 システムコールといっても当時のは単なる関数呼び出しの延長みたいなもんだしな。

2022/09/28 のコメントを読む・書く


29 (木)

%1 もくようび

晴れ。 涼しい日。

きのうの公演のやつは農業協同組合がいくつかくっついて今の形になってから 30 周年の記念で招待されたものだった。 明治座は 150 周年だそうで、そちらもなかなかすごい節目という感じがする。 坂本冬美はなんと 6 年前の 2016 年にも農業協同組合の貸し切りコンサートをやっていたんだそうで、オフィシャルサイトによると 2 月 19 日に府中でやったんだな。 知らなかった。 Twitter の書き込みによれば 26 日にツイートしている方がいらっしゃる。 公演側の情報では今週月曜から木曜まで貸し切りになっており、火曜は午前中のみで午後の公演がない。 自分が水曜の招待で、スタッフさんから 3 日間あると聞いており、それに坂本冬美本人が明日も農業協同組合だということを話していたので、どうやら 2 日目だったなということはわかっていたが、1 日目がその火曜日の半日だったのか、月曜日だったのかがそのツイートではっきりした。 6 年前の縁と、150 周年記念の節目の縁で何か値引きがあったかわからないけど、一般のチケットは S 席 (1・2 階席) 13500 円、A 席 (3 階席) 6500 円となっており、貸し切りでは 3 階席は封鎖されていたので、914+390 席で 1304 席しかない。 未使用の席も多かったがチケットが届いても来なかった人の分だとしたら相当な数だし、自分がいた 2 階席は特にあいているところが多かったので来ていたのは 700〜800 人ぐらいだったのかも知れないけど、3 日間 6 回分を貸し切ったら結構な金額だよな...

明治座の 150 周年はともかく、ふと思い出して調べたら、自分の母校の小学校は来年で創立 50 周年である。 50 年かぁ! 小学校を卒業する年には 12 歳から 13 歳になっているはずだから、つまり、48 年前の 1 期の卒業生は今年 60 歳か 61 歳、還暦ということに! ひゃー! 母校の大学も来年 10 月には 50 周年になるようだ。

%2 MASM

きのうの 8086 命令実行プログラムをさらになおしていろいろ動くようにはなったが、MASM より自分のプリプロセッサが遅い。 A4-9125 環境で SYSINIT.ASM を入力してみた時に DOSBox で 30 秒ほど、自分の命令実行で 10 秒ほどかかる。 システムコールを使いすぎたせいだろうと特に調べずにバッファリングの実装をとりあえずやってみたんだが、DOSBox でも自分の命令実行でも性能向上はごくごくわずかだった。 つまり他の処理が時間を使いすぎている。 うーん!

まぁアルゴリズムはまったくほめられたものではない。 行ごとに単語を切り出し線形探索なんてやっているんだからな。 MASM は古いプログラムなのでそれなりに最適化がされていたのかも知れないが、今のプロセッサなら強引なアルゴリズムでも結構動いてしまう。 何しろ 8086 が扱える 1MiB のメモリーは今は低スペックな A4-9125 であっても全部プロセッサのキャッシュに入ってしまうからね!

最初に C で書いたコードは消しちゃったけど、プリプロセッサはネイティブで動かすほうがよさそうだな...

2022/09/29 のコメントを読む・書く


30 (金)

%1 きんようび

晴れ。 ちょっと暑い日。

テレビでやってた映画『アダムス・ファミリー』(原題: The Addams Family)。 1991 年のアメリカ映画。 絶対見たことがある感じがする不思議な世界の物語だが、中身はほとんど覚えていない。 本当にどうでもいいけど、モーティシア・アダムスの顔が浅田舞に見えてくる不思議。 どこか顔のバランスというか目の形なのかメイクなのかが似ているのかな。

%2 MS-DOS あそび

プリプロセッサの実装、1 バイトごとに関数呼び出し (PUSH, CALL, ADD) をする上に、文字種判定をする関数なども最適化無しの C コンパイラー並に無駄だらけな実装をしていたので、見直した。 直接実行だと分岐予測などが強烈に働いて速くても、間に命令解釈のインタープリターを入れてしまうとそういうのがきかなくて、その無駄な部分がきいてくるんだろうと。 これだ、と思ってすごくシンプルにしたのに、予想に反してたいして効き目がない。 うむむ。 10 秒前後の実行時間が 3 パーセントぐらい縮むかどうかレベルだ。

結局やはり探索問題なのか。 シンボル名を線形探索で見ていくから、シンボル名が増えるに従って、えーっと、指数関数的に比較回数が増えるってやつだな。 そりゃ遅いだろうと言われればそれはそう。 しかしじゃあ高速なデータ格納方式を実装しますかと言われると、DOS プログラムのメモリー使用量の制約もあってそれはそれで難しそうな気がする。 とはいってもなぁ、簡単なハッシュ関数ぐらい使わないとあれかな... 完全一致の比較だからな... ハッシュが重なったらアレだけど、これより前にはないぞ、くらいのヒントのデータはハッシュ関数で提供すべきか... とはいえ今のデータ構造、キーワードに付随するデータをシーケンシャルに並べてあるから本当に面倒な構造してんな... 誰だよこれ作ったの...

2022/09/30 のコメントを読む・書く


prev, this, next

/var/log/hdk.log コメント一覧

トップ / 日記索引 / 日記 (2022 年 9 月)

Hideki EIRAKU