非同期リセット？同期リセット？どっちがいいの？

参考資料: [Synchronous Resets? Asynchronous Resets? I am so confused! How will I ever know which to use?](http://www.sunburst-design.com/papers/CummingsSNUG2002SJ_Resets.pdf)

2002年に書かれた上記資料を参考に、何年も前に書いたやつをアップデートした。
かなりてけとーに訳しているのと、原著者と訳者の言い分が混じっているので少しでも興味があれば上記を参照したほうが良い。(後半いくほど雑だし、なんだったら半分くらい省略しているし)


FPGAの場合の結論は、以下の通り。

* 同期リセットを使え
* 非同期リセットの場合はベンダの推奨する対応を行え


## 1 resets, Resets, RESETS, and then there's RESETS

リセットとは、回路をシミュレーションで確認されている既知の状態にするもの。この資料では、ASIC向けのリセットについて述べている。
この資料の筆者は、ASICはすべてのFFはリセット可能であるべき、また、非同期リセットを推奨、としている。
同期リセットでは、すべての回路が既知の状態になるまでに複数のクロックサイクルが必要になるのを嫌っているっぽい。

ちなみに、[Xilinxの資料](https://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2018_3/ug949-vivado-design-methodology.pdf)では、回路規模の縮小と配線の簡易化のために同期リセットが推奨されている。Xilinxに限らず、FPGAでは一般的にMTBFとかの問題で同期リセットが推奨になっていると思う。


#### 脱線(ug949の内容)

 * そもそもリセットは必要？  
	必要ないことが多いので、シミュレーションで削除が可能かどうか確認するようにする。

 * 同期リセットを推奨  
	非同期リセットは不要なリソースを使用したり、タイミング解析が複雑になることが多い。

 * アクティブHighを推奨  
	アクティブLowの場合、インバータが挿入されることがある。  
	ファンアウトが大きい配線は、アクティブHighにしたほうが良い。

上記対応を行うことで、以下のように改善するらしい(ほんとかよ)。

|           パラメータ           |     結果     |
|--------------------------------|--------------|
| リソース                       | 33%～75%削減 |
| パフォーマンス                 | 36%改善      |
| タイミングエンドポイント数     | 40%削減      |
| 220MHzでのダイナミック消費電力 | 40%削減      |


## 2 General flip-flop coding style notes


### 2.1 Synchronous reset flip-flops with non reset follower flip-flops

※以降、元の資料ではVerilogとVHDLを併記しているが、個人的好みでVHDLよりになる。

VHDLの`process`文では、FFのみを記述するべきである。また、リセットありのFFとリセットなしのFFを混在させるべきではない。
リセットなしのFFとのことをフォロワーFFと呼んでいる。フォロワーFFは単純なシフトレジスタのこと。

以下に示すコードでは、データをキャプチャしてフォロワーFFを経由して出力している。

```vhdl
library ieee;
use ieee.std_logic_1164.all;

entity badFFstyle is
	port (
		clk   : in  std_logic;
		rst_n : in  std_logic;
		d     : in  std_logic;
		q2    : out std_logic);
end badFFstyle;

architecture rtl of badFFstyle is
	signal q1 : std_logic;

begin
	process (clk)
	begin
		if (clk'event and clk = '1') then
			if (rst_n = '0') then
				q1 <= '0';
			else
				q1 <= d;
				q2 <= q1;
			end if;
		end if;
	end process;
end rtl;
```

このコードは、以下のような回路を生成するらしい。ldにリセットがつながるのはラッチを構成するためと思われる。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139130/871f8489-2715-7468-c131-a8e9c060363b.png)

なので、フォロワーFFを生成したい場合は以下のように`process`文を分けること。

```vhdl
library ieee;
use ieee.std_logic_1164.all;

entity goodFFstyle is
	port (
		clk   : in  std_logic;
		rst_n : in  std_logic;
		d     : in  std_logic;
		q2    : out std_logic);
end goodFFstyle;

architecture rtl of goodFFstyle is
	signal q1 : std_logic;

begin
	process (clk)
	begin
		if (clk'event and clk = '1') then
			if (rst_n = '0') then
				q1 <= '0';
			else
				q1 <= d;
			end if;
		end if;
	end process;

	process (clk)
	begin
		if (clk'event and clk = '1') then
			q2 <= q1;
		end if;
	end process;
end rtl;
```

このときに生成される回路は、想定通り、以下のようになる。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139130/e0220b47-6566-4082-9cef-44c6f4ef8053.png)


非同期リセットでは上記2つのコーディングスタイルで生成される回路に違いはないらしい。これは、リセットロジックが一番外側の`if`文に入るため？それでも上の(最初の)コードではラッチを生成しそうな気がするが。


### 2.2 Flip-flop inference style

推論されるFFは、独立にモデル化されるべきではない。  
推論されるFFや、各機能はすべて一つの`process`文であるべき。  
逆に機能が分割されている場合は、`process`文も分割する。  
例外は2.1で述べた、フォロワーFFである。

ちょっとよくわからない。機能でまとめておけばいいということ？


### 2.3 Assignment operator guideline

Verilogでは、推論されるFF(シーケンシャルロジック)にはノンブロッキング代入を使用する。同様にVHDLでは、signal assignmentsを使用すること。

signal assignmentsとは、variable(ブロッキング代入になる)を使用しないということと思われる。


## 3 Synchronous resets

いろんな所で非同期リセットは悪だ、同期リセットを使え、と言われているが、同期リセットには利点と欠点がある。
非同期リセットも同様である。そして、設計者は適切な方を選ばなければならない。

同期リセットの考え方は、リセット信号やFFのリセットがクロックエッジで変化することを前提としている。
同期リセットを使用すると、HDLコード上でリセット時の振る舞いと動作時の振る舞いを`if-else`で区切ることになる。
動作時の振る舞いでも`if-else`が必要になることがあるため、優先度を考慮する必要が出てくる。

このとき、2つの問題が起こる可能性がある。

1つ目の問題は、一部のシミュレータで、リセットをブロックしてしまうことである。
この問題は、シミュレーションだけの問題であるが、実機とシミュレーションで動作が変わってしまい、結果を予測できなくなる。  
(そんなシミュレータあるの？)

2つ目の問題は、リセット信号のファンアウトなどにより遅れてやってくることである。
以下、カウンタ(ロード、キャリーあり)のHDL例とその生成回路である。

```vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity ctr8sr is
	port (
		clk   : in  std_logic;
		rst_n : in  std_logic;
		d     : in  std_logic;
		ld    : in  std_logic;
		q     : out std_logic_vector(7 downto 0);
		co    : out std_logic);
end ctr8sr;

architecture rtl of ctr8sr is
	signal count : std_logic_vector(8 downto 0);

begin
	co <= count(8);
	q  <= count(7 downto 0);

	process (clk)
	begin
		if (clk'event and clk = '1') then
			if (rst_n = '0') then
				count <= (others => '0'); -- sync reset
			elsif (ld = '1') then
				count <= '0' & d;         -- sync load
			else
				count <= count + 1;       -- sync increment
			end if;
		end if;
	end process;
end rtl;
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139130/3165cac9-5635-683b-c6e6-999cb4ac3957.png)



### 3.1 Coding style and example circuit

同期リセットの書き方の例。

```vhdl
library ieee;
use ieee.std_logic_1164.all;

entity syncresetFFstyle is
	port (
	clk   : in  std_logic;
	rst_n : in  std_logic;
	d     : in  std_logic;
	q     : out std_logic);
end syncresetFFstyle;
architecture rtl of syncresetFFstyle is

