Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Поменять местами биты в байте.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
ps1x
Допустим есть

0bXY000000.

Как сделать

0bYX000000?

Надо использовать битовые маски и логические операции, только вот с масками никак не разберусь...

И еще, есть ли в CVAVR функция, возвращающая № буквы, т.е. типа chr("a")=35 ?

С уважением.
zltigo
Цитата(ps1x @ May 9 2007, 12:43) *
Допустим есть
0bXY000000.
Как сделать
0bYX000000?

xxx = ((xxx>>1)|(xxx<<1))&0xC0;
Цитата
И еще, есть ли в CVAVR функция, возвращающая № буквы, т.е. типа chr("a")=35 ?

Обалдеть sad.gif
1. "a" - это стринг, а 'буква' это 'a'
2. 'a' это и есть 'номер буквы'
ps1x
Цитата(zltigo @ May 9 2007, 13:22) *
xxx = ((xxx>>1)|(xxx<<1))&0xC0;

Обалдеть sad.gif
1. "a" - это стринг, а 'буква' это 'a'
2. 'a' это и есть 'номер буквы'

да нет, имелось ввиду номер буквы в таблице ASCII
zltigo
Цитата(ps1x @ May 9 2007, 13:36) *
да нет, имелось ввиду номер буквы в таблице ASCII

sad.gif sad.gif sad.gif sad.gif
Я догадался, что имелось ввиду и дал ПРАВИЛЬНЫЙ ответ.
haker_fox
Цитата(ps1x @ May 9 2007, 18:36) *
да нет, имелось ввиду номер буквы в таблице ASCII

А как Вы собираетесть использовать этот номер? Если внутри программы, то так и пишите 'a', 'b', 's' и что угодно и считайте, что это константы.
ps1x
Цитата(haker_fox @ May 9 2007, 14:47) *
А как Вы собираетесть использовать этот номер? Если внутри программы, то так и пишите 'a', 'b', 's' и что угодно и считайте, что это константы.

У меня есть самодельный алфавит для английских букв, и я хочу его выводить на светодиодный индикатор используя что нибудь типа display("hello world");
Для того чтобы брать данные из алфавита, мне надо парсить строку на буквы (ну это просто), а буквы на цифры, чтобы вычислить позицию данных в массиве алфавита.
Serg76
Цитата(zltigo @ May 9 2007, 13:22) *
xxx = ((xxx>>1)|(xxx<<1))&0xC0;

Обалдеть sad.gif
1. "a" - это стринг, а 'буква' это 'a'
2. 'a' это и есть 'номер буквы'

Как мне видится надо сделать так:

xxx = 0b XY00 0000; // условие
xxx = (xxx&0x33f) | ( ( (xxx&0x80)>>1) | ( (xxx&0x40)<<1) );

тогда остальные биты остануться в живых
ps1x
Цитата(Serg76 @ May 9 2007, 15:23) *
Как мне видится надо сделать так:

xxx = 0b XY00 0000; // условие
xxx = (xxx&0x33f) | ( ( (xxx&0x80)>>1) | ( (xxx&0x40)<<1) );

тогда остальные биты остануться в живых


Я это сделал так:
xxx = (((xxx>>1)|(xxx<<1))&xxx&0xBF)^0b01000000;
Serg76
Цитата(ps1x @ May 9 2007, 16:24) *
Я это сделал так:
xxx = (((xxx>>1)|(xxx<<1))&xxx&0xBF)^0b01000000;

Прошу прощения, но по-моему сильно мудрЕно и, как мне кажется, неверно. Смотрите:

при взаимных сдвижках - (xxx>>1)|(xxx<<1) без предварительного выделения нужных бит X и Y с помощью маскирования (xxx&0x80), (xxx&0x40) и последующего сложения ИЛИ непременно возникнет ошибка (Y | b = ????????). Попробуем проследить ход операций:
1. Сдвижка xxx на бит вправо даст 00 bXY0 0000;
2. Сдвижка xxx на бит влево даст bX Y000 0000;
3. После ИЛИ непонятно вообще что получится.

А далее я что-то тоже не понял: ...&xxx&0xBF)^0b01000000;

Если бы мы имели дело с регистром вида 00XY000000, то проканал бы и вариант zltigo, а так у нас имеется еще бит 'b', который как я понимаю может принимать любое значение. Поэтому мой вариант является универсальным, даже если на всех остальных позициях, кроме XY, будут биты с различными значениями.
Laksus
Цитата(Serg76 @ May 9 2007, 14:23) *
Как мне видится надо сделать так:

xxx = 0b XY00 0000; // условие
xxx = (xxx&0x33f) | ( ( (xxx&0x80)>>1) | ( (xxx&0x40)<<1) );

тогда остальные биты остануться в живых

Наверное у Вас опечатка и имелось в виду так:
xxx = (xxx&0x3f) | (((xxx&0x80)>>1) | ((xxx&0x40)<<1)));
________________________
А это, неправильно
Цитата(ps1x @ May 9 2007, 15:24) *
Я это сделал так:
xxx = (((xxx>>1)|(xxx<<1))&xxx&0xBF)^0b01000000;
zltigo
Цитата(Serg76 @ May 9 2007, 17:44) *
....то проканал бы и вариант zltigo,...

Нет. В исходном задании был конкретно описано 8bit (не 10)значение с шестью нулевыми младшими битами. Все прочие фантазии, пожалуйста, оставьте при себе.
Цитата
а так у нас имеется еще бит 'b', который как я понимаю может принимать любое значение.

Не имеется. 0b1100000 equ 0xC0 вот такие дела.
xemul
Тупое решение в лоб
Код
t = x;
x &= 0x3f;
if(t & (1<<6)) x |= 1<<7;
if(t & (1<<7)) x |= 1<<6;

дает не худший расход памяти и более компактный код и под PIC, и под AVR. На ассемблере можно обойтись без временных переменных.

2ps1x есть алфавит, есть индикатор, между ними нужно впихнуть знакогенератор. Для решение задачи требуется только место в ПЗУ под знакогенератор. В какое место знакогенератора можно пристроить интересовавшую Вас функцию, мне непонятно.
Edmundo
Цитата(Serg76 @ May 9 2007, 18:44) *
1. Сдвижка xxx на бит вправо даст 00 bXY0 0000;
2. Сдвижка xxx на бит влево даст bX Y000 0000;
... а так у нас имеется еще бит 'b', который как я понимаю может принимать любое значение...

OFF
А сдвиг 0xC0 на 4 бита вправо дает 00xC smile.gif
Вначале думал, что вы шутите... смеялся smile.gif
Visor
Есть такой флаг "Т", вот через него можно легко гонять биты регистров, с помощью команд BST и BLD. Но это асм, который не все жалуют. cool.gif
Punk
Цитата(ps1x @ May 9 2007, 12:43) *
Допустим есть

0bXY000000.

Как сделать

0bYX000000?

Надо использовать битовые маски и логические операции, только вот с масками никак не разберусь...

И еще, есть ли в CVAVR функция, возвращающая № буквы, т.е. типа chr("a")=35 ?

С уважением.


Хотел бы порекомендовать замечательную книжку: Генри Уоррен, мл. *Алгоритмические трюки для программистов* там есь ответы на все "битовые" вопросы
Dog Pawlowa
Два порта контроллера закольцевать еще не предлагали?
Буду первым в этот раз! biggrin.gif
IgorKossak
Цитата(Serg76 @ May 9 2007, 17:44) *
Прошу прощения, но по-моему сильно мудрЕно и, как мне кажется, неверно. Смотрите:

при взаимных сдвижках - (xxx>>1)|(xxx<<1) без предварительного выделения нужных бит X и Y с помощью маскирования (xxx&0x80), (xxx&0x40) и последующего сложения ИЛИ непременно возникнет ошибка (Y | b = ????????). Попробуем проследить ход операций:
1. Сдвижка xxx на бит вправо даст 00 bXY0 0000;
2. Сдвижка xxx на бит влево даст bX Y000 0000;
3. После ИЛИ непонятно вообще что получится.

А далее я что-то тоже не понял: ...&xxx&0xBF)^0b01000000;

Если бы мы имели дело с регистром вида 00XY000000, то проканал бы и вариант zltigo, а так у нас имеется еще бит 'b', который как я понимаю может принимать любое значение. Поэтому мой вариант является универсальным, даже если на всех остальных позициях, кроме XY, будут биты с различными значениями.

Комментарий в стиле клетчатого.
Что ни предложение, то шедевр!
Я плакалъ.
kv_addr
Цитата(Visor @ May 10 2007, 16:07) *
Есть такой флаг "Т", вот через него можно легко гонять биты регистров, с помощью команд BST и BLD. Но это асм, который не все жалуют. cool.gif

На ассемблере получается очень просто с использованием временного регистра и флага Т:
...
ld temp, x
bst temp, 6
bld x, 7
bst temp, 7
bld x, 6
...
Пробовал получить такую же последовательность команд при помощи IAR-C. Хотя IAR-C в самом принципе флаг Т использует, но как только ни пытался шаманить, так и не смог выдавить такую компактную последовательность. sad.gif
ae_
Цитата(ps1x @ May 9 2007, 18:43) *
Допустим есть 0bXY000000.
Как сделать 0bYX000000?
...

асм, три инструкции:
bst temp, 7
lsl temp
bld temp, 6

в С не силён, но попробую :)
temp=(temp<<1)|(0x40 & (temp>=128))
haker_fox
Цитата(ps1x @ May 9 2007, 21:16) *
У меня есть самодельный алфавит для английских букв, и я хочу его выводить на светодиодный индикатор используя что нибудь типа display("hello world");
Для того чтобы брать данные из алфавита, мне надо парсить строку на буквы (ну это просто), а буквы на цифры, чтобы вычислить позицию данных в массиве алфавита.

Я думаю что установить математическую зависимость между вашим алфавитом и кодами ASCII не проблема... На основании этого можно сделать выборку из массива...
kv_addr
Цитата(ae_ @ May 11 2007, 05:04) *
асм, три инструкции:
bst temp, 7
lsl temp
bld temp, 6

Поганятся остальные биты.

Цитата(ae_ @ May 11 2007, 05:04) *
в С не силён, но попробую smile.gif
temp=(temp<<1)|(0x40 & (temp>=128))

Не годится, потому что это - только лишь логический сдвиг влево.
singlskv
Цитата(kv_addr @ May 11 2007, 04:34) *
На ассемблере получается очень просто с использованием временного регистра и флага Т:
...
ld temp, x
bst temp, 6
bld x, 7
bst temp, 7
bld x, 6
...
Пробовал получить такую же последовательность команд при помощи IAR-C. Хотя IAR-C в самом принципе флаг Т использует, но как только ни пытался шаманить, так и не смог выдавить такую компактную последовательность. sad.gif

Длинновато... , да и лишний регистр используем smile.gif
Код
;  4 words / 4 cycles;
; Input:  tmp= abcdefgh
reversbits78:
    bst    tmp,7   ; T=a
    lsl    tmp     ; tmp= bcdefgh0
    asr    tmp     ; tmp= bbcdefgh
    bld    tmp,6   ; tmp= bacdefgh
kv_addr
Цитата(singlskv @ May 11 2007, 18:27) *
Длинновато... , да и лишний регистр используем smile.gif

Дык, не спорю. smile.gif
Правда мой вариант более универсален. Можно применить к любым битам.

Цитата(singlskv @ May 11 2007, 18:27) *
Код
;  4 words / 4 cycles;
; Input:  tmp= abcdefgh
reversbits78:
    bst    tmp,7 ; T=a
    lsl    tmp; tmp= bcdefgh0
    asr    tmp; tmp= bbcdefgh
    bld    tmp,6 ; tmp= bacdefgh

