|
Оптимизация алгоритма на С, вопрос к знатокам компиляторов |
|
|
|
Aug 23 2006, 21:50
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Есть два варианта функции вычисления CRC: Код unsigned char code[8]={0x01,0xd0,0x5e,0x3c,0x0d,0x00,0x00,0x84};
unsigned char crc8_1(unsigned char *buff,unsigned char num) { unsigned char i=0,j,tmp,data,crc=0; for (i=0;i<num;i++) { data=*buff++; for (j=0;j<8;j++) { tmp=1&(data^crc); crc>>=1; data>>=1; if (tmp!=0) crc^=0x8c; } } return crc; }
unsigned char crc8_2(unsigned char *buff,unsigned char num) { unsigned char i=num,j,tmp,data,crc=0; for (;i>0;i--) { data=*buff++; for (j=8;j>0;j--) { tmp=1&(data^crc); crc>>=1; data>>=1; if (tmp!=0) crc^=0x8c; } } return crc; }
int main(int argc, char* argv[]) { unsigned char crc_; crc_=crc8_1(code,7); crc_=crc8_2(code,7); return 0; } Как видно из рисунка, это собственно один и тот же алгоритм. Но, при компиляции под WinAVR(gcc), при любом уровне оптимизации, второй вариант работает на 10-15% быстрее. Собственно вопрос: а есть ли компилятор который может скомпилировать эти две(одинаковых!) функции в одинаковый(быстрый) код ?
|
|
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 44)
|
Aug 24 2006, 07:52
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555

|
конечно 2 вариант быстрее! дело в организации цикла! он скомпилируется по другому примерно так: Код mov r16, 8 loop: ..... ..... dec r16 brne loop а 1 вариант подразумевает лишнюю команду сравнения Код mov r16, 0 loop: ..... ..... inc r16 cpi r16, 8 brcs loop а вообще для полной потимизации я пишу такие циклы так Код j=8; do { .... .... }while(--j);
|
|
|
|
|
Aug 24 2006, 07:56
|
Знающий
   
Группа: Свой
Сообщений: 550
Регистрация: 16-06-04
Из: Казань
Пользователь №: 32

|
Цитата(singlskv @ Aug 24 2006, 01:50)  Собственно вопрос: а есть ли компилятор который может скомпилировать эти две(одинаковых!) функции в одинаковый(быстрый) код ? IAR.
--------------------
Главная линия этого опуса ясна мне насквозь!
|
|
|
|
|
Aug 24 2006, 09:41
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(defunct @ Aug 24 2006, 04:36)  Вы уверены что у вас считается именно CRC? Да уверен. Это CRC для 1-wire по полиному X8+X5+X4+1. Цитата(KRS @ Aug 24 2006, 11:52)  конечно 2 вариант быстрее! дело в организации цикла! Ну в этом и вопрос, умеет ли какой-нибудь компилятор разбираться с такой ситуацией. Цитата(vet @ Aug 24 2006, 10:56)  Цитата(singlskv @ Aug 24 2006, 01:50)  Собственно вопрос: а есть ли компилятор который может скомпилировать эти две(одинаковых!) функции в одинаковый(быстрый) код ? IAR. Вы проверяли ? Если да, то сообщите пожалуйста сколько тактов получилось у каждой функции при наилучшей оптимизации. Цитата(Old1 @ Aug 24 2006, 13:28)  К сожалению нет времени проверять... Вы уверены, что IAR эти функции скомпилирует одинаково оптимально? Вопрос задаю потому, что сами ИАРовцы рекомендуют (AN AVR035) для оптимизации кода по возможности использовать вычитающие циклические счетчики и предварительный декремент. Собственно, если кто проверит, сообщите результат.
|
|
|
|
|
Aug 24 2006, 10:20
|
Знающий
   
Группа: Свой
Сообщений: 550
Регистрация: 16-06-04
Из: Казань
Пользователь №: 32

|
Скомпилировал в IAR 4.11A два цикла for с инкрементом от 0 до 8 и декрементом от 8 до 0, макс.оптимизация по скорости. Код одинаков. Код RSEG CODE:CODE:NOROOT(1) // 3 void main() { main: // 4 char i;
// 5 for (i=0;i<8;i++) { LDI R16, 8 // 6 asm("nop"); ??main_0: nop // 7 } DEC R16 BRNE ??main_0
// 8 for (i=8;i;i--) { LDI R16, 8 // 9 asm("nop"); ??main_1: nop // 10 } DEC R16 BRNE ??main_1
// 11 } RET Выкладываю листинг компиляции вышеприведённого исходника: Код RSEG CODE:CODE:NOROOT(1) // 3 unsigned char crc8_1(unsigned char *buff,unsigned char num) crc8_1: // 4 { // 5 unsigned char i=0,j,tmp,data,crc=0; LDI R21, 0 // 6 for (i=0;i<num;i++) { LDI R20, 0 RJMP ??crc8_1_0 // 7 data=*buff++; ??crc8_1_1: MOVW R31:R30, R17:R16 LD R23, Z+ MOVW R17:R16, R31:R30 // 8 for (j=0;j<8;j++) { LDI R19, 8 // 9 tmp=1&(data^crc); ??crc8_1_2: MOV R0, R23 BST R0, 0 CLR R0 BLD R0, 0 MOV R22, R21 ANDI R22, 0x01 EOR R22, R0 ANDI R22, 0x01 // 10 crc>>=1; LSR R21 // 11 data>>=1; LSR R23 // 12 if (tmp!=0) crc^=0x8c; TST R22 BREQ ??crc8_1_3 LDI R22, 140 EOR R21, R22 // 13 } ??crc8_1_3: DEC R19 BRNE ??crc8_1_2 // 14 } INC R20 ??crc8_1_0: CP R20, R18 BRCS ??crc8_1_1 // 15 return crc; MOV R16, R21 RET // 16 } // 17
RSEG CODE:CODE:NOROOT(1) // 18 unsigned char crc8_2(unsigned char *buff,unsigned char num) crc8_2: // 19 { // 20 unsigned char i=num,j,tmp,data,crc=0; MOV R19, R18 LDI R20, 0 RJMP ??crc8_2_0 // 21 for (;i>0;i--) { // 22 data=*buff++; ??crc8_2_1: MOVW R31:R30, R17:R16 LD R22, Z+ MOVW R17:R16, R31:R30 // 23 for (j=8;j>0;j--) { LDI R18, 8 // 24 tmp=1&(data^crc); ??crc8_2_2: MOV R23, R22 ANDI R23, 0x01 MOV R21, R20 ANDI R21, 0x01 EOR R21, R23 ANDI R21, 0x01 // 25 crc>>=1; LSR R20 // 26 data>>=1; LSR R22 // 27 if (tmp!=0) crc^=0x8c; TST R21 BREQ ??crc8_2_3 LDI R21, 140 EOR R20, R21 // 28 } ??crc8_2_3: DEC R18 BRNE ??crc8_2_2 // 29 } DEC R19 ??crc8_2_0: TST R19 BRNE ??crc8_2_1 // 30 return crc; MOV R16, R20 RET // 31 } // 32 Во второй функции компилятор решил задачу по-другому, но накладные расходы на цикл одинаковы в обеих функциях.
Сообщение отредактировал vet - Aug 24 2006, 10:37
--------------------
Главная линия этого опуса ясна мне насквозь!
|
|
|
|
|
Aug 24 2006, 12:41
|
Участник

Группа: Новичок
Сообщений: 44
Регистрация: 2-05-06
Пользователь №: 16 710

|
Цитата(singlskv @ Aug 24 2006, 13:41)  Да уверен. Это CRC для 1-wire по полиному X8+X5+X4+1. Код U8 CRC8_1 (U8 val, U8 crc) { U8 tmp; U8 i = 8; do { tmp = (val ^ crc) & 0x01; crc >>= 1; val >>= 1; if (tmp != 0) crc ^= 0x8c; } while (--i); return crc; }
U8 CRC8_2(U8 data, U8 crc) { U8 i = data ^ crc; crc = 0; if (i & 0x01) crc ^= 0x5e; if (i & 0x02) crc ^= 0xbc; if (i & 0x04) crc ^= 0x61; if (i & 0x08) crc ^= 0xc2; if (i & 0x10) crc ^= 0x9d; if (i & 0x20) crc ^= 0x23; if (i & 0x40) crc ^= 0x46; if (i & 0x80) crc ^= 0x8c; return crc; } CRC8_1 это твой вариант для одного байта. CRC8_2 имеет тот же полином, но работает значительно быстрее.
Сообщение отредактировал µµC - Aug 24 2006, 12:43
|
|
|
|
|
Aug 24 2006, 19:24
|
Участник

Группа: Новичок
Сообщений: 44
Регистрация: 2-05-06
Пользователь №: 16 710

|
Цитата(Old1 @ Aug 24 2006, 21:12)  Но если поставить оптимизацию по объему кода, то появляется тот эффект о котором писал автор, функция с циклом с декрементом выполняется быстрее. Человек явно ищет идеальный компилятор, а их, как известно, в природе не бывает. От программиста требуется хорошо знать какой будет код в какой ситуации, "чувствовать селезенкой", "заставлять" компилятор быть эффективным. Например: Код U8 CRC8_1 (U8 val, U8 crc) { U8 tmp; U8 i = 8; do { tmp = (val ^ crc) & 0x01; crc >>= 1; val >>= 1; if (tmp != 0) crc ^= 0x8c; } while (--i); return crc; }
U8 CRC8_1 (U8 val, U8 crc) { U8 tmp; U8 i = 8; do { tmp = (val ^ crc); crc >>= 1; val >>= 1; if (tmp & 0x01) crc ^= 0x8c; } while (--i); return crc; } 154 цикла к 122. А, казалось бы, от перемены мест ...
|
|
|
|
|
Aug 24 2006, 19:24
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(vet @ Aug 24 2006, 14:20)  Скомпилировал в IAR 4.11A два цикла for с инкрементом от 0 до 8 и декрементом от 8 до 0, макс.оптимизация по скорости. Код одинаков. Код RSEG CODE:CODE:NOROOT(1) // 3 void main() { main: // 4 char i;
// 5 for (i=0;i<8;i++) { LDI R16, 8 .............................................................. Вы попробуйте два вложенных цикла, как в моем примере, да и еще что нибудь кроме nop вставте в середину. Цитата(vet @ Aug 24 2006, 14:20)  Выкладываю листинг компиляции вышеприведённого исходника: Код RSEG CODE:CODE:NOROOT(1) // 3 unsigned char crc8_1(unsigned char *buff,unsigned char num) crc8_1: // 4 { // 5 unsigned char i=0,j,tmp,data,crc=0; LDI R21, 0 // 6 for (i=0;i<num;i++) { LDI R20, 0 RJMP ??crc8_1_0 // 7 data=*buff++; ??crc8_1_1: MOVW R31:R30, R17:R16 LD R23, Z+ MOVW R17:R16, R31:R30 // 8 for (j=0;j<8;j++) { LDI R19, 8 // 9 tmp=1&(data^crc); ??crc8_1_2: MOV R0, R23 BST R0, 0 CLR R0 BLD R0, 0 MOV R22, R21 ANDI R22, 0x01 EOR R22, R0 ANDI R22, 0x01 // 10 crc>>=1; LSR R21 // 11 data>>=1; LSR R23 // 12 if (tmp!=0) crc^=0x8c; TST R22 BREQ ??crc8_1_3 LDI R22, 140 EOR R21, R22 // 13 } ??crc8_1_3: DEC R19 BRNE ??crc8_1_2 // 14 } INC R20 ??crc8_1_0: CP R20, R18 BRCS ??crc8_1_1 // 15 return crc; MOV R16, R21 RET // 16 } // 17
RSEG CODE:CODE:NOROOT(1) // 18 unsigned char crc8_2(unsigned char *buff,unsigned char num) crc8_2: // 19 { // 20 unsigned char i=num,j,tmp,data,crc=0; MOV R19, R18 LDI R20, 0 RJMP ??crc8_2_0 // 21 for (;i>0;i--) { // 22 data=*buff++; ??crc8_2_1: MOVW R31:R30, R17:R16 LD R22, Z+ MOVW R17:R16, R31:R30 // 23 for (j=8;j>0;j--) { LDI R18, 8 // 24 tmp=1&(data^crc); ??crc8_2_2: MOV R23, R22 ANDI R23, 0x01 MOV R21, R20 ANDI R21, 0x01 EOR R21, R23 ANDI R21, 0x01 // 25 crc>>=1; LSR R20 // 26 data>>=1; LSR R22 // 27 if (tmp!=0) crc^=0x8c; TST R21 BREQ ??crc8_2_3 LDI R21, 140 EOR R20, R21 // 28 } ??crc8_2_3: DEC R18 BRNE ??crc8_2_2 // 29 } DEC R19 ??crc8_2_0: TST R19 BRNE ??crc8_2_1 // 30 return crc; MOV R16, R20 RET // 31 } // 32 Во второй функции компилятор решил задачу по-другому, но накладные расходы на цикл одинаковы в обеих функциях. Просимулировал Ваш код в AVR Studio. Итого: (для семи байт) crc8_1 986 тактов crc8_2 774 такта разница слегка удивила, это уже 25%. очень повеселил этот код: Код MOVW R31:R30, R17:R16 LD R22, Z+ MOVW R17:R16, R31:R30 и так 7 раз подряд
|
|
|
|
|
Aug 24 2006, 19:35
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(µµC @ Aug 24 2006, 16:41)  Цитата(singlskv @ Aug 24 2006, 13:41)  Да уверен. Это CRC для 1-wire по полиному X8+X5+X4+1.
Код U8 CRC8_1 (U8 val, U8 crc) { U8 tmp; U8 i = 8; do { tmp = (val ^ crc) & 0x01; crc >>= 1; val >>= 1; if (tmp != 0) crc ^= 0x8c; } while (--i); return crc; }
U8 CRC8_2(U8 data, U8 crc) { U8 i = data ^ crc; crc = 0; if (i & 0x01) crc ^= 0x5e; if (i & 0x02) crc ^= 0xbc; if (i & 0x04) crc ^= 0x61; if (i & 0x08) crc ^= 0xc2; if (i & 0x10) crc ^= 0x9d; if (i & 0x20) crc ^= 0x23; if (i & 0x40) crc ^= 0x46; if (i & 0x80) crc ^= 0x8c; return crc; } CRC8_1 это твой вариант для одного байта. CRC8_2 имеет тот же полином, но работает значительно быстрее. Если несложно, то просимулируйте для 7 байт(как в изначальной задаче), и напишите сколько получилось тактов для этих двух вариантов.
|
|
|
|
|
Aug 24 2006, 20:20
|
Участник

Группа: Новичок
Сообщений: 44
Регистрация: 2-05-06
Пользователь №: 16 710

|
Цитата(singlskv @ Aug 24 2006, 23:35)  Если несложно, то просимулируйте для 7 байт(как в изначальной задаче), и напишите сколько получилось тактов для этих двух вариантов. Код #define U8 unsigned char
U8 code[8] = {0x01, 0xd0, 0x5e, 0x3c, 0x0d, 0x00, 0x00, 0x84};
U8 crc8_1(U8 *buff, U8 num) { U8 i, tmp, val, crc = 0; do { val = *buff++; i = 8; do { tmp = (val ^ crc); crc >>= 1; val >>= 1; if (tmp & 0x01) crc ^= 0x8c; } while (--i); } while (--num); return crc; }
U8 crc8_2(U8 *buff, U8 num) { U8 val, crc = 0; do { val = *buff++; val ^= crc; crc = 0; if(val & 0x01) crc ^= 0x5e; if(val & 0x02) crc ^= 0xbc; if(val & 0x04) crc ^= 0x61; if(val & 0x08) crc ^= 0xc2; if(val & 0x10) crc ^= 0x9d; if(val & 0x20) crc ^= 0x23; if(val & 0x40) crc ^= 0x46; if(val & 0x80) crc ^= 0x8c; } while (--num); return crc; }
volatile U8 result[4];
void main(void) { while (1) { result[0] = crc8_1(code, 7); //649 result[1] = crc8_2(code, 7); //265 result[2] = crc8_1(code, 7); result[3] = crc8_2(code, 7); } } IAR, opt = max speed, остальные опции выкл. 649 циклов к 265.
|
|
|
|
|
Aug 24 2006, 20:29
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(µµC @ Aug 24 2006, 23:24)  Человек явно ищет идеальный компилятор, а их, как известно, в природе не бывает. Лучший компилятор это человек. на ASM у меня получилось 530 тактов: Код crc8: ;Input: X - buffer; r17 - number of bytes ;Output: r16 = CRC
ldi r16,0 ;CRC ldi r20,0x8c crc8_1: ld r18,X+ ldi r19,8 crc8_2: lsr r16 brbc 0,crc8_3 eor r16,r20 crc8_3: sbrc r18,0 eor r16,r20 lsr r18 crc8_4: dec r19 brne crc8_2 dec r17 brne crc8_1
ret НО, надо отдать должное WinAVR(gcc) ИТОГО: Код CRC8_1 CRC8_2 WinAVR(-o1) 620 556 WinAVR(-o2) 620 556 WinAVR(-o3) 606 544
IAR 986 774
ASM 530 У WinAVR(-o3) удалось украсть всего 14 тактов, то есть по 2 такта на основной цикл. Приятно удививший результат А с IAR просто какая-то лабудень, возможно Вы vet там чего-то не то указали при оптимизации?
|
|
|
|
|
Aug 24 2006, 20:41
|
Участник

Группа: Новичок
Сообщений: 44
Регистрация: 2-05-06
Пользователь №: 16 710

|
Цитата(singlskv @ Aug 25 2006, 00:29)  Лучший компилятор это человек. Не спорю, лучший. Только слишком дорогой и медленный, а в остальном ... лучший.
|
|
|
|
|
Aug 24 2006, 20:45
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(µµC @ Aug 25 2006, 00:20)  Цитата(singlskv @ Aug 24 2006, 23:35)  Если несложно, то просимулируйте для 7 байт(как в изначальной задаче), и напишите сколько получилось тактов для этих двух вариантов.
Код #define U8 unsigned char
U8 code[8] = {0x01, 0xd0, 0x5e, 0x3c, 0x0d, 0x00, 0x00, 0x84};
U8 crc8_1(U8 *buff, U8 num) { U8 i, tmp, val, crc = 0; do { val = *buff++; i = 8; do { tmp = (val ^ crc); crc >>= 1; val >>= 1; if (tmp & 0x01) crc ^= 0x8c; } while (--i); } while (--num); return crc; }
U8 crc8_2(U8 *buff, U8 num) { U8 val, crc = 0; do { val = *buff++; val ^= crc; crc = 0; if(val & 0x01) crc ^= 0x5e; if(val & 0x02) crc ^= 0xbc; if(val & 0x04) crc ^= 0x61; if(val & 0x08) crc ^= 0xc2; if(val & 0x10) crc ^= 0x9d; if(val & 0x20) crc ^= 0x23; if(val & 0x40) crc ^= 0x46; if(val & 0x80) crc ^= 0x8c; } while (--num); return crc; }
volatile U8 result[4];
void main(void) { while (1) { result[0] = crc8_1(code, 7); //649 result[1] = crc8_2(code, 7); //265 result[2] = crc8_1(code, 7); result[3] = crc8_2(code, 7); } } IAR, opt = max speed, остальные опции выкл. 649 циклов к 265. 649 уже намного ближе к правде (если не сложно, листинг в студию), но у WinAVR 544. 265 - отличный результат, но мы обсуждаем алгоритм(оптимизацию компилятором) в общем виде (таблицой из 256 значений как в даташите "1-wire" все равно быстрее).
|
|
|
|
|
Aug 24 2006, 21:00
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(µµC @ Aug 24 2006, 23:41)  Цитата(singlskv @ Aug 25 2006, 00:29)  Лучший компилятор это человек.
Не спорю, лучший. Только слишком дорогой и медленный.. и 'ломается' на больших кусках кода :-( Цитата(singlskv @ Aug 24 2006, 23:45)  в общем виде (таблицой из 256 значений как в даташите "1-wire" все равно быстрее). Быстрее :-) сопроцессор поставить.... Код //--------------------------------------------------------------------------- // Verilog module containing a synthesizable CRC8 function // - Polynomial: (8 5 4 0) // - Data width: 8 // - CRC width : 8 // - Mirror //--------------------------------------------------------------------------- module CRC8_8540;
function [7:0] nextCRC;
input [7:0] Data; input [7:0] CRC;
reg [7:0] D; reg [7:0] C; reg [7:0] xCRC;
begin
D = Data; C = CRC;
// Mirror DATA and final CRC xCRC[7] = D[1]^D[3]^D[4]^D[7]^C[7]^C[4]^C[3]^C[1]; xCRC[6] = D[0]^D[2]^D[3]^D[6]^C[6]^C[3]^C[2]^C[0]; xCRC[5] = D[1]^D[2]^D[5]^C[5]^C[2]^C[1]; xCRC[4] = D[0]^D[1]^D[4]^C[4]^C[1]^C[0]; xCRC[3] = D[0]^D[1]^D[4]^D[7]^C[7]^C[4]^C[1]^C[0]; xCRC[2] = D[0]^D[1]^D[4]^D[6]^D[7]^C[7]^C[6]^C[4]^C[1]^C[0]; xCRC[1] = D[0]^D[3]^D[5]^D[6]^C[6]^C[5]^C[3]^C[0]; xCRC[0] = D[2]^D[4]^D[5]^C[5]^C[4]^C[2];
nextCRC = xCRC;
end
endfunction
endmodule Извините :-( Настроение сегодня такое :-). А верилоговский код рабочий под Dallas - вдруг кому пригодится. Использую я его, поскольку полином хорош для любых небольших пакетов.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Aug 24 2006, 21:03
|
Участник

Группа: Новичок
Сообщений: 44
Регистрация: 2-05-06
Пользователь №: 16 710

|
Цитата(singlskv @ Aug 25 2006, 00:45)  если не сложно, листинг в студию NAME crc8 RSEG CSTACK:DATA:NOROOT(0) RSEG RSTACK:DATA:NOROOT(0) EXTERN ?need_segment_init PUBWEAK `?<Segment init: TINY_I>` PUBWEAK `?<Segment init: TINY_Z>` PUBWEAK __?EEARL PUBWEAK __?EECR PUBWEAK __?EEDR PUBLIC code PUBLIC crc8_1 PUBLIC crc8_2 PUBLIC main PUBLIC result RSEG TINY_I:DATA:NOROOT(0) REQUIRE `?<Segment init: TINY_I>` // 49 U8 code[8] = {0x01, 0xd0, 0x5e, 0x3c, 0x0d, 0x00, 0x00, 0x84}; code: DS 8 REQUIRE `?<Initializer for code>` // 50 RSEG CODE:CODE:NOROOT(1) // 51 U8 crc8_1(U8 *buff, U8 num) crc8_1: // 52 { // 53 U8 i, tmp, val, crc = 0; LDI R19, 0 // 54 // 55 do { // 56 val = *buff++; ??crc8_1_0: MOV R30, R16 LD R21, Z+ MOV R16, R30 // 57 i = 8; LDI R18, 8 // 58 do { // 59 tmp = (val ^ crc); ??crc8_1_1: MOV R20, R19 EOR R20, R21 // 60 crc >>= 1; LSR R19 // 61 val >>= 1; LSR R21 // 62 if (tmp & 0x01) crc ^= 0x8c; BST R20, 0 BRTC ??crc8_1_2 LDI R20, 140 EOR R19, R20 // 63 } while (--i); ??crc8_1_2: DEC R18 BRNE ??crc8_1_1 // 64 } while (--num); DEC R17 BRNE ??crc8_1_0 // 65 return crc; MOV R16, R19 RET // 66 } // 67 RSEG CODE:CODE:NOROOT(1) // 68 U8 crc8_2(U8 *buff, U8 num) crc8_2: // 69 { // 70 U8 val, crc = 0; LDI R18, 0 // 71 // 72 do { // 73 val = *buff++; ??crc8_2_0: MOV R30, R16 LD R20, Z+ MOV R16, R30 // 74 val ^= crc; EOR R20, R18 // 75 crc = 0; LDI R18, 0 // 76 if(val & 0x01) crc ^= 0x5e; BST R20, 0 BRTC ??crc8_2_1 LDI R18, 94 // 77 if(val & 0x02) crc ^= 0xbc; ??crc8_2_1: BST R20, 1 BRTC ??crc8_2_2 LDI R19, 188 EOR R18, R19 // 78 if(val & 0x04) crc ^= 0x61; ??crc8_2_2: BST R20, 2 BRTC ??crc8_2_3 LDI R19, 97 EOR R18, R19 // 79 if(val & 0x08) crc ^= 0xc2; ??crc8_2_3: BST R20, 3 BRTC ??crc8_2_4 LDI R19, 194 EOR R18, R19 // 80 if(val & 0x10) crc ^= 0x9d; ??crc8_2_4: BST R20, 4 BRTC ??crc8_2_5 LDI R19, 157 EOR R18, R19 // 81 if(val & 0x20) crc ^= 0x23; ??crc8_2_5: BST R20, 5 BRTC ??crc8_2_6 LDI R19, 35 EOR R18, R19 // 82 if(val & 0x40) crc ^= 0x46; ??crc8_2_6: BST R20, 6 BRTC ??crc8_2_7 LDI R19, 70 EOR R18, R19 // 83 if(val & 0x80) crc ^= 0x8c; ??crc8_2_7: BST R20, 7 BRTC ??crc8_2_8 LDI R19, 140 EOR R18, R19 // 84 } while (--num); ??crc8_2_8: DEC R17 BRNE ??crc8_2_0 // 85 return crc; MOV R16, R18 RET // 86 } // 87 RSEG TINY_Z:DATA:NOROOT(0) REQUIRE `?<Segment init: TINY_Z>` // 88 volatile U8 result[4]; result: DS 4 // 89 RSEG CODE:CODE:NOROOT(1) // 90 void main(void) main: ??main_0: // 91 { // 92 while (1) { // 93 result[0] = crc8_1(code, 7); //649 LDI R17, 7 LDI R16, code RCALL crc8_1 LDI R30, result ST Z, R16 // 94 result[1] = crc8_2(code, 7); //265 LDI R17, 7 LDI R16, code RCALL crc8_2 LDI R30, result STD Z+1, R16 // 95 result[2] = crc8_1(code, 7); LDI R17, 7 LDI R16, code RCALL crc8_1 LDI R30, result STD Z+2, R16 // 96 result[3] = crc8_2(code, 7); LDI R17, 7 LDI R16, code RCALL crc8_2 LDI R30, result STD Z+3, R16 RJMP ??main_0 // 97 } // 98 } ASEGN ABSOLUTE:DATA:NOROOT,01cH __?EECR: ASEGN ABSOLUTE:DATA:NOROOT,01dH __?EEDR: ASEGN ABSOLUTE:DATA:NOROOT,01eH __?EEARL: RSEG TINY_ID:CODE:NOROOT(0) `?<Initializer for code>`: DB 1, 208, 94, 60, 13, 0, 0, 132 RSEG INITTAB:CODE:NOROOT(0) `?<Segment init: TINY_I>`: DB SFE(TINY_I) - SFB(TINY_I) DB SFB(TINY_I) DW SFB(TINY_ID) REQUIRE ?need_segment_init RSEG INITTAB:CODE:NOROOT(0) `?<Segment init: TINY_Z>`: DB SFE(TINY_Z) - SFB(TINY_Z) DB SFB(TINY_Z) DW 0 REQUIRE ?need_segment_init END
|
|
|
|
|
Aug 24 2006, 21:20
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(µµC @ Aug 25 2006, 01:03)  Цитата(singlskv @ Aug 25 2006, 00:45)  если не сложно, листинг в студию
..................... ..................... LDI R20, 140 EOR R19, R20 ..................... ..................... Ну вот она, похоже основная ошибка IAR, он загружает 0x8c много раз подряд. И еще какие-то лишние mov делает. Это код WinAVR(-o3): Код @00000045: crc8_2 20: { +00000045: 2FF9 MOV R31,R25 Copy register +00000046: 2FE8 MOV R30,R24 Copy register 21: unsigned char i=num,j,tmp,data,crc=0; +00000047: E090 LDI R25,0x00 Load immediate 22: for (;i>0;i--) { +00000048: 2366 TST R22 Test for Zero or Minus +00000049: F069 BREQ PC+0x0E Branch if equal +0000004A: E84C LDI R20,0x8C Load immediate 23: data=*buff++; +0000004B: 9121 LD R18,Z+ Load indirect and postincrement 24: for (j=8;j>0;j--) { +0000004C: E038 LDI R19,0x08 Load immediate 25: tmp=1&(data^crc); +0000004D: 2F82 MOV R24,R18 Copy register +0000004E: 2789 EOR R24,R25 Exclusive OR 26: crc>>=1; +0000004F: 9596 LSR R25 Logical shift right 27: data>>=1; +00000050: 9526 LSR R18 Logical shift right 28: if (tmp!=0) crc^=0x8c; +00000051: FD80 SBRC R24,0 Skip if bit in register cleared +00000052: 2794 EOR R25,R20 Exclusive OR +00000053: 5031 SUBI R19,0x01 Subtract immediate +00000054: F7C1 BRNE PC-0x07 Branch if not equal +00000055: 5061 SUBI R22,0x01 Subtract immediate +00000056: F7A1 BRNE PC-0x0B Branch if not equal 32: } +00000057: 2F89 MOV R24,R25 Copy register +00000058: 2799 CLR R25 Clear Register +00000059: 9508 RET Subroutine return
|
|
|
|
|
Aug 24 2006, 21:50
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Aug 25 2006, 01:00)  Быстрее :-) сопроцессор поставить.... Код //--------------------------------------------------------------------------- // Verilog module containing a synthesizable CRC8 function // - Polynomial: (8 5 4 0) // - Data width: 8 // - CRC width : 8 // - Mirror //--------------------------------------------------------------------------- module CRC8_8540;
function [7:0] nextCRC;
input [7:0] Data; input [7:0] CRC;
reg [7:0] D; reg [7:0] C; reg [7:0] xCRC;
begin
D = Data; C = CRC;
// Mirror DATA and final CRC xCRC[7] = D[1]^D[3]^D[4]^D[7]^C[7]^C[4]^C[3]^C[1]; xCRC[6] = D[0]^D[2]^D[3]^D[6]^C[6]^C[3]^C[2]^C[0]; xCRC[5] = D[1]^D[2]^D[5]^C[5]^C[2]^C[1]; xCRC[4] = D[0]^D[1]^D[4]^C[4]^C[1]^C[0]; xCRC[3] = D[0]^D[1]^D[4]^D[7]^C[7]^C[4]^C[1]^C[0]; xCRC[2] = D[0]^D[1]^D[4]^D[6]^D[7]^C[7]^C[6]^C[4]^C[1]^C[0]; xCRC[1] = D[0]^D[3]^D[5]^D[6]^C[6]^C[5]^C[3]^C[0]; xCRC[0] = D[2]^D[4]^D[5]^C[5]^C[4]^C[2];
nextCRC = xCRC;
end
endfunction
endmodule Ну, это уже из пушки по воробьям Хотя, если есть свободные ресурсы, то почему бы и нет
|
|
|
|
Guest_Serg79_*
|
Aug 25 2006, 06:07
|
Guests

|
В таких случаях поступают намного проше, пишут функцию на ASM и не ломают голову на счет компилятора. Код /** \ingroup util_crc Optimized Dallas (now Maxim) iButton 8-bit CRC calculation.
Polynomial: x^8 + x^5 + x^4 + 1 (0x8C)<br> Initial value: 0x0
See http://www.maxim-ic.com/appnotes.cfm/appnote_number/27
The following is the equivalent functionality written in C.
\code uint8_t _crc_ibutton_update(uint8_t crc, uint8_t data) { uint8_t i;
crc = crc ^ data; for (i = 0; i < 8; i++) { if (crc & 0x01) crc = (crc >> 1) ^ 0x8C; else crc >>= 1; }
return crc; } \endcode */
static __inline__ uint8_t _crc_ibutton_update(uint8_t __crc, uint8_t __data) { uint8_t __i, __pattern; __asm__ __volatile__ ( " eor %0, %4" "\n\t" " ldi %1, 8" "\n\t" " ldi %2, 0x8C" "\n\t" "1: bst %0, 0" "\n\t" " lsr %0" "\n\t" " brtc 2f" "\n\t" " eor %0, %2" "\n\t" "2: dec %1" "\n\t" " brne 1b" "\n\t" : "=r" (__crc), "=d" (__i), "=d" (__pattern) : "0" (__crc), "r" (__data)); return __crc; } И я так думаю, что эта функция будет работать быстрее приведенных выше. Реализация функции взята из заголовочного файла "crc16.h" компилятора WinAVR. А принцип простой: не изобретай велосипед. Лучше направить свои усилия на что то новое, чем пытаться заново писать стандартные функции, реализованные в библиотеках идущих вместе с компилятором.
|
|
|
|
|
Aug 25 2006, 06:13
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата(singlskv @ Aug 24 2006, 22:24)  очень повеселил этот код: Код MOVW R31:R30, R17:R16 LD R22, Z+ MOVW R17:R16, R31:R30 и так 7 раз подряд  Хорошо поможет Код __z unsigned char crc8_2(unsigned char *buff,unsigned char num) А циклы ОЧЕНЬ желательно делать Код do{}while(--var); это помогает почти всем компиляторам и процессорам, обычно архитектура процессора позволяет изготовить нечто такое: Код DEC var JUMP_IF_NZ label
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Aug 25 2006, 08:24
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Serg79 @ Aug 25 2006, 10:07)  В таких случаях поступают намного проше, пишут функцию на ASM и не ломают голову на счет компилятора. Код /** \ingroup util_crc Optimized Dallas (now Maxim) iButton 8-bit CRC calculation.
Polynomial: x^8 + x^5 + x^4 + 1 (0x8C)<br> Initial value: 0x0
See http://www.maxim-ic.com/appnotes.cfm/appnote_number/27
The following is the equivalent functionality written in C.
\code uint8_t _crc_ibutton_update(uint8_t crc, uint8_t data) { uint8_t i;
crc = crc ^ data; for (i = 0; i < 8; i++) { if (crc & 0x01) crc = (crc >> 1) ^ 0x8C; else crc >>= 1; }
return crc; } \endcode */
static __inline__ uint8_t _crc_ibutton_update(uint8_t __crc, uint8_t __data) { uint8_t __i, __pattern; __asm__ __volatile__ ( " eor %0, %4" "\n\t" " ldi %1, 8" "\n\t" " ldi %2, 0x8C" "\n\t" "1: bst %0, 0" "\n\t" " lsr %0" "\n\t" " brtc 2f" "\n\t" " eor %0, %2" "\n\t" "2: dec %1" "\n\t" " brne 1b" "\n\t" : "=r" (__crc), "=d" (__i), "=d" (__pattern) : "0" (__crc), "r" (__data)); return __crc; } И я так думаю, что эта функция будет работать быстрее приведенных выше. Реализация функции взята из заголовочного файла "crc16.h" компилятора WinAVR. А принцип простой: не изобретай велосипед. Лучше направить свои усилия на что то новое, чем пытаться заново писать стандартные функции, реализованные в библиотеках идущих вместе с компилятором. Думать не нужно, надо пробовать (С). Выполните Ваш код для 7 байтов, а потом внимательно перечитайте весь топик. Цитата(Rst7 @ Aug 25 2006, 10:13)  Цитата(singlskv @ Aug 24 2006, 22:24)  очень повеселил этот код: Код MOVW R31:R30, R17:R16 LD R22, Z+ MOVW R17:R16, R31:R30 и так 7 раз подряд  Хорошо поможет Код __z unsigned char crc8_2(unsigned char *buff,unsigned char num) Вот это ОЧЕНЬ ценный совет Цитата(Rst7 @ Aug 25 2006, 10:13)  А циклы ОЧЕНЬ желательно делать Код do{}while(--var); это помогает почти всем компиляторам и процессорам, обычно архитектура процессора позволяет изготовить нечто такое: Код DEC var JUMP_IF_NZ label Ну с этим никто и не спорит, только это уже получается не "оптимизирующий" компилятор, а "оптимизируемый пользователем" компилятор.
|
|
|
|
|
Aug 25 2006, 08:42
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата(singlskv @ Aug 25 2006, 11:24)  Ну с этим никто и не спорит, только это уже получается не "оптимизирующий" компилятор, а "оптимизируемый пользователем" компилятор. А вдруг завтра прийдется что-то написать для другого проца с совсем другим компилятором? А? Это в крови должно быть  О чем многие тут и толкуют... Почитайте темы про "идеальные компиляторы"... PS Кстати, IAR 4.40 для ARM такие циклы for переделывает в do{}while как 2 пальца... А вот для AVR видно старый оптимизатор внутри, хоть и 4.20... Переделка эта ведь перед code-генератором происходит, так что вполне мог бы и на AVR делать такое...
Сообщение отредактировал Rst7 - Aug 25 2006, 08:43
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Aug 25 2006, 11:17
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(singlskv @ Aug 24 2006, 23:29)  Цитата(µµC @ Aug 24 2006, 23:24)  Человек явно ищет идеальный компилятор, а их, как известно, в природе не бывает.
Лучший компилятор это человек. на ASM у меня получилось 530 тактов: Код crc8:;Input: X - buffer; r17 - number of bytes ;Output: r16 = CRC
ldi r16,0;CRC ldi r20,0x8c crc8_1: ld r18,X+ ldi r19,8 crc8_2: lsr r16 brbc 0,crc8_3 eor r16,r20 crc8_3: sbrc r18,0 eor r16,r20 lsr r18 crc8_4: dec r19 brne crc8_2 dec r17 brne crc8_1
ret НО, надо отдать должное WinAVR(gcc) ИТОГО: Код CRC8_1 CRC8_2 WinAVR(-o1) 620 556 WinAVR(-o2) 620 556 WinAVR(-o3) 606 544
IAR 986 774
ASM 530 У WinAVR(-o3) удалось украсть всего 14 тактов, то есть по 2 такта на основной цикл. Приятно удививший результат А с IAR просто какая-то лабудень, возможно Вы vet там чего-то не то указали при оптимизации? Вся проблема в том, что компилятор использует определенные соглашения по передаче параметров и использованию регистров. Ваша функция под соглашения, принятые, например, в IAR, не попадает. Для стыковки с Си-шными функциями ее потребуется изменить с принятыми в компиляторе соглашениями. А это приведет к увеличению и размера кода, и увеличением времени его выполнения.
Сообщение отредактировал _Bill - Aug 25 2006, 11:33
|
|
|
|
|
Aug 25 2006, 11:26
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(_Bill @ Aug 25 2006, 15:17)  Цитата(singlskv @ Aug 24 2006, 23:29)  Цитата(µµC @ Aug 24 2006, 23:24)  Человек явно ищет идеальный компилятор, а их, как известно, в природе не бывает.
Лучший компилятор это человек. на ASM у меня получилось 530 тактов: Код crc8:;Input: X - buffer; r17 - number of bytes ;Output: r16 = CRC
ldi r16,0;CRC ldi r20,0x8c crc8_1: ld r18,X+ ldi r19,8 crc8_2: lsr r16 brbc 0,crc8_3 eor r16,r20 crc8_3: sbrc r18,0 eor r16,r20 lsr r18 crc8_4: dec r19 brne crc8_2 dec r17 brne crc8_1
ret НО, надо отдать должное WinAVR(gcc) ИТОГО: Код CRC8_1 CRC8_2 WinAVR(-o1) 620 556 WinAVR(-o2) 620 556 WinAVR(-o3) 606 544
IAR 986 774
ASM 530 У WinAVR(-o3) удалось украсть всего 14 тактов, то есть по 2 такта на основной цикл. Приятно удививший результат А с IAR просто какая-то лабудень, возможно Вы vet там чего-то не то указали при оптимизации? Вся проблема в том, что компилятор использует определенные соглашения по передаче параметров и использованию регистров. Ваша функция под соглашения, принятые, например, в IAR, не попадает. Для стыковки с Си-шными функциями ее потребуется изменить с принятыми в компиляторе соглашениями. А это приведет к увеличению и размера кода, и увеличением времени его выполнения. Цитата(singlskv @ Aug 24 2006, 23:29)  Цитата(µµC @ Aug 24 2006, 23:24)  Человек явно ищет идеальный компилятор, а их, как известно, в природе не бывает.
Лучший компилятор это человек. на ASM у меня получилось 530 тактов: Код crc8:;Input: X - buffer; r17 - number of bytes ;Output: r16 = CRC
ldi r16,0;CRC ldi r20,0x8c crc8_1: ld r18,X+ ldi r19,8 crc8_2: lsr r16 brbc 0,crc8_3 eor r16,r20 crc8_3: sbrc r18,0 eor r16,r20 lsr r18 crc8_4: dec r19 brne crc8_2 dec r17 brne crc8_1
ret НО, надо отдать должное WinAVR(gcc) ИТОГО: Код CRC8_1 CRC8_2 WinAVR(-o1) 620 556 WinAVR(-o2) 620 556 WinAVR(-o3) 606 544
IAR 986 774
ASM 530 У WinAVR(-o3) удалось украсть всего 14 тактов, то есть по 2 такта на основной цикл. Приятно удививший результат А с IAR просто какая-то лабудень, возможно Вы vet там чего-то не то указали при оптимизации? Вся проблема в том, что компилятор использует определенные соглашения по передаче параметров и использованию регистров. Ваша функция под соглашения, принятые, например, в IAR, не попадает. Для стыковки с Си-шными функциями ее потребуется изменить с принятыми в компиляторе соглашениями. А это приведет к увеличению и размера кода, и увеличением времени его выполнения. такты я считал по возможности честно, т.е. не учитывая такты потраченные на передачу параметров. А мой ASM код можно легко переписать под нужные регистры.  Да и разница в тактах что-то великовата, что бы ее объяснять только передачей параметров.
Сообщение отредактировал singlskv - Aug 25 2006, 11:39
|
|
|
|
|
Aug 25 2006, 11:47
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(singlskv @ Aug 25 2006, 14:26)  такты я считал по возможности честно, т.е. не учитывая такты потраченные на передачу параметров. А мой ASM код можно легко переписать под нужные регистры.  Не сомневаюсь, но код все равно получится длиннее. И, опять же, если Вы используете свои собственные соглашения по передаче параметров и использованию регистров в ваших модулях на ассемблере, то Вы будете вынуждены писать Ваши функции в соответствии с принятыми Вами соглашениями. А это неизбежно приведет к увеличению кода аналогично тому, как это делается компилятором. В свое время я написал небольшой опус на эту тему. К сожалению, он и сейчас далек от завершения.
|
|
|
|
|
Aug 25 2006, 12:30
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(_Bill @ Aug 25 2006, 15:47)  Цитата(singlskv @ Aug 25 2006, 14:26)  такты я считал по возможности честно, т.е. не учитывая такты потраченные на передачу параметров. А мой ASM код можно легко переписать под нужные регистры.  В свое время я написал небольшой опус на эту тему. К сожалению, он и сейчас далек от завершения. Несколько месяцев назад прочитал Ваш опус, очень понравилось Так что Вас можно считать идейным вдохновителем данного топика Цитата(_Bill @ Aug 25 2006, 15:47)  Не сомневаюсь, но код все равно получится длиннее. И, опять же, если Вы используете свои собственные соглашения по передаче параметров и использованию регистров в ваших модулях на ассемблере, то Вы будете вынуждены писать Ваши функции в соответствии с принятыми Вами соглашениями. А это неизбежно приведет к увеличению кода аналогично тому, как это делается компилятором. Вот код для IAR (если я ничего не напутал): Код crc8iar: ;Input: r17:r16 buffer; r18 - number of bytes ;Output: r16 = CRC
movw r31:r30,r17:r16 ldi r16,0 ;CRC ldi r19,0x8c crc8iar_1: ld r20,Z+ ldi r21,8 crc8iar_2: lsr r16 brbc 0,crc8iar_3 eor r16,r19 crc8iar_3: sbrc r20,0 eor r16,r19 lsr r20 crc8iar_4: dec r21 brne crc8iar_2 dec r18 brne crc8iar_1
ret Добавилась всего одна инструкция: Код movw r31:r30,r17:r16
|
|
|
|
|
Aug 25 2006, 12:59
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(singlskv @ Aug 25 2006, 15:30)  Вот код для IAR (если я ничего не напутал): Код crc8iar:;Input: r17:r16 buffer; r18 - number of bytes ;Output: r16 = CRC
movw r31:r30,r17:r16 ldi r16,0;CRC ldi r19,0x8c crc8iar_1: ld r20,Z+ ldi r21,8 crc8iar_2: lsr r16 brbc 0,crc8iar_3 eor r16,r19 crc8iar_3: sbrc r20,0 eor r16,r19 lsr r20 crc8iar_4: dec r21 brne crc8iar_2 dec r18 brne crc8iar_1
ret Добавилась всего одна инструкция: Код movw r31:r30,r17:r16 Вроде все правильно. Только я думаю, что если Вы переведете ваш код на Си, то компилятор сделает код, аналогичный вашему. Лично я добавил бы еще одну переменную - указатель: Код #define BIT_0 (1<<0) unsigned char crc8iar(char *buffer, char nbytes) { char *bp = buffer; char crc = 0, tmp, x8C = 0x8C; char i;
do { tmp = *bp++; i = 8; do { if ((crc >>= 1) & BIT_0) crc ^= x8C; if (tmp & BIT_0) crc ^= x8C; tmp >>= 1; } while (--i); } while (--nbytes); return crc; } Вроде так, если я нигде не ошибся.
Сообщение отредактировал _Bill - Aug 25 2006, 13:22
|
|
|
|
|
Aug 25 2006, 13:30
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(singlskv @ Aug 25 2006, 15:30)  Вот код для IAR (если я ничего не напутал): Код crc8iar:;Input: r17:r16 buffer; r18 - number of bytes ;Output: r16 = CRC
movw r31:r30,r17:r16 ldi r16,0;CRC ldi r19,0x8c crc8iar_1: ld r20,Z+ ldi r21,8 crc8iar_2: lsr r16 brbc 0,crc8iar_3 eor r16,r19 crc8iar_3: sbrc r20,0 eor r16,r19 lsr r20 crc8iar_4: dec r21 brne crc8iar_2 dec r18 brne crc8iar_1
ret Добавилась всего одна инструкция: Код movw r31:r30,r17:r16 Вот результат трансляции. Можете сравнить. Код 70 #define BIT_0 (1<<0)
\ In segment CODE, align 2, keep-with-next 71 unsigned char crc8iar(char *buffer, char nbytes) \ crc8iar: 72 { 73 char *bp = buffer; \ 00000000 01F8 MOVW R31:R30, R17:R16 74 char crc = 0, tmp, x8C = 0x8C; \ 00000002 E000 LDI R16, 0 75 char i; 76 77 do { 78 tmp = *bp++; \ ??crc8iar_0: \ 00000004 9141 LD R20, Z+ 79 i = 8; \ 00000006 E018 LDI R17, 8 80 do { 81 if ((crc >>= 1) & BIT_0) \ ??crc8iar_1: \ 00000008 9506 LSR R16 \ 0000000A FB00 BST R16, 0 \ 0000000C F416 BRTC ??crc8iar_2 82 crc ^= x8C; \ 0000000E E83C LDI R19, 140 \ 00000010 2703 EOR R16, R19 83 if (tmp & BIT_0) \ ??crc8iar_2: \ 00000012 FB40 BST R20, 0 \ 00000014 F416 BRTC ??crc8iar_3 84 crc ^= x8C; \ 00000016 E83C LDI R19, 140 \ 00000018 2703 EOR R16, R19 85 tmp >>= 1; \ ??crc8iar_3: \ 0000001A 9546 LSR R20 86 } 87 while (--i); \ 0000001C 951A DEC R17 \ 0000001E F7A1 BRNE ??crc8iar_1 88 } 89 while (--nbytes); \ 00000020 952A DEC R18 \ 00000022 F781 BRNE ??crc8iar_0 90 return crc; \ 00000024 9508 RET 91 }
|
|
|
|
|
Aug 25 2006, 13:49
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(_Bill @ Aug 25 2006, 17:30)  Вот результат трансляции. Можете сравнить. Код 70 #define BIT_0 (1<<0)
\ In segment CODE, align 2, keep-with-next 71 unsigned char crc8iar(char *buffer, char nbytes) \ crc8iar: 72 { 73 char *bp = buffer; \ 00000000 01F8 MOVW R31:R30, R17:R16 74 char crc = 0, tmp, x8C = 0x8C; \ 00000002 E000 LDI R16, 0 75 char i; 76 77 do { 78 tmp = *bp++; \ ??crc8iar_0: \ 00000004 9141 LD R20, Z+ 79 i = 8; \ 00000006 E018 LDI R17, 8 80 do { 81 if ((crc >>= 1) & BIT_0) \ ??crc8iar_1: \ 00000008 9506 LSR R16 \ 0000000A FB00 BST R16, 0 \ 0000000C F416 BRTC ??crc8iar_2 82 crc ^= x8C; \ 0000000E E83C LDI R19, 140 \ 00000010 2703 EOR R16, R19 83 if (tmp & BIT_0) \ ??crc8iar_2: \ 00000012 FB40 BST R20, 0 \ 00000014 F416 BRTC ??crc8iar_3 84 crc ^= x8C; \ 00000016 E83C LDI R19, 140 \ 00000018 2703 EOR R16, R19 85 tmp >>= 1; \ ??crc8iar_3: \ 0000001A 9546 LSR R20 86 } 87 while (--i); \ 0000001C 951A DEC R17 \ 0000001E F7A1 BRNE ??crc8iar_1 88 } 89 while (--nbytes); \ 00000020 952A DEC R18 \ 00000022 F781 BRNE ??crc8iar_0 90 return crc; \ 00000024 9508 RET 91 } 696 тактов однако ??? Код \ 0000000E E83C LDI R19, 140 \ 00000010 2703 EOR R16, R19 83 if (tmp & BIT_0) \ ??crc8iar_2: \ 00000012 FB40 BST R20, 0 \ 00000014 F416 BRTC ??crc8iar_3 84 crc ^= x8C; \ 00000016 E83C LDI R19, 140 А не слишком ли мы часто загружаем константу 140 (0x8c).
|
|
|
|
|
Aug 25 2006, 15:26
|
Участник

Группа: Новичок
Сообщений: 44
Регистрация: 2-05-06
Пользователь №: 16 710

|
Приятный алгоритм, возьму на вооружение. IAR - 515 циклов. Код U8 crc8_3(U8 *buff, U8 num) { U8 i, crc = 0; do { crc ^= *buff++; i = 8; do { if (crc & 0x01) { crc >>= 1; crc ^= 0x8C; } else { crc >>= 1; } } while (--i); } while (--num); return crc; }
|
|
|
|
|
Aug 25 2006, 15:38
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(µµC @ Aug 25 2006, 19:26)  Приятный алгоритм, возьму на вооружение. IAR - 515 циклов. Код U8 crc8_3(U8 *buff, U8 num) { U8 i, crc = 0; do { crc ^= *buff++; i = 8; do { if (crc & 0x01) { crc >>= 1; crc ^= 0x8C; } else { crc >>= 1; } } while (--i); } while (--num); return crc; } а листинг можно в студию ? (ну не стоит у меня IAR) Цитата(µµC @ Aug 25 2006, 19:26)  Приятный алгоритм, возьму на вооружение. IAR - 515 циклов. Код U8 crc8_3(U8 *buff, U8 num) { U8 i, crc = 0; do { crc ^= *buff++; i = 8; do { if (crc & 0x01) { crc >>= 1; crc ^= 0x8C; } else { crc >>= 1; } } while (--i); } while (--num); return crc; } а листинг можно в студию ? (ну не стоит у меня IAR)
|
|
|
|
|
Aug 25 2006, 16:19
|
Участник

Группа: Новичок
Сообщений: 44
Регистрация: 2-05-06
Пользователь №: 16 710

|
Цитата(singlskv @ Aug 25 2006, 19:38)  а листинг можно в студию ? (ну не стоит у меня IAR) Код NAME crc8
RSEG CSTACK:DATA:NOROOT(0) RSEG RSTACK:DATA:NOROOT(0)
EXTERN ?need_segment_init
PUBWEAK `?<Segment init: TINY_I>` PUBWEAK `?<Segment init: TINY_Z>` PUBWEAK __?EEARL PUBWEAK __?EECR PUBWEAK __?EEDR PUBLIC code PUBLIC crc8_3 PUBLIC main PUBLIC result
// C:\1z\CRC8\crc8.c // 1 #define U8 unsigned char // 2
RSEG TINY_I:DATA:NOROOT(0) REQUIRE `?<Segment init: TINY_I>` // 3 U8 code[8] = {0x01, 0xd0, 0x5e, 0x3c, 0x0d, 0x00, 0x00, 0x84}; code: DS 8 REQUIRE `?<Initializer for code>` // 4 /*
// 100 */
RSEG CODE:CODE:NOROOT(1) // 101 U8 crc8_3(U8 *buff, U8 num) crc8_3: // 102 { // 103 U8 i, crc = 0; LDI R18, 0 // 104 // 105 do { // 106 crc ^= *buff++; ??crc8_3_0: MOV R30, R16 LD R19, Z+ MOV R16, R30 EOR R18, R19 // 107 i = 8; LDI R19, 8 // 108 do { // 109 if (crc & 0x01) { ??crc8_3_1: BST R18, 0 LSR R18 BRTC ??crc8_3_2 // 110 crc >>= 1; // 111 crc ^= 0x8C; MOV R20, R18 LDI R18, 140 EOR R18, R20 // 112 } else { // 113 crc >>= 1; // 114 } // 115 } while (--i); ??crc8_3_2: DEC R19 BRNE ??crc8_3_1 // 116 } while (--num); DEC R17 BRNE ??crc8_3_0 // 117 return crc; MOV R16, R18 RET // 118 } // 119
RSEG TINY_Z:DATA:NOROOT(0) REQUIRE `?<Segment init: TINY_Z>` // 120 volatile U8 result[4]; result: DS 4 // 121
RSEG CODE:CODE:NOROOT(1) // 122 void main(void) main: ??main_0: // 123 { // 124 while (1) { // 125 result[0] = 0; LDI R16, 0 LDI R30, result ST Z, R16 // 126 /* // 147 */ // 148 // 149 //result[0] = crc8_2(code, 7); // 150 result[1] = crc8_3(code, 7); LDI R17, 7 LDI R16, code RCALL crc8_3 LDI R30, result STD Z+1, R16 // 151 // result[2] = crc8_2(code, 7); // 152 result[3] = crc8_3(code, 7); LDI R17, 7 LDI R16, code RCALL crc8_3 LDI R30, result STD Z+3, R16 RJMP ??main_0 // 153 // 154 } // 155 }
ASEGN ABSOLUTE:DATA:NOROOT,01cH __?EECR:
ASEGN ABSOLUTE:DATA:NOROOT,01dH __?EEDR:
ASEGN ABSOLUTE:DATA:NOROOT,01eH __?EEARL:
RSEG TINY_ID:CODE:NOROOT(0) `?<Initializer for code>`: DB 1, 208, 94, 60, 13, 0, 0, 132
RSEG INITTAB:CODE:NOROOT(0) `?<Segment init: TINY_I>`: DB SFE(TINY_I) - SFB(TINY_I) DB SFB(TINY_I) DW SFB(TINY_ID) REQUIRE ?need_segment_init
RSEG INITTAB:CODE:NOROOT(0) `?<Segment init: TINY_Z>`: DB SFE(TINY_Z) - SFB(TINY_Z) DB SFB(TINY_Z) DW 0 REQUIRE ?need_segment_init
END // 156 // 157 //IAR, opt = max speed, остальные опции выкл.
|
|
|
|
|
Aug 25 2006, 17:15
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(µµC @ Aug 25 2006, 19:26)  Приятный алгоритм, возьму на вооружение. IAR - 515 циклов. Код U8 crc8_3(U8 *buff, U8 num) { U8 i, crc = 0; do { crc ^= *buff++; i = 8; do { if (crc & 0x01) { crc >>= 1; crc ^= 0x8C; } else { crc >>= 1; } } while (--i); } while (--num); return crc; } Вот, ЭТО уже по настоящему КРУТОЙ алгоритм  , НО, если уже пошла такая пьянка, то ВОТ: Код crc8new: ;Input: r17:r16 buffer; r18 - number of bytes ;Output: r16 = CRC
movw r31:r30,r17:r16
ldi r16,0x00 ldi r19,0x8c crc8new_1: ld r17,Z+ eor r16,r17 ldi r17,0x08 rjmp crc8new_3 crc8new_2: lsr r16 eor r16,r19 dec r17 breq crc8new_4 crc8new_3: sbrc r16,0 rjmp crc8new_2 lsr r16 dec r17 brne crc8new_3 crc8new_4: dec r18 brne crc8new_1 Всего 427 тактов.
|
|
|
|
|
Aug 26 2006, 05:42
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Чето слабовато: Код __z char crc8_3(char *buff, char num, char poly) { char i, crc = 0; do { crc ^= *buff++; i = 8; do { crc >>=1; if (SREG_Bit0) crc^=poly; } while (--i); } while (--num); return crc; }
__z char crc8(char *buff, char num) { return crc8_3(buff, num, 0x8C); } Зовем конечно crc8 Код \ In segment CODE, align 2, keep-with-next 58 __z char crc8_3(char *buff, char num, char poly) \ crc8_3: 59 { 60 char i, crc = 0; \ 00000000 E030 LDI R19, 0 61 do 62 { 63 crc ^= *buff++; \ ??crc8_3_0: \ 00000002 9121 LD R18, Z+ \ 00000004 2732 EOR R19, R18 64 i = 8; \ 00000006 E028 LDI R18, 8 65 do 66 { 67 crc >>=1; \ ??crc8_3_1: \ 00000008 9536 LSR R19 68 if (SREG_Bit0) crc^=poly; \ 0000000A F408 BRBC 0, ??crc8_3_2 \ 0000000C 2731 EOR R19, R17 69 } 70 while (--i); \ ??crc8_3_2: \ 0000000E 952A DEC R18 \ 00000010 F7D9 BRNE ??crc8_3_1 71 } 72 while (--num); \ 00000012 950A DEC R16 \ 00000014 F7B1 BRNE ??crc8_3_0 73 return crc; \ 00000016 2F03 MOV R16, R19 \ 00000018 9508 RET 74 } 75
\ In segment CODE, align 2, keep-with-next 76 __z char crc8(char *buff, char num) \ crc8: 77 { 78 return crc8_3(buff, num, 0x8C); \ 00000000 E81C LDI R17, 140 \ 00000002 .... RJMP crc8_3 79 }
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Aug 26 2006, 21:29
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Rst7 @ Aug 26 2006, 09:42)  Чето слабовато: Цитата НО, если уже пошла такая пьянка, то ВОТ: Код crc8new: ;Input: r17:r16 buffer; r18 - number of bytes ;Output: r16 = CRC
movw r31:r30,r17:r16
ldi r16,0x00 ldi r19,0x8c crc8new_1: ld r17,Z+ eor r16,r17 ldi r17,0x08 rjmp crc8new_3 crc8new_2: lsr r16 eor r16,r19 dec r17 breq crc8new_4 crc8new_3: sbrc r16,0 rjmp crc8new_2 lsr r16 dec r17 brne crc8new_3 crc8new_4: dec r18 brne crc8new_1 Всего 427 тактов. Дык это Вообще не мой код, это код сгенерированный WinAVR(-o3) из: Код U8 crc8_3(U8 *buff, U8 num) { U8 i, crc = 0; do { crc ^= *buff++; i = 8; do { if (crc & 0x01) { crc >>= 1; crc ^= 0x8C; } else { crc >>= 1; } } while (--i); } while (--num); return crc; } алгоритма предложенного µµC и просто тупо переведенный мною для IAR. Свой код не готов был уже сгенерить :cheers для данного алгоритма. Код __z char crc8_3(char *buff, char num, char poly) { char i, crc = 0; do { crc ^= *buff++; i = 8; do { crc >>=1; if (SREG_Bit0) crc^=poly; } while (--i); } while (--num); return crc; }
__z char crc8(char *buff, char num) { return crc8_3(buff, num, 0x8C); } Вот это мне очень понравилось  , незнал что так можно писать: Код crc >>=1; if (SREG_Bit0) crc^=poly; КРУТО!!! Но, это уже какой-то асемблерный код Хотя так и не понял зачем там лишняя функция: Код __z char crc8(char *buff, char num) { return crc8_3(buff, num, 0x8C); } типа для общности??? ИТОГО: (типа подводим итоги): (как автор данного топика кажись мне это можно  ) 1. компиляторам нужно подсказывать как они должны компилировать. 2. алгоритм имеет значительно большее влияние на производительность чем просто тупое улучшение неудачного алгоритма. 3. учим матчасть: Код __z Код crc >>=1; if (SREG_Bit0) crc^=poly; ИТОГО N 2: µµC  за оригинальный алгоритм. Rst7  за "__z". Rst7  за очень грамонтную реализацию предложенного алгоритма : Код __z char crc8_3(char *buff, char num, char poly) { char i, crc = 0; do { crc ^= *buff++; i = 8; do { crc >>=1; if (SREG_Bit0) crc^=poly; } while (--i); } while (--num); return crc; }
__z char crc8(char *buff, char num) { return crc8_3(buff, num, 0x8C); } Все кто принял участие в данном обсуждение, спасибо.
|
|
|
|
|
Aug 27 2006, 05:20
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата(singlskv @ Aug 27 2006, 00:29)  Хотя так и не понял зачем там лишняя функция: Код __z char crc8(char *buff, char num) { return crc8_3(buff, num, 0x8C); } типа для общности??? Нет, тут хитрость, без этого IAR психует и грузит 0x8C непосредственно перед выполнением xor, т.е. каждый раз в цикле, итого +1*8*sizeof по тактам. Чето там у него не срослось с отделением инвариантного кода. А так лечим, заставляем его принципиально xor с переменной делать. Так что это тоже шаманство  Цитата Все кто принял участие в данном обсуждение, спасибо. Лишь бы на здоровье
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Aug 27 2006, 05:38
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
В досыл... Цитата(singlskv @ Aug 27 2006, 00:29)  Вот это мне очень понравилось  , незнал что так можно писать: Код crc >>=1; if (SREG_Bit0) crc^=poly; КРУТО!!! Но, это уже какой-то асемблерный код  Ну с этим надо поаккуратнее, а то в следующий раз может переоптимизировать нафиг все, например местами поменять сдвиг и проверку. А вообще-то эта идея родилась при реализации TCP/IP стека, там надо считать контрольные суммы с учетом переноса при прибавлении к 16-битному инту, его надо добавлять к сумме. А код, как вы понимаете, все время кривой. В результате родилось такое: Код unsigned int rxcrc; //Контрольная сумма в принимаемом пакете
#pragma optimize=no_inline void subrxcrc(unsigned int i) { i=rxcrc-i; if (_CARRY) i--; rxcrc=i; } Быстро и качественно: Код 98 #pragma optimize=no_inline
\ In segment CODE, align 2, keep-with-next 99 void subrxcrc(unsigned int i) \ subrxcrc: 100 { \ 00000000 REQUIRE __RSTACK_in_external_ram 101 i=rxcrc-i; \ 00000000 .... LDI R30, LOW(rxcrc) \ 00000002 .... LDI R31, (rxcrc) >> 8 \ 00000004 REQUIRE ?Subroutine0 \ 00000004 ; // Fall through to label ?Subroutine0 102 if (_CARRY) i--; 103 rxcrc=i; 104 }
\ In segment CODE, align 2, keep-with-next \ ?Subroutine0: \ 00000000 8120 LD R18, Z \ 00000002 8131 LDD R19, Z+1 \ 00000004 1B20 SUB R18, R16 \ 00000006 0B31 SBC R19, R17 \ 00000008 0189 MOVW R17:R16, R19:R18 \ 0000000A F410 BRBC 0, ??Subroutine0_0 \ 0000000C 5001 SUBI R16, 1 \ 0000000E 4010 SBCI R17, 0 \ ??Subroutine0_0: \ 00000010 8300 ST Z, R16 \ 00000012 8311 STD Z+1, R17 \ 00000014 9508 RET Тоже гон, конечно (MOVW там совсем лишний), но намного лучше других способов...
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Aug 27 2006, 09:30
|
Участник

Группа: Новичок
Сообщений: 44
Регистрация: 2-05-06
Пользователь №: 16 710

|
А что такое "__z"? Что нужно сделать чтоб этим пользоваться, где почитать? WinAVR 2006421 пишет: * crc8.c, line 104: error: syntax error before "unsigned" В описании упоминаний не нашел.
|
|
|
|
|
Aug 27 2006, 09:56
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата(µµC @ Aug 27 2006, 12:30)  А что такое "__z"? Что нужно сделать чтоб этим пользоваться, где почитать? WinAVR 2006421 пишет: * crc8.c, line 104: error: syntax error before "unsigned" В описании упоминаний не нашел. Это IAR-овская фича, в GNU такого нет. В IAR-е этот модификатор говорит, что первый указатель будет передан через регистр Z. Еще есть модификаторы __x, __z_x, __x_z, соответственно использование X для передачи первого указателя, использование Z для первого, X для второго и наоборот.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Aug 27 2006, 10:10
|
Участник

Группа: Новичок
Сообщений: 44
Регистрация: 2-05-06
Пользователь №: 16 710

|
Цитата(Rst7 @ Aug 27 2006, 13:56)  Понял. спасибо. В IAR этим пользуюсь. Просто мне почему-то показалось, что singlskv тоже может, а IAR у него нет.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|