|
|
  |
антипод модификатора __raw |
|
|
|
Jun 22 2007, 13:42
|

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

|
Цитата(ArtemKAD @ Jun 22 2007, 16:18)  Ну собственно после той темы я и задался этим вопросом. Да и хотелось бы, чтобы сохранялись только используемые в функции регистры, а не все кроме возможных глобальных. так в том примере вызывается функция strcmp, а если все сделать руками, то сохранит только нужные регистры Код 6 //Также линкеру запретить w22 7 #pragma diag_suppress=Ta006
\ In segment CODE, align 2, keep-with-next 8 __interrupt void IntLong(void) \ IntLong: 9 { \ 00000000 93BA ST -Y, R27 \ 00000002 93AA ST -Y, R26 \ 00000004 93FA ST -Y, R31 \ 00000006 93EA ST -Y, R30 \ 00000008 931A ST -Y, R17 \ 0000000A 930A ST -Y, R16 \ 0000000C B71F IN R17, 0x3F 10 char *a=(char *)0x1234; \ 0000000E E3E4 LDI R30, 52 \ 00000010 E1F2 LDI R31, 18 11 char *b=(char *)0x3456; \ 00000012 E5A6 LDI R26, 86 \ 00000014 E3B4 LDI R27, 52 12 while((*a++=*b++)); \ ??IntLong_0: \ 00000016 910D LD R16, X+ \ 00000018 9301 ST Z+, R16 \ 0000001A 2300 TST R16 \ 0000001C F7E1 BRNE ??IntLong_0 13 } \ 0000001E BF1F OUT 0x3F, R17 \ 00000020 9109 LD R16, Y+ \ 00000022 9119 LD R17, Y+ \ 00000024 91E9 LD R30, Y+ \ 00000026 91F9 LD R31, Y+ \ 00000028 91A9 LD R26, Y+ \ 0000002A 91B9 LD R27, Y+ \ 0000002C 9518 RETI 14 #pragma diag_default=Ta006
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Jun 22 2007, 17:36
|
Профессионал
    
Группа: Свой
Сообщений: 1 508
Регистрация: 26-06-06
Из: Киев
Пользователь №: 18 364

|
Цитата Или что Вам нужно, задачу полнее обрисуйте? Есть ШИМ на нулевом таймере, каждые 4 цикла которого надо менять его значение. Тактовая таймера равна тактовой Меги. Т.е. каждые 256 тактов МК влетает в прерывание и 3 раза из 4-х должен сделать три действия (сложить, сохранить и проверить) и выйти. Любые лишние сохранения там кушают драгоценный ресурс процессора - его такты. На каждый регистр - 4 такта. А при сохранении всех 15-ти - 60 тактов из 256 улетает "в трубу". Цитата так в том примере вызывается функция strcmp, а если все сделать руками, то сохранит только нужные регистры Хм... А это Мысль! У меня там вызовов библиотечных функций нет, но два CALL-а там точно есть. Возможно при их наличие IAR-а сохраняет регистры "на полную катушку". В понедельник попробую без CALL-ов...
|
|
|
|
|
Jun 23 2007, 03:43
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(ArtemKAD @ Jun 23 2007, 00:36)  Есть ШИМ на нулевом таймере, каждые 4 цикла которого надо менять его значение. Тактовая таймера равна тактовой Меги. Т.е. каждые 256 тактов МК влетает в прерывание и 3 раза из 4-х должен сделать три действия (сложить, сохранить и проверить) и выйти. Любые лишние сохранения там кушают драгоценный ресурс процессора - его такты. На каждый регистр - 4 такта. А при сохранении всех 15-ти - 60 тактов из 256 улетает "в трубу". Все ясно. Вы вызываете из прерывания другую функцию и поэтому компилятор просто обязан сохранить все scratch регистры - он ведь не знает, какие из них используются вызываемой функции, поэтому для обеспечения целостности работы программы он должен их все сохранить. Количество этих регистров у EWAVR достаточно велико - почти половина регистрового файла. Выход тут простой - не надо из обработчика прерываний вызывать функций, либо можно вызывать только встраиваемые ( inline) - тело встраиваемой функции видно комплятору, он в этом случае "знает" какие регистры используются и сохраняет только их. Когда комплятор видит весь код обработчика прерываний, он сохраняет только то, что надо. Цитата(ArtemKAD @ Jun 23 2007, 00:36)  Хм... А это Мысль! У меня там вызовов библиотечных функций нет, но два CALL-а там точно есть. Возможно при их наличие IAR-а сохраняет регистры "на полную катушку". В понедельник попробую без CALL-ов... Именно! Не вызывайте функции - чтобы не было call, и все будет в лучшем виде.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Jun 25 2007, 08:18
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(ArtemKAD @ Jun 25 2007, 14:03)  Не понял, а кому кроме него знать как он распределит регистры для этой функции? Не я же их распределяю... А как же принцип раздельной компиляции? Функция-то может вообще в библиотеке лежать, и компилятор к ней доступа не имеет - ее потом уже линкер подлинкует. Компилятор обрабатывает один текущий файл и видит только код этого файла. Если используется встраиваемая фукнция, т.е. тело которой непосредственно встраивается в точку вызова, то тут да, комплятор все видит и сохраняет только то, что используется. А если фукнция вызываемая, то тут он не видит конкретного кода этой вызываемой фуникции, не знает, какие конкретно регистры в ней используются, поэтому сохраняет весь набор scratch регистров. Это для него единственный способ обеспечить целостность программы. Вывод: для эффективности не использовать вызовов функции в ISR либо использовать только встраиваемые фукнции. Для пущей уверенности - чтобы компилятор точно встроил тело функции (иногда он "умничает" и делает вызов), использовать для этой функции прагму принудительного встраивания (#pragma inline=forced).
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Jun 25 2007, 09:05
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(dxp @ Jun 25 2007, 11:18)  ... А если фукнция вызываемая, то тут он не видит конкретного кода этой вызываемой фуникции, не знает, какие конкретно регистры в ней используются, поэтому сохраняет весь набор scratch регистров. ... Что-то я не все понимаю. Компиляция раздельная - понимаю, но сохранение регистров ведь в части компиляции, когда сама функция компилируется, а не вызов ее. Или?
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Jun 25 2007, 13:02
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(Dog Pawlowa @ Jun 25 2007, 16:05)  Что-то я не все понимаю. Компиляция раздельная - понимаю, но сохранение регистров ведь в части компиляции, когда сама функция компилируется, а не вызов ее. Или? Представьте, что вы компилятор. У вас есть соглашения о сохраняемых регистрах - конкретно у EWAVR примерно половина регистров при вызове фукнции предоставляется в использование вызываемой фукнции без сохранения - бери и юзай, как хошь, в этих регистрах вызывающая функция ничего не хранит - это так называемые scratch регистры, а вторая половина регистров, если вызываемая фукнция "хочет" их поиспользовать, должна быть сохранена - это так называемые local или preserved регистры. Вот вам предлагается сгенерить код для ISR. В этом коде присутствует вызов функции. Вы на него генерируете инструкцию call. НО! Поскольку ISR - это не обычная функция и получает управление асинхронно по отношению к потоку управления остальной программы, то в нем должны быть сохранены ВСЕ регистры, которые могут быть использованы. Здесь про local регистры нам волноваться не надо - если вызываемаая фукнция ( потроха которой мы не видим) будет их использовать - она сама их сохранит, столько, сколько ей надо. Но вот scratch регистры она сохранять не будет (по вышеописанному соглашению). Поэтому мы просто обязаны их сохранить сами. Поскольку мы не знаем, какие именно регистры вызываемая фукнция будет использовать, мы должны сохранить их все. Отсюда и неэффективность. Если же фукнцию сделать встраиваемой, т.е. когда ее тело видно нам на момент кодогенерации, то мы, видя, что в ней используется, сохраняем только используемые регистры. Все логично.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|