/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 のコメントを読む・書く


10 (火)

%1 8088

8086 Architecture

この図を見て悩まされている。ALU とつながる内部のバスが 16 ビット。 このバスは共用なのだろうか? つまり、複数の 16 ビットレジスターの内容を同時に ALU に食わせることはできないのだろうか? Temp.Registers の存在もあって、できないというのもあり得るとは思う。

問題はシフト命令のクロック数で、1 ビットのシフト命令は、なんと 2 クロックで済むということになっている。 シフト命令もフラグの反映があるので ALU での処理と見て間違いないだろう。 また、1 ビットシフトなので 1 入力 1 出力で、インクリメントなどの命令が 2 クロックというのに近い。 しかし、2 クロックの INC 命令が 1 バイトなのに対し、シフト命令は 2 バイトである。 そして 2 バイト目を見ないとどのレジスターに対する操作かがわからない。 レジスター同士の足し算などの命令は 3 クロックだが、全加算器がキャリーを処理していくのに時間がかかるからかとも考えた。 しかしそれでは論理演算命令も 3 クロックなのが説明できない。1 クロックの間に 2 バイト分の命令の処理ができるのか? 3 クロックかかる 2 バイト命令は 2 オペランドだからか? それも 2 バイト分の命令のデコードは 1 クロックで済んで、レジスターを 1 個ずつ内部バスで転送しているから 3 クロックなのか? ウーン... 2 バイト 2 クロックの MOV CS 命令の時に半分の時点で %cs が変わっているっぽかったのも気になるし...

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


11 (水)

%1 すいようび

12 月中旬にしてはやや暖かい日。 職場近くの銀杏の色づき具合が、先週頃は日当たりの差でバラバラになっていておもしろかったけど、だいぶマシになっていた。 とはいえ、まだほとんど散っていないあたり、去年以上に変な感じ。

夜帰る頃に、職場近くの駐車場に駐まっていた車が濡れているのに気づいて、あれ、雨降ったんだな、みたいな感じで、まったく雨に降られることなく帰宅できた。

%2 Portfolio

Grp3 の 1, TEST 命令の隣が TEST 命令かどうかを調べた。

 9c50f6c8019c50f6c8049c50 11311311 01B4 F102 01B4 F146 01B4 F102
 9cf6c0019cf6c0049c 13131 F102 F146 F102

値も変わっていないしフラグは同じで TEST っぽい。

しかし... ここでまた発見があった。 フラグレジスターのビット 12〜15 が必ず 1 だというのは、Intel のマニュアルにも書かれている話で、まったく問題ない。 問題はビット 1 で、80x86/80x87 ファミリー・テクニカルハンドブックという本には、8086 のフラグレジスターはビット 1 が 0 だよ、と書かれていたはずなのだが、今ここで見えているのは、Intel 80C88 のフラグレジスターはビット 1 が 1 ということだ。 はぁ。

じゃ、JX に積まれていた 8088 はどうだったか? というと、メモリーダンプを保存した時のデータが手元にあって、ディスケットに書き込むプログラムごとまるまる残っていたのでスタック領域もそこに含まれていた。 その中でそれっぽい値を見つけると、0xf246 というのがあった。Disk BIOS を呼び出した時のものだろうか、割り込み許可でゼロフラグが立っている、ありがちなやつだ。 さらに、BIOS の中で発生した割り込みらしき、0xf800 の手前に 0xf093 というのも残っている。 ビット 1 は立っていることになる。 意外と本もあてにならないよな...

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


12 (木)

%1 東京大学

仕事で某 Summit のため昼頃から東京大学へ。 学食に行ってみると昼間の時間帯は学生教職員優先で部外者は遠慮しろとある。 なかなか面倒な大学だ。 筑波大学ではそんなのなかったのに。 それで学外のカレー屋さんに入ってみるとなかなかよかった。

帰りはなんか途中駅で非常停止ボタンが扱われたとのことで駅間で非常停止があった以外は普通だった。 なんか、非常停止、体感でわかるな。 立っている人の一部がバランスを崩すほどの減速感、やや常用ブレーキより強く感じられる。 怪しいなと思っていると、緊急停止しますの自動音声アナウンス。 そこまで来てもボケッとしている人達は構えができておらず、停車寸前にばたばたとバランスを崩していく。 おいおい。 非常制動入ってたら運転士でもゆるめられないもんな。

%2 Portfolio

まだまだ undocumented instructions を試す。

fed050 00000000000000000000...

CALL AL? にあたる機械語、まさかの無限ループw こりゃなかなか難しいかな? まぁもうちょっと試そう。

31c0fed0 2A 0002 0366 F146 F1B8
31c0ffd0 2A 0002 0366 F146 01B8
31c0fee0 2A 0002 0366 F146
31c0ffe0 2A 0002 0366 F146

%ax をゼロクリアしてからの CALL AL, CALL AX, JMP AL, JMP AX 相当、なんか CALL AX と同じような挙動をしているように見える。 が... よく見るとスタックに差異があるな。 しかし 0 番地に cd 20 入ってないのかな? いやこれ割り込みのスタックか? 割り込みって TF クリアされるんじゃなかったっけ? まぁいいか。

31fffed7 2B F1B8
31ffffd7 2B 0002 0366 F146 01B8

%di で試そうとしたやつ。 よく考えたら %bl になっているような気がする。 全然違う結果になったなと思っていたがそのせいか。 しかし 01B8 のところが戻り番地のはずで、それが F1B8 と push されている。

50fef050 121 01B4 F1B4 01B4
50fef850 121 01B4 F1B4 01B4
31c0fef0 22 F100
31c048fef0 212 F1FF

PUSH AL にあたる機械語、1 バイト分だけスタックに積まれているように見えるw 上位 8 ビットが 0xf1 って何だろうと思っていたが、もしかしてこれ、TF 立てているから必ずスタックにフラグが残っていて、その上位 8 ビットが見えているだけかも。 もうちょっと試したいが、ま、いいや。 気分を変えて LEA AX,AX を試そう。

8dc050 21 FFF8
8dc150 21 FFF8
8dc851 21 FFF8
508dc050 121 FFF6 01B4
a100008dc050 321 FFF8

ふん、なんかどれもスタックポインターっぽいな。 もしかしてこれも TF のせいか? 試しに MOV SS を使ってみる。

8c1600018e1600018dc050 461 0100

ほぅ、0x100 が出てきた。 前の EA (Effective Address) がそのまま出てくるっぽい感じが... まぁありそうな話だが、そうなると TF クリアして試したほうがよさそう。

9c519da100008dc09d50 1118 0000 0000
9c519d90a100008dc09d9050 1119 0000
9c519d9001c88dc09d9050 1118 FFF6
9c519d90f6e48dc09d9050 1118 FFF6
9c519d90ac8dc09d9050 1117 0001
9c519d90ad8dc09d9050 1117 0002
9c519d90e2008dc09d9050 1117 FFF6

TF を消して試したいろいろ。 ちょっと POPF で面倒な感じになったので NOP を入れた。mov 0,%ax 後に LEA AX,AX すれば 0 が出てくる。 つまりクロック数計算に +EA が出てこない命令でも、メモリーアクセスで使ったっぽいアドレスが残っている。 レジスター同士の ADD 命令や MUL 命令では、変化しないらしくスタックのアドレスが残っている。 そして LODSB を試したら 1, LODSW を試したら 2 が出てくる。LOOP も試してみたらこれは変化はない。 何なのかというと、LODSB がアクセスしたのは 0 番地なのに、1 が出てくるってことは、LODSB の後の %si の更新で EA として残っているアドレスが変化するということ。 よくわかんないけど +EA のシステムと同じ計算機能を使っているのだろう。 それで LOOP も (フラグが変化しないので) EA を使うのかと一瞬思ったが、関係はないわけだ。

あとスタックポインターも POP の後、足した後の値が残っているのはおもしろいところ。8086/8088 が PUSH SP の際に 2 引いてから SP を書き込んで、POP SP の際は 2 足してから SP に書き込むので POP 前に戻ってしまうのは有名な話。 しかし 2 足した後の値が残るということは、POP 命令が BIU に SP のアドレスで読み取り要求を出してから、その結果をもらってレジスターに書き込む前までの間に、2 を足してレジスターに書き戻しているということか。

というわけでまたしても新発見をしてしまった。 残っている EA が読み取れるというのは、なんだかレジスターがひとつ増えたみたいで楽しい。

なお、全然別の Atari Portfolio の操作上の癖も発見した。Fn+O で電源をオフにするときは、Fn よりも O を先に離さないといけない。Fn を先に離すとその時点でオフになり、O を離した時にまた電源がオンになってしまう。

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


13 (金)

%1 きんようび

寒い日。

飯田橋と水道橋を勘違いして列車を降り、改札まで行ってから様子がおかしいなと思って調べて、また列車に乗り直すというあるある事例。 中央線の各駅停車 (中央総武線) の駅だということはわかるが、水道橋、飯田橋、市ヶ谷、あたりの位置関係はどうもあやふやな感じ。

%2 Portfolio

9c519d905159fef0589d9050 1119 00B4

フーン。 上位 8 ビットは前の値が残っている様子だから、やはりこれは、下位 8 ビットしか書き込まない PUSH 命令か。fef0 で push %al (?) ということ。

9c519d90fef4589d9050 1117 F001

ちゃんと push %ah (?) もできる。 例によって fefc にしても同じ挙動であった。JMP 命令や CALL 命令は挙動を調べるのが大変... せっかく TF で試すプログラム作ったんだからへんなところに飛んだ時の CS:IP を出すべきだった。 いや、それくらいなら簡単に試せそうだな。

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


14 (土)

%1 スクーター

スクーター (アドレス) の後輪ブレーキの戻りが悪い件の対策、先日に続いて再挑戦。 前カウルをすいすいと外し、メーターまわりをおそるおそる外したら何とかできた。 外してみてわかったが、ヘッドライトの向き調整用のねじは外さなくていいみたいだ。 方向指示器やヘッドライトはくっついたままでいい。

さて、カウルの裏にはママチャリみたいな金属製のハンドルが存在する。 スクーターのハンドルってこうなっていたのか。 確かに強度を考えると中まで全部プラスチックというわけにはいかないのだろう。 で、左側のブレーキレバーのところは、自転車なんかと同じようなものだ。 カバーを外し、ねじをゆるめ、ゆる、...、ゆるまない。 ウーン。 このねじをなめるわけにはいかないぞ...

それで、反対側のナットをゆるめようとしたら、方向指示器のスイッチの本体の部分が邪魔をしてソケットレンチが入らなさそう。 それで方向指示器のスイッチのねじをゆるめたが、あんまり動かせない。 ちゃんとスイッチを外さないといけないのか? とぐりぐりやっていた時、カウルがプラスチックなものだから、少し変形してソケットレンチが入りそうなことがわかった。 なるほどこうやるのか。 そんなわけで六角ナットは簡単にゆるみ、レバーを外すことができた。

そして、ブレーキワイヤーを、これどうやって外すんだっけな、と調べて、ずらしてワイヤーのところを合わせれば外れるのか、と理解して、何とか外せた。 引っ張られて作業しづらい時は、後輪タイヤ脇のブレーキを直接押し込めば多少マシになる。 で、ワイヤーに注油するのだが、手頃なオイルがないなと思って、とりあえずチェーンソーオイルを突っ込んでみたら、全然入っていかない。 ウーン。 何度も動かしながらちょっとずつ入れていったが、後輪タイヤ脇のブレーキを押し込みながらやるのはなかなか難しい作業である。 今思えばタイヤ脇のねじをゆるめてしまったほうが早かったな。

そんなこんなであんまり注油できた気がしないまま、手で動かしているとなんか多少軽くなっている気がした。 それでとりあえずワイヤーをはめ込み、レバーを元の位置に戻して、握ってみると、なるほど良好である。 ブレーキレバーに近い側がひどかったんだな。

それじゃ試運転だ、というわけで、ねじとカウル類を全部元に戻し (線を挟みそうになって焦った)、レバー位置の調整をしつつ出発。 良い。 かなり良い。 チェーンソーオイルを使ったのはちょっとアレだが、まぁいいか。 ジョルカブやジョルノなどと違って、アドレスの場合、ブレーキレバーのまわりまでカウルがガッツリある分、作業性はとことん悪いけれども、汚れの入りにくさという点では結構良いはずだし。 カウルだけでなく、ちゃんとブレーキレバーのねじの部分のゴムカバーまである。

%2 Portfolio

こないだのテストプログラムで lea 8(%bp), %sp のところの 8 を 2 に変えれば、フラグレジスターと CS:IP も見えるようになるので、バイナリーで書き換えて準備した。

JMP の前にまず PUSH 命令の確認。 バイト幅 PUSH にメモリーアドレスを指定してみた。0 番地には cd 20 が入っているのでそれを利用する。

fe360000 4 01B8 0366 F102 F1CD

メモリーアドレスの場合もやはり、SP は 2 引かれて、そこに 1 バイトだけ書き込まれる形のようだ。 それでは CALL 命令の確認。

fe160000 9 FFCD 0366 F102 F1B8

おっ? IP の下位 8 ビットしか書き込まれないのは PUSH 命令と同じだが、その後 IP が 0xffcd になっている。0xff はどこから出てきたのか? CALL FAR も試そう。

ff1e0000  20CD 16FE F102 01B8 0366
fe1e0000  FFCD FFFE F102 03B8 F166

上が通常の CALL FAR [0] で下がバイト幅の CALL FAR。 このコードに入ってくる直前の IRET 命令で使ったフラグレジスターの 0xf1xx と CS の 0x0366 が残っているはずと考えれば、CS:IP の書き込みもやはり下位 8 ビットしか書き込まれないようである。 そしてジャンプ先の上位 8 ビットが 0xff なのも同じで、セグメントもオフセットもそうなっているが、上と比較すると、ちゃんとセグメントがオフセット 2 から読み取られたらしいことがわかる。 読み取り長は 1 バイトにされてしまっているが、それ以外の SP の計算やダブルワードの読み取りでの 2 という数字はそのままなんだな。 さて 0xff とは...

81ec0001fe1e0000 4 FFCD FFFE F182 03BC F166 F206 F206 ...
8c1600018e160001fe1e0000 4 FFCD FFFE F102 03C0 F166

%sp を 0x100 引いてやることで、0xfe になるのでは、という期待を持っていたが、ならなかった。 また、0x100 番地を使って %ss に書き込んだ直後にすると 0x01 になるかも、という期待もあったが、ならなかった。 特に理由無く、単に 0xff になるのか。

さて、CALL FAR はすぐに止まってくれて実験しやすいので、もっとひねくれたことをしよう。CALL FAR AX はどうなる?

ffd8  0164 E000 F102 01B6 0366
fed8  0164 FF00 F102 03B6 F166
31c0ffd8 2 0164 E000 F146 01B8 0366
31c0fed8 2 0164 FF00 F146 03B8 F166
acffd8 1 0164 E000 F102 01B7 0366
acfed8 1 0164 FF00 F102 03B7 F166
ff36f8ff 4 01B8 0366 F102 24D7
ff36faff 4 01B8 0366 F102 E000
8c1600018e160001ffd8 4 0366 E801 F102 01BE 0366
8c1600018e160001fed8 4 0366 FF01 F102 03BE F166
1617ffd8 1 0164 E000 F102 01B8 0366
511617ffd8 11 0164 24D7 F102 01B9 0366 0004

どこから出てきた 0xe000, と思ったら見事にスタックポインター由来、いや、これは EA 由来だ。mov 0x100, %ss を入れたテストで 0xe801 の 0x01 はテストプログラムの最初の mov の最後のバイトで、0xe8 は次の call の最初のバイトなので、EA を見ていると言ってよさそう。 しかし最初の 0x0164 の由来がわからない。0xfff8 に書き込まれているのは 0x24d7 らしいし、%ax に入っているのは開始番地の 0x01b4 である。 いや、31c0 は xor %ax, %ax でつまり %ax を 0 にしても結果は変わらない。ffd9 など、違うレジスターを試しても結果は変わらなかった。

テストプログラムのバイナリーを見直すと、そうか、コード開始前とトラップのリターン前に書き込んでいる to のアドレスが 0x164 だ。 しかし EA はその後の pop と iret で変化しているはずだし、それだと mov 0x100, %ss の後だと 0x100 にならないとおかしいような? とにかく何らかのチャネルに残された値がそのまま出てきているということか? なんもわからん。

いや、ひょっとして、LES 命令でも同じことを試せる?

c4d85306 211 01B8 0366 F102 E000 F102
9c519dc4d88dc09d90530650 111711 01C0 0366 F102 FFF8 24D7 F006

んー? 違うのか... わからん...

ところで、関係ないけど LES 命令の後って割り込み禁止になるのかどうか。

c43f90 21 01B7 0366 F102

ならないみたいだ。

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


15 (日)

%1 クリスマスパーティー

某研究室のクリスマスパーティーに顔を出してみた。

バイクで、行きは首都高・常磐道経由。 首都高の中央環状線の一部が工事で通行止め、さらには 6 号が中央環状線と交わるあたりから渋滞、また 6 号に分岐するところが工事中で車線規制だった。 まぁバイクだったのでするっと割り込み...

帰りは一般道で。 寒い! 橋のところで気温 5 度と出ていて、そりゃー寒いわな。GOLDWIN のインナーグローブというのを買ってみたので試してみたんだけど、ごわごわして操作しづらい割には指先は冷えるという結果に... 環八通りまで来てやっとマシな気温になった。

%2 Portfolio

LES 命令にメモリーオペランドを指定しなかった場合の挙動、どうも最後にアクセスしたメモリーの内容が出てくるっぽいんだな、これ。

9c519d3904c4d88dc09d90530650 111911 01C2 0366 F102 0002 16FE 20CD
9c519d3804c4d88dc09d90530650 111911 01C2 0366 F102 0002 16FE FFCD
9c519d803e000101c4d88dc09d90530650 111C11 01C5 0366 F102 0102 E801 FFBF
9c519d833e000101c4d88dc09d90530650 111C11 01C5 0366 F102 0102 E801 B4BF
9c519d823e000101c4d88dc09d90530650 111C11 01C5 0366 F102 0102 E801 FFBF
9c519d803e010001c4d88dc09d90530650 111C11 01C5 0366 F102 0003 0016 FF20
9c519dc6060001dec4d88dc09d90530650 111C11 01C5 0366 F102 0102 E801 FFDE
9c519dc606000178c4d88dc09d90530650 111C11 01C5 0366 F102 0102 E801 0078
9c519d880e0001c4d88dc09d90530650 111B11 01C4 0366 F102 0103 E801 0004
9c519d50c4d88dc0599d90530650 111911 01C2 0366 F102 FFF6 F102 01B4

で、バイトアクセス時の上位 8 ビットが 0xff なのはやはり内部の挙動なんだな。 と思ったんだけど 0x78 のところ符号拡張だな... つまり、読み取り時は符号拡張ではなく 0xff が入るっぽいが、書き込み時は符号拡張になるのか。 即値で符号拡張を使うケースが (上の cmpw もそうだけど) あるので、使うにしろ使わないにしろ、符号拡張がされているというのは変ではない。 ま、それはいいとして、EA の他にデータが残る場所があるってことだ。BIU 側の内部レジスターなのかな。

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


16 (月)

%1 休暇

久しぶりに天気のいい平日休暇。

整形外科。 こりはともかく、痛みがなければ来なくて大丈夫、痛みが出る時は集中的にリハビリに来たほうがいい、的な。 ふむ。 最近は横向いて寝られるのでだいぶ調子はいいほうなんだよな。

武蔵境通り、なんか工事していたのは終わって片側 2 車線の区間がかなり伸びたんだな。 何も知らずに軽い気持ちで原付で通って、予定外の二段階右折をする羽目になった... ここを通るバスの時間もだいぶ安定するようになったんじゃないかな。

レンタルカート。 飯能。3 回乗ってベストタイムは 33.96 秒くらい。 何度か 7 コーナーでジャンプしてしまった... インリフトを意識してみたら、7 コーナーもできてはいるが、そこからアクセルをポンと踏んで、外側しか接地していない後輪がそれでグリップの限界を超えて滑って横向きの力が生まれ、その結果内側の後輪も接地するというだめパターン。 慎重な操作が必要だ。 スタッフさんよれば 4 コーナーと 9 コーナーは意識的にリフトさせるそうだ。 なお 4 コーナーは確かに浮くんだけど、それは高速からの減速があるからで、浮かせるのたのしーとやっているとクリッピングポイントを外してしまう気がする。 たぶん、後輪しかブレーキがないのに、その片方が浮いてしまうことで減速の力が足りていないような、つまりもっとまっすぐの状態でちゃんと減速したほうがよさそうな感じかなぁ。 まぁともかく、自分はもっとステアリングの操作を精密にするべきだとは思った。 もちろん 10 年前の自分と比べれば遙かにいいけど、意識しながら走ってみるといろんなところで雑に回していることがあるのに気づくので、それがタイムが安定しない要因のひとつなんだろう。

飯能へは車で、東青梅ルートを使ったんだけど、帰り、ボケッと走っていたら橋を渡るのをすっかり忘れて都バスが走るルートを行ってしまった。 頭の中で道順が整理されておらず、交差点の順番が混乱していたせいでもある。 そうしたら成木五丁目の交差点にパトカーが何台か駐まっていて、何かあったっぽい雰囲気。 なんだろうな。 道を間違えていたのに気づいたのはその後の交差点だった。 別に方向は間違えていなかったけど、なんでこっちの道に来たんだっけとそのときは首をかしげていた。

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


17 (火)

%1 かようび

朝は雨。 しかも寒い。

テレビドラマ『新米姉妹のふたりごはん』、フォアグラでてきちゃったし、「ちょっとフランスに行ってくる」ってせりふもなかなかw しかし美味そうに食べるなぁ。

テレビドラマ『釣りバカ日誌』の再放送をやっているっぽいだけでなく、TVer に過去作の『弁護士のくず』と『結婚できない男』が出ているのを見つけてしまった。 全話はないのかも (よく見ていない) だけど『弁護士のくず』は原作もドラマも全部見たし懐かしいな。

%2 Portfolio

そういえば TF をセットするのに POPF の後に NOP を入れておかないと変な挙動をするなぁ、というのがあったので少し試した。

9c519d9d9090909090 1113111 01BD 0366 F102
9c519d9d87c0909090 111411 01BD 0366 F102
9c519d9d2687c09090 111411 01BD 0366 F102
9c519d9d262687c090 11151 01BD 0366 F102
9c519d9d26262687c0 1116 01BD 0366 F102
9c519d9da900009090 11151 01BD 0366 F146
9c519d9db800009090 11151 01BD 0366 F102
9c519d9df7c0000090 1116 01BD 0366 F146
9c519d9df74600000090 1117 01BE 0366 F146
9c519d9deb009090 11141 01BC 0366 F146
e2fe 0002 01B6 0366 F146
9c519d9de2fe 111102 01BA 0366 F146

ははーん。TF をセットする POPF 命令の、すぐ次の命令の実行後に割り込みが発生するのが今時の x86 だが、当時は次の次の命令の実行後になっているっぽいな。 ただし、プリフィックスを 1 命令として数えて、だ。 なのでプリフィックスをたくさん付けて命令長を無駄に伸ばせば、今時の x86 と同様に次の命令で発生する。 最初はプリフェッチキューが関係あるかと思ったが、eb00 でわかるように、プリフェッチキューは関係ないようだ。

f4f4f4f4 1111 01B8 0366 F102
fb9c519d9df4 1111 1545 E000 F002 01BA 0366 F302
9c519dfbf4f4f4f49d9090 1118 01BF 0366 F102

これはおまけの HLT の実験。 試行錯誤の結果うまく取れる方法が見つかった。 なんと TF をセットしたまま HLT しても、止まってくれないw POPF の次の命令直後に割り込みが発生しないのを逆手に取り、POPF の次に HLT を入れると、いい具合に HLT に入るってことかな。TF をクリアしておいて HLT に入るのは OK, 何個か並べておいたら、キーを 2 回ほど押すまで先に進まなかった... つまりタイマー割り込みは毎秒 1 回も発生していないようだ。 カーソルの点滅もハードウェア側だな。

なお、Linux KVM 上で試したら fb (sti) 入れただけで hardware error 0x80000021 が出たww そんなバカなw

How does single-stepping on the 8086 interact with internal and external interrupts? - Retrocomputing Stack Exchange

TF の話はこちらにも載っている。8088-1 だが説明を良く読むと次の次の命令というのは同じ挙動のようだ。 ここでは外部割り込みも絡んでおもしろい話になっている。 通常であれば INT 1 の中が割り込み禁止で、IRET で割り込み許可になっても、その直後の命令で外部割り込みは発生しないはず。 たぶん。 しかし INT 1 の中で IRET の直前に割り込み許可にしたら、うまく割り込みが発生させられるかも知れない。

c6066601b8fbe2fee2fe  1545 E000 F002 01BC 0366 F302

と思いつつこんな実験をした。 バイト数を表示するルーチンをつぶした上で、割り込み許可して何もしない LOOP。 止まっている間にキーを押す。 すると、割り込みは発生してしまった。 それも... LOOP 命令に戻る割り込み PUSH 後に続けてキーボード割り込みハンドラーらしきアドレスの PUSH である。 なんだこりゃ、と思ったが、これって動作としてはさっきの Stack Exchange の書き込みと一致しているわけか。 フーン。IRET 命令の直後に割り込みは発生しないのかと思ったが、そうでもないってことかな。

c6066601b8e2fee2fefb909090  1545 E000 F002 01BE 0366 F302

さらなる変形パターン。LOOP 後に割り込み許可、LOOP 中にキーを押す。 これも STI 直後に割り込み発生という結果。 しかしこれは? TF 絡みだからでは?

fb9c519de2fee2fe9d909090 1111 1545 E000 F002 01BE 0366 F302
9c519de2fee2fe9dfb909090 111 1545 E000 F002 01BE 0366 F302

ウーン、それっぽいかな。 ま、いいや。 この知識を使えば CALL FAR AX の件の詳細を追えると思う。

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


18 (水)

%1 すいようび

暖かい日... どうなっているんだ、この気温は...

%2 Portfolio

まだまだ試すぞー!

9c519de2fee2fe9dfbfa9090 111711 01C0 0366 F102
9c519c519d9d9d9d909090 111113111 01BF 0366 F102
9c519c519d9d909d9d9090 1111133 01BF 0366 F102
9c519c519d9d909d 111113 01BC 0366 F006 F102
9c519c519d9d9d909d9090 1111133 01BF 0366 F102
9c519c519d9d9d90 111113 01BC 0366 F006 F102
16161617171790 1114 01BB 0366 F102
16f317ac51 131 01B9 0366 F102 0004
1617f3ac51 1100021 01B9 0366 F102 0000
9c16519c519d9d9d179d9090 1111116 01C0 0366 F102
9c51169c519d9d179d9d9090 11111133 01C0 0366 F102

CLI の状態で外部割り込みが発生するのか実験、さすがに発生しなかった。 それから TF のクリアとセットを繰り返す実験、なんとクリアした状態でも発生した。 ほう。 それで検討のため少し POP SS を試す。 念のためと思って POP SS を連続して並べて実行してみたら、なんと全部の POP SS の間でシングルステップ割り込みは発生しなかった。 これは予想外! だから、PUSH SS までブロックがされちゃうバグ入り 8086 でも、動作に支障はないんだな。

ま、それはいいとして、それで POP SS が実は prefix 的な挙動なのではないかと疑って、prefix と混ぜて使ってみた。 が、さすがに prefix とは別扱いだ。 割り込みが発生しないだけ。POP SS 直後に REP も試したけど、最初の 1 周分の後はちゃんとシングルステップが働いている。

それで... だ、POPF で TF=1 に戻した時、その次の次の命令の実行後にシングルステップ割り込みが発生するというわけだった。 なので、TF=1 にした命令の次で TF=0 にして、その次に POP SS を入れたらどうなるか? というと、TF=1 は無かったことになった。 ここまで見て思ったのだが、TF=1 にした命令の次の次の命令というより、TF=1 にした命令の次の命令の実行前に TF はちゃんとチェックされていて、しかしその命令がもうひとつ次の命令まで割り込み禁止のように扱われて (STI 後の割り込み禁止的な)、それで遅れているように見える感じがする。 なので POP SS を入れればまた 1 命令割り込み禁止が働いて、シングルステップ割り込みも禁止対象となり忘れ去られたのでは。 でもこれきのうの実験でそのタイミングで外部割り込みが発生しているから、完全な割り込み禁止ほど強力ではなさそう。

あときのうの TF=1 でも外部割り込みが発生するやつ、ひょっとして受け付けた外部割り込みが 1 命令分の扱いになっている? 機械語があるわけじゃないので 0 バイト命令だけど。 それならきのうの fb9c519de2fee2fe9d909090 実験で 9d90 の次で割り込みが発生したのも納得だし、そのときに割り込みハンドラーの入口でシングルステップ扱いになるのも納得できる。 以下の通りキーボードは割り込み 9 でベクターは E000:1545 になっている。

31c08ed8ff362400ff362600 264 01C0 0366 F146 E000 1545

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


19 (木)

%1 もくようび

ついに職場で流行性感冒感染者が発生。 社長!

TVer で久しぶりにテレビドラマの『弁護士のくず』を見た。 懐かしい。 ドラマを見ていると原作漫画を思い出した。 今は同じ作者が刑事ものを連載しているが、くずの主人公の顔は今思い出しても特徴的だったな。 なお今の刑事ものもある意味くずである。

%2 Portfolio

まだ CALL FAR AX の実験にたどり着けていないw この中では最初に書いた項目が興味深くて、命令実行後のシングルステップ発動前に外部割り込みが割り込むんだな、と。 この前見つけた書き込みでは、シングルステップのハンドラーの中で割り込み信号が来ると、IRET で割り込み許可になるとともに割り込みハンドラーに飛んでその入口でシングルステップ発動するという話だったので、割り込みチェックは命令実行前なのかなと思うんだけど、何がなんだか。

さて、TF に関する IRET と POPF の挙動の違いを見ていると、IRET で割り込み許可にした場合、次の命令を実行する前に外部割り込みが発生する場合があるとしか思えない。 それを検証する方法を考えていて、ひらめいた。 わざとフラグレジスターの予約ビットを異なる値にして IRET 命令を実行する。 そしてすぐ次の命令でスタックを読む。 割り込みが発生していたなら、予約ビットは固定値に戻るはずである。

というわけで、IRET で割り込み許可にすると直後の命令で割り込みが発生することが検証できた。TF=1 にした時の挙動とも整合性が保たれているし納得。8086 のマニュアルっぽい資料で、IRET も STI も、次の命令が終わるまで割り込みが発生しないと書かれているものがあったが、この実験結果からすればそれは間違いということになる。

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


20 (金)

%1 きんようび

テレビドラマ『結婚できない男』。2006 年のやつ。3 話まで見た。 なるほど、『まだ結婚できない男』と雰囲気はかなり似ている。 何より主要な登場人物が同じだし、同じ設定の人物がいる感じだ。 ほー。 折りたたみ式の携帯電話を登場人物が皆使っているのがちょっと懐かしい。 あと、高島礼子は同時期の『弁護士のくず』と両方出ていたんだな。

%2 Portfolio

CALL FAR 実験!

楽しい。 少し見えてきたんだけど、CALL FAR AX で出てきているオフセットアドレスは、計算だけでも変化するということは、ALU の入力側テンポラリーレジスターなのでは? それは 2 個あることになっていて、計算に使う入力値を置いておく場所のはずだが、その片方が見えているというならだいぶ納得できる話ではある。 以下はすべて想像だが...

そうすると調べるのは結構やっかいなんだけれども、おそらくは LEA AX,AX で出てきた EA は BIU 側のテンポラリーレジスターに保持されているものと見ていいと思うし、LES AX,AX の最後のメモリーアクセス結果というのも EA とは別に BIU 側のテンポラリーレジスターに保持されているのではないかと思うし、そしてスタックポインターの計算は BIU 側でできてしまうのか、あるいは、ALU に +2, -2 の演算機能があるとするならば、足す側のレジスターは使わずに演算が可能か。INC で変化しなかったから、INC 2 回的なことをやっていたとしても確かに変化しないことになる。 もし、EU が 8086 と 8088 で共通で、BIU が 16 ビットアクセスを 4+4 クロックですませられるということであれば、BIU 側で +1 の計算ができても不思議はなさそうな感じはしている。16 ビットアクセスしても EA に +1 のアドレスは残っていないしな。

そうそう、DOS のシェルの懐かしのコマンドライン入力操作、意外と覚えているもので、右矢印キー (または F1 キー) で直前のコマンドから 1 文字ずつ取り出し、左キーで 1 文字削除 (バックスペースと同等)、F3 で残り全部取り出し、Del キーで直前のコマンドを 1 文字削除、Ins キーで直前のコマンドに挿入するかどうかの切り替え、Esc キーで全部取り消し (\ が出て改行表示は大昔の UNIX の @ みたい)、的なやつ。Ins キーが最初きかない気がしていたが、Fn キーでちゃんと使えた。 なおファンクションキーは Fn を押して離してからの操作が可能だが、Ins キーとか電源オフ (O) とかはだめみたいだ。 他に F2 キーで直前コマンドから指定文字手前までまとめて取り出しもあったな。 細かいことは忘れたけど、この程度の雑な知識であとは触ってみればだいたいわかるもの。

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


21 (土)

%1 どようび

テレビドラマ『結婚できない男』、4〜6 話を見た。 この主人公は病院行きまくりだなw

テレビドラマ『弁護士のくず』、2〜4 話をまとめて見た。 各話 1/4 ずつぐらいは記憶にあったかな... オープニングで画面が微妙に小さいんだけど、これアナログ放送とディジタル放送が両方あった頃の番組なので、4:3 画面一杯に拡大しても問題なく話が理解できるようにしてあったんだな。 いや、この頃ってたぶん、16:9 では上下が少し切れていて、4:3 では左右が少し切れていたのかな。 『結婚できない男』もそうだな。

テレビドラマ『新米姉妹のふたりごはん』、またしても女同士でほんわか雰囲気のちょっと百合っぽさを醸し出していたがw 次が最終回ということで、これはやはりこのまま両親は出てこないのかな。

テレビドラマ『孤独のグルメ Season8』、こちらは最終回。 シンプルにカツ丼かと思ったら、冷し麻婆麺も食べてるw たくさん食べるよなーこの人w

テレビアニメ『歌舞伎町シャーロック』、最初の頃の話は 1 話ごと完結に近い感じだったが、最近は殺人事件の話でごちゃごちゃしていてなぞめいている。 まぁそれはいいとして、USB メモリーのことを「USB」「USB」と呼ぶのが気になるよねw まるでカップ麺をカップと呼ぶみたいで。

テレビアニメ『名探偵コナン』、珍しく 3 話構成だった。 しかし舞台で話をする小五郎おじさんはマイクを使っていたに違いないのに、コナンが眠らせて袖から変声機使ったらすぐわかるだろw

%2 Portfolio

TF テストプログラム修正版。 いろいろわかってきたので仕様を大幅に変えた。

さて。

さてさて。

ふむ。JMP FAR/LES/LEA で取り出せる 3 つの秘密のレジスターがあって、JMP FAR がレジスター間演算だけでも変化しうる危ういやつで、LEA はメモリーアクセスがあれば変化するし LEA 自身でも変化して、LES も LEA と同じくといったところか? いや、LEA だけだと LES の結果は変化なしか?

まぁそれで、どうやら EA 計算に ALU が使われていることもわかったわけだけど、即値の MOV など計算がいらない場合でもどうも一時的な置き場所として ALU の手前が使われているっぽいわけで、その使われ方を調べていくのはなかなか骨が折れる作業と思われる。 試しにかけ算割り算を...

MUL 命令で掛ける数が残っているのは意外、複雑な演算だから、テンポラリーレジスターフル活用しているかと思った。DIV 命令のほうはテンポラリーレジスターを活用していそうな雰囲気がある。

そうそう、Grp3 の 0, TEST の隣の 1 を一応試してみたらやはり TEST のようだった。 簡単なテストしかしていないけど。 あとはいかにも無視されそうな 0x8f と 0c6 と 0xc7 の 2 バイト目の真ん中、0xc7 は試していないけど、やはり無視されている。

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


22 (日)

%1 にちようび

朝からのどの調子がおかしい。 乾燥しすぎだったかな、といっても湿度 35% ぐらいはあったし、なんか変。 それで午前中はよく寝たのだが、昼になっても変。 軽い咳も出る。 ウーン。 体温は、15 時頃の時点では 36.8 度程度で、平熱っぽい感じだった。

それが、夕方ぐらいになるとさらに体調に変化が現れ始めた。18 時頃に測った体温は 37.2 度、体内で免疫系ががんばり始めている様子だ。 風邪か、いや、流行性感冒の可能性も高い。 職場でもらったとすれば感染者と同じ部屋にいたのは水曜日 (感染発覚がその翌日)、潜伏期間 4 日は少し長いかも知れないが、あり得ないほど長いわけでもない。 あるいは、木曜日は朝晩公共交通機関 (鉄道) を使ったし、ランチの店や弁当屋でもウイルス遭遇の機会はあったと言える。

夜 22 時頃になると軽い頭痛も感じられるようになった。 体温は変化がないが、咳が出ると頭痛が響くというのも多少つらい感じはする。 まぁ、流行性感冒の合併症のハイリスクの対象ではないはずだし、ひとまずゆっくり休む他ないだろう。 一晩で治ればまぁ普通感冒だろうねでいいけど、今のところ一晩で治る気はしないな。

午後は、体調が怪しいので、家でおとなしく、Lode Runner (1983) というビデオゲームで遊んでいた。https://archive.org/details/msdos_Lode_Runner_1983_1983 で遊べる。DOS 版あったんだな。 ちょっとスピードがおかしい感じがする。 ずーっと進めていくとレベル 80 までたどり着いた。 古いビデオゲームでルールはシンプルだが、適度な難しさで各レベルが作り込まれているのが市販ゲームらしい。 いくら古いとはいえ Broderbund もよく許可を出したな。 えっ? 許可はないんじゃないかって? いやいや、まさかそんな...

%2 Portfolio

ふと思いついて WAIT と HLT を再び。TF と IF を同時に 1 にして実験。

たぶんだけど WAIT は配線がされていなくて永遠に終わらないのだと思うが、この命令、割り込み許可であれば割り込みを受け付けるんだな。 で、POPF で TF=1 にしたら、その直後の命令ではシングルステップがまだ起動しないから、WAIT も HLT も、静かに割り込みを待つ形。 いやまぁ、WAIT は WAIT 信号 (?) を待つんだけど、割り込みがあれば割り込みが処理されるので。 で、割り込みの時には REP と同様、バイト数固定で IP を引くようだ。 これはもう 8086/8088 の実装上どうしようもないんだろうな。 たぶん元の IP はどこにも残されていないんだと思う。80286 以降だと、一般保護例外みたいに問題を起こした命令から進まないままの例外というのが存在するけど、8086/8088 の頃はなかったんだから。 除算例外でさえも次の命令に進んでから発生するらしいし。

備忘録としてこれまでにわかった割り込み受付の挙動をまとめて擬似コードっぽくしておきたいのだが、なかなかうまく書けない。HLT/WAIT/REP ***S* は皆、内部で繰り返しつつ、割り込みが来たら次に進んだり中断したりする命令だ。 なので、命令を実行してから割り込みをチェックする、みたいなシンプルな話にはならないんだ。 それに加えて TF やら IF やらの遅延の挙動、もうカオスである。

優先度的にはゼロ除算やソフトウェア割り込みなど命令が原因のものが一番優先度が高いらしくて、その次が NMI, その次が外部割り込みで、最後にシングルステップらしい。 しかしシングルステップは IF が無関係なのと、TF=0 に変化していても命令の実行前の値が反映されてしまう特徴があるので、優先度の高い割り込みのハンドラーの入口でシングルステップ発動というのがあるわけだ。 で、そうやって考えていくと、最悪パターンはソフトウェア割り込みと NMI とシングルステップが同時に処理されるケースでは? NMI を好きな時に投入できる PCjr/JX みたいなマシンか、自分で組んだボードでも使わない限り試しようがないけど、3 つ同時、きっとあるんだろうなぁ。PCjr/JX でどうやって試せばいいかと言うと、セグメントレジスターへの MOV を 64KB 分埋めて、最後に INT 命令を入れて、その入口に TF=1 で IRET するので OK だと思う。 セグメントレジスターへの MOV の間は NMI も発生しないから、かなりの時間稼ぎができる。 その間にキーボードをたたけば NMI も、というわけだ。 まぁ、ポート A0 を使う手もありそうだけど。

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


23 (月)

%1 上皇誕生日

平成元年に小学校入学した世代の自分には、祝日じゃない 12 月 23 日は記憶になく、ほとんど初めてみたいなもので違和感がある。

きのう、一晩で治る気はしないと書いた風邪の諸症状。 未明の 4 時頃体温が 36.8 度くらいで、今朝 8 時頃には 36.5 度まで下がっていた。 頭痛も解消して、気分もすっきりしていて、咳が少し出るのとのどが変なだけ、みたいな感じ。 微熱が一晩で引くとは、これは流行性感冒じゃなさそうだな。 高熱が出るのを覚悟していたから、いい意味で予想外だった。 でもなんか、夜やたら眠くなるのはやっぱり回復途上なのかな。

%2 8088

どうやったら命令クロック数の計測ができるかな。 ぱっと思いつくのは、違いがわかるくらいの回数繰り返す方法だ。5MHz なら、5M 回実行すれば、1 クロック差が 1 秒になる、という具合だ。 プリフェッチの影響には注意が必要だけど、CL 指定のシフト命令や AAM/AAD 命令などで調整する手もある。

しかし... 例えばかけ算命令の掛ける数の違いによる実行時間の差を見たいとすると、かけ算 1 回で 100 クロックばかり使うわけで、5M 回が 500M クロック... 100 秒もの時間になる。 つまり 100 秒なのか 101 秒なのかで差を見ることになる。 まぁ、できなくはなさそうだけど、電池が一気に消耗しそうだな。 あと動画撮影でもしておかないと、目視でストップウォッチ操作はつらいところだ。Portfolio だと内蔵時計は秒単位っぽいので、プログラムで計測するのは厳しそうかな。

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


24 (火)

%1 かようび

耳鼻科。 いつものに加えて風邪っぽい症状であることを伝えた。 流行性感冒でも熱が出ない人もいるらしいのだが、熱は出なくても全身だるーい感じにはなるらしい。 自分は熱が出ていないだけでなく、全身だるいとか痛いとかいう症状もないので、風邪でしょう、と。 のどの違和感と軽い咳だけだったら薬もいらないですねー、って感じで。

そんな感じだったんだけど、夕方ぐらいから軽い頭痛がしてちょっと咳も出ている。 咳はだいたいなんともなさそうに見えて、突然げほっと出たかと思うと立て続けにげほげほげほ、となるやつ。 まぁ、まだ治っていないんだろうな、という感じ。 引き続き無理はしないようにしよう。 なお、職場では流行性感冒に感染した人が 1 人増えていた。 流行っているなぁ。 風邪は流行るし、外は北風で原付のスピードでもめちゃくちゃ寒いし、自然は厳しい。

%2 Portfolio

そういえば JMP の 8 ビットレジスター指定をちゃんと試していなかった。 今のテストプログラムなら、シングルステップで IP が大小関係なく範囲外になった時点で終了するので非常に試しやすい。

これは... AL, CL, DL, BL に対してはそれぞれ AX, CX, DX, BX 指定と同じになり、AH, CH, DH, BH に対してはそれぞれ、AX, CX, DX, BX を 8 ビットローテートした値と同じになっている。 へぇ! そういえば、ディスティネーションが 16 ビットでソースが不正に 8 ビットにできる命令って JMP と CALL くらいだよな。 しかし、上位 8 ビットを下位 8 ビットに持ってくるのは理解できるけど、下位 8 ビットを上位 8 ビットに持ってくるのって、アキュームレーター以外は用途なくない? なんでわざわざそんな配線を持っているのだろうか? いや... AA*/DA*/*AHF などの用途を考えたけど、アキュームレーターだけ持たせても、入力側と出力側がそれぞれ必要になるのだろうし、セレクターに持たせたとしても配線量は一緒か。 そうすると仕組み上は残りの SP, BP, SI, DI も上下 8 ビットの入れ替えができるのかも知れないな、機械語で表現できないだけで。

さて、調べてみると Portfolio の BIOS には INT 61H でメロディートーンをならす機能があって、長さは 10ms 単位で指定するらしい。 ほう? どうやって待っているのか? まさかビジーウェイトか? 割り込みは許可っぽいが。 何とかして調べてみるしかないな! あるいは、clock tick speed の変更ができるらしいので、これを 1 秒ごとに変えれば命令実行時間の計測に役立つかも。1 秒間に何回実行できたかを計測できるので。

というわけで、clock tick speed を変えて、1 秒あたりの実行回数を数える簡単なプログラムをとりあえず作った。 これ、int $0x61 をコメントアウトすれば PC 互換機でも動くはずだが、dosemu のエミュレーションはバグっててクラッシュするので注意。Portfolio では、90 で 7E05, 9090 で 32F6 か 32F5 が出てきて、40 だと 7E05。 思ったより安定した数字が出る。90 と 40 の差がないのはジャンプでプリフェッチキューが消えているためだろう。90 も 40 もフェッチ待ちより短い実行時間な命令だからな。 フェッチ待ちがどれだけかは最速 4 クロックってだけで想像だけど、Portfolio はスタティック RAM を使っているのでシンプルに 4 クロックだろうと思っている。VRAM もリフレッシュを別途やらないと書き換えただけでは画面は更新されないらしいので。

もう少し試すか。b10dd50a - mov $0xd, %cl; aad で、D982。b10dd3c0 - mov $0xd, %cl; rol %cl, %ax でも、D982。 これは狙い通り。AAD 命令は値によらず一定のクロック数だそうなので、それにぴったり一致する別の命令を入れても同じになるのは当然。 わざとローテートするビット数を変えれば、例えば b10cd3c0 とすれば E3DD ぐらいになるし、b10ed3c0 とすれば D00D になる。 これが 4 クロックの差。 このくらいの精度なら、1 クロックの差も見えそうだな。 長時間かかる命令と、それに実行時間が近いであろうシフト命令を用意すれば比較ができそう。 とりあえずかけ算だけの簡単な実験では、b80000f6e4 で BBA7, b80100f6e4 で B9D5, b8ff00f6e4 で AE02, b80001f6e4 では BBA7 と、%al の 1 のビットの数で実行時間が変わることが確認できた。 あれ? ひょっとして... b10dd501 とすると速くなるのか? ...DC02 だ! AAD 命令も実は (かつては undocumented だった) オペランドの値の 1 のビットの数が重要なんだな! 逆に 4 ビット増やして b10dd5fa とすれば D00D となり、ちょうど上のビット数を増やしたローテートと一致する。 いいね。

というわけで、クロック数でも遊んでいきたい。

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


25 (水)

%1 すいようび

整形外科。1 週間ほど行っていなかったが、未明にややつらめな神経痛が出たので。

風邪の諸症状は変わらず、いや、きのうよりはややいいかな。

%2 Portfolio

かけ算命令のまた簡単なところからやってみよう。 きのうの実験から、8 ビットのレジスター同士の符号無しかけ算は、70〜77 クロックで、%al の 1 のビットの数が影響するので間違いなさそうだ。16 ビットだと 118〜133 クロックということになっているが、果たして。 比較用は 28 ビットシフトで 120 クロックというのを使おう。

うむ、予想通り %ax の 1 のビット数が影響するようだ。 実にシンプル、なのはいいけど、8086/8088 の ALU は 16 ビットでできていると思うので、中がどうなっているのか、おもしろいところではある。 いや。もうちょっと試すか。

ほーん、なんか微妙に最適化というか、打ち切り処理的なものが入っているんだな。 ここでは %ax 掛ける %bx なので、%ax の 1 のビットの位置に %bx を合わせて足す、という動作だが、えっ、いや待てよ、%bx が 0 の時より値が入っている時のほうが速い、というのは... やばいな、また難しいのを見つけてしまった...

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


26 (木)

%1 もくようび

風邪なんだけど、そういえば、きのうの朝は少し汗をかく感じで目が覚めたんだった。 そして今日は日中さらに回復した感じ。 まぁたまに咳は出るけど、それ以外で体調が悪い感じはほぼなくなった。

テレビドラマ『結婚できない男』、ほんと、どの話もノリが同じだな。 いちおう新しい小ネタを混ぜてくるけど、最終的な結果は同じ、みたいな、このマンネリ感がいいんだろうな。 すげぇ気軽に見られる。

%2 Portfolio

きのうのやつ、もしかしてオーバーフロー絡みではないか。8 ビットのかけ算をもう一度やってみる。

ということで... MUL 命令は上位側が 0 以外になると OF と CF をセットする機能があるが、そのセットされる時のほうが 1 クロック短いんだな。 きのうの 16 ビットも同じパターンのように見える。0 を掛けるとオーバーフローはしないので、70〜77 クロックとか 118〜133 クロックとか、その範囲は外れないけど。IMUL も見てみるか。80〜98 クロックのはず。

えーっと、こんな感じでいろいろと試した結果、どうやら中で符号反転をして計算しているらしいことが推測できた。 正掛ける正は MUL と同じ形。 負掛ける負は正掛ける正の +1 クロックで予想以上に高速である。 いや、そこに、MUL の時と同様に、OF および CF がセットされるケース (★) については -1 クロックというのがあるようである。 なお、そのケースは 8 ビットで表現できるかどうか、で、つまり上位が下位を符号拡張した内容になるかどうかとなっている。 で、オペランドだけが負の時が次に遅く 91〜、アキュームレーターだけが負の時は最高に遅く 95〜、らしい。

まぁ、符号ありかけ算が符号無しと同じように実現できるのは入力と出力のビット数が同じ場合だけで、IMUL 命令では違うわけだから、別にそのアルゴリズム自体はいいんだが、最大 101 クロックというのは気にくわない... 80〜98 じゃなかったのかよ! どの本にも載っていなかった事実... 長年だまされていたぞw

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


27 (金)

%1 仕事納め

大掃除、仕事納め、納会。

%2 Portfolio

なんとなく、8086/8088 のかけ算のアルゴリズムが見えてきた気がする。

かけ算のアルゴリズム (0200〜)

この 0200〜は 8 ビットの MUL AH と同じ AX を返すサブルーチンを MUL なしで実装したものである。0100〜は比較用の実験コード。 味噌はループ用の CX を除けば AL と AH とテンポラリーに DL しか使っていない点で、16 ビットも AX と DX とテンポラリーの 16 ビットがあれば行ける。 シフトをローテートと組み合わせて 2 命令にすることになるけど、例の 8086/8088 の構成図にあるレジスターと ALU だけで十分実現できそう。 固定回数ループについてはたぶん、EU の中で何とかできるんだと思う。

で。 そうすると ALU の入力側のテンポラリーレジスターに、MUL のオペランドの中身が入って、それは最後までそのままになる。 まぁ、実際、JMP FAR AX で取り出せるのがその値なわけ。 そういえば 8 ビットだとどうなるんだっけな。

フーン。 例によって上下ひっくり返るアレだ。 ま、いいや。IMUL 命令だとどうなるかな?

0 だ... 符号絡みの処理で 0 になるのかな... ま、じゃあ、次は MUL 命令でフラグレジスターを見てみる。CF と OF は仕様にある通りなので、未定義の AF, PF, SF と ZF について。

SF, ZF と PF については予想通りだった。 上に書いたプログラムと同じように、最後に AH (おそらく 16 ビットでは DX) の内容が反映される。 しかし AF は違うみたいだ。AF は足し算引き算におけるビット 0〜3 のキャリーを表すのだが、ここでは常に 0 か? 最後が足し算じゃなくて、論理演算か? いや、足し算じゃないと上のプログラムは動かない。 例えば %ax=0xff81 の例はそうで、最後は 0x7f80+0xff を計算して、0x807f になるので、AF=1 になるところ、実際の MUL 命令の結果では AF=0 になっている。 ウーン? まぁエミュレーター的には単に AF=0 にすればいいのかなー? (そもそも仕様外なところまで合わせる意味はあまりない)

あと、ちょっと割り算の話。IDIV 命令は負の最小値を範囲外扱いでエラーにしてしまうという。

本当だ!

つまりだ、アレ、IMUL 命令では AF=1 になっているな? まぁいいとして、とにかくだ、-128 に 1 掛けて 1 で割ろう、とすると、IMUL 命令は -128 が答えに出た時に CF も OF もクリアしているのに、1 で割った時には除算エラーになる、というおもしろ現象である。 っていうかそうか、かけ算がある程度わかったところで割り算アルゴリズムも気になりだしたんだけど、IMUL 命令のフラグレジスターもなかなか難しそうだな。

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


28 (土)

%1 どようび

Google Maps を見てみたところ、都内の道は空いているようだ。 というわけで飯能まで行ってみたが、そこまで空いているというわけではなかった。 まぁ、混雑はしていない、程度。 この季節らしく、なぜか急ぎすぎている人やら、なぜかのんびりしすぎている人やらいるので、安全運転でね。

そんなわけでレンタルカート。 飯能。4 回乗ってベストタイムは 33.825 秒ぐらい。7 コーナーは、コーナリングスピードを稼ぐより、距離重視できゅっと曲げてドーンと加速したほうが速いよという、超速い人の貴重なアドバイスをいただいた。 いわんとすることはわずかにわかるような気はする。 極端な話、間違って後輪を一瞬ロックさせてしまっても、うまく向きが変わって加速できるとタイムはそんなには落ちないというのがある。 逆にタイヤのグリップをうまく使えたと思っても、加速していかないケースがあるのもなんとなく理解できる。 あと、以前スタッフさんもおっしゃっていたことだが、早い段階でアクセルを踏み始めることで挙動が乱れにくくなるはずなのに、自分はそれができていない。 パーシャルスロットルに関しては以前よりかなり使うようになったが、7 コーナーでの操作のタイミングは相変わらず難しい。

そうそう、今日は青梅 IC 側のルートで行ったけど、こないだのパトカーが駐まっていた成木のところ、あれ殺人事件があったところの近くだったのね。 後でニュースで知った。 たぶんだけど、現場付近を通行止めにしていて、あの交差点で、現場手前までに用事がある人は通して、現場より先に用事がある人には迂回するよう案内していたんだろう。 交通事故にしてはなんだか様子が変だなーとは思ったが、まさか殺人事件だったとは。

%2 除算命令

割り算アルゴリズム
割り算アルゴリズムテストコード

きのうのかけ算のノリで 16 ビット割る 8 ビットの割り算も書いてみた。 エラーチェック無し。 最初適当に書いたら商が 1 ビットズレていて、それはすぐに直して、よさそうだなと思ってテストコードを走らせたら、0x100/0x81 が商 0 になってしまった。 おかしいなと考え直して、0205 の条件ジャンプを追加したら解決。8 ビット同士の比較では 0x100 との比較はできないから、シフトでビットがあふれたらもう大小関係は確定、みたいな処理になる。 さらにコードを整理して上のように短くなった。 これなら 16 ビットも同じやり方で行ける。

さて... このコードはエラーチェック無しなので、0 除算とか、商が 8 ビットにおさまらない場合とかでも、そのまま実行できる。 どんな結果になるだろうか? 「商...余り」の形で示す。

ふむ。0 除算は商が全ビット 1 になり、余りが割られる数の下位ビットになる。 まぁこれは比較的わかりやすい。0 より小さくなることはないからだ。 しかし、桁がおさまらないほうは様々だ。 除算で例外が発生しないプロセッサを作るとすれば、こういう挙動になるものもあるだろうけど、仕様上は未定義とすることになるだろう。

で。8086/8088 が除算エラー割り込みを作った理由を想像する。 このエラーチェックは一番最初に行える。 最初のシフトの前に大小比較、上のプログラムで言えば CMP AH,DL を最初にやればいい。 それでキャリーがなければエラー。0 除算もシンプルにこれだけで排除できる。 符号付きのほうもおそらく、-128 がエラー扱いになることからして、符号反転して正の数にした後、最上位ビットまで 2 回分を比較すれば、桁あふれはチェックできる。 しかし、ただでも遅い除算命令が、このチェックのためにさらに遅くなっているとも考えられる。 そこまでして何でチェックを入れたのだろうか? 8080 には除算命令は無かったらしいので、8080 の互換のためではない。 こうしてみると... 未定義の答えが出る命令というのを排除したかったのではないか。 加減算は符号付きかどうかにかかわらず同じ命令を使うので、桁あふれはあり得るが、未定義にはならない。 乗算命令は答えのビット数が倍なので、AAD 命令を除いて桁あふれすら存在しない。 つまり、8086/8088 の命令セットでは、除算命令さえ何とかなれば、結果が未定義になる命令はなくなる。(ただし、フラグレジスターの結果には未定義が存在する。)

ところで... 内部のレジスターの構成から考えると、もしかして、除算エラー時には汎用レジスターの内容は変更されているのではないか? Portfolio で実験してみる。 例の TF 実験プログラムで簡単に調べられる... いや、レジスターの内容を勝手にはダンプしないんだった。 ふむむ。

これで %dx と %ax が見られるが、結果、変化していなさそうだ。 ふーん。 詳細はわからんなぁ。

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


29 (日)

%1 にちようび

ちょっと外の掃除をした。

テレビドラマ『女王の教室』、2005 年に見たやつだけど、なんか今 TVer で見られるのがあるので見てみた。 懐かしい。 このときの子役達の中に今も普通に俳優をしている人は何人もいるようで、なんか大人の俳優として見たような顔がいるなぁと調べてみたが名前がわからなかった。 子役でも脇役は名前がわからないやつw

%2 Portfolio

今更ながら、Atari キーと E キーでテキストエディターが起動するというショートカットを発見した。 キーボードにちゃんと書いてある。

MUL 命令の結果の未定義のフラグレジスターを 8 ビットに関して全部確認する。

すべての組み合わせについて一致した。OK。

さて、ちょっと AAA 命令について試した。

フーン。 フラグがよくわからん。 気分を変えてクロック数推定をしよう。

短いクロック数の推定は難しいな。 実行時間の長い AAD 命令でプリフェッチキューを埋めれば見えるかと思ったが、どうもうまく出ている感じじゃない。AAD 命令で挟んでみるか。

これならまぁまぁだな。 やっぱりシフト系命令は最短 2 バイトの癖に最短 2 クロックなんだな。 プリフェッチキューが消えるジャンプ命令はちょっと難しいか。 この中では ADD 命令で +EA が違って 17 クロックになるはずのところだけ謎だ。LEA 命令ならちゃんと 9 クロックと 10 クロックで +EA の差が見えたのに。 他がメモリーアクセスを伴ってもやたら精度良く見えているだけに... (Portfolio はスタティック RAM なので、メモリーアクセスはおそらく最短時間の 4 クロックで済んでいるようで、計算しやすい。)

9 日に電池交換してから、こんなにいろいろ遊んでもまだ電池が切れない Portfolio, やはりなかなかの出来。 これにもし日本語サポートがあったら日本でも売れていただろうなぁ、と思うけど、メモリーの少なさと画面の狭さから、日本語対応しようと思ったら結構苦労しただろうな、とも思う。1990 年代に DOS/V が出てきて、ソフトウェアによる日本語表示が実用的になったのは、やっぱり 32 ビット CPU の存在は大きかったみたいなのだ。80C88 な Portfolio だと、拡張カードで何とかせざるを得なかっただろうな。 それでも画面の狭さはどうにもならないけど。

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


30 (月)

%1 冬休み 1 日目

のんびりした日。 曇り時々雨。

%2 Portfolio

きのうの続き。 試しに CL 指定のシフト命令を入れたところこんな結果が得られた。

数字がだんだん変わっていくのは、CL の値が 8 から 1 まで変化しているため。 それで、シフト命令 (ローテートだけど) のクロック数としては 40 クロックから 4 ずつ減って 12 クロックまで変化しているはずである。 ところが、きのうの計算と見比べると 1 クロック違う。 例えば 7D1A は 12 クロックのはずだが、きのうの aaa; nop の 11 クロックと一致してしまっている。 なんだかよくわからないけど、add (%bx,%di),%al で起きた謎はこのへんも関係がありそうだな。 あっ、きのうの 10 と 11 の間の差が少し大きいな。 もしかして...

フーン、なんもわからん... まぁこれはおいておくとして、いろんな命令での ALU のところのテンポラリーレジスターの使用状況を調べた。 単なるレジスター間 MOV 命令でも変化するが、MOVS/STOS/LODS 命令では変化しない。 アキュームレーターに対するメモリーアドレス直接指定の MOV 命令でも、残るのはメモリーのアドレスで、中身は残らない。 とするとアキュームレーターについては BIU 側と直接やりとりできる経路があるっぽい? いや、セグメントレジスターと汎用レジスターの間の MOV 命令でも変化しないんだよな。EU 内で完結するやりとりで使用されるのか。

ストリング命令による %si/%di の演算は ALU を使っていないのではないかと思う。PUSH/POP 命令やリターン命令の %sp も同様。 しかし RET/RETF 命令の即値引数を使った場合は、足す前の %sp の値が残るので、ALU を使っているように見える。 つまり 1 や 2 を足したり引いたりするだけなら BIU 側で行える、ということではないかと見ている。IP の足し算も必要だしな。

シフトの CL 指定はシフト後の値が残るみたいだが、8 ビットローテート時に上位 8 ビットも動いているみたいでもう少し調査が必要。 なお各種割り込み命令後はジャンプ先の IP の中身が残るみたいで、おかしいな、IP は BIU 側が持っているはずだから別に EU 側に持ってこなくてもいいと思うんだが...

4 日にプリフェッチキューのことを少し調べていたが、あらためて振り返ってみた。 きのうのクロック数推定の謎を解くためにも、そのあたりの知識が必要そうだし。 以前図書館で借りた本に長い例があって、インターネットで見つけたマニュアルにも英語で同じものがあったけど、やはり、1 バイトに 1 クロックサイクルは使っているように見える。 そうすると 2 バイトの MOV CS 命令の途中で CS が変わっているというのはおかしい。 そこで、プリフェッチが 1 クロック遅れて始まると仮定すると、MOV CS 命令の途中で CS が変わることがなくなり、一応先日の話との整合性は保てるような気がする。1 クロック遅れて始まるというのも理解できるところはあって、プリフェッチキューから取り出した 1 バイトを元に順序回路の次の値を準備する、その間はまだキューに残っているから次のフェッチは開始できない、というのはまぁ、ありそうかな、みたいな。 ただ、シフト命令が 2 バイト 2 クロックなのがどうも納得しづらいところがあるが、まぁいいか...

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


31 (火)

%1 冬休み 2 日目

昼間は暖かかったが、夕方頃から北風が吹きすさみ急に冷え込んできた日。

今年は新しいディジタルカメラを買ったわけだが、そういえばまだそれで三脚を使ったことが無かった。10 年近くも前に、ドンキホーテでわずか 1280 円で買った三脚を持っていて、しばらく使っていなかったが、使えるはずだと思って出してみたら、プラスチックのパーツがポキッと... 壊れてしまった。 アチャー。 それで、ビックカメラに行ってみたら、三脚だけでピンからキリまで、数千円から数万円のものまで勢揃いである。4000 円ぐらいの、定価の半額ぐらいの少し頑丈そうなやつを見つけて、いいかなと思ったが、在庫はありになっているのに見当たらないということで、おそらく誰かが買おうとして持って店内にいるのだろうとのこと。 こういうの、在庫があれば勢いで買っちゃうんだけどな、ないって言われるとそうですか、って終わっちゃうやつ。 まぁしかしとにかく選択肢がおそろしく豊富なことはわかった。

夜は兄者とめし。 そろそろ給油しなきゃと思ってスクーターで行ったら寒いのなんの。 大晦日の夜だけど店の混雑はまぁそれほどでもない感じ。 そば屋じゃないしな。 それより帰り道のガラガラっぷりが大晦日だったw 普段なら 19 時台にこんなに空いているわけがない。 深夜か早朝か、というくらいガラガラだった。

紅白歌合戦はラジオで途中から適当に。

%2 スクーター

アドレス V100 タイプ S, 前のオーナーにより方向指示器が LED 化されている。 これ、点滅時に車幅灯みたいに薄く光るので本当はだめなやつじゃないかと思う。 それはともかく、先日まで点滅間隔が短くなっていることがあった。 球切れを起こした時のようで、一応確認したが点滅が変なだけで光ってはいた。 急に間隔が正常になることもあり、電圧の問題かと思ったがエンジン回転数を上げてもだめな時はだめで、LED 絡みの制御回路の不良か何かか、なんだろうなと思っていた。

で、この前のブレーキワイヤー注油の際に、ついでに、方向指示器のスイッチに何気なく注油した。 こういうのには本当は良くないと言われる KURE CRC 5-56 を、さらっと、ちょろっとさしただけ。 そうしたら、方向指示器の点滅間隔が短くなることはなくなった。 例えばオートチョークのコネクターのほうはその後も何度か怪しくなっているが、オートチョークが戻らずアイドリングが低く不安定になっている時でさえも、方向指示器の点滅間隔は短くはならない。

つまり? 制御回路なんかの問題ではなくて、ただ単にスイッチの接点の抵抗が大きくなっていただけだと思う。5-56 は接点復活剤としても機能するので、抵抗値が元に戻ったのである。 なんか、灯台もと暗しというか、そこに接点があって、直列で方向指示器の回路があるはずというのは言われてみればそうなんだけど、思考がディジタルに侵されていて、トランジスターみたいなものでスイッチングしている感覚というか、まぁその...

%3 Portfolio

MOV CS 実験の改良版。 他の実験プログラムと同じようにコマンドライン引数から入力するように変更したのと、%dl をぶっ壊してもいいように変更したので cwtd が使えるようになった。%bx は引き続き壊しちゃだめだが、その %bx を使って数えるようにしてある。

さて、cwtd は 5 クロックなので結構微妙なところが見られるかなと期待している。

えぇー? MOV CS が 2 バイトなので、99999999 で 2 になっているところは、MOV CS の次の 1 バイトも含めた 7 バイト分を MOV CS の完了までにフェッチして、しかもその次の 1 バイトのフェッチも始めている計算。 最初の 1 バイトはフェッチが済まないと実行できないから無視するとして、残りの 6 バイトのフェッチをすませるには 24 クロック必要。 でも 20 クロックと MOV CS の 2 クロックとなると足りない。 あれれれれ?

そんなはずはないけど cwtd が 6 クロックだと計算は合う。 どの資料も cwtd (CWD) は 5 クロックになっているからそんな間違いがあるはずはないけど。 そもそも 37273740 と 37274037 で差があるのもアレだ。

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


Powered by Tomsoft Diary System 1.7.4

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

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

Hideki EIRAKU