6809でオリジナルモニタ(2) [6809]
前回は6801用モニタをニーモニック変換等でとりあえず動くようにしたが、その状態では起動はするがまともには動作しない。
1.変更点はモニタコマンドとしては以下の3つ。
(1)Rコマンド
レジスタ表示/編集コマンドは6809で追加されたレジスタも表示/編集できるように修正。
(2)Bコマンド
ブレークポイントコマンド、というよりブレーク後の動作はレジスタ追加にともないスタックが違うので対応。
(3)Gコマンド
実行コマンドはブレークポイントと関連があり、レジスタを全プッシュしてRTIでユーザプログラムへ分岐させているのでブレーク動作と同様に修正。
RTIはIRQとFIRQを判別するためCCRのEビットをチェックする。CCRをスタックにプッシュする前にEビットをたてておく。
2.その他変更点
USB-シリアル変換等に使っているPICは10ms間隔で短パルスをだしていて、6809ボードはそれをFIRQに受けている。したがってFIIRQをシステムタイマとして使用。実際の処理は他のタイマ対応ボードと同様に、内部カウンタをカウントアップするだけ。
FIRQを使用するにはコンディションコードレジスタのFビットをクリア。
3.簡単なテストプログラム。
各レジスタの値を変更して終了するだけのプログラムを作成。
Lで読み込んでGで実行し、モニタ復帰時に表示されるユーザプログラム終了時レジスタの値がセットした値と一致するか?
一致しているのでだいたい動作している模様。
その他、6809らしくプログラムを書き換えようかと思ったが、元々の6800用から6801用変更時にもそのままにしている部分も多く、面倒くさいのでとりあえずおいといて気が向いたら変更していこうかと思う。
一応、C言語でいうところのmemcpyとかstrcpyみたいな内部ルーチンがあって、そういうブロック転送的なところにはX以外にYレジスタを使うよう変更してみた。
1.変更点はモニタコマンドとしては以下の3つ。
(1)Rコマンド
レジスタ表示/編集コマンドは6809で追加されたレジスタも表示/編集できるように修正。
(2)Bコマンド
ブレークポイントコマンド、というよりブレーク後の動作はレジスタ追加にともないスタックが違うので対応。
(3)Gコマンド
実行コマンドはブレークポイントと関連があり、レジスタを全プッシュしてRTIでユーザプログラムへ分岐させているのでブレーク動作と同様に修正。
RTIはIRQとFIRQを判別するためCCRのEビットをチェックする。CCRをスタックにプッシュする前にEビットをたてておく。
2.その他変更点
USB-シリアル変換等に使っているPICは10ms間隔で短パルスをだしていて、6809ボードはそれをFIRQに受けている。したがってFIIRQをシステムタイマとして使用。実際の処理は他のタイマ対応ボードと同様に、内部カウンタをカウントアップするだけ。
FIRQを使用するにはコンディションコードレジスタのFビットをクリア。
3.簡単なテストプログラム。
各レジスタの値を変更して終了するだけのプログラムを作成。
Lで読み込んでGで実行し、モニタ復帰時に表示されるユーザプログラム終了時レジスタの値がセットした値と一致するか?
一致しているのでだいたい動作している模様。
その他、6809らしくプログラムを書き換えようかと思ったが、元々の6800用から6801用変更時にもそのままにしている部分も多く、面倒くさいのでとりあえずおいといて気が向いたら変更していこうかと思う。
一応、C言語でいうところのmemcpyとかstrcpyみたいな内部ルーチンがあって、そういうブロック転送的なところにはX以外にYレジスタを使うよう変更してみた。
6809でオリジナルモニタ(1) [6809]
色々手を出して全てが中途半端になってしまっているが、今回は6809。
前回の6800と6809の話の続きでもある。
新しく6809ボード。
ACIA(MC6850)とUSB-COM変換のPICといういつもの構成。6802ボードのCPUを6809に変えただけでもある。
ここでは初見ながら既にリビジョンがC(苦笑)。新しくと言いながらも製作したのは約1年前だし色々ポカやって、実はこれもジャンパ飛ばしていてリビジョンDに進むのが決定している。
まずはオリジナルモニタを移植。
MC6802ボード用につくったモニタをベースにMC6801(HD6303)向けに修正したので、今度はMC6801のモニタをMC6809用に修正。
6303用モニタがベースなので、まずは内蔵ペリフェラル関係のものをごっそり削る。
かわりにACIA関係をMC6802モニタからコピー。
追加された割込(FIRQ,SWI2,SW#)を念のため実装。ただしRTIするだけ。
メモリマップはほぼ変更なし。
この状態でとりあえずアセンブルしてみる。
そしてエラーを修正していく。
(1)スタック関連
まず、6809になって大きく変わったのがスタック関係。
ユーザスタックポインタが追加されただけでなく、命令も大きく変わっている。
6800はpsha,pshb,pula,pulbと、個々のレジスタ(アキュムレータ)に対して個々の命令を割り当てている。インデックスレジスタに対するモノがないのが、個人的に感じる6800の一番の問題点。これは6801になって追加されている。
6809はシステムスタックポインタ、ユーザスタックポインタに対してそれぞれpshs,puls,pshu,puluとなっている。
どのレジスタを退避/復帰するかはオペランドで指定する。これは
pshs a,b,x,y
とまとめて指定できるのは非常に便利。
したがってスタックに関する命令は全て変更。
(2)コンディションコードレジスタ関連
コンディションコード関係は6800/1ではビット毎に個別のセット/リセット命令があったが、6809ではORとANDで一括でセット/リセット。ニーモニックはORCC、ANDCC。
つまり、OR,ANDの論理演算命令がアキュムレータに対してだけでなく、コンディションコードレジスタにまで拡張されているという解釈。ただしイミディエイトアドレッシングしか使えない。
割込マスクのセット/リセットはシステム関係をやらない限りあまり使う事はないが、キャリーのセット/リセットぐらいはよく使うので要変更。
(3)インデックスレジスタのインクリメント/デクリメント
6809ではなくなっている。
INX,DEXは特定レジスタ向けの特定命令だったという解釈なのだろうか?アキュムレータに対するINC,DECはなくなったわけではない。
INC,DECは簡潔で便利なんだが、
LEAX 1,X
に変更。
まぁ+3したいときは
LEAX 3,X
とできるのでこれも便利といえば便利。
(4)ニーモニック変更
6800/1 →6809変更に伴う命令の変更は以上だが、
大量にでたアセンブルエラーは
本来6800/1、6809どちらにもある命令なのだがニーモニック表記が変更されている。
LDAA等は確かにくどいとは思うが、同じ命令で大半はマシンコードも同じ、さらにCPU別になっているとはいえソースも共有されている同じモトローラのアセンブラなんだから通してくれても良いと思う。
以上、もろもろ修正しただけでとりあえず動くことは動く。
レジスタ増えてスタックが変わってしまっているので、ブレークポイントコマンドなんかはたぶんおかしくなるだろうが。
では次に6809固有の命令を使って修正していき、モニタを完成させたい。
前回の6800と6809の話の続きでもある。
新しく6809ボード。
ACIA(MC6850)とUSB-COM変換のPICといういつもの構成。6802ボードのCPUを6809に変えただけでもある。
ここでは初見ながら既にリビジョンがC(苦笑)。新しくと言いながらも製作したのは約1年前だし色々ポカやって、実はこれもジャンパ飛ばしていてリビジョンDに進むのが決定している。
まずはオリジナルモニタを移植。
MC6802ボード用につくったモニタをベースにMC6801(HD6303)向けに修正したので、今度はMC6801のモニタをMC6809用に修正。
6303用モニタがベースなので、まずは内蔵ペリフェラル関係のものをごっそり削る。
かわりにACIA関係をMC6802モニタからコピー。
追加された割込(FIRQ,SWI2,SW#)を念のため実装。ただしRTIするだけ。
メモリマップはほぼ変更なし。
この状態でとりあえずアセンブルしてみる。
そしてエラーを修正していく。
(1)スタック関連
まず、6809になって大きく変わったのがスタック関係。
ユーザスタックポインタが追加されただけでなく、命令も大きく変わっている。
6800はpsha,pshb,pula,pulbと、個々のレジスタ(アキュムレータ)に対して個々の命令を割り当てている。インデックスレジスタに対するモノがないのが、個人的に感じる6800の一番の問題点。これは6801になって追加されている。
6809はシステムスタックポインタ、ユーザスタックポインタに対してそれぞれpshs,puls,pshu,puluとなっている。
どのレジスタを退避/復帰するかはオペランドで指定する。これは
pshs a,b,x,y
とまとめて指定できるのは非常に便利。
したがってスタックに関する命令は全て変更。
変更前 | 変更後 |
---|---|
PSHA | PSHS A |
PSHB | PSHS B |
PULA | PULS A |
PULB | PULS B |
PSHX | PSHS X |
PULX | PULS X |
(2)コンディションコードレジスタ関連
コンディションコード関係は6800/1ではビット毎に個別のセット/リセット命令があったが、6809ではORとANDで一括でセット/リセット。ニーモニックはORCC、ANDCC。
つまり、OR,ANDの論理演算命令がアキュムレータに対してだけでなく、コンディションコードレジスタにまで拡張されているという解釈。ただしイミディエイトアドレッシングしか使えない。
割込マスクのセット/リセットはシステム関係をやらない限りあまり使う事はないが、キャリーのセット/リセットぐらいはよく使うので要変更。
変更前 | 変更後 |
---|---|
SEI | ORCC #$10 |
CLI | ANDCC #$EF |
SEC | ORCC #$01 |
CLC | ANDCC #$FE |
(3)インデックスレジスタのインクリメント/デクリメント
6809ではなくなっている。
INX,DEXは特定レジスタ向けの特定命令だったという解釈なのだろうか?アキュムレータに対するINC,DECはなくなったわけではない。
INC,DECは簡潔で便利なんだが、
LEAX 1,X
に変更。
まぁ+3したいときは
LEAX 3,X
とできるのでこれも便利といえば便利。
変更前 | 変更後 |
---|---|
INX | LEAX #1,X |
DEX | LEAX #-1,X |
(4)ニーモニック変更
6800/1 →6809変更に伴う命令の変更は以上だが、
大量にでたアセンブルエラーは
LDAA | LDAB | STAA | STAA |
本来6800/1、6809どちらにもある命令なのだがニーモニック表記が変更されている。
LDAA等は確かにくどいとは思うが、同じ命令で大半はマシンコードも同じ、さらにCPU別になっているとはいえソースも共有されている同じモトローラのアセンブラなんだから通してくれても良いと思う。
変更前 | 変更後 |
---|---|
LDAA | LDA |
LDAB | LDB |
STAA | STA |
STAB | STB |
以上、もろもろ修正しただけでとりあえず動くことは動く。
レジスタ増えてスタックが変わってしまっているので、ブレークポイントコマンドなんかはたぶんおかしくなるだろうが。
では次に6809固有の命令を使って修正していき、モニタを完成させたい。
6800と6809の互換性 [6809]
今回は製作記事ではなくて、インストラクションセットの話
あらためて言うまでもないが、6809は6800とオブジェクトレベルでは互換性はない。が、全くの別物というわけではない。あくまで6800、正確には6801を拡張/変更したものであり、両方に存在する命令の多くはマシンコードも同じである。
残念ながら、全てが同一でないし、6800から削られた命令の中にはなくては困るものもあり、またその代替となる新規命令も当然のように元とはマシンコードがことなるため、同一オブジェクトで6800、6809両方で動作させる事は不可能に近い。
6800にたいしての6809の変更点であるが、
CPUはメモリ上にあるデータを処理していくという事を基本として、その部分の強化に重点が置かれていると思う。
そのためにインデックスレジスタYとユーザスタックポインタを追加し、アドレッシングモードの大幅な拡張が行われている。
それに対して特定のレジスタに特化した命令(コンディションコードのセット/リセット等)、レジスタ間の命令(TAB,TBA等)は削除されている。
CPU(レジスタ)-メモリ間の転送と処理(演算等)を柔軟に行えるように強化変更されている。
では、6800に対してどういう変更が行われているのであろうか?
実際には6801に対して変更されているので、6801に対してみてみる。
どのCPUでもそうだがマシンコードは適当に割り振られているわけではなく、特定のビットに命令の種類等が割り振られている。
8080ならb7b6の上位2bitが転送、演算、分岐等の命令の種類を示し、続くb5b4b3の3bitがディスティネーション、b2b1b0の3bitがソースのような感じにだいたいなっている。
もちろん、分岐命令ではソース/ディスティネーションのところは別の意味となる。
6800はどうか?大雑把に言うと
最上位ビットが1、マシンコードで$8x以降に関しては
上記の表より、例えばマシンコードが
10100110(=$A6)はLDAAのインデックスアドレッシングであり、インデックスアドレッシングは2バイト目がオフセットなので、オフセットが5の場合はアセンブルリスト風に書けば
となる。
上位4bitが0000~0111に関しては
主にオペランドをとらないInherentとRelativeアドレッシングをとる分岐命令が存在するが、
b5b4が10,11となる$6x,$7xは、IndexedおよびExtendedアドレッシングのシフト、ローテート命令が並んでいる。
それ以外では$2xの行が条件ブランチ命令、$0x,1x,3x,4x,5xはInherentアドレッシングの命令が、下位4bitを命令種別としてわりときれいに並んでいる。
6800から削られた命令は$0x,$1xの行にあるので、この2行からごっそり削り取られ、新規命令が追加された形になる。
追加された命令にはDirectアドレッシングをとるものがあり、Directアドレッシングのマシンコードは上の表よりb5b4が01なので$1xに割り振られた、
のかと思いきや、なぜか$0xの行に並んでいる。
その影響で元から存在するNOP命令のマシンコードが$01から$22に変更されている。
それ以外では継承されている命令のマシンコードに変更はないようである。$00~$7Fに関しては。
後半($80~)で変更があるのは$xEと$xFの2列。
$8E,$9E,$AE,$BEがLDS,$9F,$AF,$BFがSTSとスタックポインタに関する命令だったのが
LDXとSTXに変更。LDX,STXは$Bx~$Fxの$xE,$xFの列にあったのでずらした感じになる。
かわりに$Bx~$FxのE,F列にスタックポインタ命令が入っているので入れ替わったようになっているが、実際に入ったのはユーザスタックポインタに関する命令LDU,STUであり、システムスタックポインタのPage2の$Bx~$Fxの$xE,$xF列に移動している。
Page2命令はプリフィクスコード$10がつくので、システムスタックポインタへのロードストアは
命令長、実行時間ともに長くなる。
あらたに追加されたインデックスレジスタYに関する命令群もPage2に存在する。
マシンコードもインデックスレジスタXに関するLDX,STX,CMPXと同じ配置なのでプリフィクスコード$10がつけばY、つかなければXに対する命令となる。
Page3も存在し(プリフィクスコード$11)、SWI命令はPage2がSWI2、Page3がSWI3となる。
Page3にはそれ以外にスタックポインタの比較命令が存在する。
コードマップを見る限り、アドレッシングモードは6800からあいかわらずの
Inherent,Immidiate,Direct,Indexed,Extenedの5つしかない。
マニュアルを見てもまとめられた命令表にはその5つしかなく、命令表を見比べただけでは6800との差はあまりない。
では6809ではアドレッシングモードが大幅に拡張されているが、どうなっているのであろうか?
追加されたアドレッシングモードは
全てインデックスレジスタを介したアドレッシングモードである。
したがってインデックスアドレッシングを拡張する形で追加されている。
6800のインデックスアドレッシングは第2バイトがオフセット値となるが、6809では第2バイトがポストバイトコードとなり、このポストバイトコードによって数あるインデックスアドレッシングモードから具体的なアドレッシングモードが決まる。
このうち上位4bitが0の場合がゼロ・オフセット・インデックスで6800の
インデックスアドレッシングとほぼ同じものであるが、符号付なのでオフセットは-8~+7となる。
6800、6809ともに存在する命令でインデックスアドレッシングを使い、オフセットを0~7の範囲に留めておくとマシンコードは同一となるので、上記で示した
LDA #5,X
という命令は6809でも同一のマシンコードとなる。
命令表を見比べた限りでは6800/1と6809の違いはあまりなく、6800 -> 6801 -> 6809と順当に進化していっているような印象で、同一命令の大部分はマシンコードも同じなため、共通の命令だけを使っていれば共有オブジェクトコードができるのでは?という錯覚に私などは陥ってしまう。
実際にはマシンコードマップが一部変更されているので完全上位互換とはいかないが
アセンブリ言語レベルでは小変更でアセンブルし直せばすむレベルにはなっている。
6809の真骨頂は拡張された部分にあるのだが。
ほぼ文字だけの長文にお付き合いいただき、ありがとうございました。
あらためて言うまでもないが、6809は6800とオブジェクトレベルでは互換性はない。が、全くの別物というわけではない。あくまで6800、正確には6801を拡張/変更したものであり、両方に存在する命令の多くはマシンコードも同じである。
残念ながら、全てが同一でないし、6800から削られた命令の中にはなくては困るものもあり、またその代替となる新規命令も当然のように元とはマシンコードがことなるため、同一オブジェクトで6800、6809両方で動作させる事は不可能に近い。
6800にたいしての6809の変更点であるが、
CPUはメモリ上にあるデータを処理していくという事を基本として、その部分の強化に重点が置かれていると思う。
そのためにインデックスレジスタYとユーザスタックポインタを追加し、アドレッシングモードの大幅な拡張が行われている。
それに対して特定のレジスタに特化した命令(コンディションコードのセット/リセット等)、レジスタ間の命令(TAB,TBA等)は削除されている。
CPU(レジスタ)-メモリ間の転送と処理(演算等)を柔軟に行えるように強化変更されている。
では、6800に対してどういう変更が行われているのであろうか?
実際には6801に対して変更されているので、6801に対してみてみる。
どのCPUでもそうだがマシンコードは適当に割り振られているわけではなく、特定のビットに命令の種類等が割り振られている。
8080ならb7b6の上位2bitが転送、演算、分岐等の命令の種類を示し、続くb5b4b3の3bitがディスティネーション、b2b1b0の3bitがソースのような感じにだいたいなっている。
もちろん、分岐命令ではソース/ディスティネーションのところは別の意味となる。
6800はどうか?大雑把に言うと
最上位ビットが1、マシンコードで$8x以降に関しては
b7 | b6 | 対象レジスタ |
---|---|---|
1 | 0 | AccA |
1 | 1 | AccB |
b5 | b4 | アドレッシングモード |
---|---|---|
0 | 0 | Immidiate |
0 | 1 | Direct |
1 | 0 | Indexed |
1 | 1 | Extended |
b3 | b2 | b1 | b0 | 命令種別 |
---|---|---|---|---|
0 | 0 | 0 | 0 | SUB |
0 | 0 | 0 | 1 | CMP |
0 | 0 | 1 | 0 | SBC |
0 | 0 | 1 | 1 | SUBD(6801),ADDD(6801) |
0 | 1 | 0 | 0 | AND |
0 | 1 | 0 | 1 | BIT |
0 | 1 | 1 | 0 | LDA |
0 | 1 | 1 | 1 | STA |
1 | 0 | 0 | 0 | EOR |
1 | 0 | 0 | 1 | ADC |
1 | 0 | 1 | 0 | ORA |
1 | 0 | 1 | 1 | ADD |
1 | 1 | 0 | 0 | CMP,LDD(6801) |
1 | 1 | 0 | 1 | JSR(BBSR),STD(6801) |
1 | 1 | 1 | 0 | LDS,LDX |
1 | 1 | 1 | 1 | STS,STX |
上記の表より、例えばマシンコードが
10100110(=$A6)はLDAAのインデックスアドレッシングであり、インデックスアドレッシングは2バイト目がオフセットなので、オフセットが5の場合はアセンブルリスト風に書けば
A6 | 05 | LDAA | #5,X |
となる。
上位4bitが0000~0111に関しては
主にオペランドをとらないInherentとRelativeアドレッシングをとる分岐命令が存在するが、
b5b4が10,11となる$6x,$7xは、IndexedおよびExtendedアドレッシングのシフト、ローテート命令が並んでいる。
それ以外では$2xの行が条件ブランチ命令、$0x,1x,3x,4x,5xはInherentアドレッシングの命令が、下位4bitを命令種別としてわりときれいに並んでいる。
6800から削られた命令は$0x,$1xの行にあるので、この2行からごっそり削り取られ、新規命令が追加された形になる。
追加された命令にはDirectアドレッシングをとるものがあり、Directアドレッシングのマシンコードは上の表よりb5b4が01なので$1xに割り振られた、
のかと思いきや、なぜか$0xの行に並んでいる。
その影響で元から存在するNOP命令のマシンコードが$01から$22に変更されている。
それ以外では継承されている命令のマシンコードに変更はないようである。$00~$7Fに関しては。
後半($80~)で変更があるのは$xEと$xFの2列。
$8E,$9E,$AE,$BEがLDS,$9F,$AF,$BFがSTSとスタックポインタに関する命令だったのが
LDXとSTXに変更。LDX,STXは$Bx~$Fxの$xE,$xFの列にあったのでずらした感じになる。
かわりに$Bx~$FxのE,F列にスタックポインタ命令が入っているので入れ替わったようになっているが、実際に入ったのはユーザスタックポインタに関する命令LDU,STUであり、システムスタックポインタのPage2の$Bx~$Fxの$xE,$xF列に移動している。
Page2命令はプリフィクスコード$10がつくので、システムスタックポインタへのロードストアは
命令長、実行時間ともに長くなる。
あらたに追加されたインデックスレジスタYに関する命令群もPage2に存在する。
マシンコードもインデックスレジスタXに関するLDX,STX,CMPXと同じ配置なのでプリフィクスコード$10がつけばY、つかなければXに対する命令となる。
Page3も存在し(プリフィクスコード$11)、SWI命令はPage2がSWI2、Page3がSWI3となる。
Page3にはそれ以外にスタックポインタの比較命令が存在する。
コードマップを見る限り、アドレッシングモードは6800からあいかわらずの
Inherent,Immidiate,Direct,Indexed,Extenedの5つしかない。
マニュアルを見てもまとめられた命令表にはその5つしかなく、命令表を見比べただけでは6800との差はあまりない。
では6809ではアドレッシングモードが大幅に拡張されているが、どうなっているのであろうか?
追加されたアドレッシングモードは
- ゼロ・オフセット・インデックス(6800のインデックスアドレッシングとほぼ同等)
- コンスタント・オフセット・インデックス
- アキュムレータ・オフセット・インデックス
- オート・インクリメント/デクリメント・インデックス
- インデックス・インダイレクト
全てインデックスレジスタを介したアドレッシングモードである。
したがってインデックスアドレッシングを拡張する形で追加されている。
6800のインデックスアドレッシングは第2バイトがオフセット値となるが、6809では第2バイトがポストバイトコードとなり、このポストバイトコードによって数あるインデックスアドレッシングモードから具体的なアドレッシングモードが決まる。
このうち上位4bitが0の場合がゼロ・オフセット・インデックスで6800の
インデックスアドレッシングとほぼ同じものであるが、符号付なのでオフセットは-8~+7となる。
6800、6809ともに存在する命令でインデックスアドレッシングを使い、オフセットを0~7の範囲に留めておくとマシンコードは同一となるので、上記で示した
LDA #5,X
という命令は6809でも同一のマシンコードとなる。
命令表を見比べた限りでは6800/1と6809の違いはあまりなく、6800 -> 6801 -> 6809と順当に進化していっているような印象で、同一命令の大部分はマシンコードも同じなため、共通の命令だけを使っていれば共有オブジェクトコードができるのでは?という錯覚に私などは陥ってしまう。
実際にはマシンコードマップが一部変更されているので完全上位互換とはいかないが
アセンブリ言語レベルでは小変更でアセンブルし直せばすむレベルにはなっている。
6809の真骨頂は拡張された部分にあるのだが。
ほぼ文字だけの長文にお付き合いいただき、ありがとうございました。