このページをはてなブックマークに追加このページを含むはてなブックマーク このページをlivedoor クリップに追加このページを含むlivedoor クリップ
  • 追加された行はこの色です。
  • 削除された行はこの色です。
  • CRC方式 へ行く。

*目次 [#va91304f]

#contents


*CRC [#j6a954c1]

 ''CRC(Cyclic Redundancy Check:巡回冗長検査)''とは、誤り制御の一種である。[[パリティチェック]]よりも高度な仕組みとなっている。

 CRCは、ビット列のデータをある生成多項式で割った余りを検査用のCRC符号として、データに付加して送信する方式である。受信側は、受信したデータが同じ生成多項式で割り切れるか否かで誤りの発生を検出する。

 用いられる生成多項式はビット長によって代わるが、代表的なものとしてXSUP{16};+XSUP{12};+XSUP{5};+1がある。この生成生成多項式で割るということは、係数がmod 2としてみたときのビット列10001000000100001で割るということである。


*CRCの特徴 [#i7ab3ff6]

-他の冗長符号の方式である[[パリティチェック方式]]よりも冗長度に比較して高い誤り検出能力を持つという利点を持つ。
-データ伝送制御系(例:[[HDLC]]を用いたシステム)やフレキシブルディスク装置にはビット誤りの検出を目的としてCRCが広く用いられている。
-これらの制御系にはマイクロコンピュータを使用し、同期制御・入出力制御などの機能と合わせてCRC演算を実行することが多い。
--この場合、マイクロコンピュータの処理負荷(ステップ数)の中でCRC演算を実現する部分は比較的大きな割合を占めているので、その最適化は重要である。
-生成多項式で割った余りを検査用のCRC符号として利用する。パリティチェックよりも計算は複雑になるが、バースト誤り(誤りが集中して発生する現象)に強い。


*CRCの仕組み [#la0b429d]

 CRCのデータブロック(nビット)は、情報ビット(kビット)と検査ビット(n-kビット)から構成される。

#img(http://security2600.sakura.ne.jp/main2/image3/CRC_block.jpg)
#img(,clear)

 これらは一般に多項式で実現される。

例:1101のようなビット列Dは、多項式D(x)=XSUP{3};+XSUP{2};+1のように表すことができる。

 CRCによる誤り検出は、送信側でメッセージをひとつの多項式で表現し、これをCRCの生成多項式G(X)で割り算し、その剰余を情報ビットに続けて伝送路に送り出す。よって、情報ビットと付加された検査ビットを多項式で表現したものはG(X)で割り切れる。

例:1101を101で割ったとき、商が11、余りが10になる。1101の後に10を付加した結果の110111は101で割ると、商が1110、余りが0になる。 ◇

 そこで、受信側では受信データをG(x)で割り算し、剰余が0であれば誤りがなしとし、剰余が0でなければ誤りがあったと判定する((HDLCではあらかじめ剰余をすべて1にセットする方式を採用しているので、最終剰余が0とならないが、演算の基本的な方式はここで説明する仕組みと同様である))。


*CRCの演算 [#m820a49f]

 例えば、生成多項式がG(X)=XSUP{3};+X+1のとき、データビットDに対する剰余は次のように行われる。

&mimetex("\{ DX^3+(R_2 X^2+R_1X+R_0)X \} \div (X^3+X+1)");~

 このときの商と剰余は次の通りである。

-商:&mimetex("R_2 \oplus D");
-剰余:&mimetex("R_1X^2+(R_0 \oplus R_2 \oplus D)X+(R_2 \oplus D)");

 よって、旧剰余の係数と新剰余の係数の関係は次のように表される。ただし、RSUB{i};(i=0,1,2)は新しい係数である。この3つの漸化式を(*)と置く。

-&mimetex("R_2'=R_1");
-&mimetex("R_1'=R_0 \oplus R_2 \oplus D");
-&mimetex("R_0'=R_2 \oplus D");

[補講]任意の長さmのデータに対応する多項式f(X)をt次生成多項式G(X)で割る演算は、t段線形帰還シフトレジスタ(G(X)の項に対応したフィードバックを持つ)によって、m回のシフトで実行できる。 ◇

 CRCでは標準的に生成多項式としてG(X)=XSUP{16};+XSUP{12};+XSUP{5};+1が使われる。このとき、nビットのデータD(0),D(1),…,D(n-1)に対するCRC演算は、漸化式(*)をn回繰り返すことに相当する。ただし、k=0,1,…,n-1である。この3つの漸化式を(**)と置く。

-&mimetex("R^{(k+1)}(i)=R^{(k)}(15) \oplus D(k) (\equiv Q^{(k)})"); (i=0)
-&mimetex("R^{(k+1)}(i)=R^{(k)}(i-1) \oplus Q^{(k)}"); (i=5,12)
-&mimetex("R^{(k+1)}(i)=R^{(k)}(i-1)"); (i≠0,5,12)

 ここで、&mimetex("R^{(0)}(15), R^{(0)}(14),\cdots,R^{(0)}(0)");は旧剰余、&mimetex("R^{(n)}(15), R^{(n)}(14),\cdots,R^{(n)}(0)");は新剰余(いずれも高次の係数より低位の係数へ)を指す。


*CRCの演算の高速化 [#t04c357b]

 ここでは8ビットのマイクロコンピュータのプログラムで実現することを前提として考える。


**XOR命令+シフト命令の方法 [#c1f55712]

 漸化式(**)の&mimetex("R^{(0)}");から&mimetex("R^{(n)}");への変換をXOR(排他的論理和)命令とシフト命令を用いて演算する方法について考える。XOR命令の使用回数が最小となるようにシフト命令の仕様手順を考えればよい。

 単位処理ビット数が8ビットのとき、XOR命令回数は5回になる。

 また、シフト命令の回数はマイクロコンピュータのシフト命令の機能によって異なる。例えば、1ビット右シフト/左シフトによる場合、単位処理ビット数が1〜8ビットにおいて、シフト命令の回数は10回前後をふらつく。

 XOR命令回数とシフト命令の回数を合わせて考慮すると、単位処理ビット数が1〜8ビットの中で8ビットのときに最も効率がよい。結論を述べれば、1ビットのとき(ビットシリアルの演算)と比べると、4倍効率がよくなっている。

***8080における実装 [#refa56ce]

 Intel 8080系(例えば[[8080A]]などを含む)での実装例である([[Z80]],[[F-8]]も同様)。

 このとき、レジスタの使い道は次の通りである。

|Aレジスタ|8ビットのデータ|
|Bレジスタ|剰余の高位の8ビット(RSUB{U};)|
|Cレジスタ|剰余の低位の8ビット(RSUB{L};)|
|D,Eレジスタ|ワークレジスタ|

 このときアルゴリズムは次のようになる。ただし、演算直前のAレジスタには8ビットのデータ、BとCレジスタには旧剰余が格納されているものとする。

+AレジスタとBレジスタ間でXOR演算を行い、その結果をDレジスタに格納する。
+Dレジスタの内容を4ビット左シフトした結果を、Dレジスタの元の内容でXOR演算する。その結果をDレジスタに格納する。
--しかし、1ビット左シフトすることは2倍することと同値なので、ここでは1ビット左シフト命令より命令実行時間の短い加算命令でシフト命令を代行する。
+Dレジスタの内容を3ビット左シフトし、その結果をEレジスタに格納する。
+Eレジスタの内容とビットパターン"1111 1000"(16進数でF8)をAND演算する。その結果をCレジスタとXOR演算して、その結果をBレジスタに格納する。
+Eレジスタの内容を1ビット左シフトした後に、ビットパターン"0000 1111"(16進数で0F)とAND演算を行う。その結果とBレジスタのXOR演算を行い、その結果をBレジスタに格納する。
+Eレジスタの内容とビットパターン"0000 0111"(16進数で07)とAND演算を行う。そして、その結果とDレジスタとでXOR演算を行い、その結果をCレジスタに格納する。
+最終的にBとCレジスタの内容が新剰余になる。Bレジスタが高位の8ビット(RSUB{U};)、Cレジスタが低位の8ビット(RSUB{L};)に対応する。
--このBとCレジスタの内容がそのまま次の8ビットデータに対しては旧剰余に対応する。よって、次の8ビットデータに対しては、このデータをAレジスタにセットして、同一のアルゴリズムを実行すればよい。このようにして、入力データに対応する回数分繰り返した結果のBとCレジスタの内容が全入力データに対するCRCデータになる。

 次のコードは上記のアルゴリズムをIntel 8080のアセンブリ言語に実装したものである。コメントアウトの数字はアルゴリズムの箇条書きの番号と対応している。

#code(asm){{
XRA B		; A←A XOR B
MOV D,A		; D←A
ADD A		; 以下4行合わせて、A+A+A+A、即ち4×Aと同等の動き
ADD A
ADD A
ADD A
XRA D		; A←A XOR D
MOV D,A		; D←A
RLC			; 0焚3行合わせて、Aを3ビット左シフト
RLC
RLC
MOV E,A		; E←A
ANI 0F8H	; A←A AND "1111 1000" A=Eの状態でこの演算をするので、レジスタEに対して行っていることと同じ
XRA C		; A←A XOR C
MOV B,A		; B←A
MOV A,E		; A←E
RLC			; 1ビット左シフト
ANI 0FH		; A←A AND "0000 1111"
XRA B		; A←A XOR B
MOV B,A		; B←A
MOV A,E		; A←E
ANI 07H		; A←A AND "0000 0111"
XRA D		; A←A XOR D
MOV C,A		; C←A

}}


***M6800における実装 [#of550ada]

 モトローラ社のM6800での実装例である(MC6502も同様)。8080Aの例と比較すると、M6800はレジスタの構成が異なるので、次のように両者のレジスタとエリアの使い方が対応する。

|''8080A''|''M6800''|
|Aレジスタ|Aレジスタ|
|Bレジスタ|JOYO+1レジスタ|
|Cレジスタ|JOYOレジスタ|
|Dレジスタ|Bレジスタ|
|Eレジスタ|WORKレジスタ|


**テーブルルックアップの方法 [#ya0419f9]

 テーブルルックアップとは、テーブルが格納されている右端アドレスを指示し、この場合データレジスタと剰余レジスタのXOR演算の結果がテーブルのインデックスと一致しているかどうかを調べて、もし一致していればそのときの内容を出力する。

 漸化式(**)の&mimetex("R^{(0)}");の上位nビットと下位(16-n)ビットを分離して取扱い、前者とデータビットとのXOR演算の結果に対する剰余演算をテーブルルックアップにより求めて、その結果と下位(16-n)ビットとのXOR演算の結果が求める剰余となる。

 この方法は、CRC演算の場合、テーブルの内容によってテーブルを引く回数が異なる。テーブルを大きくすれば、引く回数が少なくなる。一方、テーブルを小さくすれば、引く回数が多くなる。よって、テーブルの大きさによって演算時間が大きく左右される。


**まとめ [#q94dc9a2]

 XOR命令+シフト命令の方法とテーブルルックアップの方法を比較する。前者は単位処理ビット数が8ビットのときが最も効率がよい(ただし、1〜8ビットの中に限定したとき)。後者は前者より数倍早くできるが、メモリ容量が大きくなってしまう。よって、総合的なコスト性能では前者の方が優れているといえる。


*参考文献 [#x0296b9c]

-『1週間で分かる基本情報技術者集中ゼミ【午前編】 2006春秋』
-『インターフェース 1977年2月号 No.13』