Пытался вышаманить из IAR-C, а там, как на мой взгляд, с asr ещё более проблематично, чем с флагом Т. 05.gif
singlskv
Цитата(kv_addr @ May 11 2007, 19:50) *
Пытался вышаманить из IAR-C, а там, как на мой взгляд, с asr ещё более проблематично, чем с флагом Т. 05.gif

Дык с ASR как раз просто,
вот код на С:
Код
volatile unsigned char x=0b10101010;
volatile unsigned char y;

int main()
{
  char tmp=x;
  tmp >>=1;
  y=tmp;

  while (1);
  return tmp;
}

А вот результат компиляции:
Код
7:          char tmp=x;
+00000032:   91800060    LDS     R24,0x0060       Load direct from data space
8:          tmp >>=1;
+00000034:   9585        ASR     R24              Arithmetic shift right
9:          y=tmp;
+00000035:   93800062    STS     0x0062,R24       Store direct to data space

правда на Gcc, но я думаю на IAR будет аналогично (лень проверять)

А вот с флагом T непонятно...
kv_addr
Цитата(singlskv @ May 11 2007, 19:39) *
Дык с ASR как раз просто,
вот код на С:
Код
volatile unsigned char x=0b10101010;
volatile unsigned char y;

int main()
{
  char tmp=x;
  tmp >>=1;
  y=tmp;

  while (1);
  return tmp;
}

А вот результат компиляции:
Код
7:          char tmp=x;
+00000032:   91800060    LDS     R24,0x0060       Load direct from data space
8:          tmp >>=1;
+00000034:   9585        ASR     R24              Arithmetic shift right
9:          y=tmp;
+00000035:   93800062    STS     0x0062,R24       Store direct to data space

правда на Gcc, но я думаю на IAR будет аналогично (лень проверять)

IAR-C дает следующий результат:
Код
...
        LDI     R30, `x`
        LDI     R31, 0
        LD      R16, Z
        LSR     R16
        STD     Z+1, R16
...

Как видите, результат зависит от выбранного компилятора.
singlskv
Цитата(kv_addr @ May 12 2007, 00:13) *
IAR-C дает следующий результат:
Код
...
        LDI     R30, `x`
        LDI     R31, 0
        LD      R16, Z
        LSR     R16
        STD     Z+1, R16
...

Как видите, результат зависит от выбранного компилятора.

А у Вас случайно не стоит опция воспринимать char как unsigned char ?


Цитата(singlskv @ May 12 2007, 00:20) *
А у Вас случайно не стоит опция воспринимать char как unsigned char ?


Отвечу сам...
У Вас таки стоит опция char как unsigned char smile.gif

Вы так меня заинтриговали, что я даже не поленился включить второй копм
на котором есть IAR и таки проверить соблюдает ли IAR стандарт С (ну хотябы пусть и не
по умолчанию), оказалось соблюдает smile.gif :
Код
6:          char tmp=x;
+00000016:   EAE0        LDI     R30,0xA0         Load immediate
+00000017:   E0F0        LDI     R31,0x00         Load immediate
+00000018:   8100        LDD     R16,Z+0          Load indirect with displacement
8:          y=tmp;
+00000019:   9505        ASR     R16              Arithmetic shift right
+0000001A:   8301        STD     Z+1,R16          Store indirect with displacement
kv_addr
Цитата(singlskv @ May 11 2007, 23:20) *
А у Вас случайно не стоит опция воспринимать char как unsigned char ?

Проверил, стояло дефолтное "Plain 'char' is Unsigned", поменял на "Signed", получилось следующее:
Код
...
        LDI     R30, `x`
        LDI     R31, 0
        LD      R16, Z
        ASR     R16
        STD     Z+1, R16
...

Ну, с asr вроде как разобрались. А вот с флагом Т пока не совсем понятно. Заметил, что компилятор его использует при проверках битов и при установках либо снятиях битов в регистрах, а вот чтобы флаг Т был установлен по биту из регистра и потом любой бит этого или иного регистра был установлен по этому флагу, такого не вышаманил.
singlskv
Цитата(kv_addr @ May 12 2007, 01:07) *
Проверил, стояло дефолтное "Plain 'char' is Unsigned", поменял на "Signed", получилось следующее:
Код
...
        LDI     R30, `x`
        LDI     R31, 0
        LD      R16, Z
        ASR     R16
        STD     Z+1, R16
