自作CPU #15 外部端子割り込みと周辺機能って同時に使用できるんですね

f:id:Hamakita:20180117111830j:plain

開発中の4ビットCPUの名前を発表します。

TTM4

と名付けました。実はずっと前からこの名前をつけていました、この名前はとりあえずの仮名としてつけていて後からもっと良い名前をつけようと思っていたのですが結構かっこ良いし、ずっと開発中TTM4と自分の中で呼んでいたので愛着がわきました。

由来は

ちかちか祭り4bit

です。名前をつける必要性が生じたときにブレッドボードでチカチカしていたLEDが目に留まってこの名前になりました。あくまで仮名のつもりだったので

開発の参考にさせていただいた"CPUの創り方"で紹介されているTD4と名前が似ちゃってます。

さてこのTTM4にはブートローダが載っています。パソコンで言うところのBIOSで、プログラムをROMからRAMへ読み込むのが主な役目です。

ブートローダにはRX220というマイコンを採用しました。ブートローダの方が圧倒的に高性能だというツッコミはなしで。秋月電子で売ってます。

RX220マイコン R5F52206BDFM: マイコン関連 秋月電子通商 電子部品 ネット通販

採用した理由は

  • 5Vで動作すること
  • ピン数が多い
  • 秋月で売ってる
  • 自分がさわったことがあるので開発しやすい

RX220にはクロックジェネレータから生成したクロックやリセット、一部のレジスタ、アドレスバスなど繋いであります。パソコンとシリアル通信も可能ですので工夫すればパソコンからTTM4をコントロールできます。

今はそのためのプログラムを書いている途中です。

TTM4はLEDがたくさん付いているのでその点滅で動作の様子がわかります。しかしクロックの周波数を上げていくと点滅が早すぎて人間には動いているのか、止まっているのか判断できません。そこでRXでクロックをカウントしパソコンへカウンタを表示させるようにしました。このカウンタにはRX220の周辺機能のTMRという機能を使いました。TMRの初期化関数を下に示したいと思います。37ピンを使ってます。

void TMRinit(void){
	//TTM4CLKをカウントする
	//TMR0.TCNTで8bit,TMR1.TCNT:TMR0.TCNTで16bit
	//IOポート設定
    MPC.PWPR.BIT.B0WI = 0;      //プロテクト解除
    MPC.PWPR.BIT.PFSWE = 1;		//プロテクト解除
    MPC.PB1PFS.BIT.PSEL = 0x05; //PB1/TMCI0
    MPC.PWPR.BIT.PFSWE = 0;     //プロテクト
    MPC.PWPR.BIT.B0WI = 1;		//プロテクト
    PORTB.PDR.BIT.B1 = 0;		//入力
    PORTB.PMR.BIT.B1 = 1;       //PB1/周辺

    SYSTEM.PRCR.WORD = 0xA502;  //プロテクト解除
    MSTP(TMR0) = 0;             //モジュールストップ解除
    MSTP(TMR1) = 0;             //モジュールストップ解除
    SYSTEM.PRCR.WORD = 0xA500;  //プロテクト

    IPR(TMR1, OVI1) = 1;                    //割り込み優先度設定
    IEN(TMR1, OVI1) = 1;                    //割り込み有効
    TMR0.TCORA = 0xFF;
    TMR0.TCR.BYTE= 0x00;
    TMR1.TCR.BYTE= 0x20;//オーバーフロー割り込み有効
    TMR0.TCSR.BYTE= 0x00;
    TMR1.TCSR.BYTE= 0x00;
    TMR0.TCNT = 0;
    TMR1.TCNT = 0;
    TMR0.TCCR.BYTE= 0x01;
    TMR1.TCCR.BYTE= 0x18;//コンペアマッチでカウントで16ビットカウンタとして使う
}

これでカウンタはできたのですが、RXをクロックの立ち上がりに動作させる必要性が出てきました。外部端子状態変化割り込みで立ち上がりを検出するのが良いと思ったのですが37ピンはすでに周辺機能に割り当てられているのでTMRと同時に使用はできないと思ってました、端子に周辺機能を割り当てるレジスタには外部端子割り込みと周辺機能割り当てが別で設定できるようになっていたのを見て、ためしに同時に設定したら使えました。

