日立HD6301はモトローラMC6801をCMOS化し、メモリ論理演算命令とレジスタ交換命令を追加したワンチップマイコンです。
内部はマイクロプログラム化されており、メモリアクセスを必要としない命令はほとんどが1クロックで実行できます。
元となった6801は6802にROM、パラレルI/O、シリアルI/O、タイマーを追加したもの。6802は6800にクロックジェネレータと128バイトのRAMを追加したものとなっています。
MC6800 | オリジナル |
MC6802 | MC6800にクロックジェネレータと128バイトのRAMを追加 |
MC6801 | MC6802にROM、パラレルI/O、シリアルI/O、タイマーを追加 多数の命令を追加 |
80系に比べると、整った命令体系を持っていたと言われる68系ですが、どのようなプログラミングモデルだったのでしょうか。
レジスタ構成
8080やZ80に比べると半分程度のレジスタ数です。8bitアキュムレータAとBの2本、インデックスレジスタX、スタックポインタSP、プログラムカウンタPC、コンディションレジスタCCRの6本だけです。
データ保持に使えるのはアキュムレータ2本とインデックスレジスタ1本だけなので、レジスタのやりくりが大変そうです。特にインデックスレジスタが1本しかないので、メモリの比較や転送は手間がかかりそうです。
レジスタ同士の演算はごく一部を除いて存在しません。レジスタの演算対象は即値かメモリの内容です。
フラグ
フラグ類はコンディションコードレジスタに集められています。
- キャリーフラグ:演算の結果、繰り上がりや繰り下がりが発生するとセットされます。
- ゼロフラグ:転送や演算結果がゼロになったときにセットされます。
- ネガティブフラグ:MSBと同じ値がセットされます。
- オーバーフローフラグ:算術オーバーフローを起こした場合にセットされます。
- 割り込みフラグ:このフラグをセットすると割り込みがかからなくなります(マスクする)。また割り込みがかかると自動的にセットされます。ただしNMI割込みとTRAP割り込みに対しては無効です。
- ハーフキャリーフラグ:加算の結果、アキュムレータのビット3からビット4に繰り上がりがあった場合にセットされます。Dレジスタの加算では変化しません。また減算でも変化しません。
- 常に’1’です。
- 常に’1’です。
80系と違い、ロードやストアするだけでフラグが変化するのが特徴です。うまく使えば比較命令を使わずに条件分岐できそうです。
アドレッシングモード
下記のアドレッシングモードを持っています。
- イミディエイト(Immediate)
- ダイレクト(Direct)
- エクステンド(Extended)
- インデックス(Indexed)
- レラティブ(Relative)
- インプライド(Implied)
- アキュムレータ(Accumulator)
イミディエイト(Immediate)
オペランドの内容を即値として解釈します。
ldaa #$68
Aレジスタに$68をロード(代入)します。#は即値、$は16進数であることを表しています。
ダイレクト(Direct)
オペランドの内容をダイレクトページのアドレスとして解釈します。
68系MPUはアドレスの上位8bitを0に固定したダイレクトページというメモリ領域が存在します。ここにアクセスするなら1サイクル・1バイト少なく済みますので、メモリが高価で貴重だった当時はありがたかったはずです。変数やレジスタの退避領域として使うことになると思います。
ldaa $68
Aレジスタにアドレス$0068の内容をロード(代入)します。
エクステンド(Extended)
オペランドの内容を16bitのアドレスとして解釈します。
ldaa $6800
Aレジスタにアドレス$6800の内容をロード(代入)します。
インデックス(Indexed)
インデックスレジスタXにオペランドの数値を加えたアドレスとして解釈します。
ldaa 2,x
Aレジスタにインデックスレジスタ+2のアドレスの内容をロード(代入)します。
例えばインデックスレジスタの内容が$6800だった場合、アドレスは$6802になります。
レラティブ(Relative)
プログラムカウンタにオペランドの内容を2の補数として加算した結果をアドレスとして解釈します。条件分岐はすべてこのアドレッシングモードになります。
; 実行アドレスは$1000
bra $fe
上記命令をフェッチした段階でプログラムカウンタは$1002になっています。そこに$fe(2の補数表現なので-2)を足すのでプログラムカウンタは$1000になります。これは自身に分岐するので永久ループになります。
インプライド(Implied)、アキュムレータ(Accumulator)
オペランドなしの1バイト命令です。
命令体系上は分かれていますが、プログラマ視点では区別が付きません。
‘#’を付け忘れるとイミディエイトアドレッシングのつもりがダイレクトアドレッシングやエクステンドアドレッシングになってしまうので注意が必要です。
アセンブラによってはオペランドの直前に”<“を付けるとダイレクト、”>”を付けるとエクステンドアドレッシングになるので積極的に使うべきです。
命令一覧
転送命令
Operations | Mnem.| Immed | Direct | Index | Extend | Implied | Flag |
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Load Accumulator A | ldaa | 86 2 2 | 96 3 2 | a6 4 2 | b6 4 3 | | --XX0- | M -> A
Load Accumulator B | ldab | c6 2 2 | d6 3 2 | e6 4 2 | f6 4 3 | | --XX0- | M -> B
Load Accumulator D | ldd | cc 3 3 | dc 4 2 | ec 5 2 | fc 5 3 | | --XX0- | M -> D
Load Index Register | ldx | ce 3 3 | de 4 2 | ee 5 2 | fe 5 3 | | --XX0- | M -> X
Load Stack Pointer | lds | 8e 3 3 | 9e 4 2 | ae 5 2 | be 5 3 | | --XX0- | M -> SP
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Store Accumulator A | staa | | 97 3 2 | a7 4 2 | b7 4 3 | | --XX0- | A -> M
Store Accumulator B | stab | | d7 3 2 | e7 4 2 | f7 4 3 | | --XX0- | B -> M
Store Accumulator D | std | | dd 4 2 | ed 5 2 | fd 5 3 | | --XX0- | D -> M
Store Index Register | stx | | df 4 2 | ef 5 2 | ff 5 3 | | --XX0- | X -> M
Store Stack Pointer | sts | | 9f 4 2 | af 5 2 | bf 5 3 | | --XX0- | SP -> M
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Transfer A to B | tab | | | | | 16 1 1 | --XX0- | A -> B
Transfer B to A | tba | | | | | 17 1 1 | --XX0- | B -> A
Transfer A to CCR | tap | | | | | 06 1 1 | XXXXXX | A -> CCR
Transfer CCR to A | tpa | | | | | 07 1 1 | ------ | CCR -> A
Transfer X to SP | txs | | | | | 35 1 1 | ------ | X - 1 -> SP
Transfer SP to X | tsx | | | | | 30 1 1 | ------ | SP + 1 -> X
Exchange D and X | xgdx | | | | | 18 2 1 | ------ | D <-> X
先にも書きましたが、ロードやストアするだけでフラグが変化するのは注意が必要です。
tsx
命令はスタックポインタの値を+1したものをインデックスレジスタに転送しています。68系のスタックポインタは次にデータが入るべきアドレスを指しているので、こうすることでインデックスレジスタがスタックトップを差すようになります。
xgdx
命令は非常に有益な命令です。それぞれのレジスタにない算術命令や比較命令が使えるようになります。
算術命令
Operations | Mnem.| Immed | Direct | Index | Extend | Implied | Flag |
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Add M to A | adda | 8b 2 2 | 9b 3 2 | ab 4 2 | bb 4 3 | | X-XXXX | A + M -> A
Add M to B | addb | cb 2 2 | db 3 2 | eb 4 2 | fb 4 3 | | X-XXXX | B + M -> B
Add M to D | addd | c3 3 3 | d3 4 2 | e3 5 2 | f3 5 3 | | --XXXX | D + M -> D
Add B to A | aba | | | | | 1b 1 1 | X-XXXX | A + B -> A
Add B to X | abx | | | | | 3a 1 1 | ------ | B + X -> X
Add (M + C) to A | adca | 89 2 2 | 99 3 2 | a9 4 2 | b9 4 3 | | X-XXXX | A + M + C -> A
Add (M + C) to B | adcb | c9 2 2 | d9 3 2 | e9 4 2 | f9 4 3 | | X-XXXX | B + M + C -> B
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Subtract M from A | suba | 80 2 2 | 90 3 2 | a0 4 2 | b0 4 3 | | --XXXX | A - M -> A
Subtract M from B | subb | c0 2 2 | d0 3 2 | e0 4 2 | f0 4 3 | | --XXXX | B - M -> B
Subtract M from D | subd | 83 3 3 | 93 4 2 | a3 5 2 | b3 5 3 | | --XXXX | D - M -> D
Subtract B from A | sba | | | | | 10 1 1 | --XXXX | A - B -> A
Subtract (M + C) from A | sbca | 82 2 2 | 92 3 2 | a2 4 2 | b2 4 3 | | --XXXX | A - M - C -> A
Subtract (M + C) from B | sbcb | c2 2 2 | d2 3 2 | e2 4 2 | f2 4 3 | | --XXXX | B - M - C -> B
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Unsigned Multiply | mul | | | | | 3d 7 1 | -----a | A * B -> D
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Clear Memory | clr | | | 6f 5 2 | 7f 5 3 | | --0100 | 0 -> M
Clear Accumulator A | clra | | | | | 4f 1 1 | --0100 | 0 -> A
Clear Accumulator B | clrb | | | | | 5f 1 1 | --0100 | 0 -> B
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Increment Memory | inc | | | 6c 6 2 | 7c 6 3 | | --XXb- | M + 1 -> M
Increment Accumulator A | inca | | | | | 4c 1 1 | --XXb- | A + 1 -> A
Increment Accumulator B | incb | | | | | 5c 1 1 | --XXb- | B + 1 -> B
Increment Index Register | inx | | | | | 08 1 1 | ---X-- | X + 1 -> X
Increment Stack Pointer | ins | | | | | 31 1 1 | ------ | SP + 1 -> SP
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Decrement Memory | dec | | | 6a 6 2 | 7a 6 3 | | --XXc- | M - 1 -> M
Decrement Accumulator A | deca | | | | | 4a 1 1 | --XXc- | A - 1 -> A
Decrement Accumulator B | decb | | | | | 5a 1 1 | --XXc- | B - 1 -> B
Decrement Index Register | dex | | | | | 09 1 1 | ---X-- | X - 1 -> X
Decrement Stack Pointer | des | | | | | 34 1 1 | ------ | SP - 1 -> SP
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Complement Memory | com | | | 63 6 2 | 73 6 3 | | --XX01 | ~M -> M
Complement Accumulator A | coma | | | | | 43 1 1 | --XX01 | ~A -> A
Complement Accumulator B | comb | | | | | 53 1 1 | --XX01 | ~B -> B
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Negate Memory | neg | | | 60 6 2 | 70 6 3 | | --XXbd | 0 - M -> M
Negate Accumulator A | nega | | | | | 40 1 1 | --XXbd | 0 - A -> A
Negate Accumulator B | negb | | | | | 50 1 1 | --XXXX | 0 - B -> B
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Rotate Left Memory | rol | | | 69 6 2 | 79 6 3 | | --XXeX | <-- reg,M <--
Rotate Left A | rola | | | | | 49 1 1 | --XXeX | | |
Rotate Left B | rolb | | | | | 59 1 1 | --XXeX | ----> C ---->
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Rotate Right Memory | ror | | | 66 6 2 | 76 6 3 | | --XXeX | --> reg,M -->
Rotate Right A | rora | | | | | 46 1 1 | --XXeX | | |
Rotate Right B | rorb | | | | | 56 1 1 | --XXeX | <---- C <----
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Shift Left Arithmetic M | asl | | | 68 6 2 | 78 6 3 | | --XXeX | C <-- reg,M <-- 0
Shift Left Arithmetic A | asla | | | | | 48 1 1 | --XXeX |
Shift Left Arithmetic B | aslb | | | | | 58 1 1 | --XXeX |
Shift Left Arithmetic D | asld | | | | | 05 1 1 | --XXeX |
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Shift Right Arithmetic M | asr | | | 67 6 2 | 77 6 3 | | --XXeX | --> reg,M --> C
Shift Right Arithmetic A | asra | | | | | 47 1 1 | --XXeX | |____|
Shift Right Arithmetic B | asrb | | | | | 57 1 1 | --XXeX |
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Shift Right Logical M | lsr | | | 64 6 2 | 74 6 3 | | --0XeX | 0 --> reg,M --> C
Shift Right Logical A | lsra | | | | | 44 1 1 | --XXeX |
Shift Right Logical B | lsrb | | | | | 54 1 1 | --XXeX |
Shift Right Logical D | lsrd | | | | | 04 1 1 | --XXeX |
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Decimal Adjust A to BCD | daa | | | | | 19 2 1 | --XXXf | BCD補正
a(mul): 演算の結果、BレジスタのMSBが1ならばセットされ、0ならばリセットされます。
b(inc, neg): 演算の結果、値が$80ならばセットされ、それ以外ならリセットされます。
c(dec): 演算の結果、値が$7fならばセットされ、それ以外ならリセットされます。
d(neg): 演算の結果、値が$00ならばリセットされ、それ以外ならセットされます。
e(rol, ror): 演算の結果、N != C だとセットされ、N == C だとリセットされます。
f(daa): 演算の結果、上位4bitの値が10以上であればセットされ、9以下であれば変化しません。
Dレジスタによる16bit演算は便利そうです。
インデックスレジスタにレジスタBを加算するabx
命令や8bit同士の乗算mul
命令は配列の計算に使えそうです。
論理演算命令
Operations | Mnem.| Immed | Direct | Index | Extend | Implied | Flag |
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
AND M to A | anda | 84 2 2 | 94 3 2 | a4 4 2 | b4 4 3 | | --XX0- | A & M -> A
AND M to B | andb | c4 2 2 | d4 3 2 | e4 4 2 | f4 4 3 | | --XX0- | B & M -> B
AND Immidiate to M | aim | | 71 6 3 | 61 7 3 | | | --XX0- | M & imm -> M
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
XOR M to A | eora | 88 2 2 | 98 3 2 | a8 4 2 | b8 4 3 | | --XX0- | A ^ M -> A
XOR M to B | eorb | c8 2 2 | d8 3 2 | e8 4 2 | f8 4 3 | | --XX0- | B ^ M -> B
XOR Immidiate to M | eim | | 75 6 3 | 65 7 3 | | | --XX0- | M ^ imm -> M
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
OR M to A | oraa | 8a 2 2 | 9a 3 2 | aa 4 2 | ba 4 3 | | --XX0- | A | M -> A
OR M to B | orab | ca 2 2 | da 3 2 | ea 4 2 | fa 4 3 | | --XX0- | B | M -> B
OR Immidiate to M | oim | | 72 6 3 | 62 7 3 | | | --XX0- | M | imm -> M
oim
命令とaim
命令は各ビットのセット・リセットに使えそうです。ダイレクトページの1バイトにつきフラグを8本確保できます。
比較命令
Operations | Mnem.| Immed | Direct | Index | Extend | Implied | Flag |
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Bit test Accumulator A | bita | 85 2 2 | 95 3 2 | a5 4 2 | b5 4 3 | | --XX0- | A & M
Bit test Accumulator B | bitb | c5 2 2 | d5 3 2 | e5 4 2 | f5 4 3 | | --XX0- | B & M
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Compare Accumulator A | cmpa | 81 2 2 | 91 3 2 | a1 4 2 | b1 4 3 | | --XXXX | A - M
Compare Accumulator B | cmpb | c1 2 2 | d1 3 2 | e1 4 2 | f1 4 3 | | --XXXX | B - M
Compare Index Register | cpx | 8c 3 3 | 9c 4 2 | ac 5 2 | bc 5 3 | | --XXXX | X - M
Compare B to A | cba | | | | | 11 1 1 | --XXXX | A - B
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Test Memory | tst | | | 6d 4 2 | 7d 4 3 | | --XX00 | M - 0
Test Accumulator A | tsta | | | | | 4d 1 1 | --XX00 | A - 0
Test Accumulator B | tstb | | | | | 5d 1 1 | --XX00 | B - 0
Test Immediate Memory | tim | | 7b 4 3 | 6b 5 3 | | | --XX0- | M & imm
レジスタを使わずにメモリ内容をテストできるtim
命令が非常に便利そうです。
レジスタD対象のcmp
命令がないのは残念です。cmpa
とcmpb
を組み合わせるか、xgdx
とcpx
を組み合わせればなんとかなりますが、完全に置き換えられるわけではなさそうです。
条件分岐命令
Operations | Mnem.| Immed | Direct | Index | Extend | Implied | Flag |
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Branch If Carry Clear | bcc | | | | | 24 3 2 | ------ | C = 0
Branch If Carry Set | bcs | | | | | 25 3 2 | ------ | C = 1
Branch If = Zero | beq | | | | | 27 3 2 | ------ | Z = 1
Branch If >= Zero | bge | | | | | 2c 3 2 | ------ | N ^ V = 0
Branch If > Zero | bgt | | | | | 2e 3 2 | ------ | Z + (N ^ V) = 0
Branch If Higher | bhi | | | | | 22 3 2 | ------ | C + Z = 0
Branch If <= Zero | ble | | | | | 2f 3 2 | ------ | Z + (N ^ V) = 1
Branch If Lower or Same | bls | | | | | 23 3 2 | ------ | C + Z = 1
Branch If < Zero | blt | | | | | 2d 3 2 | ------ | N ^ V = 1
Branch If Minus | bmi | | | | | 2b 3 2 | ------ | N = 1
Branch If Not Equal Zero | bne | | | | | 26 3 2 | ------ | Z = 0
Branch If Overflow Clear | bvc | | | | | 28 3 2 | ------ | V = 0
Branch If Overflow Set | bvs | | | | | 29 3 2 | ------ | V = 1
Branch If Plus | bpl | | | | | 2a 3 2 | ------ | N = 0
条件分岐は相対分岐しかなく、-126〜129バイトの範囲でしかジャンプできません。とはいえ困る場面はほとんどないと思います。
条件が成立してもしなくても実行サイクルが変わらないのは分かりやすくていいですね。
符号付きの条件分岐も用意されているのはさすがです。
条件 | unsigned | signed |
Acc == M | beq | beq |
Acc != M | bne | bne |
Acc < M | bcs | blt |
Acc <= M | bls | ble |
Acc > M | bhi | bgt |
Acc >= M | bcc | bge |
ジャンプ命令
Operations | Mnem.| Immed | Direct | Index | Extend | Implied | Flag |
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Jump | jmp | | | 6e 3 2 | 7e 3 3 | | ------ | 分岐
Branch Always | bra | | | | | 20 3 2 | ------ | 分岐
Jump To Subroutine | jsr | | 9d 5 2 | ad 5 2 | bd 6 3 | | ------ | サブルーチンコール
Branch to Subroutine | bsr | | | | | 8d 5 2 | ------ | サブルーチンコール
Return From Subroutine | rts | | | | | 39 5 1 | ------ | サブルーチン復帰
絶対分岐と相対分岐が同じ実行サイクル数です。
スタック命令
Operations | Mnem.| Immed | Direct | Index | Extend | Implied | Flag |
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Push Accumulator A | psha | | | | | 36 4 1 | ------ | A -> [SP]; SP-
Push Accumulator B | pshb | | | | | 37 4 1 | ------ | B -> [SP]; SP-
Push Index Register | pshx | | | | | 3c 5 1 | ------ | X -> [SP]; SP--
-------------------------+------+--------+--------+--------+--------+---------+-HINZVC-+-----------------
Pull Accumulator A | pula | | | | | 32 3 1 | ------ | SP+; [SP] -> A
Pull Accumulator B | pulb | | | | | 33 3 1 | ------ | SP+; [SP] -> B
Pull Index Register | pulx | | | | | 38 4 1 | ------ | SP++; [SP] -> X
フラグ変更命令
Operations | Mnem.| Immed | Direct | Index | Extend | Implied | Flag |
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Clear Carry | clc | | | | | 0c 1 1 | -----0 | 0 -> C
Clear Interrupt Mask | cli | | | | | 0e 1 1 | -0---- | 0 -> I
Clear Overflow | clv | | | | | 0a 1 1 | ----0- | 0 -> V
Set Carry | sec | | | | | 0d 1 1 | -----1 | 1 -> C
Set Interrupt Mask | sei | | | | | 0f 1 1 | -1---- | 1 -> I
Set Overflow | sev | | | | | 0b 1 1 | ----1- | 1 -> V
その他命令
Operations | Mnem.| Immed | Direct | Index | Extend | Implied | Flag |
-------------------------+------+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-OP ~ #-+-HINZVC-+-----------------
Software Interrupt | swi | | | | | 3f 12 1 | -1---- | ソフトウェア割り込み
Wait for Interrupt | wai | | | | | 3e 9 1 | -g---- | 割り込み待機
Return From Interrupt | rti | | | | | 3b 10 1 | XXXXXX | 割り込み復帰
Sleep | slp | | | | | 1a 4 1 | ------ | スリープモード
No Operation | nop | | | | | 01 1 1 | ------ | 何もしない
Branch Never | brn | | | | | 21 3 2 | ------ | 分岐しない
g(wai): 割り込みが発生するとセットされますが、割り込み前に既にセットされていた場合は変化しません。
コメント