Posts Issued in August, 2019

FM-7 ROM吸出し器の製作 (5)

posted by sakurai on August 29, 2019 #160

サブシステムのROM吸出しの際に、サブシステムの動作確認をするために、Arduinoからランダムなボックスフィルを実行してみました。いかにもFBASICで描画しているように見えますが、Z80カードのエミュレーションをArduinoがやっています。その様子を図160.1に示します。

図%%.1
図160.1 サブシステムの動作

以下の動作を実行するスケッチを作成しました。

  • \$FD05のMSBが0になるのを待つ
  • \$FD05のMSBを1に(サブシステムをHALT)、LSBを1に(メインシステムをHALTしZ80側に)するーつまり\$FD05に\$81をwrite
  • 共有メモリにLineコマンド及びランダムな座標パラメータを書き込む
  • \$FD05のMSBを0に(サブシステムHALTの解除)、LSBを1に(メインシステムをZ80側のまま)するーつまり\$FD05に\$01をwrite
  • 最初に戻りループ

左矢前のブログ 次のブログ右矢

FM-7 ROM吸出し器の製作 (4)

posted by sakurai on August 28, 2019 #159

メインシステムROMの吸出しは非常に単純で、アドレスをセットして、データをリードするだけでしたが、サブシステムのROMはサブシステム側に依頼しないと読み出せません。従って、前に述べたように、メンテナンスコマンド(いわゆるYAMAUCHIコマンド$\dagger$)を用いてブロックコピーし、分割読み出しすることになります。これは、サブシステムのROMが10,240バイトもあるのに比べて、窓である共有メモリがわずか128バイトしかなく、コマンドにいくらか使用するため、データ転送用の窓を64バイトとしているためです。そのため、この転送を160回繰り返します。64バイト毎に16進ダンプを行います。

FM-7/8 Subシステムメンテナンスコマンドのページ(魚拓)を参考にスケッチを作成します。作成したスケッチをここに置きました。

図%%.1
図159.1 サブROMコピーの動作図

いちいちサブシステムを止めてコマンドを(2度)発行してダンプを行うので、かなり面倒でしたが、このスケッチにより得られたダンプ画面の最初と最後を示します。

d800 00 00 00 00 00 00 00 00 70 40 70 1a 7a 0e 0a 0a
d810 70 40 70 12 74 08 14 22 70 40 70 42 74 08 14 22
d820 70 40 70 40 7e 04 04 04 e0 80 e0 8c f2 12 12 0d
d830 20 50 70 52 54 18 14 12 70 48 70 4c 74 04 04 07
:
ffc0 02 10 ae a4 10 9f 47 bd b5 9c bd 9b 35 be 01 82
ffd0 20 d3 be 01 84 ae 02 20 a9 bd 02 69 34 ff 86 00
ffe0 1f 8b 10 ff 03 16 10 fe 03 16 bd 9b 35 86 2a 8d
fff0 e0 00 e0 00 e0 00 fd ac e0 6e e0 00 fe bf e0 00

同じくネットで入手したSubrom_c.romと比較したところ、全てのバイトが一致しました。若干疑問なのは、スクラッチから作成したと言われているROMデータが実ROMデータを全て一致するということがあるのだろうかということです。とりあえず、実機から抜き出したROMデータを使用している分には問題が無いので、気にしないことにします。

$\dagger$山内さんは入社した時の課内ソフトウェアグループのサブシステムチームのリーダでした。


左矢前のブログ 次のブログ右矢

FM-7 ROM吸出し器の製作 (3)

posted by sakurai on August 27, 2019 #158

Arduino Mega 2560 Proの端子図を図158.1及び図158.2に示します。

図%%.1
図158.1 Arduino Mega 2560 Proの端子図

図%%.2
図158.2 Arduino Mega 2560 Proの端子図(右側の端子)

アドレス、データ、制御信号を全てソフトコントロールしています。スケッチはここに置きました。ただし、初版からデータピンの位置を変更しているため、ボードの版数に合わせて適宜修正する必要があります。