外部端子割り込み初期化同じく37ピン

	//外部端子割り込み設定//CLK立ち上がり割り込み
    ICU.IER[0x08].BIT.IEN4=0;//割り込み要求禁止
    ICU.IRQFLTE0.BIT.FLTEN4=1;//デジタルフィルタ無効
    ICU.IRQFLTC0.BIT.FCLKSEL4=0x01;//デジタルフィルタサンプリング周波数
    MPC.PWPR.BIT.B0WI = 0;      //プロテクト解除
    MPC.PWPR.BIT.PFSWE = 1;		//プロテクト解除
    //MPC.PB1PFS.BIT.PSEL = 0x05; //PB1/TMCI0
    MPC.PB1PFS.BIT.ISEL =1;		//割り込み端子として使用
    MPC.PWPR.BIT.PFSWE = 0;     //プロテクト
    MPC.PWPR.BIT.B0WI = 1;		//プロテクト
    PORTB.PDR.BIT.B1 = 0;		//入力
    //PORTB.PMR.BIT.B1 = 0;       //PB1/GPIO
    //PORTB.PMR.BIT.B1 = 1;       //PB1/周辺
    ICU.IRQCR[4].BIT.IRQMD=0x02;//割り込み要因設定
    ICU.IR[68].BIT.IR=0;	//割り込みフラグを初期化
    ICU.IRQFLTE0.BIT.FLTEN4=1;//デジタルフィルタ有効
    ICU.IPR[68].BIT.IPR=1;	//割り込み優先度設定
    ICU.IER[0x08].BIT.IEN4=1;//割り込み要求有効

外部端子割り込みと周辺機能が同時に使用できるとは自分はいままで知りませんでした。他のマイコンもそうなんですかね?自分が無知なだけですか?

自作CPU #14 スタックが動いた!


前回の記事でかいた通り、自作CPUでスタックへPUSH命令が実行できませんでした。

そこでロジックアナライザーを使って解析したら原因が判明しました。

波形

f:id:Hamakita:20180117143712j:plain

CLK:クロック

SPC:SPへのクロック

WE:スタックを構成するRAMへの書き込みパルス

SP-D/U:SPのカウント方向を制御

AD0:PCの最下位ビット

00番地にpush命令、01番地に00番地へジャンプという命令を書き込みクロック1MHzでテストしてみました。AD0はプログラムカウンタの最下位ビットです。クロックの立ち上がりでアドレスが切り替わりメモリから読み出し、制御バスの値が切り替わるのですが、そのうちの一つで今回の命令で関係あるのがsp-D/Uです。これはスタックポインタのカウント方向を制御するビットで0の時カウントアップ、1の時カウントダウンとなります。

PUSH命令はカウントダウンする必要があるので00番地の命令が読み出されると1になるはずです。

普通クロックの立ち上がりで命令をロードした後、次のクロックの立ち上がりの時に実行完了するのですが、つまり00番地がカウント命令なら次の01番地の命令をリードするクロックの立ち上がりでカウントする。しかしPUSH命令のときは少し特殊でスタックポインタは常にデータが入っている先頭をさしますので次のクロックの立ち上がりまでに

SPの値を-1

スタックを構成するRAMへデータ書き込み

を行う必要がありました。そこで

命令が読み出されるクロックの立ち上がりをトリガーにしてマルチバイブレータでパルスを生成、その後クロックの立下りをトリガーにしてRAMへの書き込みパルスを生成

という仕組みをつくりました。

しかしサンプリングされた波形をみてみると

00番地の命令をロードした後、SPCにマルチバイブレータにより 生成されるべきクロックが確認できません。これの原因は明白でSP-D/Uのロードに時間がかかっているせいです。SPCはマルチプレクサを通して、クロックとマルチバイブレータとで切り替えています。この切り替えもSP-D/Uが行っているので、ロードに時間がかかるとSPCにパルスが出てこなかったのだろうと思います。

そこでクロックの立ち上がりをトリガーにするのではなくSP-D/Uをトリガーにするように変更してみました。SP-D/Uが立ち上がるのはPUSH命令の時だけで他の命令では常に0ですので期待通りの動作が実現できると思います。

パターンを切ってつなぎ変えました。

 

f:id:Hamakita:20180118013625j:plain

修正後動作確認しましたら無事PUSH命令を実行できました。

修正後の波形 SPCに短いパルスが確認できる

f:id:Hamakita:20180118013158j:plain

