等号と不等号

[] [] []


処理をN回繰り返すとき、ソフトウェアでは

 for( i=0; i<N; i++ )

と繰り返し条件をN未満と不等号で書くが、実際にはiはゼロからカウントアップしているので

  for( i=0; i!=N; i++ )

と等号の否定で書いても同じである。

ソフトウェアでは、比較処理は両辺の引き算をしてゼロに等しい(equal to zero)か負(less than zero)かをCPU内のALU回路で判定しているので、どちらにしても損得はないのだが、FPGAではその判定回路自身を合成するので、どちらにするか気にした方がよい。

等号eq=(a==b)の回路を考えると、ビットごとのXOR(等しければ0)をとって全ビットが0であることを判定すればよいので

equal = ~|(a[N-1:0] ^ b[N-1:0])

と、ビット間のロジックはNORだけですむ。

一方、不等号 lt=(a<b)の回路を考えると、最上位ビットN-1から順に比較していかなければならないから

if(a[N-1]==0 & b[N-1]==1)  lt=1;

else if(a[N-2]==0 & b[N-2]==1) lt=1;

 ...

else if(a[0]==0 & b[0]==1) lt=1;

else lt=0;

else ifが続いて等号よりも深い回路になることがわかる。

したがって、なるべく不等号(<,>,<=,>=)は使わずに等号(==,!=)を使う方がよい

◇◇

FPGAにはLUTだけでなく加算器やキャリ伝搬回路もついているので、不等号を、両辺を引き算して符号を見る回路にすれば速くなる可能性がある

実際、次の3とおりの書き方を論理合成してみた。

input[N-1:0] ain,bin;

assign eq_cmp = (ain==bin)? 1'b1 : 1'b0;

assign lt_cmp = (ain<bin)? 1'b1 : 1'b0;

wire[N:0] sub;

assign sub = ain - bin;

assign lt_sub = sub[N];  // ain-bin<0ならば1

(1) QuartusArriaVにマッピングした場合

回路要素はLUTAdder(carry伝搬回路付き)。等号eq_cmpより不等号lt_cmpの方が回路規模は大きくなり最長パスも少し長くなる。引き算による比較lt_subLUTでなくAdderを使うので単純には比較できないが、キャリ伝搬回路だけを使うのでlt_cmpより速くなる可能性はある。

N

eq_cmp

lt_cmp

lt_sub

回路規模

最長パス

回路規模

最長パス

回路規模

最長パス

8

4 LUT

2 LUT

5 LUT

3 LUT

9 Adder

9 carry

16

7 LUT

2 LUT

15 LUT

4 LUT

17 Adder

17 carry

32

14 LUT

3 LUT

40 LUT

4 LUT

33 Adder

33 carry

 (2) Vivado 7seriesにマッピングした場合

回路要素はLUTCARRY4(carry伝搬回路)。等号eq_cmpより不等号lt_cmpの方が回路規模は大きくなり最長パスも少し長くなる。引き算による比較lt_sublt_cmpよりCARRY4の段数が多くなっているのでかえって遅いかもしれない。

N

eq_cmp

lt_cmp

lt_sub

回路規模

最長パス

回路規模

最長パス

回路規模

最長パス

8

3 LUT

2 LUT

6 LUT

1 LUT + 1 CARRY4

8 LUT + 3 CARRY4

1 LUT + 3 CARRY4

16

6 LUT + 2 CARRY4

1 LUT+ 2 CARRY4

16 LUT + 2 CARRY4

1 LUT + 2 CARRY4

16 LUT + 5 CARRY4

1 LUT + 5 CARRY4

32

11 LUT + 3 CARRY4

1 LUT+ 3 CARRY4

32 LUT + 4 CARRY4

1 LUT + 4 CARRY4

32 LUT + 9 CARRY4

1 LUT + 9 CARRY4


[] [] []