Tiếp theo chúng ta sẽ xem một ví dụ về phép chia : Trong phép tính thông thường : http://pg.photos.yahoo.com/ph/kienbi &.dnm=ea6d.jpg Trong phép tính của CRC : http://pg.photos.yahoo.com/ph/kienbi &.dnm=f8b1.jpg Kết quả của phép chia ở đây không quan trọng , và không hiệu quả để nhớ bởi vì nó sẽ chỉ là một cặp các bít nhỏ hơn bitstring nơi mà bạn muốn tính toán theo CRC . Vậy thì điều quan trọng chính là số dư ! Đó là vấn đề phải bàn luận ,nói nhiều nhất khi chúng ta tìm hiểu về file gốc . Đó là điều cơ bản về CRC. Going over to the real CRC computation - Để thực hiện một phép tính CRC chúng ta phải chọn một số chia , từ bây giờ chúng ta gọi số này là “poly’” . Chiều rộng (W) của một poly chính là vị trí của bít cao nhất. Vì vậy chiều rộng của poly 1001 là 3 , chứ không phải là 4 . Chú ý rằng bít cao nhất luôn luôn là một , khi bạn đã chọn chiều rộng của poly bạn chỉ được chọn một giá trị cho những bít W thấp hơn . Nếu chúng ta muốn tính toán CRC thông qua bitstring , chúng ta phải chắc chắn rằng tất cả các bít đều được xử lý. Vì vậy chúng ta cần phải thêm các bít 0 tương ứng với chiều rộng W mà ta tìm được vào sau bitstring . Trong ví dụ 3 ở trên , thì bitstring chính là 1111 . Sau đây chúng ta sẽ xem thêm một ví dụ nữa : http://pg.photos.yahoo.com/ph/kienbi &.dnm=9fa0.jpg Có hai vấn đề quan trọng cần phải nói ở đây: - Chỉ có bít cao nhất là bít một trong bitstring , chúng ta XOR nó với poly , còn trường hợp khác chỉ là việc chúng ta dịch bitstring đi một bít về bên trái. - Mục đích của các vòng XOR là , nó chỉ được XOR với các bit thấp của W bits, bởi vì bít cao nhất luôn cho giá trị 0 . (Ặc ặc các bác cố gắng hiều cái ví dụ trên ) To be continue :) Tut Continue Going over to a Table-Driven Algorithm Tất cả các bạn đều hiểu rằng các thuật toán dựa trên việc tính toán từng bít sẽ rất chậm và không hiệu quả. Nó sẽ có hiệu quả cao hơn nếu như bạn có thể tính toán nó dựa trên việc tính toán theo từng byte.Do đó chúng ta có thể đồng ý các poly sẽ có độ rộng là 8 bít ( đó chính là byte) . Bạn hãy tưởng tượng nó trong ví dụ sau với poly có chiều rộng là 32 bít (W = 32). http://pg.photos.yahoo.com/ph/kienbi &.dnm=d55c.jpg Đó là một thanh ghi bạn sử dụng để lưu trữ kết quả tạm thời của CRC , ở đây tôi gọi nó là thanh ghi CRC ( CRC register ) hoặc chỉ là một thanh ghi kể từ bây giờ. Bạn đang dịch chuyển các bít từ bitstring bắt đầu từ phía bên phải , và các bít được dịch ra ngoài từ phía bên trái ( tức là theo chiều mũi tên như thế này < ) . Khi mà bit vừa được dịch ra ngoài từ phía bên trái là một , thì toàn bộ thanh ghi được XOR bằng lower W bits của poly ( in this case 32) . Trên thực tế , chúng ta đang thực hiện một cách tương tự , chính xác như là phép chia đã thực hiện ở trên. Vậy thì ( như tôi đã nói ) nếu chúng cùng lúc dich chuyển một nhóm bít (shift in & out ) thì sao. Hãy xem một ví dụ của 8 bit CRC với việc dịch chuyển 4 bit cùng một lúc (shift in & out ) : Quote: The register just before the shift : 10110100 Then 4 bits (at the top) are shifted out at the left side while shifting 4 new bits in at the right side. In this example 1011 is shifted out and 1101 (new) is shifted in. Then the situation is this: 8 bits currently CRC/Register : 01001101 4 top bits just shifted out : 1011 We use this poly : 101011100, width W=8 Bây giờ chúng ta tính toán như bình thường với giá trị mới của thanh ghi : http://pg.photos.yahoo.com/ph/kienbi &.dnm=bbb1.jpg Bây giờ bạn có thể thấy rằng các bít ở vị trí topbits đều bằng 0 . Vì vậy trong trường hợp này chúng ta sẽ không phải tiếp tục XOR topbits với Poly nữa . Bạn cũng có thể có được một kết quả tương tự như trên bằng việc thực hiện các thao tác sau : Nếu đầu tiên bạn XOR (*1) với (*2) và kết quả với thanh ghi . Kết quả này có được là bởi vì vòng XOR này sẽ được thực hiện như sau : (a XOR b) XOR c = a XOR (b XOR c). http://pg.photos.yahoo.com/ph/kienbi &.dnm=2fa3.jpg Bạn hãy quan sát nhé! Sau khi tính toán theo cách trên chúng ta đã có được một kết quả tương tự. Bây giờ kết quả mà chúng ta có được (*3) sau khi XOR hai Poly với nhau là rất quan trọng, bởi vì với topbits là 1010 thì chúng ta luôn luôn có được giá trị của (*3) = 10111100 (only the lower W=8 bits) . Điều này có nghĩa là bạn có thể thực hiện tính toán trước giá trị XOR values cho mỗi tổ hợp của topbits. Chú ý rằng giá trị của topbits sẽ luôn là 0 sau khi thực hiện lặp lại các vòng XOR (this must be because the combination of XORring leads to it.). Bây giờ chúng ta lại quay trở lại với hình minh họa thứ 1 ((figure 1).Với mỗi giá trị của byte đầu tiên (8 bits) vừa mới được dịch ra ngoài , chúng ta có thể tính tóan trước được một giá trị . Trong trường hợp này nó sẽ là một bảng bao gồm 256 (2^8) phần tử của doube word (32 bits) (Bảng CRC-32 nằm ờ phần phụ lục _ tôi sẽ đưa ra sau ). Vậy thuật toán của giải thuật của chúng ta bây giờ là : Quote: While (byte string is not exhausted) Begin Top = top_byte of register ; Register = Register shifted 8 bits left ORred with a new byte from string ; Register = Register XORred by value from precomputedTable at position Top ; End The direct Table Algorithm Giải thuật đã được nêu trong phần trên có thể được tối ưu . Các byte từ byte string không cần phải dịch chuyển qua tòan bộ thanh ghi trước khi chúng được sử dụng. Với giải thuật mới này chúng ta có thể XOR một cách trực tiếp một byte từ một byte string với byte đã được dịch chuyển ra ngoài thanh ghi . Kết quả sẽ trỏ tới một giá trị trong bảng đã được tính từ trước mà sẽ đựơc đem XOR với thanh ghi . Tôi cũng không biết được một cách chính xác rằng tại sao chúng đều cho ra cùng một kết quả , nhưng nó lại có một thuận lợi rất lớn là bạn sẽ không phải thêm các bít hoặc byte 0 vào byte string của bạn. (if you know why, pleaz tell me :) Hãy hình dung về giải thuật : http://pg.photos.yahoo.com/ph/kienbi &.dnm=a05f.jpg Kết thúc nốt phần I của Tut này : The 'reflected' direct Table Algorithm : Để làm cho mọi thứ trở nên phức tạp hơn có một phiên bản ‘reflected’ của chính giải thuật này.Một Reflected value/register là giá trị mà các bít được trao đổi xung quanh vị chính giữa. Lấy vị dụ 0111011001 chính là giá trị reflection của 1001101110 . Điều này được nêu ra bời vì UART (chip that performs serial IO) nó gửi từng byte với bit đầu tiên có ý nghĩa ít nhất và bít cuối cùng có ý nghĩa lớn nhất (this is the reverse of the normal situation.) Do đó tất cả các byte khác nữa cũng được reflected , thay vì việc phải reflecting từng byte trước khi xử lý . Lợi ích của quá trình này là nó cho ta một đoạn code ngắn gọn, cô đọng hơn trong quá trình thi hành. Vì vậy trong quá trình tính toán table , các bit được dịch sang bên phải và poly thì được reflected. Còn trong việc tính toán CRC thì thanh ghi được dịch sang bên phải (of course) và reflected table được sử dụng. Minh họa : http://pg.photos.yahoo.com/ph/kienbi 2573.jpg<br /> Some implementations in Assembly : Để giải quyết cho tất cả những gì đã đề cập ở trên sau đây là thông tin đầy đủ về CRC-32 : Name : "CRC-32" Width : 32 Poly : 04C11DB7 Initial value : FFFFFFFF Reflected : True XOR out with : FFFFFFFF Thêm vào đó là thông tin về CRC-16 cho những ai muốn tìm hiểu thêm Name : "CRC-16" Width : 16 Poly : 8005 Initial value : 0000 Reflected : True XOR out with : 0000 ‘XOR out with’ là giá trị mà đã được XOR với giá trị cuối cùng của thanh ghi trước khi chúng ta có được kết quả cuối cùng là CRC. Đó cũng chính là việc 'reversed' CRC poly's nhưng chúng không thích hợp trong bài viết này . Để làm việc với assembly tôi sử dụng 32 bit code trong môi trường DOS 16 bit , vì vậy bạn sẽ thấy sự trộn lận của 32 bit code và 16 bit code nhưng cũng rất dễ dàng để convert nó hoàn toàn sang 32 bit code. Chú ý rằng đoạn code bằng assembly này đã được test rất kỹ để sao cho nó hoạt động chính xác nhất.Đoạn code này cũng có thể được chuyển hóa sang C hoặc Java. Ok sau đây là đoạn code bằng hợp ngữ dùng để tính toán CRC-32 table : Code: xor ebx, ebx ;ebx=0, because it will be used whole as pointer InitTableLoop: xor eax, eax ;eax=0 for new entry mov al, bl ;lowest 8 bits of ebx are copied into lowest 8 bits of eax ;generate entry xor cx, cx entryLoop: test eax, 1 jz no_topbit shr eax, 1 xor eax, poly jmp entrygoon no_topbit: shr eax, 1 entrygoon: inc cx test cx, 8 jz entryLoop mov dword ptr[ebx*4 + crctable], eax inc bx test bx, 256 jz InitTableLoop Notes: - crctable is an array of 256 dwords - eax is shifted to the right because the CRC-32 uses reflected Algorithm - also therefore the lowest 8 bits are processed In Java or C (int is 32 bit): . Then the situation is this: 8 bits currently CRC/Register : 01 0 01 1 01 4 top bits just shifted out : 10 11 We use this poly : 10 1 01 1 100 , width W=8 Bây giờ chúng ta tính toán như bình thường với. giá trị mà các bít được trao đổi xung quanh vị chính giữa. Lấy vị dụ 01 1 1 01 1 0 01 chính là giá trị reflection của 10 01 1 01 1 10 . Điều này được nêu ra bời vì UART (chip that performs serial IO). before the shift : 10 1 10 100 Then 4 bits (at the top) are shifted out at the left side while shifting 4 new bits in at the right side. In this example 10 11 is shifted out and 11 01 (new) is shifted