しばっち電機
-

100.ともかくFablic(FPGA)を使ってみよう (簡単計算機編)

100-1. はじめに

今回はSmartFusionの特徴である...というか、本来の機能であるFablic(FPGA)部分を使って簡単計算機(計算部分だけね)を作ってみます。
目的はFPGA部分を設計して、ARMからアクセスできるってことを第一の目的とするので計算機部分はこだわらない(あるいみ何でもいい)ということにします。

マニュアルは
SmartFusion_Build_APB3core_AN.pdf Building an APB3 Core for SmartFusion FPGAs
User_Logic_MSS_AN.pdf Connecting User Logic to the SmartFusion Microcontroller Subsystem
SmartFusion_MSS_UG.pdf の P22 Figure 2-6 ? Memory Map with eSRAM Remapped
を参考にします。

FPGAというとともかくRTL書いて、即実機で動作チェックとなりがちですが、ここはきちんと仕様策定、仕様設計、RTL作成、検証仕様設計、けん検証(シミュレーション)、合成フィッティング の手順をとります。RTLはVerilogを仕様します。VerilogであればLiberoIDEに付属のModelSimでシミュレーションできますからね。

100-1. 簡単計算機の仕様を決定しよう

さてさて、仕様を決定しないことには作れませんので列挙してみます。
  • ARMとのバス接続はAPBバスとする
  • レジスタマップで機能を割りつける
  • 数体系は2の補数とする
  • 機能は、加算、減算、乗算とする
次に、これらの機能をもう少し詳細に落し込みます。

SmartFusionにはARM Coretex-M3が載っていますが、これとのインターフェースにはAMBA AHBかAPBが使えます。今回は簡単なAPBバスを使うことにします。
APBデータバスは32bitですが、今回は入力8bitとします。この8bitは2の補数として扱うので、-128(0x80)〜127(0x7F)をとります。出力は加算、減算は桁上がりするので9bit、乗算は17bitとします。乗算で-1*-1をすると1になるので8+8+1bitですね。この1bitはそのうち割り込みを出して例外処理させて「あんたバカァ?@アスカ」みたいな表示をさせてみることにします。 ←訂正。小数点位置が符号ビットの1つ下にあるのならオーバーフローしますが、今回は整数の乗算なのでオーバーフローしないです。スミマセン。-128*-128=16384で16進だと、4000hですね。-128*127=-16256だと、C080hです。15bit目はサインビットとします。以下17bit->16bitに修正します。

使わない上位のビットは今回は符号拡張せず0とします。

使い方は、例えば Aに10進20をライト、Bに10進5をライトした後、加算結果をリードすると10進25、減算結果をリードすると15、乗算結果をリードすると100となるようにします。

アドレス割付をします。データ幅は32bitのうち下位から使うことにします。
アドレスは、8bit単位(Byte)で4アドレス単位(32bit単位)にします。

2つの数の演算なので、
00番地:入力A
04番地:入力B
とします。計算結果は
08番地:加算結果
0C番地:減算結果
10番地:乗算結果
です。


100-2. 簡単計算機の設計をしよう


では、設計を開始します。まずはレジスタマップから

レジスタマップ
 アドレス レジスタ名   ビット幅 リードライト 機能 
 0 r_a  8  R/W  入力 A
 4 r_b  8  R/W  入力 B
 8 w_add  9  R  加算結果 A+B
 C w_sub  9  R  減算結果 A-B
 10 w_mul  16  R  乗算結果 A*B

次に端子表です。
今回はFPGA部の接続はFPGA外部ピンやアナログ部(ACE)からのアクセスは無くAPBバスだけです。
APBバスの詳細は SmartFusion_Build_APB3core_AN.pdf を参考にすることにして、端子はP3にある通りです。
PSELがどこまで上位アドレスデコードしてくるのかがよくわからないですが、イメージ(同じレジスタが別アドレスに見える、例えば2番地のレジスタが、0x102,0x202・・・にあるように見える)が起こってもよしということにします。ですのでアドレスデコードは下位8bitとします。
論理は正論理で、唯一PRESETnだけが負論理です。

端子表
端子名 MSB  LSB  入出力  機能説明 
PCLK     in  クロック。回路で使用する基準クロック入力
PRESETn     in リセット。最初に回路を初期化する信号
PADDR 7 in アドレス。32bit単位アクセスなので下位2ビットは未使用
PSELx     in セレクト。この回路が選択されたことを示す
PENABLE     in イネーブル。データ転送期間であることを示す
PWRITE     in ライト、ライト時1、リード時0
PWDATA 31 in ライトデータ、32bitのうち下8bit使用
PREADY     out レディ。今回は1固定で使用
PRDATA 31 out リードデータ、未使用のビットは0を出力
PSLVERR     out スレーブエラー。今回は0固定で使用

これだけです。少ないですね。今回PREADYによるウエイト期間は回路も小さいことですし使わないことにします。リード時は出力DFFで1遅延だけでデータが出力されることにします。もっと大きい(遅延が何クロックか入る)回路の時はきっちりPREADYを使う事にします。


仕様が決まったところで、回路図を書きます。作成する回路によって抽象度は変わってきますが今回は丁寧に細かく、RTL作成にそのままつかえるレベルでかきます。
回路図は左から右に流れるように書くのが基本です。Verilogに書きやすいように信号名やビット幅も入れます。DFFの出力はr_、入力側や組み合わせ回路はw_を接頭語にしておくと分かりやすいですね。
実際のところ、ここまで細かく書くかというと、例えばDFFの手前は1つの箱にしてデコード信号は作らないとかいうこともあります。

回路図
   SmartFusion Scematioc design


タイミング図も並行して作成します。APBについては SmartFusion_Build_APB3core_AN.pdf のP4にあるタイミングを参考にします。内部信号でデコードするだけの物は入力と同タイミングで変化。DFF出力はPCLKで1clk遅れます。

タイミング図
  SmartFusion TimingChart

この回路図とタイミング図は LibreOffice3.4(OpenOffice)のDrawで書いてみました。LibreOfficeのツール->オプション->LibreOffice Draw->罫線 の解像度で横も縦も0.2cmにして、グリッド線での位置合わせにしておくと書きやすいです。
図はCADでもVisioでも使い慣れたもので良いです。


DECとSELの真理値表も作成
最初の入力データ保持用DFFに使用するデコード信号
PADDR[7:0] PSEL PENABLE PWRITE w_dec_0 w_dec_4
00h 1 1 1 1 0
04h 1 1 1 0 1
上記以外 - - - 0 0
- 0 - - 0 0
- - 0 - 0 0
- - - 0 0 0

出力選択セレクタに使用するデコード信号
PSEL PENABLE PWRITE w_dec
1 1 0 1
0 - - 0
- 0 - 0
- - 1 0

出力信号選択
w_dec PADDR[7:0] w_prdata[31:0]
1 00h {24'd0,r_a[7:0]}
1 04h {24'd0,r_b[7:0]}
1 08h {23'd0,r_add[8:0]}
1 0Ch {23'd0,r_sub[8:0]}
1 10h  {16'd0,r_mul[15:0]}
0 - 32'd0
- 上記以外 32'd0

これぐらい書いておけば、次のVerilogRTLの作成が楽になります。メンドクサイなどといわずにきちんと書きます。

100-3. 簡単計算機のVerilogRTLを書いてみよう

Verilogを書くにはTextエディターがあれば書けますので、使いなれたエディタで良いです。ただVerilogの予約後やコメントを色付けできるエディタだと分かりやすくて良いです。

ここでは折角 Libero IDE があるのでこのエディタを使ってみます。
スタート -> すべてのプログラム -> Actel Libero IDE v9.1 -> Libero IDE v9.1 でLibero IDEを立ち上げます。
まずはProjectをつくらなければいけません。Project -> New Project で New Projcet Wizard を起動して、
・Project name: calc
・Projcect location: C:\Actelprj\simplecalc\calc
・Perfomed HDL type: Verilog
とします。
Nextで次ページへ。

Family,Die and Package
・Fmily: Smartfusion
・Die: A2F200M3F
・Package: 484FBGA
こればメガメガボード設定でのお約束ですね。
Nextで次ページへ。

Select Integrated Tools
ここはそのまま Nextで次ページへ。

Add files to your project
もし、すでに何らかのエディタでVerilog書いているならAdd Filesで HDL Source Files で追加できます。
まだ書いていないので そのまま Nextで次ページへ

Completing the New Projcect Wizard
内容確認して Finish

Add Microcontroller Subsystem
・Design Name: calc_cont
としておきます。OK

SmartDesign MSS Configurator が立ち上がりますがこれは後回しにするのでとりあえず閉じます。File -> Exit


さて、やっとVerilogを書く方向になってきましたね。SmartFusionを生かせるのもも少し...でもうだいぶん位ありますけどね(^^;))
Project Manager の Design Entry Tools の HDL Editor を選択するか、File->New でVerilog Source File で Name: calc_rtl として OK

真ん中のペーンに calc_rtl.v というタブで、// calc_rtl.v というのが先頭に入った画面が開きました。
右側ペーンのタブをTemplatesにしてVerilogの展開マークをクリックすると、いろいろ雛形が用意されています。Verilogに慣れていないときはこれらを参考にしていきます。使い方は簡単で、挿入したい行にカーソルを持ってきておいて、右側の項目 例えば File Header をダブルクリックするだけでOKです。どのような物があるかいろいろプチプチやってみてください。後でざくっと削除すればOKです。
(後で気づいたのですが、項目の上にマウス合わせてちょっと待つと内容が表示されるようです。)
   SmartFusion ProcectManager calc_rtl.v


Verilogを書くときのコツですが、縦長に書くってことです。多少長くなっても、そのほうが見やすいし、編集しやすいですからね。
Verilogの構文の書き方はいろいろありますが、今回は組み合わせ回路もalways文で書いてみます。というか、assignを使うのは単純な代入の時に限った方が分かりやすくていいのではと思っています。センシビリティリスト抜けとかはチェッカーも充実してきているし、Verilog2001の文法で書けばあっさり書けますしね。
今回は説明も多いので長くなりますが、1信号1always文方式で書いてみます。余裕があれば短縮版も書いてみます。

コメントは沢山いれます。RTL書いたときには分かっていてもしばらくするとなんだっけ?ってなことになりがちです。


Verilog
エディタで作成したものを貼りつけてみましたが、HTMLになると字下げが詰められてしまって、なにがなんやらわからないですねぇ。
ですのでVerilogソースファイルはリンクで貼り付けますね。

Verilogソース: calc_rtl.v

100-4. 簡単計算機の検証仕様を書いてみよう

さて、早速合成して...ちょっと待て、その前にちゃんと設計通りに動くか検証します。
そのためには検証仕様を書きます。こういう入力、操作をするとこういう出力、動作をするっていうのを予め書いておいて後のテストベンチを作成してのテストに使います。

今回はAPBからレジスタに設定値を書いて、計算結果をリードしそのリードされるであろう値を期待値とします。初期値の値、レジスタリードライト、演算は2項の演算ですので、正、負の最大値の組み合わせと、途中の値を少し検証することにします。
 番号 内容   入力 期待値  備考 
 1  リセット時初期値  PRESETnを0にする  内部をモニタし不定値が残っていないこと
レジスタが0となること
 
 2  レジスタ初期値  APBより0h,4h,8h,ch,10h番地をリードする  0が読み出されること  
 3  設定レジスタ W/R  0hにffh,00h,1bitずつ1を行い都度リード
4hも同様に行う
 書き込んだ値がそのままリードできること  
 4  計算、A=正の最大値、B=正の最大値  0hに7Fh書き込み、4hに7Fh書き込み  8hに0FEh,Chに000h,10hに3F01hがリードできること  
 5  計算、A=正の最大値、B=負の最大値  0hに7Fh書き込み、4hに80h書き込み  8hに1FFh,Chに0FFh,10hにC080hがリードできること  
 6  計算、A=負の最大値、B=正の最大値  0hに80h書き込み、4hに7Fh書き込み  8hに1FFh,Chに101h,10hにC080hがリードできること  
 7  計算、A=負の最大値、B=負の最大値  0hに80h書き込み、4hに80h書き込み  8hに100h,Chに000h,10hに4000hがリードできること  
 8  計算、A=34h、B=12h  0hに34h書き込み、4hに12h書き込み  8hに046h,Chに022h,10hに03A8hがリードできること  
 9  計算、A=FFh、B=01h  0hにFFh書き込み、4hに01h書き込み  8hに000h,Chに1FEh,10hにFFFFhがリードできること  
 10  計算、A=00h、B=00h  0hに00h書き込み、4hに00h書き込み  8hに000h,Chに000h,10hに0000hがリードできること  

今回は入力を決めてテストしましたが、回路をモデリングしておいて、ランダムな数値を入力して出力とのコンペアを取るっていうのも今後行ってみたいです。これはまた後日試してみます。
また、APBバスの制御信号線系にはアサーションも入れてみたいです。これも後日試してみます。

テストベンチの仕様も検討します。
APBバスリードライトはverilogのtaskにします。リードタスクは期待値比較してOK/NGを出せるようにしておきます。
ライトタスク apb_w(addr アドレス8bit、wdat ライトデータ32bit);
リードタスク apb_r(addr アドレス8bit、rcmp リード期待値32bit);
シンプルですね。
   SmartFusion TestBlock T_cal_rtl

100-5. 簡単計算機のテストベンチを書いてみよう

LiberoIDE の File->Newで Select a Type: で HDL Stimulus File を選び、Name: は T_calc_rtlとします。あとはサクサク書いていきます。
何を行っているかはファイルの方にコメントとして書いていますので参考にしてください。
書き方に特殊なところはありませんが、コメントを入れる、今どのテストを行っているかわかるようにする(テスト番号を入れる)といったところです。書き終わったらセーブします。保存するホルダは C:\Actelprj\simplecalc\calc\simulation です。

ファイルはこちら

Verilogテストベンチ:T_calc_rtl.v

100-6. 簡単計算機のシミュレーションをModelsimでしてみよう

さて、RTLもテストベンチもできたので早速シミュレーションしてみます。
RTLは C:\Actelprj\simplecalc\calc\hdlのcalc_rtl.v、テストベンチは C:\Actelprj\simplecalc\calc\simulationのT_calc_rtl.v です。
まず、C:\Actelprj\simplecalc\calc\simulation にModelsimのショートカットを持ってきます。
  SmartFusion Forder Modelsim 

スタート->すべてのプログラム->Actel Libero IDE v9.1->ModelSim にあるModelSim Actel 6.6dをドラッグしてテストベンチと同じところにショートカットを作ります。ショートカットを右クリックしてプロパティで作業フォルダー(S)の欄を空白にします。OKで閉じます。
  SmartFusion ModelSim Propaty 

アイコンをダブルクリックして立ち上げます。
IMPORTANT Infomationが開きますが、これはCloseします。
   SmartFusion Modelsim

さて、まず始めにworkライブラリを作成します。このworkはRTLやテストベンチをコンパイルしたのを入れておく所といったところです。
ツールバーからFile->New->Libraryを開きます。Create a New Library が開きます。
・Create が a new library and a logial mapping to it
・Library Name: work
・Library Phisical Name: work
になっていることを確認してOKをクリックします。
   SmartFusion Library Create


いよいよ待ちにまった、コンパイルです。
Compile->Compile... でファイルを選択するウィンドが開きます。
  SmartFusion Modelsim File Select 

まずはRTLをコンパイルします。ファイルの場所を1つ上がって、hdlフォルダに入るとcalc_rtl.vがあります。これを選択してCompileをクリックします。問題なければ
# -- Compiling module calc_rtl
#
# Top level modules:
# calc_rtl
のように表示されます。
もし間違いがあるようなら赤文字でエラーの内容と行番号が示されますので、エディタでRTLを修正して再度コンパイルです。
何回か繰り返してエラーがなくなればOKです。

次にテストベンチをコンパイルします。1つ上がって、simulationに戻ります。T_calc_rtl.vを選んでコンパイルです。これもエラーが無くなるまで修正、コンパイルを繰り返します。コンパイルウィンドはDoneで閉じます。

やっとシミュレーションです。さっそく実行してみましょう。
Simulate->Start Simulation ... でウィンドが開きます。そこのNameにある workの下位のT_calc_rtlを選択します。
   SmartFusion ModelSim Start Simulation

OKをクリックするとウィンドの状態が変わります。
   SmartFusion ModelSim Load Desgin

waveウィンドが開いていない場合は結果を波形でみるために View->wave でwaveウィンドを開きます。
InstanceウィンドからT_calc_rtlをクリックします。そうするとObjectsウィンドにT_calc_rtlにある信号が表示されます。
もし、Objectsウィンドが無いというときは ツールバーのViewからObjectsを選択すると表示されるはずです。

Objectsの一番上の信号をクリックしスクロールさせて一番下の信号をシフトキーを押しながらクリックすると全部の信号を選択できます。
その状態を左クリックでつかんでWaveウィンドまでドラッグしてからドロップします。カーソルのアイコンに四角と+のマークになっているところであればドロップできます。
このままでは2進表示なので、Waveウィンドの信号を同じように全信号選択して右クリック->Radix でHexadecimalにしておきます。

準備が整ったので実行してみます。ModelSimのウィンドのSimulate->Run->Run -All を選択します。テストベンチのソースコードのウィンドが開き、Waveウィンドには波形が表示されたはずです。またTranscriptウィンドには実行した結果、OK/NG判定等が表示されます。
   SmartFusion ModelSim Simulation wave

Waveウィンドで波形の時間を広げて見るときは、ツールバーにある+の虫眼鏡マーク(Zoom In)をクリックしても良いですし、コントロールキーを押しながら左クリックを押しながら横にずらすことによってその区間を拡大表示することもできます。縮小するときは黒い虫眼鏡マーク(Zoom Full)をします。拡大しておいて下のカーソルを動かす事により見たい位置(時間)の波形を見ることができます。

どうでしょうか。予定していたのと同じ動作になっていますか。またTranscriptに表示された結果にNG!は無くOK!だけになっていますか。
もし予定外の動作をしていたら、RTL、テストベンチを見直して、修正して再度コンパイルしてください。(ModelSimをいちいち閉じる必要はありません。)

再実行は Simulate -> Run -> Restart... でOKをしてから、再度 Simulate -> Run -> Run - All でOKです。
   SmartFusion Modelsim Restart

Modelsimを終了するときは File -> Quit で はい をクリックします。

実行した結果も添付しておきますね。

シミュレーション実行結果 : T_calc_rtl.log


100-7. 簡単計算機をインプリしてみよう(MSS)

RTLも完成しましたのでFPGAにインプリします。
すでにプロジェクトはsimplecalc\calc\calc.prjで作成されているので、これのMSSに今回作成したRTLをAHB->APBバスを通じて接続します。
まず現在の状態はこんな感じです。
  SmartFusion Impre Project Manager 

真ん中のペーンのProject FlowからMSSをダブルクリックします。
今回必要なのは Fabclic Interface だけですが、後々USBから読み書きできるように、UART_0も有効にしておきます。なので ACE,WATCHDOC,MAC,SPI_0,I2C_0,UART_1,SPI_1,I2C_1,External Memory Controller はOFFにします。各ブロックの右下のチェックを外します。
   SmartFusion SmartDesign MSS SmartDesign


まず、ClockManageMentをダブルクリックします。
PLL右横のセレクタで真ん中を選択します。そこから出ている信号をたどって行ってFAB_CLK(GLA1)の横のチェックをONにします。OKをクリックし終了。
   SmartFusion SmartDesign MSS Clock Setting

次に Clock Managementのブロックの下の方にある、Reset Managementをダブルクリックします。
Fabric Resetsで Enable MSS To Fabric Reset にチェックを入れます。OKでとdじます
   SmartFusion SmartDesign MSS Reset Setting


次に Fablic Interfaceをダブルクリックします。
Configuring MSS_FIC_0で、Interface Type を AMBA APB3、Use Master Interfacesにチェックを入れます。ここでのMaster,SlaveはどうもCortex-M3がMasterか?という見方をするようです。
   SmartFusion SmartDesign MSS Configuring MSS_FIC_0

SmartDesignで Canvas -> Show Nets をすると、クロックやリセットのFABまでの配線が見えます。
こんな感じ。
   SmartFusion SmartDesign MSS Show Nets

Firmwareタブで HAL_0,MSS_UART_Drive_0,SmartFusion_CMSIS_PAL_0のチェックを付け、それ以外は外します。
   SmartFusion SmartDesign MSS Firmware

Saveします。
Design -> Genarate で生成します。
Logに毎度のことながら Error: Unable to create directory: と出ますがこれは無視して、 Info: Design "calc_cont" was successfully generated.と出ればOKです。

100-8. 簡単計算機をインプリしてみよう(回路配置)


さて、これからがちょっとややこしいです。しばっちもしばらく試行錯誤して、マニュアル見つつあーでもない、こーでもないと悩んだ所です。
1つづつ注意深く行って行きます。


Project Managerの Design Explorerで workを左クリックしておいて(もしかするとこれはいらないかもしれませんが)、真ん中ペーンのProjectFlowでSmartDesginをクリックします。Select a Type: SmartDesign Componet で Name: を calc_top としOKをクリックします。
   SmartFusion SmartDesign Component

真ん中ペーンにCanvasが開きます。(MSSのCanvasではありません。ProjectManagerのCanvasです。)
左のペーンの Design Explorer で calc_topを左クリック後、右クリックしてSet as Root を選びます。calc_topが太文字になります。

真ん中ペーンのCanvasに左ペーンのcalc_rtlをドラッグしてドロップします。
同じく左ペーンのcalc_contをドラッグしてドロップします。

右ペーンのCatalogのCoreタブで Bus Interfaces の CoreAPB3をドラッグドロップします。
Configuring CoreAPB3_0が開きます。
・Direct or Indirect Addressing を Direct Addressing(legacy)にします。
・APB Master Data Bus Width は 32bit
・Enable APB Slave Slots を Slot 0: だけチェックを残し後はチェックを外します。
・APB Slot Sizeは 256 locations にします。
・Testbench:はUserにします。
OKをクリックします。
Slotというのは1つのAPBのPSELを何個用意するかということで、今回はcalc_rtlを1つなのでSlot0だけを有効にしています。Slot Sizeは1つのSlotの大きさで今回は5アドレス(00h〜10h)だけなので256locaitions(たぶん1locationsはDataBusWidthからくるサイズ刻みでの個数)にします。
   SmartFusion Configuring CoreAPB_3_0


次にこれが一番分かりにくい所です。
Catalog から Bus Definisions タブを選択します。
・APB AMBA AMBA2 slave を選択し、真ん中ペーンのcalc_rtlの上にドラッグドロップします。
Add Bus Interface to [calc_rt_0]が開きます。
Bus Interface Name: は ABP_bif とします。
InstanceのSignalの所をクリックすると信号名が現れるのでBus DefinisionのSignalと同じ名前を選択します。
すべて設定し終わったらOK。
  SmartFusion Add Bus Interface to [calc_rtl_0 

まん中ペーンのCanvasで左クリック後、右クリックし、AutoConnect をします。
Modify Memory Map が開きます。これはそのままOKにします。
   SmartFusion Modify Memory Map

配線が接続されたのを確認します。
Canvasで右クリックし、 Auto Arrange Instances を選びます。
Canvasで右クリックし、 Auto Arrange Connections を選びます。

Project Managerのツールバーから File -> Save calc_top でセーブしておきます。
左のDesign Explorerの配置が変わります。
ここまでで、Design Explorerと Canvasは このようになります。
   SmartFusion Project Manager Design Exploer Canvas Result


さて、ここまできたらGenerateします。
ツールバーのSmartDesign->Generate Design を選びます。
Design "calc_top" was successfully generated と表示されればOKです。
これで回路設計は完了です。
   SmartFusion Project Manager


100-9. 簡単計算機をインプリしてみよう(合成)

次は合成して、実際の回路に落としこみます。いわばRTLからSmartFusionの回路情報に変換するわけですね。
ProjectFlowペーンの真中にあるSyntyesis Synplifyをクリックします。
Synplify Pro が立ち上がります。
Did you know... とかポップアップがでますが、OKとします。
合成は簡単で、左上のへんにあるRunをクリックするだけです。1分もかからずに終了するはずです。
warningやnotesはありますが、errorsがなければOKとします。
File->Exitで閉じます。
   SmartFusion Symplify


100-9. 簡単計算機をインプリしてみよう(配置配線)

次はPlace&Ruteです。合成で作成した回路情報をSmartFusionのデバイス上の素子のどこに置くか、また置いた素子間の接続を決定します。
ProjectFlowペーンの下の方にあるPlaceRoute Designerをクリックします。
Organize Constrains for Designer でどのファイルを使用するか設定できますが、すでにcalc_top.pdcとcalc_top_scd.sdcが入っているのでこのままOK
  SmartFusion PlaceRoute 

Device Selection Wizrdで
・Family:Die A2F200M3F、Package:484FBGA、Speed -1 で次へ
・I/O Attributes : LVTTL で次へ
・Junction Temperature Voltage : すべてCOM で完了
と設定します。(デフォルトでそうなっているはずです)

No patch is 〜 とメッセージがでますが、OKで閉じます。

DesignerのウインドでCompileをクリックします。
Compile Optionで
・Phsical Design Constraints : About〜にチェック、Display〜のチェック外す、Limit〜 は 10000
・Globals Management : Demote〜のチェック外す、Promote〜のチェック外す、Limit〜は12、When〜は12
・Netlist Optimization : Combine〜のチェック外す、Delete〜のチェック外す
・Display of Results : Linmit〜は10
と設定します。(デフォルトでそうなっているはずです)

OKでコンパイルが始まり、10秒もかからず終わります。
The Compile command succeeded ( 00:00:03 ) のようにsucceeded表示されたら完了です。

次にLayoutです。
・Timing-driven,Run place,Run route にチェック、Use Muliple Passesのチェック外す。
OKでレイアウトが始まり、数十秒で終わります。
The Layout command succeeded ( 00:00:42 ) のようにsucceeded表示されたら完了です。

最後にデータファイルにします。
FlashPro Data File をクリックします。
10秒位でしょりが終わり、
The Export command succeeded ( 00:00:10 ) のようにsucceeded表示されたら完了です。
処理が完了したところは緑色に変わっています。
  SmartFusion PlaceRoute result 

File->Exitで抜けます。Save changes to calc_top.adbとでますが、はいをクリックします。

この後、Programming FlashProに進みたい所ですが、そのまえにCoretex-M3のCプログラムを作成します。
プログラムが無いとSmartFusion FPGAに書きこんでもなんにも起きませんからね。


100-10. 簡単計算機のCプログラムを書こう

calcを動作させるためにはCoretex-M3 CプログラムでAPBバスにライト/リードさせます。

いきなりC書き始めることはせず
まずは仕様を決めます。最初なので最低限動作確認ができることを目標にします。
  • 変数の設定はSoftconsoleのデバッガで行う。
  • 同様に、計算結果の確認もSoftconsoleのデバッガで行う。
  • ベースアドレスはDefineで0x40050000を設定、各レジスタはオフセットとする。
  • オフセット名はこれもDefine 0番地:INPUT_A,4番地:INPUT_B、8番地:RESULT_ADD、C番地:RESULT_SUB、10番地:RESULT_MUL
  • 追記:32bitデータ幅にすると、1づつで4番地飛ばしになるようです。ですので、ここは、 0番地:INPUT_A,1番地:INPUT_B、2番地:RESULT_ADD、3番地:RESULT_SUB、4番地:RESULT_MULとなります。
  • calcのレジスタには直接値設定せず、デバッガで確認しやすいよう変数に入れてアクセスする。
なんか仕様ぽくないですがこんなところで。
フローチャートも書いてみます。
   SmartFusion flowchart
フローチャートの各項目の粒度がバラバラですので、後で書き直す予定です。ひとまず今のところはこれでいきます。

いよいよCプログラムを書きます。
スタート->すべてのプログラム->Microsemi SoftConsole v3.3->Microsemi SoftConsole IDE v3.3.0.14 でSoftConsoleを立ち上げます。
Workspace Launcher で Workspace:を C:\Actelprj\simplecalc\calc にしてOKをクリックします。
   SmartFusion Workspace

SoftConsoleのFile->New->C Projcectを選択します。
Project name: simplecalc を入力します。後はそのままでOKです。
   SmartFusion SoftConsole

Next> をクリックし、DebugとReleaseにチェックが入っているのを確認したら、Finishをクリックします。

次に、MSSで作成した、ライブラリ、ドライバーをインポートします。これを忘れるとCコンパイルの後のリンクで、ライブラリが無いとかファイルが無いとかのエラーになります。
左ペーンのProject Explorer の simplecalcを左クリック後、右クリックし、Importを選びます。
Import Selectのウィンドが開くので、Generalをクリックし、File Systemを選択してNext
From directory: の Browseを選び C:\Actelprj\simplecalc\calc\firmware を選択します。
左のペーンにfirmwareと現れます。CMSISとdriversにだけチェックを入れます。halはチェックを入れてはいけません。halにチェックを入れるとリンク時にエラーとなります。
Finishで完了です。
   SmartFusion Import

次に、例のお約束の設定をしておきます。そう、ライブラリの設定です。
Project Explorer の simplecalcを左クリックで選択したあと右クリックでPropertiesを選びます。
左のペーンからC/C++ buildのSettings をクリックします。
右ペーンにSettingsが開くので、Tool SettingタブのGNU C LinkerのMiscellaneousを選択します。
ここの Linker flags の所に、-T ../CMSIS/startup_gcc/debug-in-actel-smartfusion-esram.ld を入力します。
設定し終わったら Apply->OK で閉じます。
   SmartFusion Linker flag



Cのソースコードを入力します。
File->New->Source File を選択します。
Source File: にmain.c
Template: は Default C source template で良いです。
Finishをクリックします。
   SmartFusion source


Cプログラムはこちら。
Cプログラム:main.c

プログラムは特に難しい事はしていませんが、1箇所だけ注意すべき点があります。

// ファブリック(FPGA)のベース設定
volatile unsigned int* CALC_BASE = (unsigned int*)FPGA_FABRIC_BASE;

ここで変数を volatile修飾子をつけて宣言しています。このことにより最適化を防ぐ事ができます。
今回のプログラムの場合は無くても動作すると思いますが、フラグをループでポーリングしているような時は、この宣言をしないと、読み出しが最適化されてしまいフラグの変化が読み取れなくなって、いつまでたってもループを抜けないというような事が起こりえます。

さて、コンパイルします。
Project->Clean を選択します。
Clean all projects が選択されており、simplecalcにチェック、Start a build immediatelyにチェック、Build the entire workspaceが選択されているのを確認してOKでコンパイルが始まります。これぐらいのプラグラムなら数秒で完了します。
真ん中下のペーンProblemsのDescriptionで赤文字でErrorsとかでなければOKです。黄色のWarningsもできるだけ出ないように修正します。


100-11. 簡単計算機のプログラムロードと実行をしよう

まずは、FPGAのデータをメガメガボードに転送します。

メガメガボードをPCに接続します。
ジャンパー設定はいままでのままでOKです。一応書いておくと
JP10:1と2
JP7:1と2
J6:1と2
JP6:2と3
J13:USBケーブルでPCに接続
J14:USBケーブルでPCに接続
です。

ここの手順は 7-2-4. FlashProで構成とプログラムの転送 と似ているところも多いのでそちらも参照してください。
LiberoIDEのProjectManager,ProjectFlowのProgramming FlashPro を選択します。Verupを確認しているので起動に少し時間がかかります。

Configure Device アイコンクリック。

Programming file の Modify をクリック
FlashPoint - calc_top.pdb ウィンドが開きます。
FPGA Array のところはデフォルトでパスが入っています。
eNVMのImportを選択します。
C:\Actelprj\simplecalc\calc\component\work\calc_cont\MSS_ENVM_0 の MSS_ENVM_0.efc が選択されていることを確認します。
Save PDB で完了

ViewProgrammersを行うとProgrammer List window に現れます。なにも現れないときはボードの接続を確認します。

PROGRAM アイコンをクリックすると書き込みが始まります。1分位まちます。
Programmer List window の Programmer Statusに RUN PASSED と表示されれば完了です。
File->Exitで閉じます。Saveするかどうか聞かれるので はい を選んで終了です。


SoftConsoleで Run->Debug Configurationsを選択します。左ペーンからMicrosemi Cortex-M3 RAM Targetをダブルクリックし simplecalc Debug を開きます。
Project simplecalc
C/C++ Application: Debug\simplecalc
になっていることを確認し、Debugをクリック。
Confirm Perspective Swich は Yesをクリック
デバッガが開くので、Run->Resume で実行できます。
ソフトコンソールフローの時のようにレジスタ値やブレークなどいろいろ見てみます。

終了するには Debug ペーンで、右クリックして Terminate and Remove を選択します。もしくはTerminate で実行を止めて Debug ペーンで、右クリックして Remove All Terminate を選択します。

ツールバーから File -> Exit を選択し、ソフトコンソールを終了します。


100-12. PCから制御できるようにしよう

2011/09/19↓
いちいちデバッガで実行するのもめんどくさいですし、ここはスマートにPCから計算値設定と計算結果の取り込みができるようにしてみたいと思います。
   

PCでTeraTermとかのシリアルコンソールを立ち上げて、USBを通じてメガメガボードを制御します。
メガメガボード内では送られてきたPCからのコマンド/データを受け取り、ファブリックのレジスタにセット、またレジスタから読み出し、PCへ転送するということをします。

まずは制御するコマンドとデータの仕様(プロトコル)を考えます。
コマンドとしては、ライトする(PC->ボード)とリードする(ボード->PC)の2種類とあとはどのアドレスにアクセスするかという情報だけです。
それにつづくデータは実際に書きこむ/読みだすデータとなります。

ざっくりライトとリードに分けて考えると
ライト時
 アドレス、ライトコマンド、ライトデータ
リード時
 アドレス、リードコマンド
で、リード時には読み出されたデータが帰ってくるとします。
アドレスは1桁固定、コマンドも1桁固定、データは最大3桁とします。
送る文字はASCII、数字は16進数ということにします。(マイナスの数字は予め考えてから設定する)
コマンドの終わりは改行コード(CR)

ライト例
 1番地に12Hをセット:1W12(CR)
リード例
 3番地から読み出す:3R(CR)
プロトコルといってもたいそうなものではありません。

一つ気になるのが、ARMのCってライブラリはどこまで使えるのかなという所、例えばatoi()とかです。この辺りが使えないとできなくも無いですが手間がふえるなぁと思います。これはおいおい書いて試してみます。

さて、プロトコルも決まったことなのでフローチャート書いてみます。まずはアウトライン書いて、後で細かくしていきます。
   

UARTの仕様に付いては SmartFusion_MSS_UG.pdf の 15 ? Universal Asynchronous Receiver/Transmitter (UART) Peripherals にあります。25ページほどの英文ですが頑張って読みます。これとUARTのTutorialを参考にします。


上記フローチャートを書いたものの、ボーレートの設定とかうまくいくの?とか、本当にUARTから送受信できるのかちょっと不安なのでまず、UARTのループバックプログラムを作成して試してみます。これはPCから来たUARTのデータを折り返して、PCに返すだけのプログラムです。
本当に書けたか確認するために受信した文字に###を付けて返すようにしてあります。ボーレートは9600Bps、パリティ無し、ストップ1ビットにしてあります。

---------------------------------------------------------------------------------
//
// SmartFusion UART RX->TX TestProgram
// 2011/09/19
// @Shibatchii
//

#include "./drivers/mss_uart/mss_uart.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * main function.
 */

int main()
{
    uint8_t rx_buff[256];
    int rx_size;
    int i;

    for(i=0;i<256;i++)rx_buff[i]=0;
    /* Initialize and configure UART0. */
    /* 9600baud,8bit,nonparity,stop1 */
    MSS_UART_init(
        &g_mss_uart0,
        MSS_UART_9600_BAUD,
        MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT
    );

    while( 1 )
    {
        // UART recieve
        rx_size = MSS_UART_get_rx( &g_mss_uart0, rx_buff, sizeof(rx_buff) );
        if (rx_size > 0)
        {
            // add ### for indicate
                strcat((char *)rx_buff,"###");
                // UART transmit
            MSS_UART_polled_tx( &g_mss_uart0, rx_buff, sizeof(rx_buff));
            for(i=0;i<256;i++)rx_buff[i]=0;
        }
    }
    return 0;
}

---------------------------------------------------------------------------------

このプログラムで解ったことは、 ・1文字ずつポツンポツンと打つとその1文字毎に帰ってくる、例えばabcとゆっくり打つとa###b###c###のようになる。素早くabcと打つとバッファリングされるらしくabc###となる。
・ボーレトはファームの方で自動的にAPBクロックから分周比を計算してくれるらしい。
ということです。

バッファリングについては改行コードCRが来るまで別バッファに貯めて、CRが来た所で初めて処理動作するという具合に変更してみます。
以下は主に変更した箇所です。
---------------------------------------------------------------------------------
    while( 1 )
    {
        while(1){
            // UART recieve
            rx_size = MSS_UART_get_rx( &g_mss_uart0, rx_buff, sizeof(rx_buff) );
            if (rx_size > 0)
            {
                strcat((char *)buff,(char *)rx_buff);
                if(strstr((char *)rx_buff,"\n")!=NULL)break;
                for(i=0;i<256;i++)rx_buff[i]=0;
            }
        }
        // UART transmit
        MSS_UART_polled_tx( &g_mss_uart0, buff, sizeof(buff));
        for(i=0;i<256;i++)buff[i]=0;
    }
---------------------------------------------------------------------------------
良い感じに1行ごとに出力されます。

2011/09/19↑


2011/09/25↓

UARTからSmartFusionのFablicにライト、リードさせるプログラムを作成しました。エラー処理とか入っていないので設定外の値を設定したりするとNGですが、ともかくシリアルコンソールからきちんとライト、リードできたので良しとします。
今日は日がな一日、このデバッグに費やしていました。(^^;)

プログラムはこちら
---------------------------------------------------------------------------------
//
// SmartFusion UART RX->TX TestProgram
// 2011/09/19
// @Shibatchii
//

#define FPGA_FABRIC_BASE        0x40050000U
#define INPUT_A                 0x00U
#define INPUT_B                 0x01U
#define RESULT_ADD              0x02U
#define RESULT_SUB              0x03U
#define RESULT_MUL              0x04U

#include "./drivers/mss_uart/mss_uart.h"
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

// ASCII Hexvalue to int
unsigned int hextodec(const char str[ ])
{
    int i,n,x;
    char c;
    i=0;n=0;x=0;
    while (str[i] != '\0') {
        if ('0' <= str[i] && str[i] <= '9')
            n = str[i] - '0';
        else if ('a' <= (c = tolower(str[i])) && c <= 'f')
            n = c - 'a' + 10;
        else {
            return(0xFFFF);
        }
        i++;
        x = x*16 + n;
    }
    return (x);
}

/*
 * main function.
 */

int main()
{
    uint8_t rx_buff[256],buff[256],obuff[256],tmpbuff[256];
    int rx_size;
    int i;
    int value;
    int kaigyou;
    char *index;

    // ファブリック(FPGA)のベース設定
    volatile unsigned int* CALC_BASE = (unsigned int*)FPGA_FABRIC_BASE;

    for(i=0;i<256;i++){rx_buff[i]=0;buff[i]=0;obuff[i]=0;tmpbuff[i]=0;}
    /* Initialize and configure UART0. */
    /* 9600baud,8bit,nonparity,stop1 */
    MSS_UART_init(
        &g_mss_uart0,
        MSS_UART_9600_BAUD,
        MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT
    );

    while( 1 )
    {
        while(1){
            // UART recieve
            for(i=0;i<256;i++)rx_buff[i]=0;
            rx_size = MSS_UART_get_rx( &g_mss_uart0, rx_buff, sizeof(rx_buff) );
            if (rx_size > 0)
            {
                strcat((char *)buff,(char *)rx_buff);
                if(strstr((char *)rx_buff,"\r")!=NULL)break;
            }
        }
        kaigyou = '\r';
        index = strchr((char *)buff,kaigyou);
        if(index != NULL) *index=0;
        // Write
        if(buff[1]=='W'||buff[1]=='w'){
            switch(buff[0]){
                case '0':{  value = (int)hextodec((const char *)&buff[2]);
                            *(CALC_BASE + INPUT_A) = value;
                            break;}
                case '1':{  value = (int)hextodec((const char *)&buff[2]);
                            *(CALC_BASE + INPUT_B) = value;
                            break;}
            }
            strcpy((char *)obuff,(char *)buff);
            strcat((char *)obuff,"\n");
        }else{
            switch(buff[0]){
                case '0':{ value = *(CALC_BASE + INPUT_A);break;}
                case '1':{ value = *(CALC_BASE + INPUT_B);break;}
                case '2':{ value = *(CALC_BASE + RESULT_ADD);break;}
                case '3':{ value = *(CALC_BASE + RESULT_SUB);break;}
                case '4':{ value = *(CALC_BASE + RESULT_MUL);break;}
            }
            strncpy((char *)obuff,(const char *)buff,2);
            sprintf((char *)tmpbuff,"%X\n",value);
            strcat((char *)obuff,(char *)tmpbuff);
        }
        // UART transmit
        MSS_UART_polled_tx( &g_mss_uart0, obuff, sizeof(obuff));
        for(i=0;i<256;i++){buff[i]=0;obuff[i]=0;tmpbuff[i]=0;}
    }
    return 0;
}
---------------------------------------------------------------------------------

結果はこちら
---------------------------------------------------------------------------------
0W34
1W12
0R34
1R12
2R46
3R22
4R3A8
---------------------------------------------------------------------------------

最初の数字がアドレス、次がWだとライトで書き込む16進の値が続きます、Rだとリードで読み出された値が表示されます。
0x34+0x12=0x46、0x34-0x12=0x22、0x34*0x12=0x3A8 ですのでキチンと動作していますね。

ちょっとプログラムがごちゃごちゃしていますので、今度整理しようと思います。


100-13. まとめ


いろいろ、右様曲折ありましたが、なんとかPCからARMと通信し、ARMからFablicを制御することができました。
感想としては、
・ARMのCって特別な事は無くパソコンとかで使う普通のCの感覚で使えます。
・当たり前の事かもしれませんが、デバッガって結構便利。ブレークポイントかけて値を見たりとデバッグに大いに有効です。
・SmartFusionのFablicもARMとの接続がAPBであれば簡単。注意することは32bitアクセスでもARMのCからは4飛ばしでなく、1飛ばしのアドレスになること
・SmartFusionのFablicはAPBでアクセスするときは100MHzではちょっと厳しい。少しクロックを落とす必要がある。今回は20MHzまで落としましたけど、
 80MHzくらいでも大丈夫かもしれないです。
・UARTのボーレート設定はドライバ関数無いで供給されているクロックから自動で分周値を計算しているので、ボーレートさえ設定すればOKです。
 ただしあまりにシステムクロックが遅くなると誤差が大きくなってコケるかもしれません。
 どこまで大丈夫かはITU-T V.24とかANSI/TIA/EIA-232-F-1997を見れば良いかもしれません。
といったところです。

簡易計算機はひとますこれで完とします。
さて、次は何をしてみましょうかね。(^^)

2011/09/25↑



1つ上
1つ上へもどる


トップ
トップページへもどる


mark  Copyright(c) shibatchii 2011 All Rights Reserved.

-