この記事は、マイクロコントローラコアの設計方法を学習することに焦点を当てており、教育用のみを目的としています。 ぜひご覧くださいwww.zilog.com そしてあなたのプロジェクトの必要性に合うマイクロ制御回路を選ぶために製造業者の製品種目を点検して下さい(8ビットZ8Encoresから! そしてez80は32ビットARM Cortex-M3ベースのZNEO32に称賛します! 高度の運動制御の機能を含んでいるかどれが)。
マイクロコントローラとマイクロプロセッサとの私の恋愛は、1988年にCEFET-PR(クリチバにあるブラジルの二次/技術学校と大学)で技術学位を取得していたときに始まりました。 私は古典的なZilog Z-80を探索しながら基本を学ぶことから始めました(図1a)。
図1A.Zilog Z-80A(ウィキメディア-コモンズの提供)。
マイクロコントローラプログラミングに関する本の作成(“参考文献”を参照)、小さなデザインハウス(ScTec)の開始、CEFET-SC(フロリアノポリスにあるブラジルの別の大学)での卒業後のプログラムの終了など、プログラミングのキャリアを早送りしました。 私はプログラマブルロジックとVHDLとのより多くの接触を持っていたし、私の好奇心がピークに達したとき、これは、2008年にありました。 数年後の2016年、私は非常に手頃な価格のFPGA(Field-Programmable Gate Array)キットを見つけ、それにチャンスを与えることに決め、FPGA技術についてもっと学び始めました。
VHDL(VHSIC hardware description language)、Fpga、およびマイクロプロセッサコア自体についてもっと学ぶためにソフトコアを設計するよりも良いものは何でしょうか? 私は現代のZ-80親戚を選ぶことになりました:Zilog Z8アンコール! (別名、ez8;図1b)。
図1B.Zilog ez8.
これは、シンプルで強力な命令セットと非常に素晴らしいオンチップデバッガを備えた八ビットマイクロコントローラコアです。 軽量のIDE(integrated development environment)と無料のANSI Cコンパイラにより、組み込みシステムについて学ぶ(また教える)ための優れたプロジェクトです。
コア動作、VHDL、Fpgaの深さに飛び込む前に、Zilog Z8Encoreを一目で見てみましょう! 特徴。
図1C.FPGA上のFpz8。
Zilog Z8アンコール!
ez8は、Zilogの成功したZ8ファミリと偉大なZ-80遺産に基づいた八ビットマイクロコントローラファミリです。 それはRAM(ファイル記録および特殊関数の記録区域)の4,096バイトまで、プログラム記憶(通常フラッシュ-メモリ)の64KBまで、およびデータ記憶(RAM)の64KBまでのハーバードCISC機械を特色にする。 Ez8コアには、プログラマブルな優先度を持つベクトル割り込みコントローラと、非同期シリアル通信を使用してホストコンピュータと通信するオンチップデバッガも含まれています。 これらのマイクロコントローラには、汎用性の高い16ビットタイマからモータ制御タイマ、複数のUart(IrDA ready)からUSBデバイスまで、非常に優れた周辺機器セッwww.zilog.com 完全な製品種目を点検するため)。
ez8プログラミングモデルの大きな特徴の一つは、固定アキュムレータの欠如です。 代わりに、4,096個の可能なRAMアドレスのいずれかがアキュムレータとして機能します。 CPUは、メインRAM(ファイルとSFRs—特殊関数レジスタ—領域)をCPUレジスタの大きなセットとして扱います。 これを達成するために、RAMはレジスタグループに分割されます(それぞれ256の16の作業レジスタのグループがあります)。 命令は通常、RP(register pointer)という名前のSFRによって選択される単一のワーキングレジスタグループ内で動作します。 すべてのSfrはRAMの最後のページ(0xF00から0xFFFまでのアドレス)にあることに注意してください。
命令セットについては、83の異なる命令が二つのオペコードページに分割されています。 これは、加算、減算、論理演算、データ操作命令、シフト命令、フロー変更命令、いくつかの16ビット命令、ビットテストと操作、8×8乗算などの基本的な操作のための通常の命令で構成されています。
プログラムメモリ領域は、最初のアドレスが特別な目的専用になるように編成されています。 アドレス0x0000と0x0001は設定オプション専用で、アドレス0x0002と0x0003はリセットベクトルを格納します。 表1に、プログラムメモリの構成を示します。
0x0000 | Option bytes |
0x0002 | Reset vector |
0x0004 | WDT vector |
0x0006 | Illegal instruction vector |
0x0008 to 0x0037 | Interrupt vectors |
0x0038 to 0xFFFF | User program memory area |
TABLE 1. Simplified program memory organization.
一部のデバイスには、LDE/LDEI命令を使用してのみアクセスできる第二のデータ空間(最大65,536アドレス)も含まれています。 この領域は、あまり使用されていないデータを格納するために使用できます(RAM/SFR領域よりも読み取り/書き込みが遅いため)。
Fpz8
Fpz8の最初の実装は、プログラムメモリ用とレジスタメモリ用の二つのメインバスで非常に保守的でハードワイヤード設計アプローチを使用しています。 データメモリ領域を含めないことを選択したため、LDE/LDEI命令は実装されていません。
プログラムメモリバスは、16ビット命令アドレスバス(IAB)、八ビット命令データバス(プログラムメモリからデータを読み出すためのIDB)、八ビット命令書 Fpz8には、同期ブロックRAMを使用して実装された16,384バイトのプログラムメモリが含まれています(これは、デバイスの電源が切断されるとプログラムメモリの内容が失われることを意味します)。
5つのレジスタ-エリア-バスは、ファイル-レジスタ-エリア(ユーザー RAM)用の3つと、特殊機能レジスタ専用の2つで構成されています。 メインの12ビット・ファイル・レジスタ・アドレスバス(FRAB)、8ビット・ファイル・レジスタ入力データ・バス(FRIDB)、8ビット・ファイル・レジスタ出力データ・バス(FRDB)、8ビット・レジスタ入力データ・バス(RIDB)、そして最後に8ビット・レジスタ出力データ・バス(RODB)があり、SFRsへの書き込みに使用されます。 Fpz8には、同期ブロックRAMを使用して実装された2,048バイトのユーザー RAMメモリが含まれています。
図2にFpz8のブロック図を示します; CPU、2つのメモリユニット(1つはプログラムストレージ用、もう1つはデータストレージ用)、および外部タイマモジュールを見ることができます。
図2. FPZ8のブロック図。
このプロジェクトでは、相互接続に双方向バスを使用していないことに注意してください。 単方向バスは、スペース効率が低いものの、使用する方が簡単です。
Fpz8のVHDLの説明は大きく、少し複雑なので、理解を容易にするために、その操作をいくつかのモジュールに分割します:
- 命令キューイングエンジン
- 命令デコード
- 割り込み処理
- デバッガ
命令キューイングエンジン
命令のフェッチは、任意のCPUの主なタスクです。 Fpz8のHarvardアーキテクチャは、同時フェッチとデータアクセスを可能にします(命令とデータのための別々のバスによる)。 つまり、別の命令がデータメモリに読み書きされている間に、CPUが新しい命令をフェッチできることを意味します。
ez8には可変長命令ワードがあります(命令長は一バイトから五バイトまで変化します); いくつかの命令は時間がかかりますが、他の命令よりも速く実行されます。 このようにして、BRK命令は1バイトの長さを持ち、2サイクルで実行されますが、LDX IM、ER1は4バイトの長さで2クロックサイクルで実行されます。
では、これらの命令をすべて正常にデコードするにはどうすればよいですか? つまり、プログラムメモリからバイトをフェッチし、それらを8バイト配列に格納し続けるメカニズムです。
if(CAN_FETCH=’1′)then
if(IQUEUE.FETCH_STATE=F_ADDR)次に
FETCH_ADDR:=PC;
IAB<=PC;
IQUEUE。WRPOS:=0;
IQUEUE.RDPOS:=0;
IQUEUE.CNT :=0;
IQUEUE.FETCH_STATE:=F_READ;
else
if(IQUEUE.その後、
IQUEUE。キュー(IQUEUE.
FETCH_ADDR:=FETCH_ADDR+1;
IAB<=FETCH_ADDR;
IQUEUE.WRPOS:=IQUEUE.WRPOS+1;
IQUEUE.CNT:=IQUEUE.CNT+1;
end if;
end if;
end if;
end if;
if(IQUEUE.CNT=7)その後、IQUEUE。フル:=’1′;そうでなければIQUEUE.FULL:=’0′;
end if;
リスト1。 命令キューエンジン。
フェッチはメインイネーブルシグナル(CAN_FETCH)によって制御され、特別な場合(割り込み処理、LDC/LDCI命令またはデバッガアクセスによる)に無効にすることができます。 また、いくつかの内部パラメータ(状態の取得、ポインタの読み書き、キュー配列自体、カウンタ、および完全なインジケータ)を格納する構造体(IQUEUE)もあります。
キューカウンタ(CNT)は、キュー内で使用(読み取り)できるバイト数を識別するために使用されます。 Decoderステージでは、この数値を使用して、命令に必要なバイト数がキュー内で既に使用可能であることを確認します。
命令デコード
これは実際の魔法が起こる場所です。 命令デコーダは、命令キューからオペコードを読み取り、対応する操作に変換します。
命令デコーダの設計は、すべての命令とアドレッシングモードの関係を理解することから始まりました。 一見すると、いくつかの命令(図3)が列(DJNZ、JR cc、X、LD r1、IM、JP cc、DA、およびINC r1)でグループ化されていることがわかりやすいです。 INC r1命令のデコードは簡単で、これらのシングルバイト命令では、上位ニブルはソース/宛先レジスタを指定し、下位ニブルは命令自体(0xe)を指定します。
図3. グループによるオペコード。
ほとんどの命令は、いくつかの基本的なルールに従って分類することができます:
- 通常、Columns(オペコードの下位ニブル)はアドレッシングモードを指定します: たとえば、列0x9命令は、主にIM、ER1アドレッシングモードを使用し、4バイト長です(2番目のバイトは即時オペランドで、最後の2バイトは宛先拡張アド
- 行(オペコードの上位ニブル)は、通常、操作を指定します。行0x0命令は主に加算操作であり、行0x2命令は主に減算操作などです。行0x1を見ると、列0x0と0x1はRLC命令であり、列0x2から0x9まではADC命令であることがわかります。 したがって、ニブルを入力として(オペコードからのより高いニブル)、それに応じてデコードするALUを設計することができます。 これは列0x2から0x9で機能しますが、最初の2つの列には別のアプローチが必要です。
そのため、ほとんどの算術命令と論理命令に集中するALUと、列0x0と0x1に示されている他の操作を実行する第二のユニット(論理ユニット2、またはLU2)(これらの列で見られるすべての操作がLU2によって実行されるわけではない)。 ALUとLU2の両方の動作コードは、図3に示すオペコード行に一致するように選択されました。
もう一つの重要な詳細は、同じ列とグループ内のすべての命令がバイト単位で同じサイズであるため、同じデコーダセクションで復号化できることです。
デコーダの設計は、各クロックティックに進む大規模な有限状態機械(FSM)を利用しています。 すべての命令はCPU_DECOD statで開始されます。 これは、デコーダが実際にオペコードをデコードし、バスと内部サポート信号を準備し、他の実行状態にステップ実行する場所です。 これらすべての状態の中で、2つは多くの命令によって広く使用されています:CPU_OMAとCPU_OMA2。 あなたはなぜ推測できますか? 彼らはALUとLU2に関連しているので、あなたが言った場合、あなたは絶対に正しいです!OMAは1つのメモリ・アクセスの略で、すべてのALU関連命令(ADD、ADC、ADDX、ADCX、SUB、SBC、SUBX、SBCX、OR、ORX、AND、ANDX、XOR、XORX、CP、CPC、TCM、TCMX、TM、TMX、およびLDおよびLDXのいくつかの変形)の最後の状態です。 一方、CPU_OMA2は、すべてのLU2関連命令(RLC、INC、DEC、DA、COM、RL、CLR、RRC、SRA、SRL、RR、およびSWAP)の最後の状態である。
さて、CPU_DECOD状態の内部を見てみましょう。 図4を参照してください。
図4. CPU_DECOD状態。
CPU_DECOD状態の中では、多くのアクションが行われていることがわかります。 最初は、いくつかの一時変数がデフォルトの条件に初期化されます。 Num_BYTESは命令デコーダによって消費されたバイト数を制御するため、非常に重要であることに注意してください。 このステージの最後の部分では、PC(プログラムカウンタ)をインクリメントし、キュー読み取りポインタを前進させ、キュー内の使用可能なバイト数を減少させ
初期化セクションに続いて、割り込み処理セクションを見ることができます。 保留中の割り込みを検出し、それに応じてCPUを準備します。 私は次のセクションでこれをカバーします。
実際の命令復号化ブロックは、低消費電力モードがアクティブでないかどうか、およびデバッガモードがオフであるかどうかをチェックします(OCDCR.DBGMODE=0)。 または、デバッグモードの間に、シングルステップデバッグコマンドが発行されました(OCDCR。DBGMODE=1およびOCD。SINGLE_STEP=1)。 次に、キュー内の使用可能なバイトをチェックし、デコードを続行します。
いくつかの命令(主にシングルバイトのもの)はCPU_DECOD状態内で完了しますが、完全に完了するまで複数の状態が必要なものもあります。
いくつかの命令デコードは、Fpz8のために特別に書かれたいくつかの関数と手順を利用することができることに注意してください:
- DATAWRITE-この手順は、書き込み操作のためのバスを準備します。 宛先が内部SFR、外部SFR、またはユーザー RAMのいずれかの場所であるかどうかを選択します。
- DATAREAD—これはDATAWRITEの逆数関数です。 これは、送信元アドレスを読み取るために使用され、内部SFR、外部SFR、またはユーザー RAMのいずれの場所であるかを自動的に選択します。
- CONDITIONCODE—条件付き命令(JRやJPなど)に使用されます。 4ビットの条件コードを受け取り、それをテストし、結果を返します。
- ADDRESSER4、ADDRESSER8、およびADDRESSER12—これらの関数は、4、8、または12ビットのソースから12ビットのアドレスを返します。 これらは、RPレジスタの内容を使用して最終的な12ビットアドレスを生成します。 ADDRESSER8とADDRESSER12は、エスケープされたアドレス指定モードもチェックします。
- ADDER16—これはアドレスオフセット計算のための16ビット加算器です。 これは8ビットの符号付きオペランドを取り、signはそれを拡張し、16ビットアドレスに追加して結果を返します。
- ALUとLU2—これらは以前に説明したもので、ほとんどの算術演算と論理演算を実行します。
割り込み処理
前に言ったように、ez8にはプログラム可能な優先度を持つベクトル化された割り込みコントローラがあります。 最初は、割り込みは大したことではないので、このセクションはそれほど難しくないと思っていましたよね? さて、私が必要なすべてのタスク(コンテキストの保存、ベクトル化、優先順位の管理など)を行う方法を理解し始めたとき。)、私はそれが私が最初に思ったよりも厳しいだろう実現しました。 数時間後、私は現在のデザインを思い付きました。
Fpz8の割り込みシステムは単純になりました。 それは8つの入力(INT0へのINT7)を有する;全体的な割込みイネーブル(IRQCTLの記録にあるIRQEビット);優先順位の設定のための2つの記録(IRQ0ENHおよびIRQ0ENL); この設計では、イネーブル割込みに関する割込みイベントの検出時にベクトルアドレスを生成するネストされたIFチェーンを使用します。
図5に割込みシステムの圧縮図を示します。 注意記号ATM_COUNTERを持つ最初のIF文があります。 これはATM命令で使用される単純なカウンタです(3つの命令サイクルの割り込みを無効にし、アトミック操作を可能にします)。
図5. Fpz8割込みシステム。
割り込みに関する最後のコメント: 割込みフラグ-レジスタ(IRQ0)は、システム-クロックの立ち上がりエッジごとに割込み入力をサンプリングします。 フラグの現在の状態と最後の状態を格納する2つのバッファ変数(IRQ0_LATCHとOLD_IRQ0)もあります。 これにより、割り込みエッジ検出が可能になり、外部入力を内部クロックに同期させることもできます(Fpgaは非同期内部信号ではうまく動作しません)。
オンチップデバッガー
これは、商用統合開発環境(IDE)を可能にするため、おそらくこのソフトコアのクールな機能です; ZilogのZDS-IIのような)Fpz8で動く伝達し合い、プログラムし、そしてデバッグソフトウェア。 オンチップデバッガ(OCD)は、autobaud機能を備えたUARTとそれに接続されたコマンドプロセッサで構成されています。 UARTは、ホストPCとシリアル通信を行い、デバッグコマンドを処理するデバッガ状態マシンにコマンドとデータを配信します(デバッガコマンド処理FSMはCPU_DECOD状態の中に位置しています)。
図6. オンチップデバッガUART(DBG_RXシンクロナイザに注意してください)。
私のOCD設計は、データメモリ(デバッグコマンド0x0cおよび0x0d)、読み取りランタイムカウンタ(0x3)、および読み取りプログラムメモリCRC(0x0e)
私が強調したいことの一つは、Fpga内の非同期信号を扱うときに注意が必要であることです。 私の最初の設計では、DBG_RX入力信号を処理している間はそれを考慮していませんでした。 結果は絶対に奇妙だった。 私の設計はシミュレーションで完璧に働いていました。 私はそれをFPGAにダウンロードし、シリアル端子を使用してデバッグシリアルインタフェースで遊んで始めました(私のFPGAボードにはシリアルUSBコンバータが内蔵されています)。
驚いたことに、ほとんどの場合、コマンドを正常に送信して期待される結果を受け取ることができましたが、デザインが単にフリーズして応答を停止 ソフトリセットは、物事が彼らの適切な操作に戻るだろうが、それは私を興味をそそられました。 何が起こっていたのですか?
多くのテストといくつかのグーグルの後、私はそれがシリアル入力信号の非同期エッジに関連している可能性があることを理解しました。 私はその後、私の内部クロックに信号を同期させるためにカスケードラッチが含まれており、すべての問題がなくなっていた! それはあなたが常に複雑なロジックにそれらを供給する前に、外部信号を同期する必要があることを学ぶための厳しい方法です!
私は、デバッガコードのデバッグと精製がこのプロジェクトの最も困難な部分であったと言わなければなりません。
合成とテスト
完全にコンパイルされると(私はQuartus II V9.1sp2を使用しました)、Fpz8コアは4,900個の論理要素、523個のレジスタ、147,456ビットのオンチッ 全体として、Fpz8はEP4CE6の利用可能なリソースの80%を使用しています。 これはたくさんありますが、周辺機器にはまだ1,200個のロジック要素があります(私の単純な16ビットタイマーは約120個のロジック要素と61個のレジ これは、私がここで使用した低コストのミニボードに搭載された最小のCyclone IV FPGA(EP4CE6)にも適合します(図7)。
図7. アルテラサイクロンIV EP4CE6ミニボード。
ミニボードの特徴(EP4CE6デバイスとともに):EPCS4シリアル構成メモリ(底面に搭載)、FTDIシリアル-USBコンバータチップ、50MHz水晶発振器モジュール、FPGAピンにアクセ 内蔵されたUSB-Blaster(FPGAプログラミング用)はありませんが、購入したパッケージには外部プログラミングドングルも含まれていました。
実世界のテストについては、言うまでもなく、Fpz8は初めて動作しませんでした! 少し考えてコンパイラの出力メッセージを読んだ後、私はそれがおそらくタイミングの問題であることを理解しました。 これはプログラマブルロジックで設計するときに非常に一般的なジレンマですが、これは私の第二のFPGA設計だったので、私はそれに十分な注意を払っ
タイミング解析メッセージを確認すると、最大クロックは24MHz前後でなければならないという警告が表示されました。 最初は、2つの分周器を使用して25MHzのCPUクロックを生成しようとしましたが、信頼性がありませんでした。 私はその後、3行の分周器を使用しました。 すべてが完璧に動作し始めました!
そのため、Fpz8は現在16.666MHzで動作しています。 内部Pllの1つを使用してメインクロックを乗算/分周することで、結果として24MHzより低く、16.666MHzより高いクロックを得ることができます。
プログラミングとデバッグ
Fpz8を使用することは非常に簡単で簡単です。 デザインがFPGAにダウンロードされると、CPUはメモリにロードされたプログラムの実行を開始します。 Hexファイルを指定し、MegaWizard Plug-in Managerを使用してプログラム・メモリー初期化ファイルを変更できます。 そうすれば、アプリケーションコードはリセット信号の後に実行を開始します。
Zilog ZDS-II IDEを使用してアセンブリまたはCコードを記述し、必要なhexファイルを生成できます(通常、Z8F1622をターゲットデバイスとして選択します。 オンチップデバッガのおかげで、zds-II IDEを使用してシリアルデバッグ接続(この場合はUSB)を使用してFpz8にコードをダウンロードすることもできます。
接続する前に、デバッガの設定が図8と同じであることを確認してください。 “点滅する前にページ消去を使用する”オプションのチェックを外し、現在のデバッグツールとして”SerialSmartCable”を選択します。 また、FTDIの仮想COMポートがデバッグポートとして正しく選択されているかどうかを確認することを忘れないでください(Setupボタンを使用します)。 115,200bpsは私のために非常にうまく動作します。
図8. デバッガの設定。
Fpz8に接続すると、ターゲット-デバイスがプロジェクトと同じではないことを知らせる警告メッセージがZDS-II IDEに表示されることに注意してくださ それは私がいくつかのIDメモリ領域を実装していないために起こります。 警告を無視してデバッグセッションを続行するだけです。
コードが正常にダウンロードされると、アプリケーションの起動(GOボタン)、手順のステップ、レジスタの検査または編集、ブレークポイントの設定などができます。 他の優れたデバッガと同様に、たとえば、PAOUTレジスタ(PORTSグループの下)を選択したり、PAOUTに接続されているLedの状態を変更したりすることができます。
いくつかの簡単なCコードの例は、ダウンロードで見つけることができます。
Fpz8には揮発性のプログラムメモリがあることに注意してください。 したがって、FPGAのパワーダウン時にダウンロードされたプログラムは失われます。
Closing
このプロジェクトは完了するまでに数週間かかりましたが、マイクロコントローラコアを研究して設計するのは楽しいことでした。
このプロジェクトが、コンピューティングの基礎、マイクロコントローラ、組み込みプログラミング、VHDLについて学びたい人に役立つことを願っています。 私は、低コストのFPGAボードと組み合わせると、Fpz8は素晴らしい学習(および教育)ツールを提供できると信じています。 楽しい時を過す! NV
CEFET-PR:
www.utfpr.edu.br
ScTec:
www.sctec.com.br
:
https://www.amazon.com/HCS08-Unleashed-Designers-Guide-Microcontrollers/dp/1419685929
Zilog ez8CPUマニュアル(UM0128):
www.zilog.com/docs/UM0128.pdf
Zilog Z8F64xx Product Specification (PS0199):
www.zilog.com/docs/z8encore/PS0199.pdf
Zilog ZDS II IDE User Manual (UM0130):
www.zilog.com/docs/devtools/UM0130.pdf
Zilog ZDS-II Software Download:
https://www.zilog.com/index.php?option=com_zcm&task=view&soft_id=7&Itemid=74
Zilog Microcontroller Product Line:
http://zilog.com/index.php?option=com_product&task=product&businessLine=1&id=2&parent_id=2&Itemid=56
Project Files available at:
https://github.com/fabiopjve/VHDL/tree/master/FPz8
FPz8 at Opencores.org:
http://opencores.org/project,fpz8