|
Поменять местами биты в байте. |
|
|
|
May 12 2007, 02:01
|

Местный
  
Группа: Свой
Сообщений: 208
Регистрация: 6-07-04
Из: Полтава
Пользователь №: 279

|
Цитата(defunct @ May 12 2007, 03:15)  Позвольте с вами несогласиться. Переносимость в большой мере зависит от нас самих, если хотите чтобы код был переносимым - пишите его таким сразу. ;> Если стоит задача переносимости, то - да. В противном случае - не обязательно. Цитата(defunct @ May 12 2007, 03:15)  Как так писать - создать прослойку между железом и программой - операционку. Писать программу уже не под железо а под ОС. То что код будет невсегда максимально эффективным, кого это волнует? Опять же, зависит от поставленой задачи. "Толстые" задачи на "толстых" чипах удобнее решать таким образом. Но 128-ю Мегу применять там, где и Тиня управится, это как бы из пушки да по воробьям. А тут уж и ужиматься приходится. Инструментов для создания программы фактически всего-то два - ассемблер да Си. Ассемблер позволяет дать максимально эффективный код, но со значительной затратой времени. Си, при соответствующем подходе, может дать код не намного избыточнее, но создание программы идет значительно быстрее, поэтому является вполне разумным компромиссом и для мелких чипов. Вот тут, как раз, и нужны наработанные приемы получения компактного кода, пускай даже в ущерб переносимости. "Кого ЭТО волнует?"©
|
|
|
|
|
May 12 2007, 02:42
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(kv_addr @ May 12 2007, 04:01)  Но 128-ю Мегу применять там, где и Тиня управится, это как бы из пушки да по воробьям. А тут уж и ужиматься приходится. Инструментов для создания программы фактически всего-то два - ассемблер да Си. Ассемблер позволяет дать максимально эффективный код, но со значительной затратой времени. Си, при соответствующем подходе, может дать код не намного избыточнее, но создание программы идет значительно быстрее, поэтому является вполне разумным компромиссом и для мелких чипов. Вот тут, как раз, и нужны наработанные приемы получения компактного кода, пускай даже в ущерб переносимости. Противоречие у Вас получается ;> C одной стороны Вы говорите о Tiny с 1-2-4Kb памяти, с другой говорите о затратах времени при написании программы на ассемблере. 2Kb на C заполнить - дурное дело не хитрое - полчаса и вся память занята - это не просто сокращенные трудозатраты, это можно сказать их вообще нет. Но и функциональность такой программы в тиньке также получится "никакой". Хотите функциональности - будьте добры потрудитесь - либо то 8k-16k на C выдавить, либо, что сравнимо по трудозатратам - 1-2k ассемблере. При этом на ассемблере вы получите оптимальный вариант кода естессно непереносимый на другие платформы. На C поизвращавшись тоже втиснете нечто сравнимое по функциональности но не в 2k, а скажем в 4k, при этом получить мало того, что непереносимый код, так еще и неоптимальный. Не проще уже тогда сделать переносимый и поставить более толстый чип? Так что или asm в руки и программим тиньки, или C - но тогда уж начинаем с M16.
|
|
|
|
|
May 12 2007, 04:01
|

Местный
  
Группа: Свой
Сообщений: 208
Регистрация: 6-07-04
Из: Полтава
Пользователь №: 279

|
Цитата(defunct @ May 12 2007, 05:42)  Противоречие у Вас получается ;> C одной стороны Вы говорите о Tiny с 1-2-4Kb памяти, с другой говорите о затратах времени при написании программы на ассемблере. 2Kb на C заполнить - дурное дело не хитрое - полчаса и вся память занята - это не просто сокращенные трудозатраты, это можно сказать их вообще нет. Но и функциональность такой программы в тиньке также получится "никакой".
Хотите функциональности - будьте добры потрудитесь - либо то 8k-16k на C выдавить, либо, что сравнимо по трудозатратам - 1-2k ассемблере. При этом на ассемблере вы получите оптимальный вариант кода естессно непереносимый на другие платформы. На C поизвращавшись тоже втиснете нечто сравнимое по функциональности но не в 2k, а скажем в 4k, при этом получить мало того, что непереносимый код, так еще и неоптимальный. Не проще уже тогда сделать переносимый и поставить более толстый чип?
Так что или asm в руки и программим тиньки, или C - но тогда уж начинаем с M16. IMHO, ложное впечатление. Не так давно рисовал программу для одного измерительного прибора. Изначально предполагалось выполнить на Меге8 как минимум, хоть алгоритм не очень сложный, но громозкой таблица получалась. Проанализировав таблицу, увидел, что зависимость достаточно близка к корню 4-й степени. После извлечения корня зависимость получилась значительно линейнее, поэтому таблица, учитывая, что для вычисления промежуточных результатов была применена кусочно-линейная аппроксимация, оказалась совсем маленькой. Вычисления все целочисленные. Только там, где необходимо было, использовались long. Поэтому сама математика много места не заняла. В результате все уместилось на Тини26 и даже чуть-чуть места осталось. Просмотр ассемблерного листинга показал, что компилятор достаточно грамотно распорядился программной памятью и врядли чисто ассемблерный код оказался бы намного компактнее. Естественно, оптимизация по размеру была выбрана максимальной. Правда пришлось попробовать разные варианты сишного кода, и далеко не всегда более компактный сишный давал более компактный ассемблерный. Но в результате получилось все значительно быстрее и удобнее, чем если бы это всё выполнялось на ассемблере. Поэтому и для "тонких" чипов Си вполне идет. PS: Да, кстати, забить 2 килобайта на Си всякой хренью за полчаса действительно - дурное дело нехитрое. Вот разумно распорядиться - заметно дольше получается. Но все же - получается. А относительно ассемблера, я отнюдь не являюсь ассемблерофобом. Напротив, знать его и уметь на нем код писать считаю необходимым.
|
|
|
|
|
May 12 2007, 12:05
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Видимо самый быстрый вариант на С будет таким: Код volatile unsigned char x=0xAA; volatile unsigned char y;
int main( void ) { char tmp=x; char tmp1=(tmp>>1)&0x40; tmp<<=1; tmp=((tmp>>1)&0xBF)|tmp1; y=tmp;
while(1); return 0; } компилируется в: Код 7: char tmp=x; +00000016: EAE0 LDI R30,0xA0 Load immediate +00000017: E0F0 LDI R31,0x00 Load immediate +00000018: 8110 LDD R17,Z+0 Load indirect with displacement 11: y=tmp; +00000019: 2F01 MOV R16,R17 Copy register +0000001A: 0F00 LSL R16 Logical Shift Left +0000001B: 9505 ASR R16 Arithmetic shift right +0000001C: 7B0F ANDI R16,0xBF Logical AND with immediate +0000001D: 9515 ASR R17 Arithmetic shift right +0000001E: 7410 ANDI R17,0x40 Logical AND with immediate +0000001F: 2B10 OR R17,R16 Logical OR
+00000020: 8311 STD Z+1,R17 Store indirect with displacement итого 7 команд/тактов
|
|
|
|
|
May 12 2007, 12:16
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(kv_addr @ May 12 2007, 06:01)  IMHO, ложное впечатление. ... В результате все уместилось на Тини26 и даже чуть-чуть места осталось. Это не впечатление, это просто мое мнение... Когда ПП <=4k - инструмент для реализации чего-то серьезного может быть только асм. Я не спорю, что некоторые простые задачи - мигалки гирлянд, управление шаговиками, динамическими индикатороми, lcd и т.п. - можно и нужно решать на Tiny + C. Сам грешен ;> Но как только появляется серьезная задача, например "что-то" over IP, программная реализация encoder'a/decoder'a FSK и т.п. - то в тиньку только на асм'е можно такое втиснуть.
|
|
|
|
|
May 12 2007, 15:09
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата программная реализация encoder'a/decoder'a FSK недавно засовывал в 48-ю мегу именно кодер/декодер FSK с автоматическим включением передачи. Писалось на C. Заняло меньше 1 К кода вместе с таблицей DDS, которая ещё и для разных сдвигов фаз при работе без разрыва фазы прописана была. Э-эх так и не понадобилось лазать по асму и поднимать тактовую  Но приходилось иногда думать  как на асме - какую переменную компилер будет перегружать, а давай ему, чтоб не перегружал, локальную переменную подсунем или порядок строк да поменяем  )) Скажу, что думали опуститься до использования хитрых иаровских модификаторов для неперегрузки z-регистров и т.п., но как-то не дошло. Думаю, что примеры, где же асм нужен априори, приведены неправильные, зависимость выбора инструмента от размера памяти программ необоснованна, хотя полностью согласен, что где надо юзать асм, там нефиг микроскопом гвозди забивать
--------------------
aka Vit
|
|
|
|
|
May 12 2007, 15:33
|
Местный
  
Группа: Свой
Сообщений: 256
Регистрация: 6-03-06
Из: Украина, г. Винница
Пользователь №: 15 017

|
Цитата(singlskv @ May 12 2007, 00:22)  А вот с флагом T компиляторонезависимого решения точно не получится  Флаг T это такая фича AVR, и каждый компилятор может ей пользоватся/не пользоваться на свое усмотрение и с С он никак не связан То есть нашаманить наверное чего-то и можно, но это будет "странное" решение Ничего странного, если использовать в IAR битовые поля: Код union ByteBit { signed char Byte; unsigned char UByte; struct { unsigned char Bit0:1, Bit1:1, Bit2:1, Bit3:1, Bit4:1, Bit5:1, Bit6:1, Bit7:1; }; };
union ByteBit s;
void main( void ) { union ByteBit ss,tt;
ss = tt = s; ss.Bit3 = ss.Bit4; ss.Bit4 = tt.Bit3; s = ss; } дает такой результат при среднем уровне оптимизации: Код 24 ss = tt = s; \ 00000000 9100.... LDS R16, s \ 00000004 2F10 MOV R17, R16 25 ss.Bit3 = ss.Bit4; 26 ss.Bit4 = tt.Bit3; \ 00000006 2F21 MOV R18, R17 \ 00000008 FB24 BST R18, 4 \ 0000000A F913 BLD R17, 3 \ 0000000C FB23 BST R18, 3 \ 0000000E F914 BLD R17, 4 27 s = ss; \ 00000010 9310.... STS s, R17 Правда, IAR странно читает 7-й бит в флаг Т - через флаг С перемещает его в 0-й бит регистра(при этом обнуляя сам регистр) и уже потом делает bst Rxx,0. Если в вышеприведенном примере менять местами не 3 и 4-й биты, а 6 с 7-м, то результат получается следующий: Код // 24 ss = tt = s; LDS R16, s MOV R17, R16 // 25 ss.Bit7 = ss.Bit6; // 26 ss.Bit6 = tt.Bit7; MOV R18, R17 BST R18, 6 BLD R17, 7 LSL R18 LDI R18, 0 ROL R18 BST R18, 0 BLD R17, 6 // 27 s = ss; STS s, R17
|
|
|
|
|
May 12 2007, 21:12
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Александр Куличок @ May 12 2007, 19:33)  Ничего странного, если использовать в IAR битовые поля: ............. Правда, IAR странно читает 7-й бит в флаг Т - через флаг С перемещает его в 0-й бит регистра(при этом обнуляя сам регистр) и уже потом делает bst Rxx,0. Если в вышеприведенном примере менять местами не 3 и 4-й биты, а 6 с 7-м, то результат получается следующий: ............... Все правильно, в варианте с битом 7, компилятор поступает правильно, тк значение tt.Bit7 есть не что иное как unsigned char (0 или 1, то есть полный байт), и если далее в коде будет работа с этим битом через обращение tt.Bit7, то он будет пользоваться значением временной регистровой переменной в которой хранится 0 или 1. А в варианте с битами 3 и 4 оптимизатор понял что дальше обращения к этим битам не будет и смог соптимизировать это на конструкцию bst/bld Вы спросите почему он не проделал тоже самое с битами 6 и 7 ? Так собственно по тому, что (8бит) это не только unsigned char(byte) но еще и просто char, для которого правила арифметики чуть-чуть отличаются...(старший бит может быть знаком) Да, и еще, в Вашем варианте для перестановки битов получилось использование двух временных регистров, что не есть гуд... то есть в тестовом варианте это конечно выглядит неплохо, но в реальной задачке, когда другие регистры тоже чем то заняты, это будет приводить к дополнительным(нежелательным) операциям сохранения регистров или в младших регистрах или в памяти/стеке. Ну и в конечном итоге, нужно понимать/помнить что все эти варианты оптимизации(и мои в том числе) в достаточной степени компиляторозависимы, то есть пишем код на С, компилим, если непонравилось, начинаем сначала, и так неколько итераций...
|
|
|
|
|
May 12 2007, 23:08
|

Местный
  
Группа: Свой
Сообщений: 208
Регистрация: 6-07-04
Из: Полтава
Пользователь №: 279

|
Цитата(sensor_ua @ May 12 2007, 18:09)  Думаю, что примеры, где же асм нужен априори, приведены неправильные, зависимость выбора инструмента от размера памяти программ необоснованна, хотя полностью согласен, что где надо юзать асм, там нефиг микроскопом гвозди забивать  Проблема применения асма/Си сама по себе надуманая. Применяется то и там, где дает оптимальный результат. Точка. Все остальное - от лукавого. Если для прибора на Тини26 прекрасно подошел Си, то перед этим нужно было реализовать устройство с 4 взаимонезависимыми каналами, генерирующее выходные импульсы, длительность и скважность которых зависела по определенному табличному закону от длительности и скважности входных, выходные асинхронны по отношению ко входным. Тут, как раз, никакой Си не помог бы, даже с ассемблером пришлось поизголяться, чтобы получить необходимые реалтаймовые параметры.
|
|
|
|
|
May 13 2007, 07:05
|
Местный
  
Группа: Свой
Сообщений: 256
Регистрация: 6-03-06
Из: Украина, г. Винница
Пользователь №: 15 017

|
Цитата Все правильно, в варианте с битом 7, компилятор поступает правильно,тк значение tt.Bit7 есть не что иное как unsigned char (0 или 1, то есть полный байт),и если далее в коде будет работа с этим битом через обращение tt.Bit7, то он будет пользоваться значением временной регистровой переменной в которой хранится 0 или 1.А в варианте с битами 3 и 4 оптимизатор понял что дальше обращения к этим битам не будети смог соптимизировать это на конструкцию bst/bldВы спросите почему он не проделал тоже самое с битами 6 и 7 ?Так собственно по тому, что (8бит) это не только unsigned char(byte) но еще и просто char, для которого правила арифметики чуть-чуть отличаются...(старший бит может быть знаком) Все равно не могу понять поведения компилятора. Почему обработка битового поля внутри байта должна отличается аналогичного поля на границе байта? И почему компилятор должен воспринимать переменную как char, если для нее явно указан модификатор unsigned? А временным регистром можно было бы обойтись и одним. Второй использовал только для того, чтобы листинг не был перегружен обращением к volatile-переменной. Хотя уже сейчас понял, что нагляднее было бы впихнуть все это в какую-нибудь процедуру, отличную от main. К тому же я не стемился минимизовать размер кода/время выполнения, а просто хотел показать, как "заставить" IAR обратиться к флагу Т стандартными средствами С, а не выражениеми типа SREG.T = (s&0x01)!=0;
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|