begin
	process (clk)
	begin
		if (clk'event and clk = '1') then
			if (rst_n = '0') then
				q <= '0';
			else
				q <= d;
			end if;
		end if;
	end process;
end rtl;
```


### 3.2 Advantages of synchronous resets

* 同期リセットは回路規模が小さい。  
* 同期リセットはシミュレーションしやすい。  
* クロックエッジでしかリセットを認識しないのでグリッチを除去できる。  
	ただ、グリッチがクロックエッジ付近で起こるとメタステーブル状態になることがある。  
* リセット信号にグリッチが発生する可能性がある場合は同期リセットでないといけない。  
* クロック周期の時間だけ、リセットの伝搬に余裕ができる。


### 3.3 Disadvantages of synchronous resets

同期リセットはクロックエッジでしか認識されないので、パルス幅に気を配る必要がある。場合によってはパルス幅の拡張が必要になる。

また、組み合わせ回路によってリセットが生成されている場合、リセットの値は不定(X)となることがある。これはシミュレータによってはリセットがブロックされる要因となる。  
(※FPGAの場合、適切に初期値を入れておけば回避できる、かつ実機でも問題ないと思われる。)

トライステートのバスがある場合は注意が必要。電源ONのときに競合を防ぐためには非同期のPower on resetが必要になる。


## 4 Asynchronous resets

著者は非同期リセットが好きだが、非常に危険。非同期リセットでもっとも注意が必要なのはリセット解除のタイミングである。

### 4.1 Coding style and example circuit

VerilogとVHDLで書き方が違うのでｍ別々に説明する。

まず、Verilogではリセットをセンシティビティリストへ追加して、`negedge rst_n`のようにエッジセンシティブに記述する必要がある。(Synopsysの合成ツールの制限？)

```verilog
// Verilogの記述例(Example 5a - Correct way to model a flip-flop with asynchronous reset using Verilog)
module async_resetFFstyle (q, d, clk, rst_n);
	output q;
	input  d, clk, rst_n;
	reg    q;

	// Verilog-2001: permits comma-separation
	// @(posedge clk, negedge rst_n)
	always @(posedge clk or negedge rst_n)
		if (!rst_n) q <= 1'b0;
		else        q <= d;
endmodule
```

次にVHDLでは`if clk'event and clk = '1'`の前にリセットの条件を入れることで非同期リセットであることを示す。

```vhdl
library ieee;
use ieee.std_logic_1164.all;
entity asyncresetFFstyle is
	port (
		clk   : in std_logic;
		rst_n : in std_logic;
		d     : in std_logic;
		q     : out std_logic);
end asyncresetFFstyle;

architecture rtl of asyncresetFFstyle is
begin
	process (clk, rst_n)
	begin
		if (rst_n = '0') then
			q <= '0';
		elsif (clk'event and clk = '1') then
			q <= d;
		end if;
	end process;
end rtl;
```

このあたりにツールに対する細かい設定方法が書いてあるが、理解できない。最近のツールではとりあえず非同期リセットピンの制約(sdc/xdcファイルで指定)には`set_false_path`を設定しておけば問題ないと思われる。


### 4.2 Modeling Verilog flip-flops with asynchronous reset and asynchronous set

Verilogのシミュレーションでは、非同期リセットと非同期セットの両方を含むデザインを正しく動かせないらしい。
その回避方法が書いてある。(これって今でもそうなの？？こわい)

```verilog
// Good DFF with asynchronous set and reset and self-
// correcting set-reset assignment
module dff3_aras (q, d, clk, rst_n, set_n);
	output q;
	input d, clk, rst_n, set_n;
	reg q;

	always @(posedge clk or negedge rst_n or negedge set_n)
		if (!rst_n)      q <= 0; // asynchronous reset
		else if (!set_n) q <= 1; // asynchronous set
		else             q <= d;

	// synopsys translate_off
	always @(rst_n or set_n)
		if (rst_n && !set_n) force   q = 1;
		else                 release q;
	// synopsys translate_on
endmodule
```

### 4.3 Advantages of asynchronous resets

データパスに依存せずにリセットできる。
(待ち時間なし、かつ任意のタイミングで、回路を既知の状態にできる)
まぁ、ASICでは重要なことなんだろうな、とは思う。

```vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity ctr8ar is
	port (
	clk   : in  std_logic;
	rst_n : in  std_logic;
	d     : in  std_logic;
	ld    : in  std_logic;
	q     : out std_logic_vector(7 downto 0);
	co    : out std_logic);
end ctr8ar;

architecture rtl of ctr8ar is
	signal count : std_logic_vector(8 downto 0);
begin

	co <= count(8);
	q  <= count(7 downto 0);

	process (clk)
	begin
		if (rst_n = '0') then
			count <= (others => '0');   -- async reset
		elsif (clk'event and clk = '1') then
			if (ld = '1') then
				count <= '0' & d;       -- sync load
			else
				count <= count + 1;     -- sync increment
			end if;
		end if;
	end process;
end rtl;
```

![Figure_4_Loadable_counter_with_asynchronous_reset.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139130/1de44cf7-78a0-6fce-8a29-3e2d78973060.png)



### 4.4 Disadvantages of asynchronous resets

* 同期/非同期リセットツリーのタイミング調整
* 非同期リセット解除(ディアサート)時のメタステーブル
* グリッチなどによる意図しないリセット動作

まぁ、そうでしょうね。


## 5 Asynchronous reset problem

これ以降、非同期リセットの問題を解消するための記述が続く。(もうおなかいっぱいなのでここでやめた)

FPGAについて言えば、デバイスベンダごとに推奨する対処方法があるので省略。

* Xilnixの場合は`async_reg`属性を使う、またはxpmで対応した上で、cdcリポートの結果を吟味する。
* Intel(Altera)の場合は、資料によって言ってることが違うが、`SYNCHRONIZER_IDENTIFICATION`とかを使うのがよさそう。