これにより吸い出したfbasic30 ROM(\$8000~\$FBFF)生データの一部を示します。

8000 8e 80 13 ce 01 f9 c6 0a bd 85 97 8e 80 26 c6 0a
8010 7e 85 97 06 80 1d 80 5a 09 80 1d 80 77 a0 a0 a0
8020 a0 a0 a0 a0 a0 a0 06 80 30 80 5a 01 80 71 80 77
8030 43 48 41 49 ce 45 52 41 53 c5 4c 4c 49 53 d4 4c
:
:
fbc0 e1 7e 9b 50 7e 8d d1 7e af 1a 7e 96 63 7e b2 34
fbd0 7e b0 ee 7e af 11 7e cc 37 7e af 97 7e ce dc 7e
fbe0 ce df 7e b0 44 7e e3 4d 7e da f9 7e da ef 7e d4
fbf0 df 7e c2 8c 7e c6 7a 7e da f6 f1 7d 86 84 84 8b

このままCOEファイルに変換するか、あるいはバイナリにすれば、前稿のスクリプトが使えますが、簡単なのでこのままawkによりCOE化することにします。

ネットで入手したFM-7エミュレータ用のROMデータと実機から吸い上げた生データを比較したところ、fbasic30.coeは全てのバイトが一致しました。 一方boot.coeは末尾の2 lineが不一致となりました。エミュレータ用のROMでは0xffとなっていますが、実機のROMは割込みベクタが置かれているためにデータが入っています。

エミュレータ用ROMの末尾32バイト:

ffe0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
fff0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

実機ROMの末尾32バイト:

ffe0 ff ff ff ff ff ff 01 04 ff ff ff ff ff ff ff ff
fff0 ff ff 01 d1 01 d4 01 e0 01 dd 01 d7 01 da fe 00

ところが、「FM-7ユーザーズマニュアルシステム仕様」を見ると、\$FFE0~\$FFFFはベクトル領域となっており、boot ROMではないため、これで全てのバイトが一致しました。

末尾32バイトはベクトル領域というRAM領域でジャンプテーブルとなっています。飛び先のRAMの内容を含めて表にまとめます。

図%%.3
図158.3 割込みベクタまとめ表
FIRQ割込みハンドラは\$C953から、IRQ割込みハンドラは\$D2FCからのようです。本カードにより(メインCPUを停止し)\$AAを書き込んだところ、以下のようになったため、\$FFE0~\$FFFDはRAM、\$FFFE~$\$FFFFはROMのようです。

ffe0 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
fff0 aa aa aa aa aa aa aa aa aa aa aa aa aa aa fe 00


左矢前のブログ 次のブログ右矢

FM-7 ROM吸出し器の製作 (2)

posted by sakurai on August 26, 2019 #157

ArduinoとPCはUSBケーブルで接続し、それを通じてプログラムするのですが、そのケーブルを通じて通信することができます。具体的にはArduino側でprintln()関数を実行すると、PC側でArduino IDEの機能であるシリアルモニターを立ち上げておけば、データを表示することができるので、これを利用します。ちなみに、Arduino IDEの機能であるシリアルプロッターという便利なものがあり、Arduino側でデータを出力すれば、IDE側でグラフをリアルタイムで書いてくれ、オートスケールまでしてくれます。

面倒なのはArduino側で並列データの概念が無く、bitの入出力しかないため、アドレスのライトはbitに分解し、データのリードはbitを統合してやる必要があることです。以下にパラシリ、シリパラ変換を示します。

16ビットアドレスの分解(パラ⇒シリ)

int apb = 54;
boolean b;
unsigned address = 0x8000;
unsigned ad;
 :
ad = address;
for (int i = 0; i < 16; i++) {
 b = ad & 1;
 digitalWrite(apb+i, b);
 ad = ad >> 1;
}

このコードの動作図を図157.1に示します。

図%%.1
図157.1 パラシリ動作図解

8ビットデータの組み上げ(シリ⇒パラ)

int dpb = 39;
boolean b;
unsigned data;
 :
data = 0;
for (int i = 0; i < 8; i++) {
 data = data << 1;
 b = digitalRead(dpb-i);
 data = data | b;
}

このコードの動作図を図157.2に示します。

図%%.2
図157.2 シリパラ動作図解

左矢前のブログ 次のブログ右矢

FM-7 ROM吸出し器の製作

posted by sakurai on August 24, 2019 #156

設計編はこちらです。

FusionPCBからベースボードが届きました。今回はベンダによる部品実装は無しで、2層ボードのみの製造なので4.9 USD+配送料と、格安です。 今回は製造に6.85日、DHLによる配送に3.34日かかりました。

図%%.1
図156.1 FM-7ROM吸出しベースボード

ベースボードとArduino Mega 2560 Proボード及び40pinコネクタの写真です。この他に動作確認用のLED及びそのドライバTr、抵抗があります。

費用は配送料別で、Arduino Mega 2650 Proが975円、基板が上記のように522円、コネクタが(写真のコネクタではなく、純正のFCN-365P040-AU)が743円、合計2,240円でした。この他に配送料が若干かかっていますが、2つの目的である、

  • FM-7側にソフトウェアを置かないこと(FM-7側にはファイルシステムが無いため管理できない)
  • 価格が安いこと

が達成できました。

図%%.2
図156.2 部品一式

組み立てました。動作確認をするため、基本動作に無関係なLED等は未実装としています。

図%%.3
図156.3 FM-7 ROM吸出し器

左矢前のブログ 次のブログ右矢

6809の割込み動作 (8)

posted by sakurai on August 23, 2019 #155

IRQ/FIRQが正常動作したので、メインCPUとサブCPUの協調動作を実行してみます。

  1. メインCPU

    • サブCPUのreadyを待つ
    • サブCPUをhaltする
    • 共有メモリにデータを書き込む
    • 共有メモリの先頭のMSB=0で指示とする
    • サブCPUのhaltを解除する
  2. サブCPU

    • リセット後サブCPUの状態はハード的にbusy
    • サブCPUの状態をreadyにする
    • 共有メモリの先頭のMSB==0となるのを待つ
    • サブCPUの状態をbusyにする
    • 共有メモリの内容をデコードする

図%%.1
図155.1 協調動作フローチャート

このフローに基づき、協調動作のシミュレーションを行ったところ、正しく動作しました。


左矢前のブログ 次のブログ右矢

6809の割込み動作 (7)

posted by sakurai on August 22, 2019 #154

タイムチャートを見直すと、例外処理中でEフラグをクリアする処理は入っていますが、一方のセット信号が初期状態からずっと不定です。このため、Eフラグが不定となっているようです。従って、セット信号を初期状態でネゲートします。

図%%.1
図154.1 割込みタイムチャート

k_set_eの初期化をしたところ、正しく動作しました。このIPは総じて割込みの実装が中途半端にしかされておらず、割込みは実質テストしていないようです。プロセッサにおいて割込みが動作しないのは致命的であり、使い物になりません。


左矢前のブログ 次のブログ右矢

6809の割込み動作 (6)

posted by sakurai on August 21, 2019 #153

次にFIRQを実装します。同様にFフラグセット、クリア論理を入れましたが、割込みハンドラまでは正しく動作するものの、RTI命令の実行時にスタックを過剰に回復しています。積んだ以上に回復するという、いわゆるスタックアンダーフローを起こしてしまいます。

図%%.1
図153.1 割込みタイムチャート

まず、FIRQの動作を見てみると図153.2のようになります。Eフラグをクリアしてからpushすると書かれていますが、クリアされずXとなっています。

図%%.2
図153.2 FIRQの動作

次に、RTIの動作を見てみると図153.2のようになります。Eフラグは0であるべきなので、スタックからはCCR及びPCのみが回復されるはずです。が、タイムチャートではさらに他のレジスタも回復しているようです。

図%%.3
図153.3 RTIの動作

この誤動作の原因は、CCR[7]のEフラグが不定となっていることです。従って、図153.2にあるとおり、例外処理中でEフラグをクリアする処理を入れれば動作するはずです。


左矢前のブログ 次のブログ右矢

6809の割込み動作 (5)

posted by sakurai on August 20, 2019 #152

割込み禁止のCCRへの反映を遅延させるタイミングを作り出しました。全レジスタの退避が終わった後のベクタフェッチは前々稿によれば、SEQ_MEM_READ_Hステートですが、そのタイミングでレジスタにCCR書き込みを指示することを考えます。このステートにはexceptionでない場合というif文がありますが、注目する場合はexception中なので、ちょうどelseの部分に以下の文を記述します。

if (k_set_i) begin
k_set_i_timing <= 1;
k_set_i <= 0;
end

k_set_i_timingとして、k_set_iを遅延させたCCR反映タイミング信号を作り出し、これをレジスタに与えます。なお、このk_set_iはSEQ_IRQステートに入った時点でセットし、一方、RTI命令でk_clear_iをセットします。

これにより正しく割込みが入り、割り込みが禁止されたかと思ったのですが、RTIから戻るところで再度割込みが入る現象が起きました。解析すると、割込みハンドラで割込み原因をクリアしたにも関わらず、CPU内部で割込みをまだ保持していることが原因と判りました。そのため、RTI実行により割り込み許可された途端にまた割り込み処理に移行してしまいます。そこで以下のように、割込み要因を無視するタイミングゲート処理を入れたところ、正しく動作するようになりました。

(修正前)
if (!k_reg_irq[2])
k_reg_irq <= { k_reg_irq[1:0], (!cpu_irq_n)};
 

(修正後) if (!k_reg_irq[2])
k_reg_irq <= { k_reg_irq[1:0], (!cpu_irq_n & !k_set_i & !k_set_i_timing)};

図%%.1
図152.1 割込みタイムチャート

このタイマ割込みによるハンドラの実行と復帰は、タイマの周期で正しく繰り返されます。割り込みハンドラでは正しく割り込みが禁止され、RTIにより割り込み許可として元のプログラムに戻ります。元のプログラムではタイマ割り込み待ち状態となり、タイマ割り込みが入ると再びスタックへのレジスタ退避やベクタフェッチ等の割り込み処理を行います。


左矢前のブログ 次のブログ右矢

6809の割込み動作 (4)

posted by sakurai on August 19, 2019 #151

そこで、CCRを参照して割込みに入る入らないを決定させようとしたら、ソースコードで以下のような定義文を見つけました。

// flags used in MC6809_cpu.v
`define FLAGI regs_o_CCR[5]
`define FLAGF regs_o_CCR[6]
`define FLAGE regs_o_CCR[7]

前稿の図150.1のCCR構成を見てもわかるように、FLAGIのビット位置が誤っています。Iフラグの位置はbit5ではなくbit4です。これを正しいbit位置の4に修正したところ、ベクタフェッチの後に再度IRQステート遷移する動作は無くなり、フェッチしたアドレスに飛び、飛び先である割込みルーチンを実行するようになりました。

ところが、不具合がありました。割込みルーチンで割込み原因クリアをしているにも関わらず、再度の割込みが入りません。

図%%.1
図151.1 割込みタイムチャート

前稿では、図151.1のタイムチャートに示すように、Eフラグと同タイミングで仮にIフラグもセットするように修正しました。ところが、スタックにCCRを退避する前にIフラグを割込み禁止にしたため、割り込み禁止状態のCCRが退避され、割り込みルーチンの最後で回復されたものです。つまりIフラグのセットが早すぎたわけです。

正しくは、図151.2の6809割込みにあるように、IフラグはCCRを退避してからセットしなければなりません。安直にEフラグと同タイミングでセットしたため、割込みが再度かからなくなってしまったものです。

図%%.2
図151.2 割込み動作
ここまで動けば後一息、IフラグセットをCCRの退避後まで遅延させれば、動作するはずです。

左矢前のブログ 次のブログ右矢


ページ: