📄 crc_v3.txt
字号:
issue. This section merely aims to put the fear of death into anyonewho so much as toys with the idea of making up their own poly. If youdon't care about why one poly might be better than another and justwant to find out about high-speed implementations, choose one of thearithmetically sound polys listed at the end of this section and skipto the next section.First note that the transmitted message T is a multiple of the poly.To see this, note that 1) the last W bits of T is the remainder afterdividing the augmented (by zeros remember) message by the poly, and 2)addition is the same as subtraction so adding the remainder pushes thevalue up to the next multiple. Now note that if the transmittedmessage is corrupted in transmission that we will receive T+E where Eis an error vector (and + is CRC addition (i.e. XOR)). Upon receipt ofthis message, the receiver divides T+E by G. As T mod G is 0, (T+E)mod G = E mod G. Thus, the capacity of the poly we choose to catchparticular kinds of errors will be determined by the set of multiplesof G, for any corruption E that is a multiple of G will be undetected.Our task then is to find classes of G whose multiples look as littlelike the kind of line noise (that will be creating the corruptions) aspossible. So let's examine the kinds of line noise we can expect.SINGLE BIT ERRORS: A single bit error means E=1000...0000. We canensure that this class of error is always detected by making sure thatG has at least two bits set to 1. Any multiple of G will beconstructed using shifting and adding and it is impossible toconstruct a value with a single bit by shifting an adding a singlevalue with more than one bit set, as the two end bits will alwayspersist.TWO-BIT ERRORS: To detect all errors of the form 100...000100...000(i.e. E contains two 1 bits) choose a G that does not have multiplesthat are 11, 101, 1001, 10001, 100001, etc. It is not clear to me howone goes about doing this (I don't have the pure maths background),but Tanenbaum assures us that such G do exist, and cites G with 1 bits(15,14,1) turned on as an example of one G that won't divide anythingless than 1...1 where ... is 32767 zeros.ERRORS WITH AN ODD NUMBER OF BITS: We can catch all corruptions whereE has an odd number of bits by choosing a G that has an even number ofbits. To see this, note that 1) CRC multiplication is simply XORing aconstant value into a register at various offsets, 2) XORing is simplya bit-flip operation, and 3) if you XOR a value with an even number ofbits into a register, the oddness of the number of 1 bits in theregister remains invariant. Example: Starting with E=111, attempt toflip all three bits to zero by the repeated application of XORing in11 at one of the two offsets (i.e. "E=E XOR 011" and "E=E XOR 110")This is nearly isomorphic to the "glass tumblers" party puzzle whereyou challenge someone to flip three tumblers by the repeatedapplication of the operation of flipping any two. Most of the popularCRC polys contain an even number of 1 bits. (Note: Tanenbaum statesmore specifically that all errors with an odd number of bits can becaught by making G a multiple of 11).BURST ERRORS: A burst error looks like E=000...000111...11110000...00.That is, E consists of all zeros except for a run of 1s somewhereinside. This can be recast as E=(10000...00)(1111111...111) wherethere are z zeros in the LEFT part and n ones in the RIGHT part. Tocatch errors of this kind, we simply set the lowest bit of G to 1.Doing this ensures that LEFT cannot be a factor of G. Then, so long asG is wider than RIGHT, the error will be detected. See Tanenbaum for aclearer explanation of this; I'm a little fuzzy on this one. Note:Tanenbaum asserts that the probability of a burst of length greaterthan W getting through is (0.5)^W.That concludes the section on the fine art of selecting polys.Some popular polys are:16 bits: (16,12,5,0) [X25 standard] (16,15,2,0) ["CRC-16"]32 bits: (32,26,23,22,16,12,11,10,8,7,5,4,2,1,0) [Ethernet]8. A Straightforward CRC Implementation---------------------------------------That's the end of the theory; now we turn to implementations. To startwith, we examine an absolutely straight-down-the-middle boringstraightforward low-speed implementation that doesn't use any speedtricks at all. We'll then transform that program progessively until weend up with the compact table-driven code we all know and love andwhich some of us would like to understand.To implement a CRC algorithm all we have to do is implement CRCdivision. There are two reasons why we cannot simply use the divideinstruction of whatever machine we are on. The first is that we haveto do the divide in CRC arithmetic. The second is that the dividendmight be ten megabytes long, and todays processors do not haveregisters that big.So to implement CRC division, we have to feed the message through adivision register. At this point, we have to be absolutely preciseabout the message data. In all the following examples the message willbe considered to be a stream of bytes (each of 8 bits) with bit 7 ofeach byte being considered to be the most significant bit (MSB). Thebit stream formed from these bytes will be the bit stream with the MSB(bit 7) of the first byte first, going down to bit 0 of the firstbyte, and then the MSB of the second byte and so on.With this in mind, we can sketch an implementation of the CRCdivision. For the purposes of example, consider a poly with W=4 andthe poly=10111. Then, the perform the division, we need to use a 4-bitregister: 3 2 1 0 Bits +---+---+---+---+ Pop! <-- | | | | | <----- Augmented message +---+---+---+---+ 1 0 1 1 1 = The Poly(Reminder: The augmented message is the message followed by W zero bits.)To perform the division perform the following: Load the register with zero bits. Augment the message by appending W zero bits to the end of it. While (more message bits) Begin Shift the register left by one bit, reading the next bit of the augmented message into register bit position 0. If (a 1 bit popped out of the register during step 3) Register = Register XOR Poly. End The register now contains the remainder.(Note: In practice, the IF condition can be tested by testing the top bit of R before performing the shift.)We will call this algorithm "SIMPLE".This might look a bit messy, but all we are really doing is"subtracting" various powers (i.e. shiftings) of the poly from themessage until there is nothing left but the remainder. Study themanual examples of long division if you don't understand this.It should be clear that the above algorithm will work for any width W.9. A Table-Driven Implementation--------------------------------The SIMPLE algorithm above is a good starting point because itcorresponds directly to the theory presented so far, and because it isso SIMPLE. However, because it operates at the bit level, it is ratherawkward to code (even in C), and inefficient to execute (it has toloop once for each bit). To speed it up, we need to find a way toenable the algorithm to process the message in units larger than onebit. Candidate quantities are nibbles (4 bits), bytes (8 bits), words(16 bits) and longwords (32 bits) and higher if we can achieve it. Ofthese, 4 bits is best avoided because it does not correspond to a byteboundary. At the very least, any speedup should allow us to operate atbyte boundaries, and in fact most of the table driven algorithmsoperate a byte at a time.For the purposes of discussion, let us switch from a 4-bit poly to a32-bit one. Our register looks much the same, except the boxesrepresent bytes instead of bits, and the Poly is 33 bits (one implicit1 bit at the top and 32 "active" bits) (W=32). 3 2 1 0 Bytes +----+----+----+----+ Pop! <-- | | | | | <----- Augmented message +----+----+----+----+ 1<------32 bits------>The SIMPLE algorithm is still applicable. Let us examine what it does.Imagine that the SIMPLE algorithm is in full swing and consider thetop 8 bits of the 32-bit register (byte 3) to have the values: t7 t6 t5 t4 t3 t2 t1 t0In the next iteration of SIMPLE, t7 will determine whether the Polywill be XORed into the entire register. If t7=1, this will happen,otherwise it will not. Suppose that the top 8 bits of the poly are g7g6.. g0, then after the next iteration, the top byte will be: t6 t5 t4 t3 t2 t1 t0 ??+ t7 * (g7 g6 g5 g4 g3 g2 g1 g0) [Reminder: + is XOR]The NEW top bit (that will control what happens in the next iteration)now has the value t6 + t7*g7. The important thing to notice here isthat from an informational point of view, all the information requiredto calculate the NEW top bit was present in the top TWO bits of theoriginal top byte. Similarly, the NEXT top bit can be calculated inadvance SOLELY from the top THREE bits t7, t6, and t5. In fact, ingeneral, the value of the top bit in the register in k iterations canbe calculated from the top k bits of the register. Let us take thisfor granted for a moment.Consider for a moment that we use the top 8 bits of the register tocalculate the value of the top bit of the register during the next 8iterations. Suppose that we drive the next 8 iterations using thecalculated values (which we could perhaps store in a single byteregister and shift out to pick off each bit). Then we note threethings: * The top byte of the register now doesn't matter. No matter how many times and at what offset the poly is XORed to the top 8 bits, they will all be shifted out the right hand side during the next 8 iterations anyway. * The remaining bits will be shifted left one position and the rightmost byte of the register will be shifted in the next byte AND * While all this is going on, the register will be subjected to a series of XOR's in accordance with the bits of the pre-calculated control byte.Now consider the effect of XORing in a constant value at variousoffsets to a register. For example: 0100010 Register ...0110 XOR this ..0110. XOR this 0110... XOR this ------- 0011000 -------The point of this is that you can XOR constant values into a registerto your heart's delight, and in the end, there will exist a valuewhich when XORed in with the original register will have the sameeffect as all the other XORs.Perhaps you can see the solution now. Putting all the pieces togetherwe have an algorithm that goes like this: While (augmented message is not exhausted) Begin Examine the top byte of the register Calculate the control byte from the top byte of the register Sum all the Polys at various offsets that are to be XORed into the register in accordance with the control byte Shift the register left by one byte, reading a new message byte into the rightmost byte of the register XOR the summed polys to the register EndAs it stands this is not much better than the SIMPLE algorithm.However, it turns out that most of the calculation can be precomputedand assembled into a table. As a result, the above algorithm can bereduced to: While (augmented message is not exhaused) Begin Top = top_byte(Register); Register = (Register << 24) | next_augmessage_byte; Register = Register XOR precomputed_table[Top]; EndThere! If you understand this, you've grasped the main idea oftable-driven CRC algorithms. The above is a very efficient algorithmrequiring just a shift, and OR, an XOR, and a table lookup per byte.Graphically, it looks like this: 3 2 1 0 Bytes +----+----+----+----+ +-----<| | | | | <----- Augmented message | +----+----+----+----+ | ^ | | | XOR | | | 0+----+----+----+----+ Algorithm v +----+----+----+----+ --------- | +----+----+----+----+ 1. Shift the register left by | +----+----+----+----+ one byte, reading in a new | +----+----+----+----+ message byte. | +----+----+----+----+ 2. Use the top byte just rotated | +----+----+----+----+ out of the register to index +----->+----+----+----+----+ the table of 256 32-bit values. +----+----+----+----+ 3. XOR the table value into the +----+----+----+----+ register. +----+----+----+----+ 4. Goto 1 iff more augmented +----+----+----+----+ message bytes. 255+----+----+----+----+In C, the algorithm main loop looks like this: r=0; while (len--) { byte t = (r >> 24) & 0xFF; r = (r << 8) | *p++; r^=table[t]; }where len is the length of the augmented message in bytes, p points tothe augmented message, r is the register, t is a temporary, and tableis the computed table. This code can be made even more unreadable asfollows: r=0; while (len--) r = ((r << 8) | *p++) ^ t[(r >> 24) & 0xFF];This is a very clean, efficient loop, although not a very obvious oneto the casual observer not versed in CRC theory. We will call this the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -