6800の未定義命令(1) 歴史と概要
現代のCPUは、定義されていない命令(利用されていないオペコード)を実行すると、未定義命令エラーが検出されてOS trapが発生する。
けれども、往年のコンピューターでは、定義済みの命令と同じ動作をしたり、似たようで違う動作をしたり、はたまた暴走したり、色々なことが起きた。
それらの命令の中でも有用なものは広く使われて、後継CPUでも互換動作をするようになったものもある(Z80の未定義命令が有名)。
ここでは、モトローラMC6800(日立HD46800,富士通MB8861)の未定義命令について見ていきたい。
未定義命令探しが流行った
発端はByte誌1977年12月号である。PP.46-47に掲載された “Undocumented M6800 Instructions” に6つの命令が掲載された。
この中で紹介された命令 "HCF (Halt and Catch Fire)” が目を惹いたのか、記事は人気になった。
Byte Dec. 1977 P.46より引用
BYTE誌1978年1月号P.84-90にもMC6800の命令セットの記事があるが、載っている未定義命令は1977年12月号と同じである。
Web検索してみたが、6800の未定義命令に関する日本語以外の記事は、BYTE誌のこの記事を引用しているものばかりであった(探し方が悪いのだろうか)。
日本の雑誌記事では
過去に6800の未定義命令についての記事を読んだ覚えがあるので、日本の雑誌を探してみた。多数の記事が見つかった。
エンサイクロペディア・アスキーの volume 2にHD46800/MB8861の未定義命令についての記事が大量に載っている。I/O誌にもMB8861の未定義命令の記事がある。
日本では日立・富士通・松下などの
ASCII誌では、1978年3月号のTBN「マイコン私情へのついしん!」にて くだんのBYTE誌記事の紹介とMB8861N(コスモターミナルD)による追試が行われており、BYTE誌で紹介された命令以外にも4命令が発見されている。
これが火付け役となって半年ほどHD46800/MB8861での未定義命令探しの投稿記事が掲載されている。
調査対象がMC6800でないのは、国産のトレーニングキットである日立H68/TR(HD46800)や富士通L-Kit8(MB8861)が主に使われていたからだろう。
最初の国産パソコンであるベーシックマスター(初代)は、これらの記事が投稿された後の1978年9月発売であり、しかも、このCPUもHD46800だ。
(本家モトローラのMEK6800も売られていたが、どれぐらいシェアがあったのだろうか)
ASCII誌の未定義命令探しで数多くの命令が発見されたが、それほど利用されずに、歴史に埋もれていった。
私はASCII誌やI/O誌、Webの記事を元にMC6800/HD46800/MB8861の未定義命令を一覧にしてみた。ニーモニックはASCII誌の案と6809など後継CPUの命令を参考にして付けてある。
動作確認はVisual 6800 in JavaScriptで行ったが、漏れがあるかもしれない。
ASCII誌掲載記事で誤っていると思われる点を書いておこう。
$CD
PSH PCになっているのは、BSRの誤りと思われる。
記事では未定義命令の後ろに$00を置いてテストしたと書かれていて、その場合はBSRはPCをスタックに積んだあと、直後の命令に分岐するのでPCをPUSHしたかのように見える。
後続バイトを変化させると、相対分岐するのでBSRで良いと思われる。
$CC-$FC
フラグ変化するので、何かが起こっている。$FCはext address先の2バイト目でフラグが変化しているようにも見えるが、詳細不明。
フラグが変化するので、ASCII記事にあるような、単純なjump命令ではない。
使える命令はあるのか?
NBA (A=A and B)は記事「6800のアセンブラプログラム最適化(1)(ベーシックマスター開発 その25)」にも書いたように、関係演算の結果(0か1)をANDしたいときに使える。
TSRはAccの再下位ビットが0か1かの判定に使える。BITA #1でもできるが、1バイト短いのとCarryが立つのが良い。0/1/それ以外の分岐にも使える(BNE/BCxで分岐)。
STX # は、IXを保存するサブルーチンとして使える(エンサイクロペディア・アスキー volume 2 P.355)。2バイト目にCE(LDX#)を入れておけば、読み出しも同じサブルーチンで行える。
STS #も同じことができるが、LDS #の後にRTSをすると、STS #の呼び出し元に戻ってしまう。setjmp/longjmpだと思えば使えないことはない?
TNGはAccが0以外ならCが立つのが利用できそう。
いくつかの命令は後継CPUでも使える
Fuzix-Compiler-Kit の6800エミュレーターは、6800/6801/6802/6803/6808/6303の命令を実行できる。この中で6303のundocumentedsとして以下の命令が挙げられている。
いくつか共通する命令があり、有効に使えるかもしれない。
* 02 if C is set A = 255, else A = 0 (no flag effect) * 03 A = 0xFF * 12 A = A - B - carry * 13 A = A - B - 1 * 14 B = A - !C * 15/1D A = B - 1 * 18 or 1A A += B but different C/H behaviour * 1E B = A * 1F A = B, set carry * 41 TSTA variant * 42/52/62/72 negate with carry (SBC from 0) on byte * 42 A 52 B * 45 LSR A * 4B DEC A * 51 TSTB variant * 55 LSR B * 5B DEC B * 61 TST x variant * 62 negate x * 65 LSR x * 6B DEC x * 71 TST M * 72 NEG M * 75 LSR m * 7B DEC m * * The NAMCO processors (60A1, 63A1) also add * 12/13 addx 1,sp
なぜこのような命令が実行されるのか
$83 (AccA = AccA – M – 1)のように、通常の加減算と1だけ値が違う演算がある。これはSN74181のようなALUを知っていると理解しやすい。
ALU(ARITHMETIC LOGIC UNITS)はCPU内部で各種演算を行うユニットで、外部から与える信号線によって演算の種類を変えられる。74181の場合はC信号を与えるかどうかで、加減算の結果に0/-1/+1が付く。通常はCには命令に応じて0や1やCarry flagの値を与えるのだけど、未定義命令の場合は命令の意図に合わないCが設定されたのだと思われる。
TNG/TSRなどフラグだけが変更される命令は、TSTやABITのような演算の結果を反映せずフラグだけが変化する命令操作が、LSR命令でも実行されたためだと思われる。
Visual 6800 in JavaScriptには、トランジスタレベルでの結線があり、ここから回路図を復元できればさらに多くのことがわかるだろう。しかし、これは私の手に余る。
参考資料
- 月刊I/O 1979年7月号 P.94「RANDOM BOX MB8861の未定義命令」
- エンサイクロペディア・アスキー volume 2 P.347 マイコン私情へのついしん!
- エンサイクロペディア・アスキー volume 2 P.354 レポート 6800未定義命令
- Investigating the HCF (Halt & Catch Fire) instruction on Motorola 6800 – X86.FR | Doc TB’s R&D Lab
- deramp.com/downloads/mfe_archive/050-Component Specifications/Motorola/CPUs/The Motorola 6800 Instruction Set (Byte)(January 1978).pdf
- https://spivey.oriel.ox.ac.uk/wiki/images-corner/1/1a/Undoc6800.pdf
- 「さあ来た!ホームコンピュータ時代」掲示板ログ2
- MN1800A の未定義命令を探る
ディスカッション
コメント一覧
まだ、コメントがありません