...

Ну, с asr вроде как разобрались. А вот с флагом Т пока не совсем понятно. Заметил, что компилятор его использует при проверках битов и при установках либо снятиях битов в регистрах, а вот чтобы флаг Т был установлен по биту из регистра и потом любой бит этого или иного регистра был установлен по этому флагу, такого не вышаманил.

А вот с флагом T компиляторонезависимого решения точно не получится sad.gif
Флаг T это такая фича AVR, и каждый компилятор может ей пользоватся/не пользоваться
на свое усмотрение и с С он никак не связан

То есть нашаманить наверное чего-то и можно, но это будет "странное" решение
kv_addr
Цитата(singlskv @ May 12 2007, 00:22) *
А вот с флагом T компиляторонезависимого решения точно не получится sad.gif
Флаг T это такая фича AVR, и каждый компилятор может ей пользоватся/не пользоваться
на свое усмотрение и с С он никак не связан

Хотел бы заметить, что в данном случае я не пытался получить какой-либо совместимости. Меня интересовало поведение конкретного компилятора с максимальным уровнем оптимизации. Т.е., в какой степени он может воспользоваться ресурсами контроллера, а именно - AVR, в пределе.

Наверно согласитесь, что Embedded C все же вещь достаточно специфическая и должна иметь возможность по максимуму использовать возможности конкретно взятого контроллера. Иначе эффективное кодирование может быть не реализованым. Это для ПиСи можна писать "гектарные" программы, не сильно заботясь о "выжимании воды", а микроконтроллер - это такой себе "ночной горшок с ручкой вовнутрь" - чтобы места меньше занимал. wink.gif

Ведь и переносимость программ, написанных на том же самом С, в определенной степени условна даже внутри семейства, не говоря о разных семействах.

Цитата(singlskv @ May 12 2007, 00:22) *
То есть нашаманить наверное чего-то и можно, но это будет "странное" решение

Предпочел бы использовать термин - "трюковое". smile.gif
defunct
Цитата
Ведь и переносимость программ, написанных на том же самом С, в определенной степени условна даже внутри семейства, не говоря о разных семействах.

Позвольте с вами несогласиться.
Переносимость в большой мере зависит от нас самих, если хотите чтобы код был переносимым - пишите его таким сразу. ;>

Как так писать - создать прослойку между железом и программой - операционку. Писать программу уже не под железо а под ОС. То что код будет невсегда максимально эффективным, кого это волнует?
kv_addr
Цитата(defunct @ May 12 2007, 03:15) *
Позвольте с вами несогласиться.
Переносимость в большой мере зависит от нас самих, если хотите чтобы код был переносимым - пишите его таким сразу. ;>

Если стоит задача переносимости, то - да. В противном случае - не обязательно.

Цитата(defunct @ May 12 2007, 03:15) *
Как так писать - создать прослойку между железом и программой - операционку. Писать программу уже не под железо а под ОС. То что код будет невсегда максимально эффективным, кого это волнует?

Опять же, зависит от поставленой задачи. "Толстые" задачи на "толстых" чипах удобнее решать таким образом. Но 128-ю Мегу применять там, где и Тиня управится, это как бы из пушки да по воробьям. А тут уж и ужиматься приходится. Инструментов для создания программы фактически всего-то два - ассемблер да Си. Ассемблер позволяет дать максимально эффективный код, но со значительной затратой времени. Си, при соответствующем подходе, может дать код не намного избыточнее, но создание программы идет значительно быстрее, поэтому является вполне разумным компромиссом и для мелких чипов. Вот тут, как раз, и нужны наработанные приемы получения компактного кода, пускай даже в ущерб переносимости.

"Кого ЭТО волнует?"© wink.gif
defunct
Цитата(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.
kv_addr
Цитата(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 килобайта на Си всякой хренью за полчаса действительно - дурное дело нехитрое. Вот разумно распорядиться - заметно дольше получается. Но все же - получается. А относительно ассемблера, я отнюдь не являюсь ассемблерофобом. Напротив, знать его и уметь на нем код писать считаю необходимым.
singlskv
Видимо самый быстрый вариант на С будет таким:
Код
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 команд/тактов
defunct
Цитата(kv_addr @ May 12 2007, 06:01) *
IMHO, ложное впечатление.
...
В результате все уместилось на Тини26 и даже чуть-чуть места осталось.

Это не впечатление, это просто мое мнение...
Когда ПП <=4k - инструмент для реализации чего-то серьезного может быть только асм.

Я не спорю, что некоторые простые задачи - мигалки гирлянд, управление шаговиками, динамическими индикатороми, lcd и т.п. - можно и нужно решать на Tiny + C. Сам грешен ;>
Но как только появляется серьезная задача, например "что-то" over IP, программная реализация encoder'a/decoder'a FSK и т.п. - то в тиньку только на асм'е можно такое втиснуть.
sensor_ua
Цитата
программная реализация encoder'a/decoder'a FSK

недавно засовывал в 48-ю мегу именно кодер/декодер FSK с автоматическим включением передачи. Писалось на C. Заняло меньше 1 К кода вместе с таблицей DDS, которая ещё и для разных сдвигов фаз при работе без разрыва фазы прописана была. Э-эх так и не понадобилось лазать по асму и поднимать тактовуюwink.gif Но приходилось иногда думатьwink.gif как на асме - какую переменную компилер будет перегружать, а давай ему, чтоб не перегружал, локальную переменную подсунем или порядок строк да поменяемwink.gif)) Скажу, что думали опуститься до использования хитрых иаровских модификаторов для неперегрузки z-регистров и т.п., но как-то не дошло. Думаю, что примеры, где же асм нужен априори, приведены неправильные, зависимость выбора инструмента от размера памяти программ необоснованна, хотя полностью согласен, что где надо юзать асм, там нефиг микроскопом гвозди забиватьwink.gif
Александр Куличок
Цитата(singlskv @ May 12 2007, 00:22) *
А вот с флагом T компиляторонезависимого решения точно не получится sad.gif
Флаг 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
singlskv
Цитата(Александр Куличок @ 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, для которого правила арифметики чуть-чуть отличаются...(старший бит может быть знаком)

Да, и еще, в Вашем варианте для перестановки битов получилось использование
двух временных регистров, что не есть гуд...
то есть в тестовом варианте это конечно выглядит неплохо, но в реальной задачке,
когда другие регистры тоже чем то заняты, это будет приводить к
дополнительным(нежелательным) операциям сохранения регистров или в младших
регистрах или в памяти/стеке.

Ну и в конечном итоге, нужно понимать/помнить что все эти варианты
оптимизации(и мои в том числе) в достаточной степени компиляторозависимы,
то есть пишем код на С, компилим, если непонравилось, начинаем сначала,
и так неколько итераций...
kv_addr
Цитата(sensor_ua @ May 12 2007, 18:09) *
Думаю, что примеры, где же асм нужен априори, приведены неправильные, зависимость выбора инструмента от размера памяти программ необоснованна, хотя полностью согласен, что где надо юзать асм, там нефиг микроскопом гвозди забиватьwink.gif

Проблема применения асма/Си сама по себе надуманая. Применяется то и там, где дает оптимальный результат. Точка. Все остальное - от лукавого. Если для прибора на Тини26 прекрасно подошел Си, то перед этим нужно было реализовать устройство с 4 взаимонезависимыми каналами, генерирующее выходные импульсы, длительность и скважность которых зависела по определенному табличному закону от длительности и скважности входных, выходные асинхронны по отношению ко входным. Тут, как раз, никакой Си не помог бы, даже с ассемблером пришлось поизголяться, чтобы получить необходимые реалтаймовые параметры.
Александр Куличок
Цитата
Все правильно, в варианте с битом 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;
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.