スレッド表示 | 新しいものから | 前のトピック | 次のトピック | 下へ |
投稿者 | スレッド |
---|---|
webadm | 投稿日時: 2008-9-19 8:56 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3092 |
RTL: CONTROL 次ぎはちょっと込み入ったCONTROLブロック。最初にスケルトンを入力した際にいくつかデバウンスする必要の無い信号等があったので見直しをかけた。
押しボタン入力のA,Bのみデバウンスを行うことにした。それ以外はチャッタリングが起こっても表示が一瞬乱れる以外には悪影響無し。 FREQUENCY COUNTERとCLOCK TIMER及びDISPLAYで必要な制御信号のみを生成するステートマシンから成る。 FREQUENCY COUNTER制御ステートマシンの状態遷移図。ACの立ち上がりで初期状態S=0に遷移し、RESET信号をアサートする。次ぎのC800HZクロックの立ち上がりでプリセット状態S=1に遷移しRESET信号をデアサートしPRESET信号をアサートすると同時に内部のカウンタに初期値をセットする。次ぎのC800HZクロックでカウンタイネーブル状態S=2に遷移しPRESETをデアサートしCEをアサートする。以降のクロックでカウンタ値が0でなければカウンタをデクリメントする。もしカウンタが0に達していたらロード状態S=3に遷移し、CEをデアサートしLOADをアサートする。次ぎのクロックで初期状態S=0に戻りLOADをデアサートする。 CLOCK TIMER制御ステートマシンの状態遷移図。ACの立ち上がりで初期状態IDLEへ遷移し、TIMMADJ,TIMHADJをデアサートする。以降のC10HZの立ち上がりでAもしくはBのどちらかがアサートされていればADJへ遷移しAとBの現在値をTIMMADJ,TIMHADJにそれぞれ保持する。次ぎのC10HZのクロックでAもしくはBが継続的にアサートされている場合には連続アサート期間を計測するためにカウンタ初期値をセットしてADJCへ遷移する。以降C10HZの立ち上がり毎に継続してAもしくはBがアサートされていてかつカウンタが0に達していない場合にはカウンタをデクリメントする。カウンタが0に達した場合にはADJRへ遷移し継続してアサートされているAもしくはBあるいはその両方に対応するTIMMADJ,TIMHADJの出力をキープする。以降のC10HZの立ち上がりでA及びB共にデアサートされた場合IDLEへ遷移しTIMMADJ,TIMHADJを0リセットする。 もう少し状態数の少ないステートマシンにしてAとBを独立して扱っても良い気がする。その場合リソースが余分にかかるかもしれない。 DISPLAY制御用ステートマシンの状態遷移図。基本的にACの立ち上がりでQ1状態へ遷移し、以降はC800HZの立ち上がり毎にQ1->Q2->Q3->Q4->Q1と循環する。DIMMER入力がアサートされていない場合には4サイクル間常にDUTY及びSTROBEはアサートされる。DIMMER入力がアサートされると1サイクル期間のみDUTY及びSTROBEがアサートされる。必要に応じてDUTYは蛍光表示管のプレート電圧制御に対応しSTROBEはグリッド電圧制御に対応する。従ってどちらもアサートしている間だけ表示が行われる。DUTYとSTROBEは同じ信号でもよさそうに思えるが、片方を少し早めにアサートし遅めにデアサートするような制御が実際には必要かもしれない。特にDUTYはセグメントに対応するプレート電圧を制御するのでグリッドがONになる前に予めプリチャージして、グリッドがOFFになってからプレート電圧をOFFするなど綺麗な点消灯のために微調整が出来るようにしてある。DISPLAYブロック側もこれに同期して4サイクル毎に桁スキャンを行う。 最後はデバウンサーサブモジュールの状態遷移。ACの立ち上がりでIDLE状態にリセットされ、C800HZの立ち上がりで入力信号dをサンプルし、アサートされていれば検出サイクル閾値をカウンタにセットしてDET状態へ遷移。入力がアサートされている限りC800HZの立ち上がり毎にカウンタ残りをチェックし0でなければカウンタをデクリメントする。入力信号がデアサートされることなくカウンタが0に至った場合には安定したとみなしてIN状態へ遷移し出力qをアサートする。次ぎのクロックでまだ入力がアサートされていればOUT状態へ遷移し以降クロック毎に入力がデアサートされるまで出力qをアサートし続ける。入力がデアサートされるとIDLEへ遷移し出力qをデアサートする。実際にどれくらいのサイクル数で安定したとみなすかは要調整。 カウンタをシステムリセット直後不定にならないようにすべてのモジュールでリセットがかかるように見直し、ボタン入力関係は独立のステートマシンを設けるようにしてRTLを記述した結果が以下の通り。 dbsm.v: デバウンサステートマシン // Quartus II Verilog Template // 4-State Mealy state machine // A Mealy machine has outputs that depend on both the state and // the inputs. When the inputs change, the outputs are updated // immediately, without waiting for a clock edge. The outputs // can be written more than once per state or per clock cycle. module dbsm ( input clk, in, reset, output reg out ); // Declare state register reg [1:0]state; reg [1:0]count; // Declare states parameter IDLE = 0, DET = 1, IN = 2, OUT = 3; parameter DETCYCLE = 2'b11; // Determine the next state synchronously, based on the // current state and the input always @ (posedge clk or negedge reset) begin if (!reset) begin state <= IDLE; count <= 0; end else case (state) IDLE: if (in) begin state <= DET; count <= DETCYCLE; end DET: if (in) begin if(count) count <= count - 1'b1; else state <= IN; end else begin state <= IDLE; end IN: if (in) begin state <= OUT; end else begin state <= IDLE; end OUT: if (in) begin state <= OUT; end else begin state <= IDLE; end endcase end // Determine the output based only on the current state // and the input (do not wait for a clock edge). always @ (state) begin case (state) IDLE: begin out = 0; end DET: begin out = 0; end IN: begin out = 1; end OUT: begin out = 1; end endcase end endmodule fcsm.v: FREQUENCY COUNTERステートマシン module fcsm(clk, ac, reset, ce, preset, load); // Input Port(s) input clk, ac; // Output Port(s) output reg reset, ce , preset, load; // Parameter Declaration(s) parameter GATETIME = 6'b1111; parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b11 , S3 = 2'b10; // Additional Module Item(s) reg [1:0] state; reg [5:0] count; always@(posedge clk or negedge ac) begin if(!ac) begin state <= S0; count <= 0; end else case(state) S0: begin state <= S1; end S1: begin state <= S2; count <= GATETIME; end S2: if(count) begin count <= count - 1'b1; end else begin state <= S3; end S3: begin state <= S0; end endcase end always@(state) begin case(state) S0: begin reset = 1; ce = 0; preset = 0; load = 0; end S1: begin reset = 0; ce = 0; preset = 1; load = 0; end S2: begin reset = 0; ce = 1; preset = 0; load = 0; end S3: begin reset = 0; ce = 0; preset = 0; load = 1; end endcase end endmodule ctsm.v: CLOCK TIMERステートマシン // Quartus II Verilog Template // 4-State Mealy state machine // A Mealy machine has outputs that depend on both the state and // the inputs. When the inputs change, the outputs are updated // immediately, without waiting for a clock edge. The outputs // can be written more than once per state or per clock cycle. module ctsm ( input clk, in, reset, output reg out ); // Declare state register reg [1:0]state; reg [3:0]count; // Declare states parameter IDLE = 0, ADJ = 1, ADJC = 2, ADJR = 3; // Determine the next state synchronously, based on the // current state and the input always @ (negedge clk or negedge reset) begin if (!reset) begin state <= IDLE; count <= 0; end else case (state) IDLE: if (in) begin state <= ADJ; end ADJ: if (in) begin state <= ADJC; count <= 15; end else begin state <= IDLE; end ADJC: if (in) begin if(count) count <= count - 1'b1; else begin state <= ADJR; end end else begin state <= IDLE; end ADJR: if (in) begin state <= ADJR; end else begin state <= IDLE; end endcase end // Determine the output based only on the current state // and the input (do not wait for a clock edge). always @ (state) begin case (state) IDLE: begin out = 0; end ADJ: begin out = 1; end ADJC: begin out = 0; end ADJR: begin out = 1; end endcase end endmodule control.v: CONTROLブロックRTLインプリメンテーション module control(a, b, dimmer, ac, c800hz, c10hz, ce, reset, preset, load, duty, strobe, timmadj, timhadj); // Input Port(s) input a, b, dimmer, ac, c800hz, c10hz; // Output Port(s) output ce, reset, preset, load, duty, strobe, timmadj, timhadj; // Inout Port(s) // Parameter Declaration(s) // Additional Module Item(s) wire db_a, db_b; dbsm dmsm_a(c800hz, a, ac, db_a); dbsm dmsm_b(c800hz, b, ac, db_b); fcsm fcsm(c800hz, ac, reset, ce, preset, load); ctsm ctsm_a(c10hz, db_a, ac, timmadj); ctsm ctsm_b(c10hz, db_b, ac, timhadj); dimsm dimsm(c800hz, dimmer, ac, duty, strobe); endmodule これらを合成した結果をRTL Viewerで見るとちょっと冗長のように見えるけど動けばよしとしよう。 |
webadm | 投稿日時: 2008-9-22 10:27 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3092 |
RTL: CLOCK TIMER CLOCK TIMERブロックはおそらく一番ロジックの規模が多い部分。概略の検討は食事の合間に検討を続けメモ帳に書き留めて頭にものこっていたので気がついたらそのままQuartusを立ち上げてコードを入力していた。その時にいくつか細かな検討漏れが発覚し、やはりちゃんと内部ブロック図を描く必要があると反省。
概略を検討した時に漏れていたのは、FREQUENCY COUNTERの時は10進数でカウントすればよかったがCLOCK TIMERは60進数と12進数それに2進数を使い分けなければならないので10進数以外に2進数、6進数と12進数をサポートするように同期BCDカウンタを拡張する必要がある点と、どうしても分と時の調整のために1HZと10HZのクロックを切り替える必要からゲーテドクロック回路になってしまうがクロック選択切り替わりのタイミングをC10HZの立ち下がりに同期させないとヒゲが出て余分に更新されてしまう点。 しかし描いてみるとかなり規模が大きい。CPLDに入るのか心配になってきたが、最悪はCLOCK TIMERブロック無しで周波数表示のみでも構わないことにしよう。 bin2bcd.v: バイナリBCDデコーダー module bin2bcd(bin, bcdout); // Input Port(s) input [3:0] bin; // Output Port(s) output reg [7:0] bcdout; always@(*) case(bin) 4'h0: begin bcdout[3:0] = bin; bcdout[7:4] = 4'h0; end 4'h1: begin bcdout[3:0] = bin; bcdout[7:4] = 4'h0; end 4'h2: begin bcdout[3:0] = bin; bcdout[7:4] = 4'h0; end 4'h3: begin bcdout[3:0] = bin; bcdout[7:4] = 4'h0; end 4'h4: begin bcdout[3:0] = bin; bcdout[7:4] = 4'h0; end 4'h5: begin bcdout[3:0] = bin; bcdout[7:4] = 4'h0; end 4'h6: begin bcdout[3:0] = bin; bcdout[7:4] = 4'h0; end 4'h7: begin bcdout[3:0] = bin; bcdout[7:4] = 4'h0; end 4'h8: begin bcdout[3:0] = bin; bcdout[7:4] = 4'h0; end 4'h9: begin bcdout[3:0] = bin; bcdout[7:4] = 4'h0; end 4'ha: begin bcdout[3:0] = 4'h0; bcdout[7:4] = 4'h1; end 4'hb: begin bcdout[3:0] = 4'h1; bcdout[7:4] = 4'h1; end default: begin bcdout[3:0] = 4'hf; bcdout[7:4] = 4'hf; end endcase endmodule ct.v: CLOCK TIMERモジュールRTLインプリメンテーション module ct(ac, cs, timmadj, timhadj, c10hz, c1hz, clcounter, ontimer, offtimer, sleeptimer, oncmpout, offcmpout, sleepout); // Input Port(s) input ac, timmadj, timhadj, c10hz, c1hz; input [2:0] cs; // Output Port(s) output oncmpout, offcmpout, sleepout; output [16:0] clcounter, ontimer, offtimer, sleeptimer; // Inout Port(s) // Parameter Declaration(s) // Additional Module Item(s) wire [20:0] clout; wire [12:0] onout, offout; wire clrst, onrst, offrst, slprst; wire clsel, onsel, offsel, slpsel; wire rst, madj, hadj; wire clmclk, clhclk, onmclk, onhclk, offmclk, offhclk, slpmclk; wire clmci, clhci, onmci, onhci, offmci, offhci, slpmci; wire cls1co, cls10co, clm1co, clm10co, clhco, clpmco; wire onm1co, onm10co, onhco, onpmco; wire offm1co, offm10co, offhco, offpmco; assign rst = (timmadj && timhadj); assign madj = (timmadj && !timhadj); assign hadj = (!timmadj && timhadj); assign clsel = (cs == 3'b111)?1'b1:1'b0; assign onsel = (cs == 3'b101)?1'b1:1'b0; assign offsel = (cs == 3'b100)?1'b1:1'b0; assign clrst = !ac || (clsel && rst); assign onrst = !ac || (onsel && rst); assign offrst = !ac || (offsel && rst); assign clmclk = (clsel && madj)?c10hz:c1hz; assign clhclk = (clsel && hadj)?c10hz:c1hz; assign onmclk = (onsel && madj)?c10hz:c1hz; assign onhclk = (onsel && hadj)?c10hz:c1hz; assign offmclk = (offsel && madj)?c10hz:c1hz; assign offhclk = (offsel && hadj)?c10hz:c1hz; assign clmci = (clsel && madj)?1'b1:cls10co; assign clhci = (clsel && hadj)?1'b1:clm10co; assign onmci = (onsel && madj)?1'b1:cls10co; assign onhci = (onsel && hadj)?1'b1:onm10co; assign offmci = (offsel && madj)?1'b1:cls10co; assign offhci = (offsel && hadj)?1'b1:offm10co; sbuc #(4, 9) cls1(c1hz, 1'b1, clrst, 4'h0, clout[3:0], cls1co); sbuc #(4, 5) cls10(c1hz, cls1co, clrst, 4'h0, clout[7:4], cls10co); sbuc #(4, 9) clm1(clmclk, clmci, clrst, 4'h0, clout[11:8], clm1co); sbuc #(4, 5) clm10(clmclk, clm1co, clrst, 4'h0, clout[15:12], clm10co); sbuc #(4, 11) clh(clhclk, clhci, clrst, 4'h1, clout[19:16], clhco); sbuc #(1, 1) clpm(clhclk, clhco, clrst, 1'b0, clout[20:20], clpmco); sbuc #(4, 9) onm1(onmclk, onmci, onrst, 4'h0, onout[3:0], onm1co); sbuc #(4, 5) onm10(onmclk, onm1co, onrst, 4'h0, onout[7:4], onm10co); sbuc #(4, 11) onlh(onhclk, onhci, onrst, 4'h0, onout[11:8], onhco); sbuc #(1, 1) onpm(onhclk, onhco, onrst, 1'b0, onout[12:12], onpmco); sbuc #(4, 9) offm1(offmclk, offmci, offrst, 4'h0, offout[3:0], offm1co); sbuc #(4, 5) offm10(offmclk, offm1co, offrst, 4'h0, offout[7:4], offm10co); sbuc #(4, 11) offlh(offhclk, offhci, offrst, 4'h0, offout[11:8], offhco); sbuc #(1, 1) offpm(offhclk, offhco, offrst, 1'b0, offout[12:12], offpmco); assign clcounter[7:0] = clout[15:8]; bin2bcd clbin2bcd(clout[19:16], clcounter[15:8]); assign clcounter[16:16] = clout[20:20]; assign ontimer[7:0] = onout[7:0]; bin2bcd onbin2bcd(onout[11:8], ontimer[15:8]); assign ontimer[16:16] = onout[12:12]; assign offtimer[7:0] = offout[7:0]; bin2bcd offbin2bcd(offout[11:8], offtimer[15:8]); assign offtimer[16:16] = offout[12:12]; assign oncmpout = (clout[19:8] == onout[11:0])?1'b1:1'b0; assign offcmpout = (clout[19:8] == offout[11:0])?1'b1:1'b0; endmodule よく考えたらスリープタイマーは減算カウンタでないといけないのでSLEEPタイマーは実装しなかった。 実際には組み合わせ論理の一部が2ページにまたがっているが、主要な1ページ目だけで十分大きな規模だということがわかる。 だんだんと無謀で無駄なプロジェクトの様相を帯びてきた。周波数カウンタだけだったらPICで組んだ方がまったくもって賢い選択である。しかしバカだけど最後までやり遂げよう。 |
webadm | 投稿日時: 2008-9-23 8:56 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3092 |
RTL: DISPLAY 遂に最後のDISPLAYブロック。
基本的には蛍光表示管のダイナミック点灯制御が主になるが、それ以外に機能によって異なる小数点表示などの小細工が必要。 これを記述すれば入力から出力までのパスが通るのでやっとPlace & Routeが行われることになる。 やっとここまできたよママン(ノ∀`) bcddec.v: BCD to 7segデコーダー module bcddec(bcd, seg); // Input Port(s) input [3:0] bcd; // Output Port(s) output reg [6:0] seg; always@(bcd) begin case(bcd) 4'b0000: seg <= 7'b1000000; // a,b,c,d,e,f 4'b0001: seg <= 7'b1111001; // b,c 4'b0010: seg <= 7'b0100100; // a, b, d, e, g 4'b0011: seg <= 7'b0110000; // a, b, c, d, g 4'b0100: seg <= 7'b0011001; // b, c, f, g 4'b0101: seg <= 7'b0010010; // a, c, d, f, g 4'b0110: seg <= 7'b0000010; // a, c, d, e, f, g 4'b0111: seg <= 7'b1111000; // a, b, c 4'b1000: seg <= 7'b0000000; // a, b, c, d, e, f, g 4'b1001: seg <= 7'b0010000; // a, b, c, d, f, g default: seg <= 7'b1111111; endcase end endmodule disp.v: DISPLAYブロックRTLインプリメンテーション module disp(c3200hz, s, fcounter, clcounter, ontimer, offtimer, sleeptimer, oncmpout, offcmpout, sleep, duty, strobe, ac, blanking, stopwatch, ambcout, pmfmout, sega, segb, segc, segd, sege, segf, segg, point, io, signalout, timerout, sleepout); // Input Port(s) input c3200hz, oncmpout, offcmpout, sleep, duty, strobe, ac, blanking; input [2:0] s; input [19:0] fcounter; input [16:0] clcounter, ontimer, offtimer, sleeptimer; // Output Port(s) output stopwatch, ambcout, pmfmout, sega, segb, segc, segd, sege, segf, segg, point, signalout, timerout, sleepout; output [4:0] io; // Inout Port(s) // Parameter Declaration(s) // Additional Module Item(s) reg [4:0] div16; wire c200hz; reg [19:0] counter; reg ampm; reg [3:0] bcd; reg dot; wire [6:0] seg; reg [2:0] scan; reg timer; assign c200hz = div16[4]; always@(posedge c3200hz or negedge ac) begin if(!ac) div16 <= 0; else if(c3200hz) div16 <= div16 + 1'b1; end always@(posedge c200hz or negedge ac) begin if(!ac) scan <= 0; else if(c200hz) begin if(scan == 3'b100) scan <= 0; else scan <= scan + 1'b1; end end always@(fcounter or clcounter or ontimer or offtimer or sleeptimer or s) begin case(s) 3'b111: begin counter <= {4'b1111,clcounter[15:0]}; ampm <= clcounter[16:16]; end 3'b101: begin counter <= {4'b1111,ontimer[15:0]}; ampm <= ontimer[16:16]; end 3'b100: begin counter <= {4'b1111,offtimer[15:0]}; ampm <= offtimer[16:16]; end 3'b110: begin counter <= {4'b1111,sleeptimer[15:0]}; ampm <= 0; end default: begin counter <= fcounter; ampm <= 0; end endcase end always@(scan or counter or s) begin case(scan) 3'b000: begin bcd <= counter[3:0]; dot <= 0; end 3'b001: begin bcd <= counter[7:4]; dot <= 0; end 3'b010: begin bcd <= counter[11:8]; if(s[2]) dot <= 1'b1; else dot <= 0; end 3'b011: begin bcd <= counter[15:12]; dot <= 0; end 3'b100: begin bcd <= counter[19:16]; if(s[2]==0) dot <= 1'b1; else dot <= 0; end default: begin bcd <= 4'b1111; dot <= 0; end endcase end always@(posedge oncmpout or posedge offcmpout or negedge ac) begin if(!ac) timer <= 0; else if(oncmpout) timer <= ~timer; else if(offcmpout) timer <= ~timer; end bcddec bcddec(bcd, seg); assign sega = (blanking)?1'bz:(~duty | seg[0]); assign segb = (blanking)?1'bz:(~duty | seg[1]); assign segc = (blanking)?1'bz:(~duty | seg[2]); assign segd = (blanking)?1'bz:(~duty | seg[3]); assign sege = (blanking)?1'bz:(~duty | seg[4]); assign segf = (blanking)?1'bz:(~duty | seg[5]); assign segg = (blanking)?1'bz:(~duty | seg[6]); assign point = (blanking)?1'bz:~(duty & dot); assign ambcout = (blanking)?1'b0:~ampm; assign pmfmout = (blanking)?1'b0:ampm; assign io = (blanking)?{5{1'bz}}:~({5{duty}} & 1<<scan); assign timerout = ~timer; endmodule あまりじっくり考えずに書いたので汚いコードになってしまっている。一応コンパイルとPlace & Routeは出来たけど規模がトラ技付録のMAXII基板には入らなかった(;´Д`) BCDデコーダー以外は全部ひとつのソースに入れてしまったのでRTL Viewerで見ると2ページにまたがってしまった。もっと細かくサブブロックにわけて全体が1ページに収まるようにすると見通しが良くなると思う。 さてあとは適当に入力信号を設定して3.2768MHzのクロックを与えてリセットしてあげれば何らかの動きをするはず。シミュレーションが楽しみ。 |
webadm | 投稿日時: 2008-9-24 3:36 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3092 |
動作シミュレーション しかしまったりと設計してきたPoorman's MSM5524もオリジナルの主要機能をカバーするものを一ヶ月ほどで設計できてしまった。ハードウェア記述言語と論理合成及びPlace & Routeツールのおかげである。
30年前にオリジナルのMSM5524を設計した人達はコンピューターも無かったから紙の上でほとんどの設計検討を行うしかない。論理合成ツールなのないのでひたすらカルノーマップを描いて自分で組み合わせ論理を合成していったのだろう。検証段階ではシミュレーターなど無いので標準ロジックICやトランジスタ回路を使って等価なプロトタイプハードウェアを製作し、実際に動かして観測することで確認していたと思われる。プロトタイプハードウェアで動作確認きたらそのネットリストにに基づいてトランジスタ回路に置き換え配置配線しマスクを描くという具合。当然最初のマスクで一発完動というのは少ないだろうから修正を重ねてようやく量産マスクが出来ると。今のソフトウェア開発がやっている人海戦術を昔のロジックLSI設計ではやっていたのだ。今日でもうそんなことをやっていたら会社は存続しないだろうけど、ソフトウェア開発会社は未だにそれをやらないと存続できないという哀れ。 余談に走ってしまった。 とりあえず最初に周波数カウンタモードに入力を設定し、クロックを入力し初回に全体リセットを入れてフリーランしたら出力信号がどうなるかシミュレーションしてみた。 予想では周波数カウントのゲートタイムは100分の8秒なので80msecこれを2回分程度見るとしてシミュレーション時間は200msecに設定。クロックを3.2768MHzで与えてみたつもり。シミュレーションには30分近く要した。 見るとセグメント出力と桁イネーブル信号は変化している。しかしduty比がDIMMERをディスエーブルにしているのに1/4になってしまっている。それに桁イネーブル信号とSEGGにヒゲが出ている。それとSW周波数カウントの時にはAM/PM表示はどちらもOFFにしないといけない気がする。 それと内部のC1HZとC10HZの周期がおかしい。よく考えたら3.2768MHzのクロック入力を生成する際に間違って10倍早い周期を与えていた。C1HZとC10HZの周期関係は期待した通り1:10になっている。まあコンパイルレポートを見ると動作クロックは数十MHzまで大丈夫くさいので10倍早いクロックでも動くということがわかった。 それと周波数カウンタ動作はどうもうまくいっていないらしい。 これから原因を探ることになるが、目的別に小さいテストベンチをいろいろ組んだ方がよさそうだ。 P.S よく見たら入力信号のSの値がall Hで時計モードになっていた..orz 確かに表示がリセット時の初期値 AM 01:00だ。ちゃんと動いているじゃないか(´∀` ) 少なくても表示が変化するのを見るには1分間以上シミュレートしないといけない、200msecで30分かかるから1秒間シミュレートするのに150分、1分間だとその60倍の9000分。150時間かかるという計算に、無理すぎ(;´Д`) 分替わり直前の状態から分替わりの前後をシミュレーションしないとやってられない。 もう一度周波数カウンタモードでやり直してみるか。 |
webadm | 投稿日時: 2008-9-24 5:08 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3092 |
Re: 動作シミュレーション 今度は改めて周波数カウンターモードでやってみた。外部クロック周期はちゃんと正しく1/3276800=305.2nsを与えた。しかし周波数カウンタ入力が意図した4.454MHzじゃなくて10倍の45.54MHzのままだった...orz
カウンタは当然ながらオーバーフローしているけどそれなりにカウント動作はしているようで、表示出力も合っている。 ちゃんと動くじゃないか(´∀` ) 一発でここまで動くとは思わなかった。 次ぎはちゃんとFINを29.999MHzに同調した時の30.454MHzを1/10プリスケールした3.0454MHzを与えてやってみよう。 P.S しかし良くみるとゲートタイムが短い気がする。80msecじゃなかったか、どうみても20msecでカウンター出力が変化している。 |
webadm | 投稿日時: 2008-9-24 5:41 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3092 |
周波数カウンターモードのシミュレーション 今一度入力条件を正しく与えて、周波数カウンタモードで動作シミュレーションしてみた。
結果はFREQUENCY COUNTERブロックの最上位桁が繰り上がりの際にあり得ないFになってしまっている。本当は1でないといけないはず。 どうやらPRESETのタイミングでカウンタの初期値がロードされていないし、カウンタがアップカウンタでなくダウンカウンター動作しているし(;´Д`) デザインを見直した方がよさそうだ。 |
webadm | 投稿日時: 2008-9-24 6:18 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3092 |
QuartusのState Machine Viewer ゲートタイムが短いのはRTL記述でパラメータ定数が間違っていたのが原因だった。修正してシミュレーションをやり直すとちゃんと80msecになった。
シミュレーション結果を良くみるとFREQUENCY COUNTER制御信号のうちRESET信号が極性が逆になっていることが発覚。 RTL記述では他の制御信号と同様に正論理で書いているのだが何故そうなる? と思って超わかりづらいQuartusのState Machine Viewerを眺めていて気づいた。 RTL Viewerで当該State Machineのネットリストを見ると。 すなわちQuartusではステートマシンの状態ビットS0,S1,S2,S3をそれぞれダイレクトにRESET,PRESET,CE,LOADの4つの制御信号として出しているということである。しかしState Machineのエンコーディング表を見るとS0は状態S0の時のみ0でそれ以外1なので負論理である。本当は符号反転しないといけないのではないだろうか? 論理合成のバグか? またいきなり当たったのか? Quartusのバージョンは最新の8sp1なのだが。 |
webadm | 投稿日時: 2008-9-24 7:17 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3092 |
どうやらバグではないようだ RESET出力が負論理なのを無理矢理正論理に反転する記述を追加してコンパイルすると、何故かTechnology Map Viewerで見るとほとんどのFREQUENCY COUNTER内部ロジックが最適化によって無くなってしまう事態が発生。
なんだこれは? どうやら負論理になっているのはQuartus自体が大域的に最適化した結果なのではないだろうかと思えてきた。 なにも内部信号をデザイナの意図に従わなくても論理が圧縮できるなら変えてしまえという最適化動作が選択されているのかもしれない。 とは言えRTL Viewerだけ見ると明らかにおかしい。 しかしTechnology Map Viewerで見るとちゃんとreset相当信号は負論理であることが前提になっているように見える。RTL Viewerの問題か? なんともお騒がせな話だ。昔はRTL Viewerは結構信用できたんだけど、8.0になったらどうにもこうにも。 P.S いや良くみたらTechnology Map Viewerのロジックもおかしいと思ったら全部下位ブロックを展開してみたら、最後の最後で論理反転していて帳尻があっていた..orz わかりづらいよ。 ということでQuartusへの有らぬ疑いは晴れた。さて原因は他にあると。 |
webadm | 投稿日時: 2008-9-24 9:10 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3092 |
周波数カウント動作は出来た どうやらPRESET時の初期値が0以外だとおかしなカウンタ論理になるらしいことが判明。とりあえず原理動作確認のために初期値はall0として、プリスケーラーが間違って分周しすぎていたのを修正して動作シミュレーションをやり直してみた。結果、与えていた2.9999MHz+45.5kHz=3.0454MHzがちゃんとカウント出来たヽ(´ー`)ノ
あとは初期値が0以外にした場合をやってみよう。初期値も当初間違えていて、455を足したら0になるBCD値でないといけないのをバイナリで計算していた。本来は100000-455=99545を与えないといけなかった。 なんとちゃんと正しく中間周波数分を差し引いた値(30454-455=29999)がカウントされるじゃないか。 結局、 ・プリスケーラー値を間違えていた ・カウンタ初期値をBCDでなくバイナリ値で与えていた のが原因だった..orz 自爆とはこのこと。 しかし今度のQuartusはPlace & Routeでかなりすごい最適化をするようになってシミュレーターの値を見ると意図したのとは全然違うのでバグではないかと誤解してしまう。外部から見た挙動は同じだが内部論理と挙動がまるで違っている。 今回の場合は、初期値に99545を指定すると、最後に出力ラッチする際にカウンタ値と初期値に対応したBCD値で排他的論理和を取っている。 すなわち初期値が9の桁のBCDカウンタはデザイン上では以下の様に変化することを意図していた 9->0->1->2->3->4->5->6->7->8->9->0 Quartusの最適化によってカウンタは初期値によらず常に0から開始し、以降指定された初期値と設計上の期待値と排他的論理和をとった値を遷移する特殊なカウンタに変更された。 デザイン上意図していたカウンタ出力の遷移 1001(9)->0000(0)->0001(1)->0010(2)->0011(3)->... これに初期値1001(9)を排他的論理和をとった値を最適化されたカウンタは遷移する 0000(0)->1001(9)->1000(8)->1011(B)->1010(A)->... という具合に一見すると変な遷移をするようになる。最終的に初期値である1001(9)と排他的論理和をとれば設計者が期待していたとおりのカウンタの出力が得られることがわかる。 つまり最終値はB0CDCとなった場合初期値99545を排他的論理和を取ると 1011 0000 1100 1101 1100 B 0 C D C xor 1001 1001 0101 0100 0101 9 9 5 4 5 0010 1001 1001 1001 1001 2 9 9 9 9 という仕掛けになっていた。 いやまったくすごい、こういう最適化論理は人間が最初から意図してRTL記述するのは大変なので感心した。 周波数カウンタ動作はこれでよしとしよう(´∀` ) もうほとんど終わったも同然。 P.S ちなみにシミュレーション時間は入力する信号の周波数が10分の1になったので劇的に短くなり、4分で終わるようになった。これだと1秒間分をやっても20分、1分間分だと20時間で終わることになる。 |
webadm | 投稿日時: 2008-9-25 20:06 |
Webmaster 登録日: 2004-11-7 居住地: 投稿: 3092 |
時計とタイマー関連 今度は時計とタイマー関連の動作もちょっと見てみようと簡単にaボタンを押しっぱなしにして時計を早送り動作させてみた。
結果はそれらしく10HZ毎に分の表示が増加しているけど、ちょっとリピートが始まるタイミングが早すぎないか? 本来は連続1.6秒押されたら10HZでリピート更新なはず。 それとC1HZとC10HZの分周がおかしいのを今更気づく。コーディングミスってた(;´Д`) リピートうんぬんの動作はctsm.vあたりに原因がありそう。 押しボタンを断続的にトグルしてみると、一回につきC10HZ周期の単一パルスが出るところは良いけれど、それによって2回カウントが変化している。一回目は意図した通りC10HZの立ち上がりだけど、2回目はTIMMADJ信号の立ち下がり、すなわちカウンタのクロックソースをC10HZからC1HZに戻すところで一旦C10HZが立ち下がった後にC1HZに切り替わりHに戻るため再び立ち上がりエッジが発生するということによる。 これはだめだな。 昔あるところで新人の外注設計者がプロセッサの低消費電力動作のための可変周波数クロックジェネレータを設計した時の事。クロック周波数設定を変更すると出力クロック信号にヒゲが出るということがデザインレビューで発覚して「だめだろこれは。誰だこんなきたない設計したのは?」とけちょんけちょんにこき下ろされていたのを思い出した。その後その新人君はある日突然姿を消した。 |
« 1 (2) 3 4 » |
スレッド表示 | 新しいものから | 前のトピック | 次のトピック | トップ |
投稿するにはまず登録を | |