スレッド表示 | 古いものから | 前のトピック | 次のトピック | 下へ |
投稿者 | スレッド |
---|---|
webadm | 投稿日時: 2008-2-9 11:34 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3095 |
だいたい動くことを確認 一カ所ステートマシンの出力信号の式が間違っていた点を除けばほぼ大きな問題は無いとみた。
もうこれで意図した通り動くと思われるで厳密にテストベンチでいろんなケースを試すよりは実際に装置を組んで実機で試してみたほうが良いかもしれない。 シミュレーションで確認していないのはテスト信号出力だけど、これは当面使う予定は無い。 とりあえずHP3456AのROMシグネチャの確認をしたい。新しく作ったROM基板が間違いないか確認したいのである。そうすれば故障原因は他にあるということで切り分けができる。 当初実機は1万年カレンダーを流用と考えていたが、あれは結構がさばるので実際に測定しようと思うと置き場所に困る。 この際、専用の基板をユニバーサルボードでこしらえて、LEDや入力信号コネクタやスイッチをつけて、そこにトラ技付録のMAX II基板をのせるとしよう。LEDは余っているし。 回路図を描いて部品を買って半田付けするだけである。 |
webadm | 投稿日時: 2008-2-9 11:25 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3095 |
Re: ステートマシンの問題(その1) 例の状態値レジスタが4つ生成されている件は、コンパイル結果のState Machinesを見ることによって、One Hotステートマシンが生成されているのに間違いないことが判明。
S00の時はすべて0で、他はどれか2つが1で残りは0という組み合わせらしい。 いずれの状態に遷移しても同時に変化するビットは2ビットだけということになるのでOne Hotに間違いない。 これはこれでクローズ。 |
webadm | 投稿日時: 2008-2-9 5:23 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3095 |
Re: ステートマシンの問題(その1) このプロジェクトはもとはと言えば、おジャンクなHP3456Aの故障原因を突き止めるためにサービスマニュアルにあるシグネチャアナライザを使った故障診断を行うのが目的だった。
で以前から気になっていたのだが、HP3456AのサービスマニュアルのROMシグネチャの測定のところでプローブを+5Vに接続して測定した場合にシグネチャ値は0003になる、と書いてある。 HP3456AのROMシグネチャの測定ではROMアドレス空間である上位32KBの時にアサートされるA15をSA START/STOP信号として使用する。SA CLOCKはシステムクロックで6MHzを4分周した1.5MHzである。ROMシグネチャアナリシス中はCPUはフリーランするのでSA START/STOPのパルス周期は65KB分、すなわち65536サイクルということになる。 実は疑似乱数生成回路があっているか確かめるためにC言語で等価なプログラムを書いて65536サイクル分data=1固定でシグネチャ値を生成したらいくつになるか調べてみたら、64KB目には初期値0に戻ってしまうことがわかった。これだと違う。本当は0003になって欲しいのだが。 今回の回路はHP5004Aの回路図を苦労して読み取って等価な回路にしたつもりだったのだが、何か違うのだろうか悩んだ。しかしやはり同じだという結論しか出てこない。 ふと今回のシミュレーション結果で計測終了時にシフトレジスタが0にクリアされた直後にヒゲでシフトレジスタが一回動作してしまい初期値が0000ではなく0001になってしまうことが発覚してふと気づいた。 初期値が0000ではなく0001なら65536サイクル後にシグネチャ値はいくつになるのだろうか? やってみたら見事に0003になった。 つまりこれはHP5004Aの仕様そのままであるということだ。 オリジナルの回路を見てもやはりヒゲは出てしまう。ヒゲも仕様のうちに含まれていたのだったのだ。 なのでこれはこのままで良いことにする。 他に気づいた点がいくつもあるのでそちらをなんとかしよう。 |
webadm | 投稿日時: 2008-2-8 22:51 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3095 |
ステートマシンの問題(その1) ステートマシンからのCLEAR出力が繰り返しトグルする原因が判明した。
仕様段階では正論理で考えていたCLEAR信号を実装時に負論理にしたのだが、その時に頭で考えたドモルガンの定理による論理式の書き換えが間違っていた...orz 仕様では正論理で CLEAR = (STOP & !CLOCK) | RESET だったのをCLEARとRESETを負論理に書き換えた際に clear = (!stop & clock) & reset としていたのだが、本来は clear = (!stop | clock) & reset であった。 このように修正すると異常なトグル動作は無くなったが別の問題が発覚。 計測終了時のCLEARパルス幅が予想より短くて、直後にSHIFTパルスがヒゲのように余分に出てしまっている。このためせっかくリセットされたシフトレジスタが誤動作してしまい、初期値が0でなくなってしまっている。 仕様上でCLEARパルスが半クロックサイクルしか出ないようにしたのが良くないので、初期状態ではCLEARはアサートしたままに変更したほうが良いかもしれない。 それにして計測終了時に状態値レジスタが全部OFFになってしまうのは何故だろう? もしかしてそのままバイナリなのか? しかし何故4ビットある? |
webadm | 投稿日時: 2008-2-8 22:13 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3095 |
波形入力(Quartus Simulator)でやってみた もしかして一発でOKかもしれないという思いから手っ取り早くその答えを知るために波形入力でシミュレーションをやってみた。
後で同じ波形を与えるテストベンチテンプレートを自動作成できるので慣れているこの方法がやりやすい。 とりあえず4桁のLEDが全部表示し終わる程度の時間をシミュレーションすることにし、SA_CLOCK入力はHP5004Aの仕様上限と同じ25MHzを与え、RESET入力のアサートとデアサート、それにSA_START/STOPのパルスを65536クロック周期で与える。その間はSA_DATAは1のまま。 おそらくLED表示コントローラー部分は何の問題も無く動作するだろう、以前に1万年カレンダー時計で培った回路なので。他は動く事は動くだろうけど疑問符がつくことは否めない。 やってみたら、回路が小さいので意外とシミュレーションが短時間で終わった。 そして結果をみたら、やはり表示コントローラーはまじめに動作しているくさい。しかし次ぎの瞬間、驚愕の事実が発覚。 まずステートマシンがしょっぱな誤動作している...orz いきなりS00,S01どちらも1になっている。よく考えたらRESETがアサートされたらS00に戻るようにしていたのにそこからして意図した動きになっていない。 S00がONになりっぱなしのままS11がON次いでS11がOFFになって代わりにS10がONになるのはまあいいとして、S10がONになったとたんにCLEARが繰り返しトグルし始めた。なんだこれは。結局このために以降シフトレジスタが意図していた通り動かなくなってしまっている。 ステートマシンに問題有りだな。シミュレーション以前の問題かもしれないので見直すことにしよう。 自分で書いたコードは動くと信じたいよね、しかしそうはいかないのが世の常。 |
webadm | 投稿日時: 2008-2-8 12:47 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3095 |
検証開始 一応論理合成とPlace & Routeが出来たので、動かすことは出来るがいきなり実機でやることは普通しない。
一発で動けば良いが、ここまで来るまでの間にもいろいろ仕様検討時のミスが発見されているので、他にも潜んでいる可能性は大である。実機でやって意図した通り動かなければやはり時間の無駄である。 普通は次ぎの段階としてシミュレーションテストを行うためにテストベンチモジュールを作成することになる。 テストベンチモジュールは今回出来たシグネチャアナライザモジュールを下位モジュールとして入力信号を与えて出力信号を検査するシミュレーション用のトップモジュールである。 以前に1万年カレンダー時計をやった時はこれが面倒でテスト波形を入力してやっていた。 実はQuartusにはtest bench template writerという機能があることに今更ながら知って、それを使わない手はないと思った。 ProcessingのStartメニューでTest Bench Template Writerというのを選択すると自動的に現在のデザインのトップモジュールを駆動するためのテストベンチモジュールのひな形を生成してくれる。 あとはテストケースに応じた信号を駆動するための肉付けをすれば良いということになる。 いやはや至れり尽くせりである。 ソフトウェア開発ツールにもこういうのがないものかのう。 satop.vt:テストベンチトップモジュール(自動生成) // Copyright (C) 1991-2007 Altera Corporation // Your use of Altera Corporation's design tools, logic functions // and other software and tools, and its AMPP partner logic // functions, and any output files from any of the foregoing // (including device programming or simulation files), and any // associated documentation or information are expressly subject // to the terms and conditions of the Altera Program License // Subscription Agreement, Altera MegaCore Function License // Agreement, or other applicable license agreement, including, // without limitation, that your use is for the sole purpose of // programming logic devices manufactured by Altera and sold by // Altera or its authorized distributors. Please refer to the // applicable agreement for further details. // ***************************************************************************** // This file contains a Verilog test bench template that is freely editable to // suit user's needs .Comments are provided in each section to help the user // fill out necessary details. // ***************************************************************************** // Generated on "02/08/2008 03:41:48" // Verilog Test Bench template for design : satop // // Simulation tool : ModelSim-Altera (Verilog) // `timescale 1 ps/ 1 ps module satop_vlg_tst(); // constants // general purpose registers reg eachvec; // test vector input registers reg clk; reg clock_pol; reg hold; reg reset; reg sa_clock; reg sa_data; reg sa_start; reg sa_stop; reg start_pol; reg stop_pol; // wires wire [3:0] led_com; wire led_data; wire led_gate; wire [6:0] led_seg; wire led_unstable; wire test_clock; wire test_data; wire test_start; wire test_stop; // assign statements (if any) satop i1 ( // port map - connection between master ports and signals/registers .clk(clk), .clock_pol(clock_pol), .hold(hold), .led_com(led_com), .led_data(led_data), .led_gate(led_gate), .led_seg(led_seg), .led_unstable(led_unstable), .reset(reset), .sa_clock(sa_clock), .sa_data(sa_data), .sa_start(sa_start), .sa_stop(sa_stop), .start_pol(start_pol), .stop_pol(stop_pol), .test_clock(test_clock), .test_data(test_data), .test_start(test_start), .test_stop(test_stop) ); initial begin // code that executes only once // insert code here --> begin // --> end $display("Running testbench"); end always // optional sensitivity list // @(event1 or event2 or .... eventn) begin // code executes for every event on sensitivity list // insert code here --> begin @eachvec; // --> end end endmodule |
webadm | 投稿日時: 2008-2-8 12:34 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3095 |
スキャン&テストオシレータの実装 最後がローカルクロック信号生成回路。
外部から基準クロックを供給してもらってそれをバイナリカウンタで分周し、必要な周期のクロックや制御信号をタップ出力する。 一部はテスト信号生成用ROMのアドレスやテストクロックやテストデータとして使用。今回はとりあずSTART/STOPのパルスが出るだけとした。 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; reg [9:0] count; assign dcount = count[3:0]; assign dclock = count[4]; assign test_clock = count[1]; assign test_data = count[2]; assign {test_stop,test_start}=testrom(count[9:5]); always @ (posedge clk) begin count <= count + 1; end function [1:0] testrom(input [4:0] addr); case(addr) 5'b00000: testrom = 2'b11; default: testrom = 2'b00; endcase endfunction endmodule RTL Viewerでみるとやはり予想通り。 これで全部のモジュールを実装したのですべての入力信号と出力信号がつながったことになる。当初から予想していた通り、以前にやった1万年カレンダーに比べればはるかに小規模な回路なので使用するLE数も91/240と少ない。これなら古いFLEX8000とかにも収まりそうである。MAXIIとかではもったいないかもしれない。 |
webadm | 投稿日時: 2008-2-8 11:54 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3095 |
データラッチの実装 次ぎは簡単なデータラッチモジュール。
唯一ややこしいのがデータが変化していることを表示するためのLED_DATA信号の生成パス。 SRFFを仕様では想定していたが、ベンダー固有のプリミティブはなるべく使いたくないのでベンダー非依存な記述を行った。RESETが最も優先順位が高く、次いでデータの変化、最後に更新クロックとしてみた。 dl.v:データラッチモジュール(実装済み) module dl(sa_data, clock, reset, dclock, data, led_data); input sa_data, clock, reset, dclock; output reg data, led_data; wire data_changed = (sa_data != data); always @ (negedge reset or posedge clock) begin // Reset whenever the reset signal goes low, regardless of the clock if (!reset) begin data <= 1'b0; end // If not resetting, update the register output on the clock's rising edge else begin data <= sa_data; end end always @(posedge data_changed or posedge dclock or negedge reset) begin // The reset signal overrides the hold signal; reset the value to 0 if (!reset) begin led_data <= 1'b0; end else if (data_changed) begin led_data <= 1'b1; end // Otherwise, change the variable only when updates are enabled else if (dclock) begin led_data <= 1'b0; end end endmodule RTL Viewerで見るとSRFFは生成されずにプリセット付きのDFFとなっていた。なるほど賢い。これでまったく問題ない。 |
webadm | 投稿日時: 2008-2-8 11:30 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3095 |
表示コントローラーの実装 次ぎは少し面倒くさい表示コントローラー。
最後に生成された疑似乱数を4桁の7セグメントLEDにダイナミック表示するのとあわせて疑似乱数が変動している場合にUNSTABLE LEDを点灯させる。 これは以前にやった1万年カレンダー時計から拝借。基本的にデコーダー回路をVerilogのfunctionで記述している。直接手続き構文中でデコードすると桁毎にデコード回路が生成されてその出力を最後にセレクトするというとんでも無い回路になったのでこのようにした記憶がある。 あとは前回の疑似乱数を保持するレジスタと、UNSTABLE出力を保持するレジスタを追加。 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 reg led_unstable; wire strobe_prn; wire strobe_unstable; reg [15:0] prev_prn; assign strobe_prn = (dcount[1:0] == 2'b00); assign strobe_unstable = (dcount[1:0] == 2'b10); assign led_seg = decoder(prnsel(prn, dcount[3:2])); assign led_com = two2four(dcount[3:2]); always @ (posedge strobe_prn) begin prev_prn <= prn; end always @ (posedge strobe_unstable) begin led_unstable <= (prev_prn != prn); end function [6:0] decoder(input [3:0] seg); case(seg) 0: decoder = 7'b1000000; // 0 1: decoder = 7'b1111001; // 1 2: decoder = 7'b0100100; // 2 3: decoder = 7'b0110000; // 3 4: decoder = 7'b0011001; // 4 5: decoder = 7'b0010010; // 5 6: decoder = 7'b0000010; // 6 7: decoder = 7'b1111000; // 7 8: decoder = 7'b0000000; // 8 9: decoder = 7'b0010000; // 9 10: decoder = 7'b0001000; // A 11: decoder = 7'b1000110; // C 12: decoder = 7'b0001110; // F 13: decoder = 7'b0001001; // H 14: decoder = 7'b0001100; // P 15: decoder = 7'b1000001; // U endcase endfunction function [3:0] prnsel(input [15:0] prn, input [1:0] sel); case(sel) 0: prnsel = prn[15:12]; 1: prnsel = prn[11:8]; 2: prnsel = prn[7:4]; 3: prnsel = prn[3:0]; endcase endfunction function [3:0] two2four(input [1:0] sel); case(sel) 0: two2four = 4'b0001; 1: two2four = 4'b0010; 2: two2four = 4'b0100; 3: two2four = 4'b1000; endcase endfunction endmodule 以前の1万年カレンダー時計の記述を見た時点で、制御すべきLEDのセグメント数が7つあるのに、信号が6本しか用意してなかったことに気づく。大失敗。何故6本になったかというと、確か7セグメントLEDには小数点のセグメントがあって、これは要らないからということでひとつ減らして6にしたというバカな間違いを犯していたためである。仕様を直さないと。 合成されたネットリストをRTL Viewerで見ると。 レジスタ周辺は予想通り。表示デコーダーが予想していたのとちょっと見た目が違うけど機能的には等価。 |
webadm | 投稿日時: 2008-2-8 10:06 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3095 |
疑似乱数生成器の実装 次ぎにややこしい疑似乱数生成器。
これもシフトレジスタの記述はテンプレートから拝借。フィードバック回路とパリティジェネレータ回路にリセットロジックを肉付けし、出力段に出力レジスタを設けてお終い。 prg.v:疑似乱数生成モジュール(実装済み) module prg(clear, shift, data, reset, prn); input clear, shift, data, reset; output reg [15:0] prn; // Declare the shift register reg [15:0] sr; // Shift everything over, load the incoming bit always @ (posedge shift or negedge clear or negedge reset) begin if (!clear | !reset) begin sr <= 0; end else begin sr[15:1] <= sr[14:0]; sr[0] <= data ^ sr[6] ^ sr[11] ^ sr[12] ^ sr[15]; end end always @ (negedge clear or negedge reset) begin if (!reset) begin prn <= 0; end else begin prn <= sr; end end endmodule 最初に入力した時に出力レジスタをリセットする回路を忘れてしまっていた。RTL Viewerで確認したらシフトレジスタをRESETがアサートされた時にリセットしないと次ぎの計測結果が正しくなくなる仕様上の不備を発見。さっそく仕様にフィードバックしてRESETでどちらのレジスタもリセットされるようにした。自分で決めた仕様の誤りはなかなか自分では気づかない。いわば盲点である。RTL Viewerはその点機械だから正直にそのまま示してくれる。人間は機械のように常に厳しく目を光らせるということはできない。 これも仕様レベルとほぼ一致する。 |
« 1 2 (3) 4 » |
スレッド表示 | 古いものから | 前のトピック | 次のトピック | トップ |
投稿するにはまず登録を | |