ログイン
ユーザ名:

パスワード:


パスワード紛失

新規登録
Main Menu
Tweet
Facebook
Line
:-?
« 1 2 3 (4)
スレッド表示 | 古いものから 前のトピック | 次のトピック | 下へ
投稿者 スレッド
webadm
投稿日時: 2008-2-8 8:31
Webmaster
登録日: 2004-11-7
居住地:
投稿: 3095
ステートマシンの実装
次ぎはちょっと面倒なステートマシンの実装。

ステートマシンは組み合わせ回路と状態値レジスタから構成されるので、HDLではそれぞれ同時並列動作する回路を記述することになる。訓練しないと人間は同時に進行する2つ以上の物事を扱いきれない。大概考え違いや見落としが生じるのは複雑なステートマシンで生じる。ステートマシンでハードウェアで実現できるとわかっていてもハードウェア設計者は大げさなCPUを載せてソフト屋にまかせたほうが楽だというのを昔から知っている。速度は遅くなるがCPUは同時に実行できる命令は1つだけなのでソフトの方が凡人でも扱える。

シグネチャアナライザも扱う信号の変化がオーディオ帯ぐらいにゆっくりならばPICマイコンとかでソフトでやったほうが簡単なのだが、あいにく1MHz〜25MHzの信号を扱うのでそういうわけにはいかない。

ここでもQuartusのテンプレートにあるState Machinesの中から4-State Mealy state machineを拝借している。Mealy state machineとは出力信号が状態値と入力信号から生成されるタイプのものである。状態に変化が無くても入力信号の変化によって出力信号を変化させなければならない回路向き。これとは別にMoore State machineというのがあり、こちらは出力が状態値によってのみ決定されるタイプ。

sm.v:ステートマシン(実装済み)

module sm(clock, start, stop, hold, reset, clear, shift, led_gate);

input clock, start, stop, hold, reset;

output reg clear, shift, led_gate;

// Declare state register
reg [1:0]state;

// Declare states
parameter S00 = 0, S01 = 1, S10 = 2, S11 = 3;

// Determine the next state synchronously, based on the
// current state and the input
always @ (posedge clock or negedge reset) begin
if (!reset)
state <= S00;
else
case (state)
S00:
if (!start)
begin
state <= S01;
end
else
begin
state <= S00;
end
S01:
if (start)
begin
if (!stop)
begin
state <= S10;
end
else
begin
state <= S11;
end
end
else
begin
state <= S01;
end
S10:
if (stop && !hold)
begin
state <= S00;
end
else
begin
state <= S10;
end
S11:
if (!stop)
begin
state <= S10;
end
else
begin
state <= S11;
end
endcase
end

// Determine the output based only on the current state
// and the input (do not wait for a clock edge).
always @ (state or stop or clock or reset)
begin
case (state)
S00:
begin
clear = reset;
shift = 0;
led_gate = 0;
end
S01:
begin
clear = reset;
shift = 0;
led_gate = 0;
end
S10:
begin
clear = (!stop & clock) & reset;
shift = clock;
led_gate = 1;
end
S11:
begin
clear = reset;
shift = clock;
led_gate = 1;
end
endcase
end

endmodule

これも便宜上CLEAR信号は負論理とした。

初めて出力ピンにまでネットリストがつながった(LED_GATE)のでその部分についてのみPlace & RouteされてLEが割り当てられた。

RTL Viewerでステートマシンのネットリストを見ると。



ステートマシンの部分が自動的に下層ブロックになっている。これを表示させると。



テンプレートを使って記述するとちゃんとステートマシンとして認識してこのように状態遷移図を描いてくれる。賢い。

ところでステートマシンがこのようにブラックボックスになっているのが気になる人はTechnology Viewerで実際にどんなふうにPlace & Rootされているか見ることができる。



外部にLED_GATEしかつながっていないので、まだその先がつながっていないCLEARやSHIFTに関する回路は最適化によって消えてしまっている。

見ると複数のLEで構成されているが、各LEの内部構成を表示すると驚愕の事実が発覚。なんとレジスタが4つ使用されている。それというのも大抵の論理合成ツールはステートマシンを高速かつロジックハザード発生が最小限となるワンホットステートマシンというのをデフォルトで生成する。これはレジスタ1ビットが取り得る一つの状態毎に割り当てられている。なのでそれぞれのレジスタの出力がそのまま状態値のデコード出力でもあり、周辺の組み合わせ回路でわざわざ状態値をデコードする必要が無く遅延も少なくなるというメリットがある。しかし2ビットでもできるのが倍の4ビットになるので状態数が多いステートマシンでは合成指示を与えてワンホットを使わないようにするということもある。

webadm
投稿日時: 2008-2-7 23:44
Webmaster
登録日: 2004-11-7
居住地:
投稿: 3095
エッジセレクタの実装
最初に簡単なエッジセレクタを実装してみる。

テンプレートから拝借した排他的論理和演算子と継続的代入と非同期リセット付きレジスタのみで記述できた。

edgesel.v:エッジセレクタモジュール(実装済み)

module edgesel(sa_clock, sa_start, sa_stop,
clock_pol, start_pol, stop_pol,
reset, clock, start, stop);

// Input Port(s)
input sa_clock, sa_start, sa_stop;
input clock_pol, start_pol, stop_pol;
input reset;

// Output Port(s)
output clock;
output reg start, stop;

// Parameter Declaration(s)

// Additional Module Item(s)

assign clock = sa_clock ^ clock_pol;

always @ (negedge reset or posedge clock)
begin
// Reset whenever the reset signal goes low, regardless of the clock
if (!reset)
begin
start <= 1'b0;
stop <= 1'b0;
end
// If not resetting, update the register output on the clock's rising edge
else
begin
start <= sa_start ^ start_pol;
stop <= sa_stop ^ stop_pol;
end
end
endmodule

コンパイルするとエラーは出ない。出力信号がまだ他のどこにもつながっていないので最適化によってPlace & Root時に回路は無くなってしまうがネットリストの段階では存在するのでRTL Viewerでどんな構成になったか見ることはできる。



見ると仕様で考えていたブロック図と同じだ。実装の便宜上RESET信号は負論理としている。
webadm
投稿日時: 2008-2-7 23:16
Webmaster
登録日: 2004-11-7
居住地:
投稿: 3095
RTLの中身の実装方法
RTLのコーディングは1年以上やっていないのでVerilogの構文もすっかり忘れてしまった。

それでも心配はない、Quartusに限らず大抵のFPGA用統合化開発環境にはランゲージテンプレートが用意されている。頻繁に使用される構文やロジック回路のプリミティブな記述のフレームワークが多数用意されていて、それを選択してソースファイルに挿入してあとは自分で肉付けすればいい。

Quartusの場合はソースファイル上で右クリックメニューから"Insert Template"を選択すればダイアログが表示され、用意されているテンプレートの一覧と、選択したテンプレートの内容が表示される。OKを押すと選択されたテンプレートがソースコードのカーソルの位置に挿入される。

Verilog,VHDL他Quartusで用いることのできる各種HDLにスクリプト言語のテンプレートが用意されている。

HDLの場合は良く使われる機能モジュールのテンプレート

・ROM/RAM
・シフトレジスタ
・ステートマシン
・演算器

デザインファイル内で頻繁に使われるHDL文法

・単体スケルトン
・宣言文
・生成文
・代入文
・順序回路
・演算子

ベンダー非依存なロジックプリミティブ

・各種レジスタ
・ラッチ
・トライステート付き(レジスタ、ラッチ、入出力)

Altera固有の合成属性付きプリミティブ

・バッファ
・レジスタ及びラッチ

が選択できるようになっている。慣れてしまえば、テンプレートを使わずに手で入力できるようになるが、それまでは備忘録代わりになる。

新しくFPGAやCPLDで作る回路の仕様や実現可能性を検討する際に、これらのテンプレートで利用可能なプリミティブにどんなものがあるか知っていれば、目的の動作の回路がそれだけを使用して記述出来るかどうかが判断できる。どんなものがあるかは自分の目で見て憶えておく必要がある。ここに無いものは自分で考えるか既にあるプリミティブを組み合わせて実現できるか検討する必要がある。ロジック回路を一通り勉強すれば何が出来て何ができないかは判断できるはず。

今回の仕様検討時にもありきたりのロジック回路のプリミティブだけで構成したので非同期信号を内部で扱う点以外は問題無いはずである。

あとFPGAベンダー独自のプリミティブ記述を一端デザインソース中で使ってしまうと、他のベンダーのツールではコンパイルエラーとなったり、該当するライブラリが見つからないとPlace & Route時に怒られることになる。その場合はそのターゲットのFPGAベンダーが等価なプリミティブを提供していればそれに合わせてソースを書き換える必要がある。ベンダー独自プリミティブを使用するときはそれ以外に実現手段が無いときに限る。

webadm
投稿日時: 2008-2-7 10:21
Webmaster
登録日: 2004-11-7
居住地:
投稿: 3095
RTLのフレームワークを入力
とりあえずQuartusを立ち上げて、新しいVerilogデザインプロジェクトを作成し、トップと各内部ブロックに対応するモジュールソースをフレームワークだけ入力。

satop.v: トップモジュール

module satop(sa_clock, sa_start, sa_stop, sa_data,
clock_pol, start_pol, stop_pol,
clk, reset, hold,
test_clock, test_start, test_stop, test_data,
led_seg, led_com,
led_gate, led_unstable, led_data);

// Input Port(s)
input sa_clock, sa_start, sa_stop, sa_data;
input clock_pol, start_pol, stop_pol;
input clk, reset, hold;

// Output Port(s)
output test_clock, test_start, test_stop, test_data;
output [6:0] led_seg;
output [3:0] led_com;
output led_gate, led_unstable, led_data;

wire clock, start, stop, data, clear, shift, dclock;
wire [15:0] prn;
wire [3:0] dcount;

// Parameter Declaration(s)

// Additional Module Item(s)
edgesel edgesel(sa_clock, sa_start, sa_stop,
clock_pol, start_pol, stop_pol,
reset, clock, start, stop);
sm sm(clock, start, stop, hold, reset, clear, shift, led_gate);
prg prg(clear, shift, data, reset, prn);
dc dc(prn, dcount, led_seg, led_com, led_unstable);
dl dl(sa_data, clock, reset, dclock, data, led_data);
stosc stosc(clk, dcount, dclock, test_clock, test_start, test_stop, test_data);

endmodule

edgesel.v:エッジセレクタモジュール

module edgesel(sa_clock, sa_start, sa_stop,
clock_pol, start_pol, stop_pol,
reset, clock, start, stop);

// Input Port(s)
input sa_clock, sa_start, sa_stop;
input clock_pol, start_pol, stop_pol;
input reset;

// Output Port(s)
output clock;
output reg start, stop;

// Parameter Declaration(s)

// Additional Module Item(s)

endmodule

sm.v:ステートマシンモジュール

module sm(clock, start, stop, hold, reset, clear, shift, led_gate);

input clock, start, stop, hold, reset;

output clear, shift, led_gate;


endmodule

prg.v:疑似乱数生成モジュール

module prg(clear, shift, data, reset, prn);

input clear, shift, data, reset;

output [15:0] prn;

endmodule

dc.v:表示コントローラーモジュール

module dc(prn, dcount, led_seg, led_com, led_unstable);

input [15:0] prn;
input [3:0] dcount;

output [6:0] led_seg;
output [3:0] led_com;
output led_unstable;

endmodule

dl.v:データラッチモジュール

module dl(sa_data, clock, reset, dclock, data, led_data);

input sa_data, clock, reset, dclock;

output data, led_data;

endmodule

stosc.v:スキャン&テストオシレーターモジュール
module stosc(clk, dcount, dclock, test_clock, test_start, test_stop, test_data);

input clk;

output [3:0] dcount;
output dclock, test_clock, test_start, test_stop, test_data;

endmodule

中身はなく単にモジュールインタフェースだけのスケルトンである。がっかりするかもしれないが、これをすることで仕様上の抜けとかが見つかったりする。実際にうっかりトップモジュールの図でSA_DATAが抜け落ちていたのを発見した。

この抜け殻のようなデザインファイルをコンパイルすると信号をドライブしてないぞとか警告は出るが記述に誤りが無ければコンパイルは正常に終了してRTL Viewerで全体ブロックの鳥瞰図を見ることが出来る。



中身はからっぽだけどももう出来たも同然のような気分が味わえる。あとはモジュールひとつひとつ中身を実装していけばよい。

さてこれからが楽しみである。
webadm
投稿日時: 2008-2-6 13:10
Webmaster
登録日: 2004-11-7
居住地:
投稿: 3095
設計開始
だいたい仕様が固まったので回路設計に入る。

オリジナルのHP5004Aシグネチャアナライザは古い時代のものなので、基本的に汎用ICのみで回路が構成されている。そのまま回路図入力すればいいじゃないかという考えもあるが、汎用ICというのは結構くせ者で非同期回路の固まりみたいなもの。等価なRTLライブラリがあればいいけれども無いと自分で作らないといけない。なまじか詳細な動作を理解していない汎用ICと等価なロジックを書くのはやっかいだ。だとすると最初からフルにHDLで書いたほうが良い。

汎用ICでまったく同じ回路をこしらえればという案は却下。ロジック部分は特別なICは使われておらずたぶん今でも売っているものが大半だが、十分な解像度でスキャンされた図面が無いので、一部配線がかすれて見えないところもあるし、それもいちいち確認しながら回路図を起こすというのもめんどうくさくリスクも多い。いざ配線して動かなかったらどうするのかと。

その点はFPGAはデザインの悪いところを見つけて直せば配線はそのままで済む。

今回の仕様は、機能仕様だけにとどまらず実現可能性もある程度めどを付けた形でタイミングチャートまで書いてチェックしている。普通は機能仕様だけで、それ以降の作業は設計と称しているが、そうしたケースでは設計の最初の作業は詳細なブロックにブレークダウンし、ブロック間の信号インタフェースを決めて、タイミングチャートを描いてとか詳細仕様を決めることから始まる。いきなりHDLをしこしこ書いたりはしない。機能仕様を見ると即座に詳細仕様が頭に展開されるような天才なら別かもしれないが。はたしてそれが正しいのかどうか他の誰も知りようが無い。普通は第三者が詳細仕様をチェックして大きな間違いや問題点を取り除いてリスクを低減するレビューを行う。

そういった段階的にリスクを取り除く作業を積み重ねることでミスがあっても些細なレベルであれば大事には至らないで済むことになる。また詳細な仕様が誰でも読めるようにアウトプットされているので、テストベンチとかを第三者がそれをベースに作るという分担作業が出来る。HDLを書いた本人がテストベンチを作るとなると、速いこと完成させたいというアクセルとバグを残してはいけないというブレーキの両方を踏むことになり、精神的によろしくない。この役割は別々の人に負ってもらうのが互いの能力を最大限に発揮する意味で良い。しかし問題は二人必要になるという点で、設計コストは二倍になる。しばしばコスト削減で一人が両方を兼ねるとバグが取りきれずに後で関係各位に大損害を与える結果に成りかねないリスクを有することを承知しなければならない。

今回の仕様ではオリジナルのHP5004Aが非同期回路と同期回路の混成になっており、FPGAで再現するにはあまりよろしくない。本当は完全な同期回路設計にすればいいのだろうけど、そうすると非常に高速の基準クロックが必要になる。それですべての入力信号を一度サンプルして内部ではすべて基準クロックに同期して変化する信号のみを扱うのがベストである。

まあ趣味なのでダメだったら直せばよいということで、最初は自分の理解できる範囲で回路を組んでみることにする。実はちゃんと同期回路設計する知識と経験が無いだけなのだが。

今回の回路規模は細かなブロックひとつひとつは小規模で、通勤電車の椅子に座っている間や、外で食事をしている間とかに考えてメモ帳に書き写していける程度簡単である。それでも信号を沢山扱うブロックはタイミングチャートを書くのが面倒くさい。それでも書いて見て問題点が見つかったり、疑問が出てきたりして理解を深めることが出来た。良く理解していないで作るのがもっともおろかである。

さていよいよRTLを書くことになるが、しばらくやっていないので大分おっくうになってしまっている。この種のスキルは使っていないと確実に衰える。

C言語で書いたものをHDLに変換してくれるというのも最近ではあるらしいが、確かにC言語は(かなり記憶が怪しくなってきてはいるが)まだおっくうではないので、それもありかもしれない。でもだいぶ寄り道をしそうな気がしないでもない。今回は止めておこう。

オーソドックスにがりがり書くしかないか。
webadm
投稿日時: 2008-2-4 3:44
Webmaster
登録日: 2004-11-7
居住地:
投稿: 3095
Re: Poorman's Signature Analyzerの仕様検討開始
○Scan & Test Oscillator



Scan & Test OscillatorはCLK信号を入力としてDisplay Controllerで必要な表示用カウンタ信号DCOUNTとData LatchでLED DATA表示用クロック信号DCLOCK及びセルフテスト用TEST CLOCK, TEST START, TEST STOP, TEST DATAを出力する。



CLK信号を入力とするバイナリカウンターの最下位4ビットからDCOUNT信号が生成される。更に上位の1ビットからDCLOCK信号が、更に上位の1ビットからTEST CLOCK信号が生成され、残りの上位ビットはTEST START, TEST STOP信号パターン生成用ROMのアドレスとして使用される。
« 1 2 3 (4)
スレッド表示 | 古いものから 前のトピック | 次のトピック | トップ

投稿するにはまず登録を
 
ページ変換(Google Translation)
サイト内検索