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

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

 時間を作るタイマーまでを設計することができました。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] &amp; (~rDFF[1]));			// 立ち上がりエッジ				~~~~~~|_|~~~~~~~~~~~~~~~~
assign	wrisingrdge = ~((~rDFF[0]) | rDFF[1]);				// 立ち上がりエッジ				______|~|________________
assign	wnfallingedge = ~((~rDFF[0]) &amp; 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はありませんし、どんなに早いクロックでも動作します。さらに再現性が良い。

 ここにあげた全部の微分回路を一度に使うことは無いと思います。その時には接続しなければ良いだけです。最近のコンパイラは優秀ですので、使っていない回路は勝手に削除してくれます。