Posts Tagged with "Design"

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

FM-7 ROM吸出し器の改版 (4)

posted by sakurai on May 18, 2020 #259

DRAMのリフレッシュタイミング

本来は基板設計の前にタイミングを検討しますが、開発環境と合わせて基板を紹介したため、後になっています。まずMB8265-15のデータシートを入手します。以下にZ80によるリフレッシュ手法である$\overline{\text{RFSH}}$リフレッシュタイミングを示します。

図%%.1
図259.1$\overline{\text{RFSH}}$リフレッシュタイミング

表259.1 MB8265-15の動的特性
Parameter Symbol MB8265-15
Min Max
$\overline{\text{RFSH}}\text{ Set Up Time Referenced to }\overline{\text{RAS}}$ $\text{t}_\text{FSR}$ 100 -
$\overline{\text{RAS}}\text{ to }\overline{\text{RFSH}}\text{ Delay}$ $\text{t}_\text{RFD}$ 100 -
$\overline{\text{RFSH}}\text{ Cycle Time}$ $\text{t}_\text{FC}$ 270 -
$\overline{\text{RFSH}}\text{ Pulse Width}$ $\text{t}_\text{FP}$ 150 -
$\overline{\text{RFSH}}\text{ Inactive Time}$ $\text{t}_\text{FI}$ 100 -

PICのプログラム

DRAMのタイミング要求からPICのプログラムを検討します。PICの書き込み自体もArduino(Z80側)にやらせることもできそうですが、動作しない等のトラブルの可能性を考え、今回はPicKit4を用いたIn Circuit Programmingを行います。PicKit4上で書き込み、書き込み済みのPICをボード上のソケットにはめ込むことにしました。

PICのプログラムは基本的には前稿のようになります。Xrefckを4回アサートする場合、PICに対して16KHzでタイマー割り込みをかけ、以下のisr (interrupt service routine)を実行します。

初期化

  1. 各種レジスタ設定。
  2. Rfreq=L、Xrefck=Hを出力(ネゲート)。
  3. Z80Wを監視し、Z80WがLのときにのみ割り込み許可。

割込みルーチン(ISR)

  1. Rfreq=H、Xrefck=Hを出力 //リフレッシュ要求
  2. Rfgnt=Hを待つ
  3. Rfreq=H、Xrefck=Lを出力
  4. Rfreq=H、Xrefck=Hを出力 (3, 4を4回繰り返す)
  5. Rfreq=L、Xrefck=Hを出力
  6. リターン

1命令1サイクルでないため、命令数のカット&トライが必要です。

Arduino(Z80側)のプログラム

一方、Arduino(Z80側)ではPICのRfreqを監視し、Rfgntを発行することでバス調停を行います。

過去記事には、

Z80カードは、FM-7の内部バスに対して、別のバスマスタを使用可能にするものであり、メインCPUである6809から$FD05のLSBを1にすれば、メインCPUにHALTがかかり、外部バスマスタであるZ80による内部バスアクセスが可能になるものです

ということから、

  1. \$FD05に1を書き込み、6809にHALTを要求する。FM-7内部では*GH($\text{Go}/\overline{\text{Halt}}$, 負論理のHALT信号)がアサートされ、6809がBA=BS=Hとし、バスを明け渡す。
  2. Rfgnt=H (初期値)
  3. アクセス前に
     ・Rfreq=Lを待つ (リフレッシュ優先のため)。
     ・Rfgnt=Lとする。
  4. アクセス(アドレス出力、データ出力、EB/QB出力、データ入力)
  5. アクセスの終了時に
     ・Rfgnt=Hとする。
  6. 終了時にはアドレスに\$FD05をセットし、EB/QBをアサートせずに6809にバスを明け渡す。

となります。このうち3, 5が今回追加したアクセス法です。このように、お互いに待つ場合はデッドロックの可能性があるため、背理法により無いことを証明しておきます。

  • Aruduinoが待つ場合は、上記3.からRfgnt=Hとした上でPICを待つ
  • 上記からデッドロックがあるとすれば、Rfgnt=Hのとき、PICがRfgnt=Lを待つ場合
  • ところが、PICが待つのはRfgnt=Hであることから、矛盾、よってデッドロックは存在しない

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

FM-7 ROM吸出し器の改版 (3)

posted by sakurai on May 15, 2020 #258

PICの開発環境

早速、開発環境とCコンパイラをインストールし、PICプログラマを購入しました。

対象となるPICマイコンは、秋月電子でも入手可能なPIC12F1501-I/Pとします。

図%%.2
図258.2 PICマイコン

Eagleによる設計

PICマイコンをプログラマブルタイマーとして使用した回路図V5を図258.3に示します。回路は多いようですが、ほとんどがコネクタであり、Arduinoが1個と今回追加した8pinのICが全てです。他はZ80コネクタ、ロジアナ用ピンヘッダ、PICプログラム用コネクタから構成されます。

図%%.3
図258.3 FM-7IntruderV5の回路図
以前に格安PCB業者を調べましたが、今回は最安だったJLCPCBにオーダーしました。5枚で送料込みで17.95 USDです。ここは安いだけでなく、製造も速くて2~3日で製造します。
図%%.4
図258.4 FM-7IntruderV5の基板図

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

FM-7 ROM吸出し器の改版 (2)

posted by sakurai on May 14, 2020 #257

DRAMの"化け"は故障とみなせる

試みに、DRAMのリフレッシュを停めると、どの程度ビット化けが起きるかを実験してみました。 注意点として、データチェックのためにリードアウトすると、リフレッシュとなってしまうということがあります。そのため、1sec毎に故障数をチェックするのではだめで、リフレッシュ停止期間を1secずつ伸ばして行き、壊れているデータの数を計数します。リフレッシュを停止しただけなので、永久故障ではないのですが、機能停止を広い意味で故障として扱うため、ここでは故障(ソフトエラー)と呼ぶことにします。

図%%.1
図257.1 リフレッシュ停止時間に対する故障割合、及び故障密度

図257.1左がリフレッシュ停止時間(sec)に対する故障バイト数の試験数に対する割合(累積故障確率関数)、図257.1右がリフレッシュ停止時間(sec)に対する1秒当たりの故障数(確率密度関数)です。このグラフはジャンクション温度により非常に変化し、当然温度が高いほうが故障しやすいわけです。

この室温では2分間でほぼ全数のバイトが化けていることになります。グラフでは分かりにくいですが、漸近値が99.2%付近となっています。100%にならない理由は、DRAMはリフレッシュが停まると\$00または\$FFになり易く、たまたま正解値が\$00または\$FFだったためと思われます。一致する確率は2/256なので、故障個数の最大は、試験バイト数\$6000個に対して$(1-\frac{2}{256})=99.2186\%$の24,384個になるはずです。実データでは139秒後に24,384個故障し、確率的な一致を除いた最大数になりました。

リフレッシュ試験

DRAM化けの試験プログラムはそのままリフレッシュ回路の試験に使用できます。リフレッシュを停止すると、正規分布を持つ確率密度に従いソフトエラーが起こります。リフレッシュ回路を追加して、さらに厳しい条件となるようにドライヤー等でDRAMを加熱し、この試験プログラムを用いて、2分程度エラーが確認されなければリフレッシュ回路はOKと判断できます。非同期DRAMのタイミングは複雑であり、RASのタイミングが規格割れしただけでソフトエラーを起こすので、試験としてはこれだけでなく、様々なタイミング切り替えを実施するほうが良いと思います。


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

FM-7 ROM吸出し器の改版

posted by sakurai on May 13, 2020 #256

FM-7 ROM吸出し器にDRAMリフレッシュ回路を追加

過去記事において、表記のボードを開発しましたが、DRAMのリフレッシュを失念していました。そこで、前回のオールソフトウエア(?)回路に対して、ハードウエアでリフレッシュ回路を追加します。バイトアクセスはオールソフトウエアで可能なことを実証できたのですが、DRAMリフレッシュは2msec以内に128カラムアドレスにアクセスが必要、という制約があるため、ソフトウエアでは厳しいと思われます。従って、ハードウエアで構成しますが、タイミング回路なので意外に回路規模を必要とします。せっかくArduino 1個で済ませたので、最小の回路構成としたいところです。

アナログタイマーIC 555

最初に思いついたのは小型のタイマーICである555です。ところがこれはアナログICであり、時定数設定のためにRやCを複数必要とします。さらに、リフレッシュ周期だけでなくリフレッシュパルス幅を確保しようとすると、555の2個入りを使用する必要があるだけでなく、外付けCRも倍の数になり、シンプルになりません。設計してみたものの嫌になりました。

図%%.1
図256.1 NE555回路図

プログラマブルタイマーPIC

そこで、プログラマブルタイマーで検討したところ、PICマイコンを使用すれば、開発環境その他は必要となりますが、8pinのIC1個で行けそうです。デジタルのほうがシンプルで、かつ調整も無くて好きです。

図%%.2
図256.2 バス権調停信号図

PICのリフレッシュアルゴリズム

リフレッシュアルゴリズムは以下のように考えています。

  • 6809が\$FD05に1を書き、Z80W信号をLにします(Z80W=$6809/\overline{\text{Z80}}$)。
  • ArduinoはPICからのバス権の要求RFREQが無ければ、RFGNTをLにしてバスを獲得します。バスアクセスはQB/EBをアサートすることで行います(RFGNT=$\text{PIC}/\overline{\text{Arduino}}$)。
  • Z80W信号がLの際に、PICから周期的にRFREQをHとしてバス権要求をArduinoに通知します。
  • Arduinoはバスアクセス中であれば終了後にバス権を放し、PICにRFGNTをHとして通知します。
  • PICはRFGNTがHであればリフレッシュ可能と判断し、*REFCKをLとします。
  • バス調停のオーバヘッドを削減するため、PICは*REFCKは4回アサートします。その代わり、リフレッシュ周期は1/4の16KHzとなります。
  • リフレッシュが終了すると、PICはRFREQをLにします。
  • ArduinoはPICがバス権を放したと判断してRFGNTをLにしてバスを獲得します。

図%%.3
図256.3 バス権調停タイミングチャート

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

posted by sakurai on May 12, 2020 #255

過去ブログの、BSVによるスペースインベーダーの再設計の記事#234~#239, #254をまとめてQiitaに投稿しました。さらに考察を加えています。

BSV (Bluespec SystemVerilog)によるスペースインベーダーの再設計

過去ブログ記事でUltra96ボードを用いた、VerilogHDLによるSpace Invadersゲームの作成を投稿しましたが、その続きです。

図%%.1
図255.1 Qiitaの投稿記事

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

BSVの設計トライアル (21)

posted by sakurai on May 11, 2020 #254

ゲームFSMのアルゴリズム

トライアルの結果、BSVによるゲームFSMが完成しました。過去記事のステートベースのサウンドステートマシンと異なり、ステート分解をしていないため、rule文を一切使用していません。全てbsc(Bluespec Compiler)の、StmtFSMライブラリにステート管理を任せました。

基本的にはCで記述するようにゲームが記述できることが分かりました。例えば、弾の移動及び衝突判定、衝突処理(爆発マーク)、爆発マーク消去等のアルゴリズムを考えると、自弾、敵弾共にアルゴリズムは共通で、疑似コードで書けば、

    if (弾爆発タイマ >= 1) {   // 弾爆発中
        弾爆発タイマ++;
        if (弾爆発タイマ == MAX) {
            弾削除;            // 論理的な消去
            弾爆発マーク消去;   // 物理的な消去
            弾爆発タイマ停止;
        }
    } else {
        if (弾が出ていない and 弾生成条件) {
            弾生成処理;
            弾発射音;     // 自弾のみ
        }
        if (弾存在) {
            衝突判定;
            if (対象物) {  // 自弾の場合はインベーダ及びUFO、敵弾の場合は自機
                弾削除;          // 論理的な消去
                対象物ステート <= 爆発;
                対象物爆発タイマ <= 0;
            } else if (上下ハズレ || ベース || 弾) { // 弾:自弾の場合は敵弾、敵弾の場合は自弾
                弾マーク消去;
                弾爆発マーク;
                弾爆発タイマ <= 1;
            } else {        // 衝突していない場合
                弾を進める;
            }
        }
    }

一方、対象物は、

    if (対象物ステート == 爆発) {
        if (対象物爆発タイマ==0) {
            対象物爆発タイマ <= 1;
            対象物爆発音;
            対象物爆発マーク;
        } else {
            対象物爆発タイマ++;
            if (対象物爆発タイマ == MAX) {
               対象物削除;          // 論理的な消去
               対象物爆発マーク消去; // 物理的な消去
            }
        }
    }

のようになりますが、StmtFSMを使うと、このようなシーケンスをクロック毎のステートに分解しなくて記述できます。

インベーダのタイミング

某所で質問があったので、タイミングについて解説します。基本の1 tickは1/60秒で、その中で、インベーダ1匹、敵弾全弾、自機、自弾、UFO、スコア等の処理を行います。以下は実際のBSVのメインループのコードです。

     while (game_flag) seq // メインループ
        for (noy <= 0; noy < `Inv_TateS; noy <= noy + 1) seq  // インベーダの行処理
           for (nox <= 0; nox < `Inv_YokoS; nox <= nox + 1) seq // インベーダの列処理
              if (inv_s[nox][noy]) seq // インベーダが生きてれば
                 ivader;      // インベーダ処理
                 gun;         // 自機処理
                 bullet;      // 自弾処理
                 for (idx <= 0; idx < extend(max); idx <= idx + 1) seq
                    invBullet(idx);  // 敵弾全弾処理
                 endseq
                 ufo;         // UFO処理
                 scores;      // スコア表示
                 endJudge;    // 終了判定
                 counter <= counter + 1;  // tickカウンタ++
                 wait_timer;  // インナーループを1/60secにするウエイト
              endseq
           endseq
        endseq
     endseq
     gameOver;  // ゲームオーバー表示

1tick=1/60secの間に、インベーダ1匹(2ピクセル移動)の処理に対して、自機(1ピクセル移動)、敵弾(1ピクセル移動)、自弾(4ピクセル移動)の処理が行われます。インベーダは初期に55匹存在するので、1/55倍のスピードで始まりますが、最終的に1倍のスピードになります。従って、インベーダを倒すたびにインベーダ全体は速くなり、一方その他の速度は変わらないわけです。

FPGAでの実装では1 tick内にインベーダ全体を移動することは可能ですし、そのような実装も見ますが、ゲーム性が変わってしまいます。具体的には、インベーダ全体の速度が次第に速くならなかったり、後ろのインベーダを撃つことができなくなります。

例えば、インベーダゲームのレインボーは、後ろのインベーダを撃つことにより出現します。インベーダは残りが一匹になると左へは2ピクセルずつ右には3ピクセルずつ移動します。下2段のインベーダは、左右2ピクセルまでの移動では跡が残らない図形になっていますが、3ピクセルだと跡が消えずに残ります。もちろん今回の実装でもレインボーを体験できます。

ゲームFSMの完成

図254.1は、BSVで再設計したゲームFSMにより動作する、インベーダーゲームの動画です。過去記事に書いたように、サウンドが4ch同時発声と高品質になりました。

図%%.1
図254.1 ゲームFSMの完成

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

BSVの設計トライアル (20)

posted by sakurai on May 4, 2020 #253

実行結果

次は、ファンクションの中にシーケンスを組み込み、ゲームFSMの設計トライアルを行います。 シーケンスを人手で分解することは、なるべくしたくありません。ファンクションでシーケンスが定義できれば、インベーダ動作、自機動作等のファンクションを作成し、順番にそれらを呼び出せば良いはずです。

import StmtFSM::*;

interface TestFSM_ifc;
   method Action inp(UInt#(8) inx);
endinterface

(* synthesize *)
module mkTestFSM(TestFSM_ifc);

Reg#(UInt#(8)) i <- mkRegU;
Reg#(UInt#(8)) x <- mkRegU;

function Stmt test1;
   return (seq
      $display("%3d 1-1", $time);
      delay(5);
      $display("%3d 1-2", $time);
   endseq);
endfunction

function Stmt test2(UInt#(8) xx);
   return (seq
      $display("%3d 2-1", $time);
      for (i <= 0; i < xx; i <= i + 1)
         $display("%3d 2-loop-%1d", $time, i);
      $display("%3d 2-2", $time);
   endseq);
endfunction

   Stmt main =
   seq
      $display("%3d fsm1.start", $time);
      test1;
      $display("%3d fsm2.start", $time);
      test2(x);
   endseq;

   mkAutoFSM(main);

   method Action inp(UInt#(8) inx);
     x <= inx;
   endmethod

endmodule: mkTestFSM

このためのテストベンチを示します。あえてモジュール外部からループ回数を入れているのは、ループ回数がダイナミックに(実行時に)決定できるかを確認するためです。ファンクションのループを8回呼び出してみます。

import StmtFSM::*;
import TestFSM::*;

(* synthesize, always_ready, always_enabled *)
module mkTb (Empty);
  TestFSM_ifc test <- mkTestFSM();
  Reg#(UInt#(8)) count <- mkReg(8);

   Stmt main =
      seq
         test.inp(count);
         repeat(40) noAction;
      endseq;

      mkAutoFSM(main);
  
endmodule

実行結果を示します。test1の次にtest2が呼び出され、ループが8回回ったことを示しています。

 20 fsm1.start
 30 1-1
 90 1-2
100 fsm2.start
110 2-1
130 2-loop-0
150 2-loop-1
170 2-loop-2
190 2-loop-3
210 2-loop-4
230 2-loop-5
250 2-loop-6
270 2-loop-7
290 2-2

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

BSVの設計トライアル (19)

posted by sakurai on May 1, 2020 #252

実行結果

以下に実行結果を示します。

senderFSM    20 FSM started
receiverFSM  20 receiver FSM started
senderFSM    30 Enq 10
senderFSM    40 Enq 20
receiverFSM     40 FIFO popped data 10
senderFSM    50 Enq 30
receiverFSM  70 FIFO popped data 20
receiverFSM  100 FIFO popped data 30

10nsずつ見ていきます。最初の10nsはリセット期間なので、20nsからFSM動作を開始します。

senderFSM    20 FSM started
receiverFSM  20 receiver FSM started

同時にセンダーFSMとレシーバーFSMが動作を開始しました。

senderFSM    30 Enq 10

センダーFSMがデータ10をエンキューしました。FIFOには1段のデータがあるはずです。

senderFSM    40 Enq 20
receiverFSM  40 FIFO popped data 10

レシーバーFSMが10をデキューすると同時にセンダーFSMがデータ20をエンキューしました。FIFOには差し引き1段のデータがあるはずです。

senderFSM    50 Enq 30

センダーFSMのレイテンシは1サイクル10nsなので次々に(FIFO FULLにならない限り)エンキューします。これが最後のデータです。FIFOには2段のデータがあるはずです。

receiverFSM  70 FIFO popped data 20

レシーバーFSMのレイテンシは3サイクル30nsなので、70nsにならないと次データの20がデキューできません。FIFOには1段のデータがあるはずです。

receiverFSM  100 FIFO popped data 30

レイテンシである3サイクル後にレシーバーFSMがデキューしました。FIFOには0段のデータがあるはずです。つまりFIFOは空になったはずです。

波形で見たほうが判りやすいです。エンキュー動作(オレンジの信号)はFIFOがフルでない限り1サイクルで行われるのに対してデキュー動作(ブルーの信号)は3サイクル毎に実行されています。

図%%.1
図252.1 センダーFSMとレシーバーFSM

以上はデータを3つエンキューした場合ですが、ここで4つ目をエンキューすると動作が異なります。図252.2に示すように、3つまではレイテンシ1でエンキューできていましたが、3つめでFIFO FULLとなり、その後はレシーバーFSMのレイテンシが見えてきます。つまりエンキュー動作もレイテンシが3となります。

図%%.2
図252.2 センダーFSMとレシーバーFSM
図252.1でもFIFOがFULLになっているのですが、その時にエンキューが無いのでレシーバー側のレイテンシが見えませんでした。図252.2ではFIFOがFULL状態でエンキューしようとして待たされています。FIFOは2段だということが分かります。

実は、FIFO段数もコントロール可能であり、任意の段数のFIFOを作成するにはmkSizedFIFOFを使用します。

      FIFOF#(Bit#(8)) fifo <- mkSizedFIFOF(2);

mkSizedFIFOFの引数サイズを2とすると、上記と同じ動作を行います。サイズを1にすると、デキューするまでエンキューが待たされる、図252.3のような動作となります。

図%%.3
図252.3  FIFOが1段の場合の動作
bscは良くできていて、FIFOフルの場合等、FIFO がデータを受け取れない場合には自動的にエンキュー動作が抑止されます。普通ならFULLで無い条件でエンキュー動作を行う記述を書かなければいけませんが、その必要がありません。これは自動ハンドシェーク機能と呼ばれます。

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

BSVの設計トライアル (18)

posted by sakurai on April 30, 2020 #251

StmtFSM

前稿ではBSVにより、ステートベースのFSMを設計しました。ステートベースとは、シーケンスを人手でステートに分解し、一つ一つのステートに対してルールを書くもので、基本的にはverilogと同程度の工数がかかります。一方、BSVにはステートマシンを効率的に設計できる、StmtFSMというライブラリが存在します。

検証用FSM

このライブラリの検証用のために検証用FSMを作成します。検証用FSMは2つのコンカレントなFSMを持ち、一方のSenderFSMがFIFOにデータを詰め(エンキュー)、他方のReceiverFSMがFIFOからデータを取り出す(デキュー)ものとします。コンカレントであり、エンキューとデキューは同時に起こります。

図%%.1
図251.1 センダーFSMとレシーバーFSM
FSMはそれぞれ別に書き、その内部ではステートメントはシーケンシャルに実行されます。このシーケンシャルの動きはBSCにより管理され、隠れた(設計者から見えない)ステートが割り付けられます。以下にBSVのコードを示します。
package Tb;
import StmtFSM::*;
import FIFOF::*;

(* synthesize *)
module mkTb (Empty);
   FIFOF#(Bit#(8)) fifo <- mkFIFOF;

   Stmt sender =
      seq
         $display("senderFSM  %4d FSM started", $time);
         action
            $display("senderFSM  %4d Enq 10", $time);
            fifo.enq(10);
         endaction
         action
            $display("senderFSM  %4d Enq 20", $time);
            fifo.enq(20);
         endaction
         action
            $display("senderFSM  %4d Enq 30", $time);
            fifo.enq(30);
         endaction
         repeat (8) noAction;
      endseq;
      FSM senderFSM <- mkFSM(sender);

      Stmt receiver =
         seq
            $display("receiverFSM %4d receiver FSM started", $time);
            while(True) seq
               action
                  $display("receiverFSM %4d FIFO popped data", $time, fifo.first());
                  fifo.deq();
               endaction
               repeat (2) noAction;
            endseq
         endseq;
         FSM receiverFSM <- mkFSM(receiver);

      rule startit;
         senderFSM.start();
         receiverFSM.start();
      endrule

      rule finish (senderFSM.done() && !receiverFSM.done());
         $finish;
      endrule
   endmodule
endpackage

コードに示すように、エンキューはレイテンシ1で実行され、デキューはレイテンシ3で実行されます。各々のFSMは、エンキューデータ、デキューデータをそれぞれ表示します。


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

BSVの設計トライアル (17)

posted by sakurai on April 29, 2020 #250

レジスタ配列によるリターンスタック

前稿のリターンスタックrsはベクター配列で構成しましたが、最初に戻りレジスタ配列を試してみます。当初から配列で試したところ、うまく行っていませんでしたが、成功したのでその方法を記述します。まずリターンスタックrsを配列宣言します。

       // return stack
       Reg#(State_t) rs[3];

次に、リターンスタックrsを3段レジスタによりインスタンシエートします。これが無かったため、今まで動作しませんでした。ちなみにverilogでは宣言しただけで使用できますが、BSVでは宣言し、次にインスタンシエートが必要です。

       for (int i = 0; i < 3; i = i + 1)
          rs[i] <- mkRegU;

マクロ命令定義はベクター配列と同じ配列によるアクセス法を用います。

`define call(SUB)        `_pushNext; state <= State_t {func:SUB, step:S0}
`define _pushNext        rs[sp] <= State_t {func:state.func, step:nextStep()}; sp <= sp + 1
`define return           state <= rs[sp-1]; sp <= sp - 1
`define next             state.step <= nextStep()

説明は表248.1と同一です。これを用いて、前稿の検証FSMを実行してみます。

$ bsc -sim -u TestFSM4.bsv
checking package dependencies
compiling TestFSM3.bsv
code generation for mkTestFSM starts
Elaborated module file created: mkTestFSM.ba
All packages are up to date.
$ bsc -sim -e mkTestFSM -o mkTestFSM
Bluesim object created: mkTestFSM.{h,o}
Bluesim object created: model_mkTestFSM.{h,o}
Simulation shared library created: mkTestFSM.so
Simulation executable created: mkTestFSM
$ ./mkTestFSM -m 15 -V dump.vcd | tee result
L1 S0
L1 S1
 L2 S0
 L2 S1
 L2 S2
  L3 S0
  L3 S1
   L4 S0
   L4 S1
  L3 S2
 L2 S3
 L2 S4
L1 S2
L1 S2
$

正しく実行することが検証できました。波形を図250.1に示します。内部信号を見ると、ベクター配列と同様、rs_0, rs_1, rs_2という3個のレジスタインスタンスが生成されています。

図%%.1
図250.1 検証用FSMのBsim波形(レジスタ配列使用)

合成結果

Vivadoによる合成結果は21 LUTのサイズでした。レジスタ配列とベクター配列は同様のサイズであったため、今後は最も素直なこの方式を採用します。

ソフトウェアの場合は高速なレジスタと低速なメモリがあるため、リターンレジスタ等の実装が必要ですが、FSMではよほどのことが無い限り全てレジスタなので、リターンレジスタを使用しない、この実装を基本的に使用していきます。


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


ページ: