MrYuran 29 17 апреля, 2009 Опубликовано 17 апреля, 2009 · Жалоба В ИАРе для МСП430 есть такая классная фича - квалификатор _even_in_range_(range) для аргументов switch(). То есть если аргумент чётный и распределён в ограниченном диапазоне, то свитч просто формирует сплошную таблицу переходов, а аргумент свича выступает индексом в этой таблице. Таким образом, осуществляется переход за одну команду независимо от количества кейсов в свиче. Оптимизация жуткая, причём это особенно актуально при обработке прерываний от второго вектора таймера В (TB_CCR1_VECTOR), когда пишем switch(TBIV) и максимально быстро выруливаем на нужный обработчик. Так вот, как бы такую штуку провернуть в GCC? На форуме mspgcc были какие-то наброски на асме, но это как-то некрасиво. типа этого Хотелось бы на чистом си, типа макроса чтоли... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 17 апреля, 2009 Опубликовано 17 апреля, 2009 · Жалоба Хотелось бы на чистом си, типа макроса чтоли...Просьба на чистом С просить только то, что и у IAR делается на чистом С :rolleyes: Так пойдёт? unsigned char foo(unsigned char sel) { // !!! проедполагается, что sel чётно И sizeof(void*)==2 // для простоты изложения для AVR в ОЗУ, static const void *sw[] = { &&la, &&lb, &&lc }; void *target = *(void**)((unsigned char*)sw + sel); goto *target; la: return 5; lb: return 8; lc: return 11; } msp-gcc под рукой нет, avr-gcc: foo: mov r30,r24 ldi r31,lo8(0) subi r30,lo8(-(sw.1469)) sbci r31,hi8(-(sw.1469)) ld __tmp_reg__,Z+ ld r31,Z mov r30,__tmp_reg__ ijmp .L2: ldi r24,lo8(5) ldi r25,hi8(5) ret .L4: ldi r24,lo8(8) ldi r25,hi8(8) ret .L5: ldi r24,lo8(11) ldi r25,hi8(11) ret Для MSP, по идее, будет несколько хуже, чем совсем красивое добавление прямо к PC, но всё же лучше стандартного switch Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 29 17 апреля, 2009 Опубликовано 17 апреля, 2009 · Жалоба Так пойдёт? Для MSP, по идее, будет несколько хуже, чем совсем красивое добавление прямо к PC, но всё же лучше стандартного switch Да, примерно в этом роде. Только бы вот ещё завернуть ещё как-то покрасивше... Но даже в таком виде красивее, чем на асме. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 29 17 апреля, 2009 Опубликовано 17 апреля, 2009 · Жалоба Ну, короче, вот что получилось. #define switch_even_in_range(index, ... ) \ static const unsigned int *sw[] = {__VA_ARGS__};\ unsigned int *target = *(void**)((unsigned int*)sw + index);\ goto *target; index - переключатель, далее следует записать все метки кейсов. interrupt (TIMERB1_VECTOR) Timerb_ccr1(void) { switch_even_in_range(TBIV, &&def, &&l2, &&l4, &&l6, &&l8, &&l10, &&l12 ) { l2: pxTimerB1ccr1expired(); l4: pxTimerB1ccr2expired(); l6: (void)pxMBPortCBTimerExpired(); l8: pxTimerB1ccr4expired(); l10: pxTimerB1ccr5expired(); l12: pxTimerB1ccr6expired(); def: } } Ничё так, гламурненько :) А вот выход: 00002eb0 <Timerb_ccr1>: 2eb0: 0f 12 push r15 ; 2eb2: 0e 12 push r14 ; 2eb4: 0d 12 push r13 ; 2eb6: 0c 12 push r12 ; 2eb8: 05 12 push r5 ; 2eba: 04 12 push r4 ; 2ebc: 05 41 mov r1, r5 ; 2ebe: 35 50 0e 00 add #14, r5 ;#0x000e 2ec2: 21 83 decd r1 ; 2ec4: 04 41 mov r1, r4 ; 2ec6: 1f 42 1e 01 mov &0x011e,r15 ;0x011e 2eca: 0f 5f rla r15 ; 2ecc: 3f 50 04 02 add #516, r15 ;#0x0204 2ed0: a4 4f 00 00 mov @r15, 0(r4) ; 2ed4: 20 44 br @r4 ; 2ed6: 1f 42 ca 03 mov &0x03ca,r15 ;0x03ca 2eda: 8f 12 call r15 ; 2edc: 1f 42 a8 03 mov &0x03a8,r15 ;0x03a8 2ee0: 8f 12 call r15 ; 2ee2: 1f 42 aa 03 mov &0x03aa,r15 ;0x03aa 2ee6: 8f 12 call r15 ; 2ee8: 1f 42 c6 03 mov &0x03c6,r15 ;0x03c6 2eec: 8f 12 call r15 ; 2eee: 1f 42 c4 03 mov &0x03c4,r15 ;0x03c4 2ef2: 8f 12 call r15 ; 2ef4: 1f 42 c2 03 mov &0x03c2,r15 ;0x03c2 2ef8: 8f 12 call r15 ; 2efa: 21 53 incd r1 ; 2efc: 34 41 pop r4 ; 2efe: 35 41 pop r5 ; 2f00: 3c 41 pop r12 ; 2f02: 3d 41 pop r13 ; 2f04: 3e 41 pop r14 ; 2f06: 3f 41 pop r15 ; 2f08: 00 13 reti ссылка по указателю на функцию в прерывании это конечно изврат, но речь сейчас не об этом. В целом вроде бы всё удалось. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 17 апреля, 2009 Опубликовано 17 апреля, 2009 · Жалоба Ну, короче, вот что получилось. #define switch_even_in_range(index, ... ) \ static const unsigned int *sw[] = {__VA_ARGS__};\ unsigned int *target = *(void**)((unsigned int*)sw + index);\ goto *target; Симпатишненько. Только вроде бы ж надо = *(void**)((unsigned char*)sw + index);, на входе чётное число, смещение в таблице в байтах. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 17 апреля, 2009 Опубликовано 17 апреля, 2009 · Жалоба "раз пошла такая пьянка" (Cлабонервным не смотреть, тут, как и в protothreads, не просто используется goto, а ещё и внутрь блока оператора цикла. Правда, "одноразового", как в ATOMIC_BLOCK или привычного в макросах do { } while(0) ) #define switch_even_in_range(index, ... ) \ static const void *sw[] = {__VA_ARGS__};\ void *target = *(void**)((unsigned char*)sw + index);\ goto *target; \ for(int s_e_i_r_I = 0; s_e_i_r_I == 0; s_e_i_r_I = 1) unsigned moo(unsigned sel) { unsigned result; switch_even_in_range(sel, &&la, &&lb, &&lc) { la: result = 2; break; lb: result = 1; break; lc: result = 11; } return result; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 29 17 апреля, 2009 Опубликовано 17 апреля, 2009 · Жалоба "раз пошла такая пьянка" (Cлабонервным не смотреть, тут, как и в protothreads, не просто используется goto, а ещё и внутрь блока оператора цикла. Чё-то я не всосал... Размер увеличился, смысл - неясен... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alx2 0 17 апреля, 2009 Опубликовано 17 апреля, 2009 · Жалоба Немного отвлеченный вопрос: а откуда берется этот самый index? Не проще ли вместо индекса сразу работать с указателем на нужный код? Не нужно было бы получать указатель из таблицы... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 17 апреля, 2009 Опубликовано 17 апреля, 2009 · Жалоба Чё-то я не всосал... Размер увеличился, смысл - неясен... Где размер увеличился? Ни на грамм, переменная s_e_i_r_I не создаётся вообще, этот for - это "обёртка" в духе do { } while(0);, не генерирующая кода (при уровне оптимизации, отличающемся от полного отсутствия) moo: mov r31,r25 mov r30,r24 subi r30,lo8(-(sw.1367)) sbci r31,hi8(-(sw.1367)) ld __tmp_reg__,Z+ ld r31,Z mov r30,__tmp_reg__ ijmp .L8: ldi r24,lo8(2) ldi r25,hi8(2) ret .L10: ldi r24,lo8(1) ldi r25,hi8(1) ret .L11: ldi r24,lo8(11) ldi r25,hi8(11) ret Зато можно писать break; Немного отвлеченный вопрос: а откуда берется этот самый index?Ну, например, из аппаратного регистра TBIV (TimerBInterruptVector, если я правильно расшифровал). Там именно индекс. Не проще ли вместо индекса сразу работать с указателем на нужный код? Не нужно было бы получать указатель из таблицы...Конечно проще! Например, так http://electronix.ru/forum/index.php?showt...mp;#entry520130 Но тут другой случай. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 29 17 апреля, 2009 Опубликовано 17 апреля, 2009 · Жалоба Немного отвлеченный вопрос: а откуда берется этот самый index? Не проще ли вместо индекса сразу работать с указателем на нужный код? Не нужно было бы получать указатель из таблицы... index - это переключатель свитча Данный подход выгоден, когда есть переключатель на большое количество индексируемых состояний. Например, стэйт машин или обработчик кодов команд (параметров, etc) То есть пишем switch(comand_code<<1,[список меток]) и максимально быстро перескакиваем на обработчик нужной команды Где размер увеличился? Ни на грамм, переменная s_e_i_r_I не создаётся вообще, этот for - это "обёртка" в духе do { } while(0);, не генерирующая кода (при уровне оптимизации, отличающемся от полного отсутствия) Зато можно писать break; А, теперь понятно... У меня почему-то вставляет цикл. Причём объявление for(int s_e_i_r_I = 0; s_e_i_r_I == 0; s_e_i_r_I = 1) не прокатывает, пишет "TimerB\TimerB.c|168|`for' loop initial declaration used outside C99 mode|" Приходится объявление int s_e_i_r_I вытаскивать наружу. Как бы эту гадость победить, давно хочу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 17 апреля, 2009 Опубликовано 17 апреля, 2009 · Жалоба `for' loop initial declaration used outside C99 mode|"Дык -std=c99 Или я чего-то не понял? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
klen 1 18 апреля, 2009 Опубликовано 18 апреля, 2009 · Жалоба typedef enum { func0=0 , func1 , .... , func_count } func_index ; typedef void (*FPRT)(void) ; inline void Func0(void) { /* код 0 */ } inline void Func1(void) { /* код 1 */ } FPRT func_table[fuc_count ] = {Func0,Func1,.....} ; // таблица адресов функий далее в коде просто в нужном месте вместо switch (arg) {} вызвать (func_table[arg]) () ; я всегда так делаю - добавлять обработчики и их индексы удобно и быстро. работает это тоже быстро вопрос тока как это для MSP сгенерится, я армами пользуюсь, про MSP ничего сказать не могу Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 29 20 апреля, 2009 Опубликовано 20 апреля, 2009 · Жалоба Дык -std=c99 Или я чего-то не понял? Я так понимаю, что данная инициализация FOR не соответствует (по мнению компилятора) стандарту С99. Щас вот как раз качаю С99, надо ж когда-то начинать обращаться к первоисточникам... Вот, нарыл. Что и требовалось доказать. 6.8.5 Iteration statements Syntax iteration-statement: while ( expression ) statement do statement while ( expression ); for ( expressionopt ; expressionopt ; expressionopt ) statement for ( declaration expressionopt ; expressionopt ) statement Чё-то компилер глюкавит... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 20 апреля, 2009 Опубликовано 20 апреля, 2009 · Жалоба Я так понимаю, что данная инициализация FOR не соответствует (по мнению компилятора) стандарту С99.Как раз соответствует. Просто у вас поддержка C99 не включена. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 29 20 апреля, 2009 Опубликовано 20 апреля, 2009 · Жалоба Как раз соответствует. Просто у вас поддержка C99 не включена. CFLAGS = -mmcu=$(MCU) -c $(OPT) $(DEBUG) -std=c99 Вроде подключил, или нет? Секундочку, чё-то я сам не пойму, куда чего подключил... Ёжкин кот! У меня галка стояла на автомэйке! А я тут чего-то исследую, оптимизацию типа меняю... Ну вот, таки подключил... Вообще чудеса пошли - ругается на всё из io.h Особенно невзлюбил sfrb и sfrw Точнее вот что: #if defined(__MSP430_HAS_PORT1__) || defined(__MSP430_HAS_PORT1_R__) __MSP430_EXTERN__ struct port_full_t port1 asm("0x0020"); #endif Пишет "c:\mspgcc\msp430\include\msp430\iostructures.h|136|syntax error before "asm"|" :maniac: И дался мне этот долбаный for с евоным с99... есть же ещё do{}while... Хотя нет, в макрос не подставишь... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться