Posts Tagged with "Design"

既に発行済みのブログであっても適宜修正・追加することがあります。
We may make changes and additions to blogs already published.

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を解除する
  1. サブ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の退避後まで遅延させれば、動作するはずです。

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

6809の割込み動作(3)

posted by sakurai on August 16, 2019 #150

調査の結果、割込み後のIRQマスクをCCRに全く反映していませんでした。ちなみに、CCRの仕様は6809マイコン・システム設計作法によれば、以下の図のようになっています。

図%%.1
図150.1 CCR

これだと動作が分からないのですが、その次に以下のような説明があります。

図%%.2
図150.2 Iフラグの説明

ついでにEフラグの説明も載せておきます。

図%%.3
図150.3 Eフラグの説明

Verilogソースコードを見ると、CCRのうち、Iフラグは全く設定されていないようですが、EフラグはIRQ割込みの際にセットされていたので、とりあえず、Eフラグを立てるタイミングでIフラグにコピーしました。本来は割込みの種類によりIフラグとFフラグのセット仕分けをしなければなりません。

ところが、タイムチャートのようにIフラグをセットしたので、これで正常動作するかと思ったのですが、動作は変わりません。Iフラグは参照もされていないようです。つまり、このIPの割込みは全く動作しないということができます。


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

6809の割込み動作(2)

posted by sakurai on August 15, 2019 #149

内部ステートを表示します。割込みがかかってから、スタックにプッシュし、ベクタフェッチするまではOKですが、その後にさらにスタックプッシュが入るところが誤っています。

図%%.1
図149.1 割込み動作のタイミングチャート

ステート遷移は以下のようになっています。

\$09 SEQ_FETCH
\$0F SEQ_DECODE
\$33 SEQ_PC_READ_L
\$34 SEQ_PC_READ_L_1
\$35 SEQ_PC_READ_L_2
\$1B SEQ_JMP_LOAD_PC
\$09 SEQ_FETCH
\$03 SEQ_IRQ
(ここから)
\$20 SEQ_PREPUSH
\$22 SEQ_PUSH_WRITE_L
\$23 SEQ_PUSH_WRITE_L_1
\$24 SEQ_PUSH_WRITE_H
\$25 SEQ_PUSH_WRITE_H_1
(16バイトストアを4回繰り返し、PC, US, IY, IX)
\$20 SEQ_PREPUSH
\$22 SEQ_PUSH_WRITE_L
\$23 SEQ_PUSH_WRITE_L_1
(8バイトストアを4回繰り返し、DP, B, A, CC)
\$36 SEQ_MEM_READ_H
\$37 SEQ_MEM_READ_H_1
\$38 SEQ_MEM_READ_H_2
\$3A SEQ_MEM_READ_L_1
\$3B SEQ_MEM_READ_L_2
\$08 SEQ_LOADPC
\$09 SEQ_FETCH
\$03 SEQ_IRQ
(再度IRQ処理)


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

6809の割込み動作

posted by sakurai on August 14, 2019 #148

メインCPUとサブCPUはお互いに割込みを掛け合います。メインCPUからは通常、サブCPUのbusyを確認し、readyであればサブCPUをHALTし、共有メモリにコマンドを書き込んだ後、HALTをネゲートします。サブCPUはすぐにbusyにした後、コマンドを解析し、処理を行います。

これが通常シーケンスですが、例えば時間のかかる処理をサブCPUがやっていた場合に中止させたい時には割込みをかけるしかありません。これをCANCEL割込みといいます。逆に、サブCPUからメインCPUに用事がある場合にはATTENTION割込みをかけます。

さて、メインCPUの割込みの一つにタイマー割込みがあり、これをシミュレーションしてみます。タイマー割り込みはIRQに接続されているため、IRQ割り込みハンドラをプログラムします。IRQは全レジスタのセーブリストアが自動で行われます。割り込みハンドラでは、まずタイマ割り込み要因のクリアを行った後、要因レジスタは負論理であるため、反転してメモリに書きだした後でRTIで元の命令列に戻ります。

1000         stack  equ   \$1000
2000         ustack equ   \$2000
FE00         start  org   \$fe00
           
FE00 10CE1000        lds   #stack
FE04 CE2000         ldu   #ustack
FE07 8EFD02         ldx   #\$FD02     ; IRQ Mask Reg
FE0A 86FF          lda   #\$FF      ; Timer IRQ unmask
FE0C A784          sta   ,X       ; Timer IRQ enabled
FE0E 20FE          bra   *
           
FE10         firq  equ *
FE10         irq   equ *
FE10 8EFD03         ldx   #\$FD03     ; IRQ event reg
FE13 A684          lda   ,X       ; IRQ clear
FE15 8AFB          ora   #\$FB
FE17 70FE17         eora   #\$FF
FE1A B73000         sta   \$3000
FE1D 3B           rti
           
FFF6             org   \$fff6
FFF6 FE10          fdb   firq
FFF8             org   \$fff8
FFF8 FE10          fdb   irq       ; Timer IRQ
FFFE             org   \$fffe
FFFE FE00          fdb   start
           
0000             end

まずリセット後にFD02をライトし、割込みマスクを許可します。'1'をライトすると許可となります。

図%%.1
図148.1 割込みイネーブルのタイミングチャート

次にタイマー割込みがかかるとスタックに全レジスタを退避します。PC, US, IY, IX, DP, B, A, CCの12バイトです。

図%%.2
図148.2 レジスタ退避のタイミングチャート

次に\$FFF8から2バイトをフェッチします。ところが、\$FFF8の示すアドレスにジャンプする前に再度全レジスタをスタックに退避しています。

図%%.3
図148.3 割込みベクタフェッチのタイミングチャート

割込みが入った場合、直ちに割込みマスクがかからなければ、無限に割込みが入るので、これはCPUのIRQマスクのバグと思われます。


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


ページ: