デジタル回路のスイッチ入力の同期化_同期微分

時間を作るタイマーまでを設計することができました。1msecのカウンターと10msecのカウンターの連携は理解できたでしょうか? 同期設計は必ず基本クロック(この場合10MHz)に同期している必要があります。
次にスイッチを押した瞬間を検出する回路である、微分回路を設計します。ブロック図では次の黄色の部分になります。

前にも述べましたが、この微分回路では同期微分を用いますので、シフトレジスタを使います。したがって、この前のブロックであるクロック同期化で使ったシフトレジスタ回路で作ったメタステーブル対策の回路とかなり似た構成になっています。よって、クロック同期化があまり有効ではありませんが、非常に大切な回路の考え方なのであえて記述することにしました。
「微分」っていうのは高校生で嫌いな数学ナンバー1になりそうな現象ですが、回路的にはそれほど難しくありません。微分はある単位時間の変化量として考えることができます。アナログ回路にも微分回路がありあますが、アナログ微分回路は時定数をもって変化量を電圧に変える事が多いと思います。
デジタル回路の中でも微分回路はあります。その中でもわざわざ同期微分という名前なのは、非同期もあるからです。非同期の微分回路はアナログの微分回路にかなり近く、時定数をCR等で作って電圧の代わりに信号の幅で微分量を表します。
同期微分の場合、時定数を使いません。クロックに同期する必要があるので、大抵は1クロックの遅れ=時定数となります。もちろん、微分解を2クロックや3クロックにしても同期微分と言えますが、あまり用途がありません。同期微分といえば、1クロック幅になります。
同期微分は入力信号の立ち上がりや立下りを1クロックで検出した回路になります。言葉で説明するよりも回路と波形で示した方が分かりやすいでしょう。

考えられられる同期微分回路をすべてあげてみました。DFFへのクロックは省略していますが、2つのDFFに同じクロックを接続します。並べてみるとわかりやすいですね。
DFFが2つですから、2ビットのシフトレジスタになっているのがわかると思います。
前にも述べましたが、同期設計をしていると、1パルス幅の信号が欲しくなります。それは1パルスの信号をきっかけとして何かを動かす。というのが多いからです。
さて、VHDLとVerilogで回路を書いてみます。今回、シフトレジスタのDFFはバスで宣言します。一般的にシフトレジスタはバスで宣言することの方が多いと思います2ビット程度であれば、どちらでも良いと思いますが・・・
-- TITLE: "SyncDiff.vhd" -- MODULE NAME: -- PROJECT CODE: -- AUTHOR: (****@nakaharagiken.com) -- CREATION DATE: 2020.7.7 -- SOURCE: -- LICENSE: Copyright (c) 2020 nakaharagiken All rights reserved. -- DESCRIPTION: 同期微分 -- NOTES TO USER: 出力は2クロック遅延 -- SOURCE CONTROL: -- REVISION HISTORY: v0.1 2020.7.7 First edition -- v0.2 2020.7.11 enable追加 -- -- -- -- -- -- -- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; use IEEE.std_logic_arith.all; entity SyncDiff is port ( clock: in std_logic; -- system clock nreset: in std_logic; -- asynchronous reset ____reset___|~~~normal~~~ indata: in std_logic; -- 入力信号 _____|~~~~~~~~~~~~|______ enable: in std_logic; -- イネーブル _________|~|_____________ nrisingrdge: out std_logic; -- not立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ risingrdge: out std_logic; -- 立ち上がりエッジ ______|~|________________ nfallingedge: out std_logic; -- not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ fallingedge: out std_logic; -- 立下りエッジ ___________________|~|___ nbothedge: out std_logic; -- not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ bothedge: out std_logic -- 両エッジ ______|~|__________|~|___ ); end entity SyncDiff; architecture rtl of SyncDiff is --------------------------------------------------------------- -- SIGNALS --------------------------------------------------------------- signal rDFF: std_logic_vector(1 downto 0); -- 2bitシフトレジスタ signal wnrisingrdge: std_logic; -- 立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ signal wrisingrdge: std_logic; -- 立ち上がりエッジ ______|~|________________ signal wnfallingedge: std_logic; -- not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ signal wfallingedge: std_logic; -- 立下りエッジ ___________________|~|___ signal wnbothedge: std_logic; -- not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ signal wbothedge: std_logic; -- 両エッジ ______|~|__________|~|___ begin ------------------------------------------ -- 2bit シフトレジスタ ------------------------------------------ process (clock,nreset) begin if nreset = '0' then -- リセット初期化 rDFF <= (others => '0'); elsif clock' event and clock = '1' then -- clock 立ち上がり指示 if (enable = '1') then rDFF(0) <= indata; rDFF(1) <= rDFF(0); end if; end if; end process; wnrisingrdge <= not(rDFF(0) and (not rDFF(1))); -- 立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ wrisingrdge <= not((not rDFF(0)) or rDFF(1)); -- 立ち上がりエッジ ______|~|________________ wnfallingedge <= not((not rDFF(0)) and rDFF(1)); -- not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ wfallingedge <= not(rDFF(0) or not(rDFF(1))); -- 立下りエッジ ___________________|~|___ wnbothedge <= (not rDFF(0)) xor rDFF(1); -- not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ wbothedge <= rDFF(0) xor rDFF(1); -- 両エッジ ______|~|__________|~|___ nrisingrdge <= wnrisingrdge; -- not立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ risingrdge <= wrisingrdge; -- 立ち上がりエッジ ______|~|________________ nfallingedge <= wnfallingedge; -- not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ fallingedge <= wfallingedge; -- 立下りエッジ ___________________|~|___ nbothedge <= wnbothedge; -- not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ bothedge <= wbothedge; -- 両エッジ ______|~|__________|~|___ end architecture rtl;
// TITLE: "SyncDiff.v" // MODULE NAME: // PROJECT CODE: // AUTHOR: (****@nakaharagiken.com) // CREATION DATE: 2020.7.7 // SOURCE: // LICENSE: Copyright (c) 2020 nakaharagiken All rights reserved. // DESCRIPTION: 同期微分 // NOTES TO USER: 出力は2クロック遅延 // SOURCE CONTROL: // REVISION HISTORY: v0.1 2020.7.7 First edition // v0.2 2020.7.11 enable追加 // // // // // // // `timescale 1ns/1ps module SyncDiff( clock, // in system clock nreset, // in asynchronous reset ____reset___|~~~normal~~~ indata, // in 入力信号 _____|~~~~~~~~~~~~|______ enable, // in イネーブル _________|~|_____________ nrisingrdge, // out not立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ risingrdge, // out 立ち上がりエッジ ______|~|________________ nfallingedge, // out not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ fallingedge, // out 立下りエッジ ___________________|~|___ nbothedge, // out not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ bothedge // out 両エッジ ______|~|__________|~|___ ); input clock; // in system clock input nreset; // in asynchronous reset ____reset___|~~~normal~~~ input indata; // in 入力信号 _____|~~~~~~~~~~~~|______ input enable; // in イネーブル _________|~|_____________ output nrisingrdge; // out not立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ output risingrdge; // out 立ち上がりエッジ ______|~|________________ output nfallingedge; // out not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ output fallingedge; // out 立下りエッジ ___________________|~|___ output nbothedge; // out not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ output bothedge; // out 両エッジ ______|~|__________|~|___ /////////////////////////////////////////////////////////////// // SIGNALS /////////////////////////////////////////////////////////////// reg [1:0] rDFF; // 2bitシフトレジスタ wire wnrisingrdge; // 立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ wire wrisingrdge; // 立ち上がりエッジ ______|~|________________ wire wnfallingedge; // not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ wire wfallingedge; // 立下りエッジ ___________________|~|___ wire wnbothedge; // not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ wire wbothedge; // 両エッジ ______|~|__________|~|___ ////////////////////////////////////////// // 2bit シフトレジスタ ////////////////////////////////////////// always @ (posedge clock, negedge nreset) begin if (!nreset) begin rDFF <= 2'b00; end else begin if (enable == 1'b1) begin rDFF[0] <= indata; rDFF[1] <= rDFF[0]; end end end assign wnrisingrdge = ~(rDFF[0] & (~rDFF[1])); // 立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ assign wrisingrdge = ~((~rDFF[0]) | rDFF[1]); // 立ち上がりエッジ ______|~|________________ assign wnfallingedge = ~((~rDFF[0]) & rDFF[1]); // not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ assign wfallingedge = ~(rDFF[0] | ~(rDFF[1])); // 立下りエッジ ___________________|~|___ assign wnbothedge = (~rDFF[0]) ^ rDFF[1]; // not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ assign wbothedge = rDFF[0] ^ rDFF[1]; // 両エッジ ______|~|__________|~|___ // output 接続 assign nrisingrdge = wnrisingrdge; // out not立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ assign risingrdge = wrisingrdge; // out 立ち上がりエッジ ______|~|________________ assign nfallingedge = wnfallingedge; // out not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ assign fallingedge = wfallingedge; // out 立下りエッジ ___________________|~|___ assign nbothedge = wnbothedge; // out not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ assign bothedge = wbothedge; // out 両エッジ ______|~|__________|~|___ endmodule
シフトレジスタは1つです。VHDLファイルの45行目でrDFFのバス宣言を行っています。
signal rDFF: std_logic_vector(1 downto 0); — 2bitシフトレジスタ
VHDLの場合バスを宣言するには上のようにstd_logic_vector(1 downto 0);宣言します。他にバスにできる宣言もありますので、VHDLの教科書で確認してください。私はできる限りstd_logic_vectorで宣言するようにしています。これはVerilogとの互換性が高いので、移植しやすい。という理由です。
一方Verilogの場合には 48行目のように reg [1:0] rDFF; という宣言になります。プログラム言語の配列に近いと思います。
実際のシフトレジスタはVHDLで63行目です。
rDFF(0) <= indata; rDFF(1) <= rDFF(0);
バスの中の1ビットを扱うときにはこのようにします。
68行目からシフトレジスタの解を論理演算して微分波形を作っています。今回、一旦論理演算の解をワイヤーで受けています。いきなりoutputに接続する方もいます。最近のコンパイラはどちらでも良いと思います。
さて、このモジュールとテストしてみます。今回もテストベンチは両方のHDLで用意しました。
-- TITLE: "TB_SyncDiff.vhd" -- MODULE NAME: TB_SyncDiff -- PROJECT CODE: -- AUTHOR: (****@nakaharagiken.com) -- CREATION DATE: 2020.7.7 -- SOURCE: -- LICENSE: Copyright (c) 2020 nakaharagiken All rights reserved. -- DESCRIPTION: TB_SyncDiff.vhdのテストベンチ -- NOTES TO USER: -- SOURCE CONTROL: -- REVISION HISTORY: v0.1 2020.7.7 First edition -- -- -- -- -- -- -- -- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; use IEEE.std_logic_arith.all; entity TB_SyncDiff is end TB_SyncDiff; architecture sim of TB_SyncDiff is component SyncDiff is port ( clock: in std_logic; -- system clock nreset: in std_logic; -- asynchronous reset ____reset___|~~~normal~~~ indata: in std_logic; -- 入力信号 _____|~~~~~~~~~~~~|______ nrisingrdge: out std_logic; -- not立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ risingrdge: out std_logic; -- 立ち上がりエッジ ______|~|________________ nfallingedge: out std_logic; -- not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ fallingedge: out std_logic; -- 立下りエッジ ___________________|~|___ nbothedge: out std_logic; -- not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ bothedge: out std_logic -- 両エッジ ______|~|__________|~|___ ); end component; constant SYSCLK_PERIOD : time := 100 ns; -- 10MHz signal i_clock: std_logic; -- system clock signal i_nreset: std_logic; -- asynchronous reset ____reset___|~~~normal~~~ signal i_indata: std_logic; -- 入力信号 _____|~~~~~~~~~~~~|______ signal o_nrisingrdge: std_logic; -- not立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ signal o_risingrdge: std_logic; -- 立ち上がりエッジ ______|~|________________ signal o_nfallingedge: std_logic; -- not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ signal o_fallingedge: std_logic; -- 立下りエッジ ___________________|~|___ signal o_nbothedge: std_logic; -- not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ signal o_bothedge: std_logic; -- 両エッジ ______|~|__________|~|___ begin inst_SyncDiff : SyncDiff port map( clock => i_clock, -- system clock nreset => i_nreset, -- asynchronous reset ____reset___|~~~normal~~~ indata => i_indata, -- 入力信号 _____|~~~~~~~~~~~~|______ nrisingrdge => o_nrisingrdge, -- not立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ risingrdge => o_risingrdge, -- 立ち上がりエッジ ______|~|________________ nfallingedge => o_nfallingedge, -- not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ fallingedge => o_fallingedge, -- 立下りエッジ ___________________|~|___ nbothedge => o_nbothedge, -- not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ bothedge => o_bothedge -- 両エッジ ______|~|__________|~|___ ); ------------------------------------ -- Clock Driver ------------------------------------ process begin i_clock <= '1'; wait for SYSCLK_PERIOD / 2; i_clock <= '0'; wait for SYSCLK_PERIOD / 2; end process; ------------------------------------ -- 信号作成 ------------------------------------ process begin i_nreset <= '0'; -- 初期値 i_indata <= '0'; wait for (SYSCLK_PERIOD / 10); wait for (SYSCLK_PERIOD * 50); i_nreset <= '1'; -- 初期値 wait for (SYSCLK_PERIOD * 100); i_indata <= '1'; wait for (SYSCLK_PERIOD * 100); i_indata <= '0'; wait for (SYSCLK_PERIOD * 50); i_indata <= '1'; wait; end process; end sim;
// TITLE: "TB_SyncDiff.v" // MODULE NAME: TB_SyncDiff.v // PROJECT CODE: // AUTHOR: (****@nakaharagiken.com) // CREATION DATE: 2020.1.1 // SOURCE: // LICENSE: Copyright (c) 2020 nakaharagiken All rights reserved. // DESCRIPTION: SyncDiff.vのテストベンチ // NOTES TO USER: // SOURCE CONTROL: // REVISION HISTORY: v0.1 2020.1.2 First edition // // // // // // // // `timescale 1ns/1ps module TB_datasel; parameter SYSCLK_PERIOD = 100; // 10MHz reg i_clock; // system clock reg i_nreset; // asynchronous reset ____reset___|~~~normal~~~ reg i_indata; // 入力信号 _____|~~~~~~~~~~~~|______ wire o_nrisingrdge; // not立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ wire o_risingrdge; // 立ち上がりエッジ ______|~|________________ wire o_nfallingedge; // not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ wire o_fallingedge; // 立下りエッジ ___________________|~|___ wire o_nbothedge; // not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ wire o_bothedge; // 両エッジ ______|~|__________|~|___ ////////////////////////////////////////////////////////////////////// // Clock Driver ////////////////////////////////////////////////////////////////////// always @(i_clock) #(SYSCLK_PERIOD / 2.0) i_clock <= !i_clock; ////////////////////////////////////////////////////////////////////// // Main ////////////////////////////////////////////////////////////////////// initial begin i_clock <= 0; i_nreset <= 0; // 初期値 i_indata <= 0; repeat(50) @(posedge i_clock); i_nreset <= 1; repeat(100) @(posedge i_clock); i_indata <= 1; repeat(100) @(posedge i_clock); i_indata <= 0; repeat(50) @(posedge i_clock); i_indata <= 1; end SyncDiff inst_SyncDiff( .clock (i_clock), // in system clock .nreset (i_nreset), // in asynchronous reset ____reset___|~~~normal~~~ .indata (i_indata), // in 入力信号 _____|~~~~~~~~~~~~|______ .nrisingrdge (o_nrisingrdge), // out not立ち上がりエッジ ~~~~~~|_|~~~~~~~~~~~~~~~~ .risingrdge (o_risingrdge), // out 立ち上がりエッジ ______|~|________________ .nfallingedge (o_nfallingedge), // out not立下りエッジ ~~~~~~~~~~~~~~~~~~~|_|~~~ .fallingedge (o_fallingedge), // out 立下りエッジ ___________________|~|___ .nbothedge (o_nbothedge), // out not両エッジ ~~~~~~|_|~~~~~~~~~~|_|~~~ .bothedge (o_bothedge) // out 両エッジ ______|~|__________|~|___ ); endmodule
ModelSimでシミュレートした結果を示します。

入力信号の立ち上がり、立下りで10MHzクロック幅のパルスが生成されていることがわかります。
私の経験上、同期微分の回路は頻繁に使用します。いままで設計した50%以上の回路に入っていると思います。たった2ビットのシフトレジスタですから、動作しないFPGAはありませんし、どんなに早いクロックでも動作します。さらに再現性が良い。
ここにあげた全部の微分回路を一度に使うことは無いと思います。その時には接続しなければ良いだけです。最近のコンパイラは優秀ですので、使っていない回路は勝手に削除してくれます。
-
前の記事
デジタル回路のスイッチ入力の同期化_10msecパルス生成 2020.07.07
-
次の記事
デジタル回路のカウンタ 2020.07.09

コメントを書く