Hi Did,
"Didi" wrote in message news: snipped-for-privacy@d70g2000hsb.googlegroups.com... "So how quickly did you do it the first time? (copying, if you just found it and took it, does not count)."
I found the algorithm's description in "pseudo-code" and just "translated" that to C. Translating assembly wouldn't have been that much harder, granted, but it still would have taken longer and been more prone to error, IMO.
I am all for people sitting around and spending the time to write highly-optimized code in assembly when the job calls for it (and your code at
While I'd grant that working in something like C occasionally takes more time when you need to get at the hardware, in any reasonably complex system overall there are great timesavings to be had. I'd even bet that John would start programming that 68k CPUs of his in PowerBASIC if it were available to run on them, for instance!
" Can you produce the binary (or, better, the native machine code as I did) for your code?"
Sure... this is for an AVR CPU with the IAR compiler. Notice that what really slows down this code is that we're forcing a little 8 bit CPU to calculate 32 bit CRCs, there's there's a lot of register thrashing:
98 ULONG CalcCRC(ULONG rc,const UCHAR* buf,UINT len) \\ CalcCRC: 99 { \\ 00000000 ........ CALL ?PROLOGUE8_L09 \\ 00000004 REQUIRE ?Register_R4_is_cg_reg \\ 00000004 REQUIRE ?Register_R5_is_cg_reg \\ 00000004 REQUIRE ?Register_R6_is_cg_reg \\ 00000004 REQUIRE ?Register_R7_is_cg_reg \\ 00000004 0108 MOVW R1:R0, R17:R16 \\ 00000006 0119 MOVW R3:R2, R19:R18 \\ 00000008 01DA MOVW R27:R26, R21:R20 \\ 0000000A C01D RJMP ??CalcCRC_0 100 while (len > 0) 101 { 102 UCHAR nb = *buf; \\ ??CalcCRC_1: \\ 0000000C 912C LD R18, X 103 UCHAR i = (rc & 0xff); \\ 0000000E 0180 MOVW R17:R16, R1:R0 104 i ^= nb; \\ 00000010 2702 EOR R16, R18 105 rc = rc >> 8; \\ 00000012 2C01 MOV R0, R1 \\ 00000014 2C12 MOV R1, R2 \\ 00000016 2C23 MOV R2, R3 \\ 00000018 2433 CLR R3 106 rc ^= CRCTable [i]; \\ 0000001A .... LDI R30, LOW(CRCTable) \\ 0000001C .... LDI R31, HIGH(CRCTable) \\ 0000001E .... LDI R19, (CRCTable) >> 16 \\ 00000020 E010 LDI R17, 0 \\ 00000022 0F00 LSL R16 \\ 00000024 1F11 ROL R17 \\ 00000026 0F00 LSL R16 \\ 00000028 1F11 ROL R17 \\ 0000002A 0FE0 ADD R30, R16 \\ 0000002C 1FF1 ADC R31, R17 \\ 0000002E BF3B OUT 0x3B, R19 \\ 00000030 9047 ELPM R4, Z+ \\ 00000032 9057 ELPM R5, Z+ \\ 00000034 9067 ELPM R6, Z+ \\ 00000036 9076 ELPM R7, Z \\ 00000038 2404 EOR R0, R4 \\ 0000003A 2415 EOR R1, R5 \\ 0000003C 2426 EOR R2, R6 \\ 0000003E 2437 EOR R3, R7 107 buf++; \\ 00000040 9611 ADIW R27:R26, 1 108 len--; \\ 00000042 5061 SUBI R22, 1 \\ 00000044 4070 SBCI R23, 0 109 } \\ ??CalcCRC_0: \\ 00000046 2F06 MOV R16, R22 \\ 00000048 2B07 OR R16, R23 \\ 0000004A F701 BRNE ??CalcCRC_1 110 111 return rc; \\ 0000004C 0180 MOVW R17:R16, R1:R0 \\ 0000004E 0191 MOVW R19:R18, R3:R2 \\ 00000050 E0E8 LDI R30, 8 \\ 00000052 ........ JMP ?EPILOGUE_B8_L09 112 }"I leave it to the rest of the group to say which piece of code is easier to read and understand - and thus keep under control."
I'd vote for neither one, since for something like a CRC understanding how a CRC really works (that you're more or less computing the remainder of one verrryyyy long division using almost-but-not-quite modulo-n arithmetic, but, oh, wait... sometimes people do things bit-reversed and use various starting and ending XORs for various purposes... and then to do things efficiently you can start using table lookup to process multiple bits at once...) is a lot harder than understanding either of the pieces of code.
---Joel