/var/log/hdk.log

2019 年 12 月上旬


01 (日)

%1 レンタルカート

藤野。3 回乗ってベストタイムは 39.4 秒ぐらい。 きのうよりコンディションが良くて、インリフトもある程度うまくいった。 以前のように跳ねる感じは 3 コーナーでだけ感じられた。7 コーナーはイン側見てれば浮いてるな、って感じだけど、走っていてそこまで実感がないのはあまりよくないな。

%2 リングフィットアドベンチャーの色問題

レベルが上がって、敵と同じ色の技を使うと攻撃力が上がるようになった。 色はかなり気を遣ったようで、きちんと判別できるし、さらに、色を合わせれば「有利」という文字も出るようになっていて、感心していた。

ところが、ミニゲームの「バンザイゲット」というのが激ムズで、おかしいなと思って写真を撮って確認したら、色名はわからないものの自分の目には区別のしにくい色を瞬時に判断しなければならないミニゲームだった。 さすがの任天堂でも気がゆるむところはあるんだな。 いや、そういえばマリオカートでは有名な緑・赤甲羅問題があるんだった。 自分はアレは大丈夫だけど。

%3 Portfolio

8088 の未定義命令について調べた。 まずは条件ジャンプ、なんと 0x60〜0x6f が 0x70〜0x7f と同じ命令だという。 テストプログラムは 20191201-jcc.s、結果は本当に同じだった。 おおお。

次に RET/RETF 命令。 これも、0xc0〜0xc1 が 0xc2〜0xc3 と同じ命令で、0xc8〜0xc9 は 0xca〜0xcb と同じ命令だという。 テストプログラムは 20191201-ret.s、全部一度にテストしようとしたらコードが大きくなっちゃったので、入力でオペコードを選択するようにした。 で、結果、本当に同じだった。 おおおお。

次に XLAT 命令。 これは 0xd6 が 0xd7 と同じだという話、元ネタは「ザ・プロテクト II」という書籍。 テストプログラムは 20191201-xlat.s、結果、違うらしい。 じゃあ何の命令になっているのか、まではわからないけど、とりあえず XLAT と同じ挙動でないことだけは確かだ。

そして LOCK 命令。 これは 0xf1 が 0xf0 と同じだという話、PCjr/JX や Portfolio のようにミニマムモードの 8088 では LOCK 命令は特に役に立たないものだけど、とりあえず prefix であるかどうかくらいは確認できるだろう。 テストプログラムは 20191201-lock.s、結果、prefix らしい。 ほおお。

そんなわけで、ここまで「ザ・プロテクト II」の 0xd6 の件以外の情報は、合っていた。 他に grp 系命令にもいくつか試してみたいものは残ってはいるけど、まぁ、とりあえずわかりやすいのはこのくらいか。

今日もうひとつ試したのは POP CS の実験プログラム。POP CS はよく JMP 相当のように書かれている気がするが、個人的な予想としてはプリフェッチキューが消されないのではないかと思っていた。 このプログラムの実行結果は 4。 予想は当たった。 じゃあ MOV CS はどうなるかというと、3 になった。 へぇ。2 クロックサイクルの命令でも 1 バイト分のプリフェッチは走るということか。 しかし mov %bx, %cs って何気なく書いちゃったけどアセンブルできるんだなw

%4 給油

136 円/l。 燃費計算 18.8km/l。 燃費表示 19.6km/l。 前回給油が御殿場だったので、標高の違いも関係あるのかな。

2019/12/01 のコメントを読む・書く


02 (月)

%1 Portfolio

MOV CS 実験の新しいやつ。MOV CS の前に実行する機械語を、16 進数で好きなように食わせられるようにした。 その場でテストコードをメモリーに書き込んで実行する。

命令のクロックサイクルの確認はどうしようかと思っていたが、これである程度見えるものがあることがわかってしまった。 例えば f6e490 は mul %ah; nop で、これで 2 になる。 後ろに 90 を並べてみると、f6e49090909090 まで行くと 1 になる。 なお nop 命令は 3 クロックサイクルとされている。 次に nop の代わりに 1 バイトの inc 命令を入れてみる。 すると f6e440 で 2、f6e4404040 で 1 である。1 バイトの inc 命令は一部の資料で 3 クロックサイクルとされていたが、これで 2 クロックサイクルであることが確認できた。