スタックは今回のCPU作りで最も気合をいれて設計したうちの一つなので無事動かせて一安心です。

自作CPU #13 PUSHがうまくできない



自作CPUにはスタックを構成して載せました。しかし動作確認をしているとスタックへデータを積み上げるPUSH操作がうまくできないことが分かりました。ブレッドボード上で実験していた時はできていたのに…普通こういう回路を組む時、スタックの操作は数クロック使ってやると思います。しかし私のは、CPUの創り方のTD4を大元にしていますので、すべての命令が1クロックで実行されます。PUSH、POPも例外でなく、1クロックで実行できるようにしています。PUSHはスタックポインタを先にデクリメントしてデータを格納、POPはデータを取り出してからインクリメントしないといけないので、(スタックポインタを操作する順番が違う)マルチプレクサやらマルチバイブレータをつかってなんとか1クロックで実行できるようにしました。

実験中

 

f:id:Hamakita:20180117111830j:plain

弄っているうちにどうやら手でマシン語を操作する分には期待通りの動作をしていることが分かりました。プログラムを書き込んで実行させるとダメみたいです。

自作CPU #12 基板届きました。部品載せました。

基板が届きうれしくなって部品を一通りはんだ付けするまでブログに書く事を忘れてました。

こちらが届いた基板です。レトロ感を出したかったので基板の色は緑色にしました。

f:id:Hamakita:20180114002105j:plain

そして一通り部品を載せたのがこちらです。

A基板

f:id:Hamakita:20180114001734j:plain

B基板

f:id:Hamakita:20180114001735j:plain

合体!!

f:id:Hamakita:20180114001720j:plain

今日簡単な動作確認をしていましたらバグが二か所見つかりました。

一つ目は、手でDIPSWを操作しマシン語でプログラミングできるようにしているのですが、その出力にあるトライステートがうまく動作しないというものです。これの原因はトライステートのICにTTLである74F373を使用したのが原因でした。

自分はCMOSを使うつもりで設計していたので誤動作したようです。

電子回路のスイッチでは一般的に抵抗でプルアップしてスイッチをONにするとGNDへつながるように設計するんですが、今回はわかりやすくするためにONでHになるようにプルダウンしてました。TTLのICでは入力端子に何もつながないとHが入力されるようになってるみたいでONでLでないと動作しないみたいです。

この問題はトライステートをCMOS版に変えれば解決すると思います。

 

二つ目はZフラグのデコーダです。ALUの演算結果が0000になるとZ(ゼロ)フラグが立つようにしているのですが、このZフラグを出力するには4入力のNORが必要なのです。普通の組み合わせでは、どうしてもICを二つ以上使う必要があったため、アドレスラッチの74HC259を使ってアドレス000と出力有効端子(負論理)をつかって4入力のNORを実現しました。ここで配線を間違っていたみたいで誤動作していました。

これはしょうがないのでパターンを切って修正するしかないです。

 

ハードウェアのバグつぶしが済んだら次はファームウェアを書いていこうと思います。

 

自作CPU #11 基板発注しました。

回路図のチェックで、それなりにミスがみつかったのでその修正に時間をとられました。大幅に配線を変更した箇所もあります。なんとか年内にハードウェアを完成できてよかった。出来上がった基板にミスがないとは限らないが、一応不安な部分はブレットボード上で実験しています。

A基板

f:id:Hamakita:20171230033852p:plain

B基板

f:id:Hamakita:20171230033910p:plain

自作CPU #10 とりあえず基板図完成

今日一気に作業を進めました。とりあえず基板図完成しました。

あとは細かい位置調整等をやっていきます。さらに回路図に間違いがないかもう一度チェックしようと思います。

A基板(ALU等)

f:id:Hamakita:20171217010922p:plain

B基板(RAM,ROM,ブートローダー等)

f:id:Hamakita:20171217010936p:plain

自作CPU #9 A基板の配線が少しすすみました

最近はあまり作業が進んでいません。A基板の配線が少しすすんだので記事にします。

ALUの部分はある程度配線完了しました。配線するときは表面の配線を縦に裏面の配線を横にするようにしています。線数が多いのでマトリックスにしたほうが配線しやすいのです。

f:id:Hamakita:20171215001702p:plain

今悩んでいるのは右上に見える4本の線をどうやって左側に持っていくかというところ。