他には daa 命令は 4 クロックサイクルの命令であり、272727... と並べても 1 である。 何しろ 8088 は 1 バイトのメモリーアクセスに最低 4 クロックサイクルを要するのだから、増えようがないだろう。 それに対して aaa 命令を並べると、37 で 1, 3737 で 2, 373737 で 3 と順に増えていく。aaa 命令もまた、資料によって 4 クロックサイクルか 8 クロックサイクルかで表記がわかれていて、何が正しいのかわからなかったが、これで 8 クロックサイクルのほうが正しそうなことが見えてきた。

あと、わざと lret 命令を入れて MOV CS とは関係ないテストになるけど、f8d600c2cb で 0, f9d600c2cb で / が出る。 これで、0xd6 が SETALC であることがわかってしまった。SETALC は 80286 以降なんじゃなかったのかよー! 様々な資料に誤りがあるものだなと実感している。 なお上の daa 命令と同じような感じなので 4 クロックサイクルと見られる。

わざと 0xf0 (lock) を mul 命令の前に入れてみたけど結果は 3。 バスロック中にプリフェッチするものかなと気になったからだけど、たぶんバスロックはしないんだな、ミニマムモードだから。lock は 2 クロックサイクル、0xf1 も同様である。 なお wait はハングアップしたw sti; wait なら割り込みは通る。

とにかく、これは楽しい。8088 (80C88) 搭載の実機があるだけでこんなにも遊べるとは。

2019/12/02 のコメントを読む・書く


03 (火)

%1 Portfolio

今日の実験プログラムは、トラップフラグを用いて 8088 のバグを観察しようというやつである。

最初に手始めに f0f190 3。3 バイトでひとかたまり、f1 が prefix と認識されていることが確認できる。

060790 12。 これは push %es; pop %es; nop で、3 命令だが、pop %es とそのうしろの nop はまとめて 2 バイト分で扱われている。8088 の頃はスタックセグメントだけでなく、他のセグメントレジスターについても blocking が働いていたという話の確認。 最初期型 8088 についてはその機能がスタックセグメントにすら働かないという致命的なバグがあったそうだが、Portfolio はだいぶ後の CMOS 版なのでそのバグはない。JX でも、デバッガーで普通にまとめて実行されていたような記憶があるので、そのバグはないと思う。 なお、Harris 80C88 では push %es までこの扱いになってしまうバグがあるそうで、バグじゃないという人もいるみたいだが、push %cs; pop %ss; mov $foo, %sp みたいなプログラムを書いた時に pop %ss の後で割り込みが発生しうることになってしまうので、やっぱりバグである。Portfolio に採用されている Intel 80C88 ではここで試した通り、push %es は単独で扱われている。

89e089c490 221。mov %sp, %ax; mov %ax, %sp; nop。 セグメントレジスターの場合のような blocking は、%sp の書き換えに対しては行われないことの確認。 子供の頃の記憶でなんか %sp から書き換えてもいいような気がしていたが、やはり間違っていた。

b90500f3ac 3000002。mov $5, %cx; rep lodsb で、rep prefix をテストする。0 が 4 個... いや、5 個出てるw %cx が 0 になってもなお rep の位置に戻るというのか。 今時のプロセッサでは 4 個。 拙作のエミュレーターでも 4 個。 マジか... これは予想外...

b9050026f3ac 3100002。mov $5, %cx; es; rep lodsb で有名な 8088 のバグの確認。 セグメントオーバーライドの prefix を rep prefix の前に入れたところ、最初の一度だけセグメントオーバーライドが処理されて、残りは処理されていない。 実際には割り込みのタイミングでこうなるらしいが、トラップフラグを使うと必ず発生するということか。 わかりやすい。

b90500f326ac 312。mov $5, %cx; rep; es lodsb で上と同様の確認。Prefix の順番を入れ替えたため、割り込みの後は rep prefix より後ろに戻ってしまい、繰り返しが一度しか行われていない。 レガシーな 8086/8088 向けプログラムでは、この順番で使って、%cx が 0 になっていなかったら rep に戻るという workaround があるそうだ。 上のように rep を後に書くと途中からセグメントオーバーライドがなくなってしまうので対策できない。GNU as は rep es lodsb と書いても rep prefix を後にして生成してしまうようなので、prefix を単独の命令として記述する必要がある。

%2 リングフィットアドベンチャー

レベルが上がって、プランクというフィットスキルが増えた。 範囲攻撃だし攻撃力も高め。 プランクといえば、足を伸ばしてひじを床につけ、そのまま耐える、というやつだけど、このゲームではそこから腰を上げ下げしろという。 軽い気持ちで選んだら、マジきつい。 何しろ、最初その姿勢を取ったつもりだったのに、足をちゃんと伸ばせていなかったみたいで、センサーが反応しなかったw こんなにリアル腹筋が必要なビデオゲームが世の中にあるのかw

まぁ回復アイテムも駆使して何とかボスを倒し、次はやっと 4 つめのワールドだっけな。 先は長そうだし、スポーツジムのお客さん減るんじゃないの、みたいなゲーム。 いや... 筋肉ガチ勢はこのゲームをスムーズに進めるためにスポーツジムに通うのかも知れない...

2019/12/03 のコメントを読む・書く


04 (水)

%1 筋肉痛だぁ

明らかに腹筋が筋肉痛! 夜になったらふくらはぎも筋肉痛! リングフィットアドベンチャーは 1 回休み!

%2 Portfolio

きのうのトラップフラグ実験で、rep が 1 個多く出たのが気になっている。 今朝思いついたのは、rep を 1 回以上処理したら、必ず IP が -2 されるのではないか、という仮説だ。 そうすると擬似コードを書けばこんな感じか?

 if (cx) {
   do_rep ();
   relative_jump (-2);
 }

この場合 rep を処理して抜けたらプリフェッチキューが飛んでしまうことになる。 そして 0 回の rep を実行の上次に進む、と。 さっそく、MOV CS の実験コードを呼び戻して、調べてみた。

予想は外れた。 というかなんで増えているのか... lodsb が遅いのか?

ちょっと待って何がなんだかわからない。 メモリーアクセスを伴う命令になるとこうも難しくなるのか。

これを見ていると、どうやら、割り込みが関係しなかった場合の rep 命令は少なくともプリフェッチキューをクリアすることはないし、むしろ時間がかかってプリフェッチができるということだ。rep lodsb のクロックサイクルは 9+13N でいいのかな、それが正しいなら 1 回分では 22 サイクルかかることになり、そのうちメモリーの読み取りが 4 サイクルなら、残りは 18 サイクルあるのでプリフェッチキューがちゃんと埋まっても不思議ではないか。 で、割り込みが絡むと IP を 2 引く処理が走るわけだ。 デクリメント後の %cx が 0 になっていてもかまわずだ。 なんで 2 を引くことにしたのか想像すると、もしかして元の IP を取っておく場所がなかったのでは... という考えに至った。 しかし 2 を引くのに ALU を使うんだろうから、rep 処理中の割り込みは普通の割り込みより余計に時間が掛かるのかも知れないな。

もうひとつ気になっているのはこの前の f6e49090909090 1 で、これ nop が 5 個なので、nop は 15 サイクルだ。nop が 4 つキューに入った状態から始まり、12 サイクルで 3 バイトフェッチできたなら、nop ひとつと MOV CS 命令の 2 バイトがフェッチ済み。5 つ目の nop を実行する時にはその次の inc のフェッチが始まっているはずだ。 問題は MOV CS 命令が 2 サイクルを要して、そのうちの最初のサイクルの終わりには最初の inc のフェッチが終わっていることだ。 ということは MOV CS の 2 サイクル目にはその次の命令フェッチが始まり... そのときの %cs は変更後なのか? というわけで...

ほー。

2019/12/04 のコメントを読む・書く


05 (木)

%1 リングフィットアドベンチャー

今日も筋肉痛が残っているので軽めで。 プランクはやばいので別のスキルに差し替えておいた。 スキルの組み合わせはステージに入る前に選べるので、自分の体調に合わせてかえておくとよさそうだ。

自分の腹筋が弱いのは何となく想像はしていた。 ふくらはぎ、足の筋肉も何となく弱そうな気はしていた。 逆に胸筋は何ともないが、まだフィットスキルが少ないだけか。 でも何となく、水泳でもプルよりキックのほうがきつく感じられるし、胸から上の筋肉は人並みにはあるのでは... まぁ、このゲームを進めていけばいずれわかるだろうw

%2 Portfolio

今日はトラップフラグを使うプログラムの改良版。 いろいろとコードを見直して小さくした上で、スタックに積まれた値を最後に表示する仕掛けを追加した。IP 見て終了判定しているので、スタックに値を積んだまま終わる機械語を入力しても大丈夫、というわけ。

それで、見てみたかったのは 8253 タイマーが存在するのかというところ。8259 割り込みコントローラーはどうやら存在しないらしいし、タイマー割り込みも 1 秒間隔だか何からしいのだが、もしかしたら 8253 タイマーはあるかなと思ったわけだ。

ウーン。 ポート番号が読めるのを見て、てっきり自分のプログラムが間違っているのかと思ったのだが (これがまた、dosemu もバグっていて in 命令のトレース実行が明らかにおかしくて 3 バイト扱いになる)、ワードアクセスしたらちゃんと上位 8 ビットに次のポート番号が入ったのを見ると、これは本当にポート番号が読めている。 まぁ、8088 はアドレス線の下位 8 ビットとデータ線が時分割で共有なので、ある種の手抜き実装をすればこういうことになりそうな気はする。 そんなわけでタイマーも未実装っぽい感じ。

タイマーがあると、命令のクロックサイクルを測定する時に役に立つかなと思ったのだが、ないのかな。 時計は動いているんだから、何か仕掛けはあるはずだが... ファームウェアを分析するしかないのか。 まぁ、何か似たようなものがあったとしても消費電力の関係でたいした精度はなさそうな気がするので、測定は他の手段で何とかするしかないか。 幸いメモリーアクセスを伴わなくて実行時間が短い命令については MOV CS で割とチェックできているしな。

あと、スタックポインターを念のためチェックしたら普通に 64KiB になっていた。 いくら RAM が小さいといっても .COM プログラム用に 64KiB は確保するのね。

2019/12/05 のコメントを読む・書く


06 (金)

%1 きんようび

くそさむい。 おまけに乾燥。 寝る前にエアコンの電源を入れに寝室に行ったら湿度 31%!

テレビでやってた映画『ホーム・アローン3』(原題: Home Alone 3)。1997 年のアメリカ映画。 ホームアローンシリーズになっているが、場所も登場人物も違うのでリブート作品に近い。 おもちゃに機密品を隠したら空港で取り違いが発生して、それをおいかけて犯人達が住居侵入を繰り返す話で始まるのだが、下見の際にディジタルスチルカメラを使い、写真をその場でノートパソコンに転送しているのは、時代を考えるとむちゃくちゃ最先端なシーンでは。 でもこう、この頃はまだ一般的にはディジタルカメラは普及していなかったから、証拠写真なんか気軽に撮れなかったよなぁ... 2000 年前後あたりから携帯端末にカメラがつき始めて、そこから 10 年ほどですっかり変わった。

%2 8088

おとといの調査により 2 バイト・2 サイクルの MOV CS 命令の 2 サイクル目には %cs は更新されていたと認識している。 しかし 2 バイトを 1 サイクルで処理しているとはどうも思えず、どういう理屈なのかを考えていた。 それで、そういえばバスサイクルの絵があったよな、と、Google で画像検索したらたくさん出てくるなぁ。 古いプロセッサだけあって、資料は多いようだ。

で、バスサイクルはクロックの立ち下がりから次の立ち下がりの単位で、最初の立ち下がりからが T1、そこから少しズレてアドレスが出る。 周辺チップとしては、立ち上がりのタイミングで見ればアドレスが出ているという形になっている。 そして T2 はもうデータに向けての準備段階。 ふむ。

これを見て思ったんだけど、たぶん立ち上がりと立ち下がりが重要なんだな。 フリップフロップ的な話で、準備しておいた信号がクロックの立ち上がりか立ち下がりで反映されて次に進むイメージ。 立ち下がりから少しズレがあるっていうことは、信号が安定するまで少し時間がかかるんだろうな。 仕様以外すべては想像だけど、例えばクロック立ち上がりでプリフェッチキューの先頭の機械語を取り込んでそれに合うマイクロコードを選択、立ち下がりでプリフェッチのサイクルを開始したり、マイクロコードによるアクションが発動して、いや、待てよ、それだとおかしいな。MOV の 2 サイクル目に移った時が立ち上がりだとして、クロックが H の間に、レジスター同士のつながりはできあがるのではないか。 そして立ち下がりで反映! それなら MOV CS で %cs がアドレスに反映されていたのが説明できるような気がする。

そのへんを想像しつつメモリーアクセスを伴う命令のことを考える、かな、次は。 一番短いのはおそらく mov mem, %al の 10 サイクルだ。8086 だと push/pop が速いと思うが 8088 だと 2 回のアクセスになってしまうのでバイトアクセスのほうが有利だ。 あるいはメモリーではないが in 命令も調査には好都合か。 基本的なバスサイクルは確か同じだし、%dx のバイトアクセスを使えば 8 サイクルと短い。 この 8 サイクル、実はプリフェッチが絡んでるんじゃないかなーと。1 バイト分のプリフェッチをして、その後にアクセス... ないかな? なお MOV CS 実験プログラムが %dx に文字コードを入れてしまっているので、アクセスするポートは 0x30 にする。

んー、予想は外れた。 この様子だと in %dx, %al 命令の間にプリフェッチはなさそうだ。 なお in $0x30, %al だと 10 サイクルのはずで、その場合はプリフェッチはしてそうな感じか。 フーン。

2019/12/06 のコメントを読む・書く


07 (土)

%1 どようび

毎年恒例、大根掘り。 寒かったが雨はほぼ降っていなかった。4 本のはずが、小さいのが混ざって 6 本出てきた。 一部 2 本並んで育っていた。 例年よりも短い大根、ちらりと品種が変わった的な話し声が聞こえてきたからそういうことなのかも知れない。

%2 FreeDOS

久しぶりに FreeDOS で遊んだ。FreeDOS のインストーラーがエラーになるのはなぜかと思えば、どうも仮想マシンの BIOS, Debian GNU/Linux のパッケージで入っている seabios がバグありで、CD-ROM ドライブへのアクセスがうまくいかないらしい。USB メモリーのインストーラーが配布されているので、そちらを使えば簡単。

FreeDOS 1.1 だったかの頃は、インストール時に追加パッケージの選択画面みたいなのがあった記憶があるんだけど、1.2 の今はそういうのがない。 フルインストールにしてもたいした容量は食わず、どうなっているのかと思っていたら、FDIMPLES というコマンドで追加パッケージをインストールできるらしい。 へぇ! 最初の AUTOEXEC.BAT に、ひとことそういうコマンドがあることを表示するようにしてあったらうれしい。 とても覚えにくいコマンド名だし。

最近遊んでいる Portfolio と違って、リソースが大変リッチな環境で遊ぶので、DOS エクステンダーも使うことができる。 パッケージで DJGPP を一通りインストールして、それっぽいところに PATH を通して gcc と元気よくたたくと SIGSEGV でクラッシュしてしまった。 あれれ? 調べてみると DJGPP 環境変数に DJGPP.ENV ファイルのパス名を設定しておかなければならないらしい。 そんなんだったっけ? 前に使ったのはわずか 20 年前のことだが記憶にない。 なお、20 年前の設定を発掘してみたところ、環境変数の設定は以下の内容だった:

set go32=fast nodpmi
set go32tmp=a:\temp

当時使ってみたのは 25 年前の gcc 2.6.3 ベースのもの、DJGPP 1.12 だったようで、それの黒木秀和氏配布の Shift_JIS 対応版、ベクターの PACK10000 か何かに収録されていたものである。 そのときは a.out 形式で出力されていたようで、実行の際に go32 コマンドを使わなければならなかったんだったかな。 今は普通に EXE ファイルが出力され、普通に実行できるようになっている。go32 も今は go32-v2 になっており、試しに昔の a.out を突っ込んだら "go32/v2: cannot find v1's go32.exe" というとても丁寧なエラーメッセージが出た。 そして高校 2 年の倫理の勉強に使ったらしい... さすがに 16 ビットの LSI C-86 試食版でも十分動きそうなデータ量だが...

ま、いいや。 今の FreeDOS なら、DJGPP のインストールは楽勝だし、なんと gdb まである。 まである、なんて書いたが、PACK10000 のコンテンツを確認したらちゃんと gdb もあった。 当時知らなかっただけだ。 なお当時の gdb のバージョンは 4.12、今は Debian の安定版で 8.2.1, gcc は 8.3.0 になっているので、特に意味はないけど gcc のほうが番号の進みが速いようだ。

さて、gdb で試しにプログラムを途中で止めてみると、コードセグメントのセレクターは 0xe7, データは 0xef, そのほか 0xdf と 0xff がロードされている。 ほー。 わざわざ LDT 使って、特権レベルもちゃんと 3 なんだな。IOPL も 3 に設定されているから、I/O 命令や割り込み禁止は OK だ。 オフセットアドレス 0 はアクセスできないので、一応 NULL ポインター部分はアクセス禁止にしてあるらしい。 それで、すぐ次の 0x1000 からデータだかコードだかが入っている。 これがどうも、セグメントベースが 0 ではないらしい。 知らなかった。 セグメントベースを得るには __dpmi_get_segment_base_address (_my_ds (), &base) のようにするらしい。DPMI か、そういえば昔ちょっとだけ試したっけ... 1996 年 8 月、はじめて読む 486 を読んでいた頃か。 確か VCPI を使うプログラムも書いたんだけどな、行方不明か。

2019/12/07 のコメントを読む・書く


08 (日)

%1 にちようび

いい天気。 家にいると意外と暖かい。

自転車のハンドルの高さを高くできないかと思って調べてみた。 六角棒スパナでハンドルのところのねじをゆるめて調整できるという話。 さっそく試してみたが、ねじがゆるまないw さび付いているようだ。 こういう時は KURE CRC 5-56 がぴったりだ。 小さな隙間にも浸透するので、ねじ山にしっかりと入り込んで動きやすくしてくれる。 予想通り、ほんのちょっと 5-56 を吹きかけただけで、ゆるめることができた。 で... ハンドルを引き上げてみると、ステムというのかな、あれが結構短くて、MIN の表示とその上に ||||| という感じの線があったのだが、その線のすぐ上あたりで使っていたことがわかった。 これ以上高くするには部品を取り替えないといけないようだ。 まぁそれはいいとして、そのステムがとにかくひどい錆びだw 15 年経つとこんなになるんだなw 錆びを軽く落としておいた。 なお寒くなるとハンドルの動きが悪くなる原因っぽいのはこのステムのほうではなくて、ステムがささる側のカバーに亀裂が入っていてそこから汚れが侵入しているみたい。 前にその隙間からオイルを流し込んだら改善したのでそのまま使っているが、きっと中は元のグリスと汚れとオイルでひどいことになっているに違いない。

スクーター (アドレス) の後輪ブレーキの戻りが最近だいぶ悪くなってきたので、調べてみることにした。 ドラムブレーキの側の問題か、ワイヤーの問題か、いずれかっぽい。 ドラムブレーキ側はワイヤーで引っ張られる部分が外から見えているので、そこを手で押し込んでみたところ、戻り具合はいい。 やはりワイヤーのほうか。 それで、とりあえずレバーのところからワイヤーまわりに注油をしてみようかと思ったんだけど、そのためには前のカウルを外さなければならない。 手探りでねじを外していったら、まず前の荷物入れが外れた。 次々にねじを外してはカウルを揺すり、どこが固定されているかいろいろとのぞき込んで見つける。 最後は爪で引っ掛かっているようなので、ヨーグルトの空き容器の縁を突っ込んで爪を外し、前のカウルは取れた。 結局荷物入れを外す必要は無かったことがわかったので、荷物入れを取り付けようとしたら、なんか変なタコ足みたいなのがねじのところについている。 正式名称を知らず、何とも説明しづらいのだが、4 本のタコ足を閉じた状態で突っ込んで、中で開いて取れにくくする部品っぽい。 それを突っ込み直す必要があって、困った。

で、凧糸の代わりにデンタルフロスを持ってきて、たこ足のところに巻いて閉じた状態にして、差し込み、糸を引き抜いた。 何とかうまくいった。 それで荷物入れは戻したからいいとして、ヘッドライトまわりのカウルも外さなければブレーキレバーの根元にアクセスできない。 そのためにライトや方向指示器のスイッチ付近のねじ 2 本と、ヘッドライトの下のボルトとねじをひとつずつ、ゆるめて、外そうとしたが、爪がしっかり引っ掛かっているみたいで外れず... 日が暮れそうな時間になってきたので、そのへんで諦めて元に戻した。 荷物入れを戻すとカウルを固定するねじひとつが回せない位置にあって困ったが、なぜか小さなソケットレンチがあったので何とかなった。 このソケットレンチは何のために買ったんだったか忘れてしまったが、役には立った。

%2 bcc

FreeDOS で 16 ビットの C コンパイラーのパッケージを見ると、Open Watcom とか Bruce's C compiler (bcc) とかがある。 なんだその Bruce さんのコンパイラーって、おもしろそうじゃないか、と思って入れてみた。 ちょっと低機能なのかな、perror() はないし、今時極めて珍しい K&R スタイルである。 つまり引数の型を名前と一緒に書けないアレ。 変数宣言もブロックの先頭でやらないといけない。 ただし、なぜか auto 変数の初期化で関数呼び出しをするのは OK。

で、一応インラインアセンブラーにも対応していて、asm() か、または、#asm と #endasm で囲むらしいのだが、引数を渡すなどの賢い機能は一切ないようだ。LSI C-86 みたいに通常の関数に渡す引数と同じようにインラインアセンブラーに引数を渡す機能もなさそう。 試しにいろいろ書いてみたが、文法が独特なのも少し気になった。 変数名の先頭に _ が付くのは割と一般的だが、変数のアドレスを参照する場合は変数名の手前に # をつける、即値は手前に * をつける、データ定義は .byte や .word を使う、など。 意外だったのはインラインアセンブラーが 32 ビット命令にも対応していること。 あと、デフォルトで .COM 形式のファイルだけど、コードセグメントとデータセグメントが異なるというのも特徴的だと思う。C だけで書いていたらメモリーを大量に使いたい時でない限り気にもとめないが、インラインアセンブラーを使うなら意識しておく必要がある。

で、なんと bcc は GNU/Linux でも動くらしくて、Debian パッケージもある。 が、GNU/Linux 上ではデフォルトでは違うフォーマットで出力されるみたいだ。-Md オプションを付ければ .COM 形式になった。

2019/12/08 のコメントを読む・書く


09 (月)

%1 Portfolio

数日ぶりにポチッと電源を入れて、dir コマンドを入力したところで、Battery Low だか Low Battery だか、メッセージが出て、シュッと電源が切れた。 ふむ。 とりあえずで突っ込んであったマンガン乾電池を抜き、代わりに新品のアルカリ乾電池を突っ込む。RAM ディスクの中身どころかプロセッサのステートまで保持されていた。 ほー、なるほどよくできている。 日本では言語の問題があって実用性は厳しいけど、英語圏の国でそこそこ売れたというのも理解できる。 どれだけ売れたのか知らないけど。

今日は簡単な実験。 セグメントレジスターの MOV 命令は 2 バイト目のビット 3〜5 でセグメントレジスターを指定するのだが、セグメントレジスターは 4 つしかないのでビット 5 を使うとどうなるのか? という疑問、80386 以降は %fs と %gs を選択するのに使っているが、まぁ 8088 ならビット 5 は無視されるだろうことは容易に想像が付く。 先週のプログラムで実験。

 31c08ec08ce8508ce050 24121 0000 0366

ふむ、予想通りだな。 次に GRP2 の 6, シフト命令が空いている部分。 当然 SHL/SAL 命令じゃないかと思うんだが、実験してみる。

 b84567d1f050d1f050d1f050d1f050d1f050 321
 21212121 FFFF FFFF FFFF FFFF FFFF
 b84567d1e050d1f050 32121 FFFF CE8A
 b80000d1f050 321 FFFF
 b84567d0f050 321 67FF

予想は外れた... っていうか全ビット 1 になるのは完全に予想外だw マジかよw なお今の Intel プロセッサも例外は生成せず SHL/SAL 命令の挙動をしているみたいだ。 つまり 80C88 の頃はあえてそうはしていなかったということか。 衝撃... なお、Undocumented 8086 Opcodes, Part I | OS/2 Museum に載っている解説とも完璧に一致している。 ふむむ...

衝撃を受けたところで、もうひとつ簡単な実験。GRP5 の 7, 隣の 6 は PUSH 命令だが、7 は空いていて謎である。 気持ち的には POP 命令が入っていれば対称性があって納得しやすいのだが、なぜか POP 命令は 0x8f が使われていて、GRP5 のここは空いているのである。 さっそく試した。

 0efff850 121 01B4 01B4 0366

POP 命令を期待して作った機械語だったが、なるほど隣も PUSH 命令か... これはこれで納得できるものがあるな。

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


Powered by Tomsoft Diary System 1.7.4

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

トップ / 日記索引 / 日記 (2019 年 12 月上旬)

Hideki EIRAKU