ICC AVR и стpоки - Page 5

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From Russian to

Threaded View
ICC AVR и стpоки
Sep 2003 19:36:35 +0000 (UTC):

[...]

HZ>>     st -Y,...        ; тут сунули в стек еще переменную

OR>  Слушай, а как это сделано у IAR/MSP430 ? Неужели тоже два стека и регистр
OR> под второй указатель занят?

    Нет, стек один. Там SP все умеет - и адресоваться как угодно, и адресную
арифметику одной командой.

OR> Напоминаю ещё раз как это сделано у x86/16 (оно короче и проще объяснить)
OR> SP - указатель стека, с которым можно кое-что сделать, но адресоваться
OR> по нему нельзя. BP - указательный регистр, который по умолчанию работает
OR> в сегменте стека и по нему удобно обращаться к стековому кадру
OR>    push bp
OR>    mov  bp,sp
OR>    sub  sp,size of locals ; резервируем место
OR> Теперь sp не трогаем, обработчики прерываний в стек могут спокойно
OR> писать. Адресация относительно bp вверх - аргументы функций,
OR> вниз - локальные переменные.

    Да, Алексей уже объяснил, спасибо.

OR> Для MSP430 это должно выглядеть как
OR>    sub sp,size of locals
OR> и вся адресация относительно SP в плюс.

    Именно так и выглядит:

        SUB.W   #0x50, SP ; выделено 80 байтов стеке

[...]

HZ>> Или сразу выделять по максимуму, сколько в функции нужно?
OR>  Ну да. И у PDP11 так было, и, думаю, IAR/MSP430 так делает.

    Да, так делает, хотя мог бы и оптимизировать, ничто этому не мешает.

HZ>>     Причем тут 430-й? У него SP нормально сделан, он позволяет
HZ>> адресоваться
OR>  А притом, что место под локальные переменные и на нём резервировать
OR> надо. Т.е. его надо модифицировать. В силу 16-разрядности процессора
OR> такая модификация атомарна автоматически, но она есть.

    У AVR модификации 16-разрядных указателей тоже атомарны.

OR> Возможно, из-за атомарности ты её и не заметил.

    :) Еще как заметил. Из-за этого кое-где в обработчиках прерываний возникают
з..цы...

[...]

HZ>>     А это в ОС используется - там зачастую удачным является решение,
HZ>> когда для прерываний свой стек.
OR>  Какой он "свой"? Тут два стека - возвратов и данных.
OR> Прерывание работает в стеке управления основной программы,
OR> как минимум вход в него. Только потом оно может переключить
OR> указатель стека на системную область и дальше работать там.

OR> "У прерывания свой стек" - это когда у ядра процессора есть
OR> отдельный указатель для этого и при прерывании даже PC прерываемой
OR> программы сохраняется в другом стеке.

    А вот это не понял: как это реализуется физически? На аппаратном уровне,
что ли? И какой смысл в этом? Насколько я понимаю, адрес возврата как раз и
нужно запоминать в стеке прерванного процесса, чтобы потом, когда нужно
передать управление этому процессу, извлечь адрес из стека данного процесса.

...so long!

### Она была от счастья на седьмом месяце...




Re: ICC AVR и стpоки
21-Sep-03 11:57 Boris Popov wrote to Harry Zhurov:

BP>>> избыточного кода.  У меня остались записи, согласно которым коэффициент
BP>>> оверхеда для AVR (компилятор ИАР) может быть от 1 до 1.47.

BP>     Забыл добавить - на проекте в 7.3KB средний оверхед по сравнению
BP> с С версией составил около 1.19.
 Т.е. gcc в режиме С несмотря на свой более толстый код даст столько же,
сколько IAR в режиме C++.

HZ>>     А если какой-то пин используется по нескольким назначениям, то тут тем
HZ>> более удобно завернуть всю функциональность в объект, который содержит в
HZ>> себе
HZ>> все, что работает с этим пином, включая и то периферийное устройство,
HZ>> которое функционирует через этот пин.

BP>     Hу да, давай будем объединять eeprom и lcd из за того, что lcd
BP> использует использует SDA как один из разрядов ШД.
 А оставшиеся разряды шины данных LCD, кстати, принимают код
полноразвязанной (диод на каждой кнопке) клавиатуры, линии сканирования
которых в "1" в момент обращения к LCD :-)

BP>     Hа C я размещаю все kbd переменные в структуре.  Каждая
BP> kbd_* функция может загружать указатель на эту структуру, а может и
BP> просто
BP> сделать lds если в ее задачи входит только проверка флагов.  Cross-call
BP> оптимизация великолепно выделит lds zl/zh, kbd_cb и сэкономит по слову
 Эх, кто бы это в gcc затолкал... У IAR/AVR есть, у KeilC51 есть...
Из-за одного стека у gcc это будет не так роскошно, как у IAR (он может
даже заталкивание в стек данных аргументов функций выделить в отдельную
подпрограммку...), но всё равно полезно.

BP> на каждой загрузке.  А пользователь функций вообще не будет загружать
BP> никакие указатели и обойдется простым (r)call.
 Что я и имел ввиду, когда говорил, что аргумент "а если спрятать от
левой записи переменные через static в файле, то будет проигрыш,
так как в классе можно поле сделать protected и читать его
через inline-функцию".
Реально if (KbdHit()) при KbdHit() - не inline функции выливается в
rcall / tst / breq, а инлайновая Kbd.IsHit() хорошо если оптимизируется
до lds Kbd.flag / tst / breq (уже не короче), а то ведь и
ldi zh/zl, Kbd / ldd Z+offset field / tst / breq может выйти (ну
нет у меня IAR EC++, а работа gcc с этим делом тут уже отмечалась :-()

BP> Ы ? (c) OR.
 Так отож :-)

wbr,
p.s. А моё отношение к незапрету прерываний на 1 такт... ну вы поняли...
Тем более, что на момент разработки AVR это не было откровением...
Так скоро в подпись затолкаю (наболело - недавно много выдачи gcc по -S
просматривал, а оно так и прёт). И вообще, надо сделать что-то
фортунообразное и набить моими претензиями к AVR :-)

--
/* Oleksandr Redchuk, Brovary, Ukraine */
/* real '\x40' real '\x2E' kiev '\x2E' ua     */


ICC AVR и стpоки
Oleksandr Redchuk wrote to Harry Zhurov on Sun, 21 Sep 2003 20:33:51 +0000
(UTC):

    Что-то тут накладка, по ходу, вышла? Отвечаешь, вроде, BP, а X-CT ко мне
(оно у меня ярко-зеленым цветом выделяется на фоне остальных сообщений). :)

BP>>     Забыл добавить - на проекте в 7.3KB средний оверхед по сравнению
BP>> с С версией составил около 1.19.
OR>  Т.е. gcc в режиме С несмотря на свой более толстый код даст столько же,
OR> сколько IAR в режиме C++.

    Здесь позволю себе усомниться в объективности цифири. Хотя бы потому, что
очень проблематично иметь два проекта приличного размера, реализованных на
разных языках, настолько идентичных по функциональности, чтобы возможно было
вылавливать эти проценты. Сравнивать можно какие-то небольшие фрагменты (на
предмет качества кодогенерации), б.м. функционально законченные куски (на
предмет соответствия подхода к решению задачи самой задаче).


[...]

BP>> на каждой загрузке.  А пользователь функций вообще не будет загружать
BP>> никакие указатели и обойдется простым (r)call.
OR>  Что я и имел ввиду, когда говорил, что аргумент "а если спрятать от
OR> левой записи переменные через static в файле, то будет проигрыш,
OR> так как в классе можно поле сделать protected и читать его
OR> через inline-функцию".
OR> Реально if (KbdHit()) при KbdHit() - не inline функции выливается в
OR> rcall / tst / breq, а инлайновая Kbd.IsHit() хорошо если оптимизируется
OR> до lds Kbd.flag / tst / breq (уже не короче), а то ведь и
OR> ldi zh/zl, Kbd / ldd Z+offset field / tst / breq может выйти (ну
OR> нет у меня IAR EC++, а работа gcc с этим делом тут уже отмечалась :-()


    В общем случае:

        C   :  rcall / lds / tst / ... / ret / tst

        C++ :  ldi   / ldi / ldd / tst

    В частном случае:

        C   :  rcall / lds / ret / tst

        C++ :  lds   / tst


    Вот пример реализации последнего:

// -------------------------------------
class TSlon
{
public:
    __z void add(int x);
    bool IsTrue() const { return f; }

private:
    int Value;
    bool f;
};

TSlon slon;
extern int y;

void main()
{
    if(slon.IsTrue()) y = 1;
}
// -------------------------------------

       main:
9100....                   LDS     R16,(slon + 2)
2300                       TST     R16
F031                       BREQ    ??main_0



    Вообще, у меня сложилось впечатление, что некоторый оверхед в С++ по
сравнению с С обусловлен не столько механизмами реализации - тут больше влияет
целевая архитектура и компилятор, а тем, что С++ более высокоуровневый язык,
чем С, и поэтому больше отдано на откуп компилятору, который, как правило,
далеко не идеал. В этом же основная причина появления оверхеда при переходе с
асма на С.


...so long!

### Пейте томатный сок. Томатный сок - это здоровье. Здоровье - это спорт.
Спорт - это победы. Победы - это женщины. Женщины - это СПИД. СПИД - это
смерть. HЕ ПЕЙТЕ ТОМАТHЫЙ СОК!




Re: ICC AVR и стpоки

Quoted text here. Click to load it

Всей поддержки C++ для linux kernel module - 617 строк/11930 байт.
Включая конструкторы/деструкторы для статических объектов,
обертки для new/delete.
Исключения я не использую.
Чего еще нужно?

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

Re: ICC AVR и стpоки

BP>>     Hа C я размещаю все kbd переменные в структуре.  Каждая
BP>> kbd_* функция может загружать указатель на эту структуру, а может и
BP>> просто
BP>> сделать lds если в ее задачи входит только проверка флагов.  Cross-call
BP>> оптимизация великолепно выделит lds zl/zh, kbd_cb и сэкономит по слову
OR>  Эх, кто бы это в gcc затолкал... У IAR/AVR есть, у KeilC51 есть...
OR> Из-за одного стека у gcc это будет не так роскошно, как у IAR (он может
OR> даже заталкивание в стек данных аргументов функций выделить в отдельную
OR> подпрограммку...), но всё равно полезно.

    Угу, сам алгоритм вроде не очень сложный.  И для полного счастья
поддержку выкидывания неиспользованных функций в линкере.  Тогда не придется
распихивать библиотечные функции в отдельные файлы, a алгоритму cross-call
будет где развернуться.

OR> p.s. А моё отношение к незапрету прерываний на 1 такт... ну вы поняли...

    Это вообще один из замечательных багов дизайна.  К более поздним
"радостям" можно отнести вылет портов F и G из области действия SBI/CBI.

--
Boris Popov
bp shift-2 vertex.kz

Re: ICC AVR и стpоки
22-Sep-03 10:59 Boris Popov wrote to Oleksandr Redchuk:

BP> поддержку выкидывания неиспользованных функций в линкере.  Тогда не
BP> придется
BP> распихивать библиотечные функции в отдельные файлы, a алгоритму cross-call
BP> будет где развернуться.
 Говорят, в этом помогает

DEADCODESTRIP := -Wl,-static -fvtable-gc -fdata-sections\
 -ffunction-sections -Wl,--gc-sections -Wl,-s

foo : foo.c
    g++ $(DEADCODESTRIP) $< -o $@

Причём благодаря -ftable-gc это даже по таблицам виртуальных функций
как-то протаптывается. А по -fdata-sections выкидываются
нигде не задействованные переменные файловой области видимости.

Ещё не проверял.


OR>> p.s. А моё отношение к незапрету прерываний на 1 такт... ну вы поняли...

BP>     Это вообще один из замечательных багов дизайна.  К более поздним
BP> "радостям" можно отнести вылет портов F и G из области действия SBI/CBI.

Ну архитектуру, сдуя по слухам, разрабатывали программисты...
Может, программисты на VB? :-)  :-((

wbr,
--
/* Oleksandr Redchuk, Brovary, Ukraine */
/* real '\x40' real '\x2E' kiev '\x2E' ua     */


Re: ICC AVR и стpоки
22-Sep-03 03:08 Harry Zhurov wrote to Oleksandr Redchuk:

HZ>     Что-то тут накладка, по ходу, вышла? Отвечаешь, вроде, BP, а X-CT ко
HZ> мне
HZ> (оно у меня ярко-зеленым цветом выделяется на фоне остальных сообщений).
HZ> :)
 Никакой накладки. Я тебе и писал, дополнения к его письму.

OR>> Реально if (KbdHit()) при KbdHit() - не inline функции выливается в
OR>> rcall / tst / breq, а инлайновая Kbd.IsHit() хорошо если оптимизируется
OR>> до lds Kbd.flag / tst / breq (уже не короче), а то ведь и
OR>> ldi zh/zl, Kbd / ldd Z+offset field / tst / breq может выйти (ну
OR>> нет у меня IAR EC++, а работа gcc с этим делом тут уже отмечалась :-()


HZ>     В общем случае:
HZ>         C   :  rcall / lds / tst / ... / ret / tst
HZ>         C++ :  ldi   / ldi / ldd / tst
HZ>     В частном случае:
HZ>         C   :  rcall / lds / ret / tst
HZ>         C++ :  lds   / tst
 Я имел ввиду размер в точке вызова (суммарный объём кода), а не
время выполнения проверки. Меня обычно не волнует время проверки
"а есть ли байт в буфере уарт?", "а закончился ли цикл оцифровки по всем
6 каналам?" и т.п.


HZ> {
HZ>     if(slon.IsTrue()) y = 1;
HZ> }
HZ> // -------------------------------------

HZ>        main:
HZ> 9100....                   LDS     R16,(slon + 2)
HZ> 2300                       TST     R16
HZ> F031                       BREQ    ??main_0
В C-шном варианте это выглядело бы как
      rcall SlonIsTrue
      tst r16
      breq
либо call для мега16 и выше. Т.е. inline не короче.
А если там проверка битового флага в поле, то инлайновый вариант
ещё толще будет.

HZ> далеко не идеал. В этом же основная причина появления оверхеда при
HZ> переходе с асма на С.
 Ну да.  Именно это я и пытаюсь тебе сказать.
 И именно поэтому есть куча задач, где C++ нафиг не нужен,
так же как и ещё остались задачи, для которых нафиг не нужен C,
можно легко и быстро сделать на асме. Но вот уже довольно много
задач, решаемых на асме "грустновато" и много людей, уверенно
перешедших на C. И в этом случае им проще и те мелкие задачки
тоже на C написать. Вот когда они (мы) будем большинство задач
делать на C++, тогда и 4-канальный АЦП на RS232 будет весь из
себя на классах писаться, чтобы "руку не сбивать".
Ну нет у меня таких задач, где C++ "аж пыщыть" как _нужен_.
А ты пытаешься доказать, что его _можно_и_нужно_ применять и
для простых задач. А я говорю, что его можно применять _И_ для
простых задач, если без него всё равно не жить, а так -- нет смысла,
разве что из любопытства или идейных соображений.

wbr,
--
/* Oleksandr Redchuk, Brovary, Ukraine */
/* real '\x40' real '\x2E' kiev '\x2E' ua     */


ICC AVR и стpоки
Sep 2003 08:22:36 +0000 (UTC):

[...]

HZ>> {
HZ>>     if(slon.IsTrue()) y = 1;
HZ>> }
HZ>> // -------------------------------------

HZ>>        main:
HZ>> 9100....                   LDS     R16,(slon + 2)
HZ>> 2300                       TST     R16
HZ>> F031                       BREQ    ??main_0
OR> В C-шном варианте это выглядело бы как
OR>       rcall SlonIsTrue
OR>       tst r16
OR>       breq
OR> либо call для мега16 и выше. Т.е. inline не короче.

    Как это не короче? В сишном варианте еще есть тело функции, где этот самый
lds и ret. Т.е. сишный вариант длиннее на [r]call и ret. И плюс время
выполнения.

OR> А если там проверка битового флага в поле, то инлайновый вариант
OR> ещё толще будет.

    Да с чего это? Я еще понимаю, тип bool вносит оверхед, поэтому нужно еще
подумать, стоит ли его применять, но инлайн всегда короче неинлайна на
инструкции вызова и возврата, как минимум! А иногда еще есть дополнительный
выигрыш от того, что не нужно копировать данные при передаче аргументов, чтобы
выполнить соглашения о вызове - в инлайне компилятор ничего копировать не
должен и распределяет аргументы как выгодно.


[...]

OR> Ну нет у меня таких задач, где C++ "аж пыщыть" как _нужен_.
OR> А ты пытаешься доказать, что его _можно_и_нужно_ применять и
OR> для простых задач. А я говорю, что его можно применять _И_ для
OR> простых задач, если без него всё равно не жить, а так -- нет смысла,
OR> разве что из любопытства или идейных соображений.

    А я пытаюсь донести еще более простую мысль: вот есть компилятор, генерит
хороший код, оверхеда особого нет - субъективно он даже не заметен, - ну, и
чего бы не использовать инструмент? Я ж не призываю все бросить, и начать из
идейных или еще каких-нибудь соображений!? Но когда есть Жигуль и Тойота,
почему бы не ездить на последней? Она не хуже! Бензина жрет (в среднем) в
пределах 10% больше, а ездит быстрее, и комфортнее на ней! В крайнем случае она
может и как Жигуль ездить. Аргумент: "А мне не надо такую тачку, я и на Жигулях
доеду нормально!" в этой ситуации выглядит смешно.

    Сегодня я при писании на С испытываю такое же чувство, какое возникало при
необходимости делать что-то на 51-м после AVR.

...so long!

### Есть книги, которые приятно взять в руки и... рвать, рвать, рвать!




Re: ICC AVR и стpоки
21-Sep-03 19:45 Alexander Derazhne wrote to Oleksandr Redchuk:

 OR>> Я таки попробую (исключительно из любопытства) плюсы если не на AVR,
 OR>> то на
 OR>> MSP, но не вижу я пока особых преимуществ у него на моих объёмах.
 OR>> Все твои примеры слонов, уартов и spi просматривал  - всё равно не
 OR>> вижу :-)

[...]
AD> Но
AD> вот в отношении развития и сопровождения... Как только в задаче появляется
AD> многопоточность, разделяемые ресурсы и обкладывание семафорами -
 Пример неоспоримого на мой взгляд преимущества C++ (в письме
Василевскому) как раз этого и касается :-)

AD> инкапсуляция становится спасением. Если необходимо в рантайме принимать
AD> решение о работе в той или иной конфигурации, то начиная с некоторого
AD> объёма
AD> _нужно_ применять наследование. В сопровождаемом мной проекте можно
 Аналогично в том же письме - про подмену клавиатуры уартом
именно _в_рантайме_ (как отладочный режим компиляцией под #if -- вполне
можно и без плюсов, если остальное без плюсов тоже ложится).
Там фрагментик на тему "как это делалось 20 лет назад на Э60 на чистом С"
и мои слова о бессмысленности делать это вручную при наличии C++.

AD> бы выбором конкретных классов из имеющихся ещё в main. Хотя и овехед
AD> налицо - код занял бы больше места, те куски, которые сейчас безусловно
AD> выполняются, попали бы дубликатами в каждый класс.
 Ну если их можно выделить в подфункции, то сделать их protected
где-то в базовом классе.
 Хотя _небольшие_ _статические_ (т.е. периода компиляции) различия
я бы всё же делал через #if. А если общие места небольшие - не грех
иповторить в разных местах. А если "куча-не куча", то тут вопрос
темперамента и чужое решение всегда не понравится :-)

 Повторюсь:
Если проект всё равно "очень хочет" плюсов, то это одно дело,
а если там всё великолепно укладывается в один "главный цикл"
с работающими в прерываниях "потоками" UART или ещё что-нибудь в этом
роде, то плюсы там -- либо "чтобы руку не сбивать", либо "чисто
ради идеи". Особых преимуществ нет. "Не особых" - тоже под вопросом.

wbr,
--
/* Oleksandr Redchuk, Brovary, Ukraine */
/* real '\x40' real '\x2E' kiev '\x2E' ua     */


Re: ICC AVR и стpоки
Hello, Oleksandr!
18:26:59 +0000 (UTC):

 OR> Если проект всё равно "очень хочет" плюсов, то это одно дело, а если
 OR> там всё великолепно укладывается в один "главный цикл"
 OR> с работающими в прерываниях "потоками" UART или ещё что-нибудь в
 OR> этом роде, то плюсы там -- либо "чтобы руку не сбивать", либо "чисто
 OR> ради идеи". Особых преимуществ нет. "Не особых" - тоже под вопросом.

    Консенсус.

With best regards,
            Alexander Derazhne.



Re: ICC AVR и стpоки
21-Sep-03 19:18 Harry Zhurov wrote to Oleksandr Redchuk:

HZ>>>>> Т.е. обычные, одиночные классы, как типы определяемые пользователем -
HZ>>>>> это так, ерунда, от которой вреда больше, чем пользы?
OR>>  Нет, от которой зачастую пользы меньше, чем высота барьера при
OR>> переходе от C на C++.

HZ>     А что определяет (составляет) высоту барьера?
 Как обычно, куча субъективных факторов, маскирующихся под объективные :-)

OR>> Я таки попробую (исключительно из любопытства) плюсы если не на AVR,
OR>> то на MSP

HZ>     А что, для него уже оно появилось? G++, в смысле?
Имелось ввиду msp430-g++?
Пока вроде бы нет, но должно, противопоказаний (кроме ненужности
плюсов с точки зрения ведущих проект mspgcc) нет никаких.


OR>> Даже можно полностью спрятать детали реализации модуля работы с
OR>> UART-ами, выдавая наружу не указатель на структуру, связанную с UART,
OR>> а индекс в массиве. Всё же в embedded заранее известна периферия, с которой
OR>> будет идти работа и внтури uart.c можно сделать
OR>> static struct {
OR>>  ...
OR>> } uarts[USED_UARTS];
OR>> и всю работу делать по индексам.

HZ>     А что, их (UART'ов) много что-ли? А если один?
 Если один, то у C++ вообще нет никаких преимуществ.

HZ>     И потом, это смахивает на проделывание вручную того, что делает
HZ> ++ный компилятор.
 Где?
 Виртуальные функции через указатели в структурах - да, вручную.
А static служебные переменные/структуры, спрятанные от пользователя
библиотеки внутрь файла её исходников - вполне рядовое явление.

OR>> Можно сказать
OR>> "зачем модули, если это всё можно сделать как частный случай класса".
OR>> а можно
OR>> "зачем классы, если _это_ вполне реализуемо на модулях".

HZ>     Вопрос-то был: "Почему в С++ нет модулей?".
 если в большинстве случаев достаточно их.

HZ> конкретное действие. Только на С будет оверхед на вызов, а в плюсах эту
HZ> функцию
HZ> просто делаешь инлайновой. Т.е. эффективность как при прямом обращении,
 А вот это (эффективность инлайновых функций) очень зависит
от того, на каком процессоре и какое действие производится.
Ну по скорости вопросов нет, inline быстрее, а вот по объёму
ещё вопрос. Даже на if( flag) при флаге равном "единице обработки"
(байт/слово). А если flag - битовое поле или if (flag & 0x20),
то inline по объёму проиграет (если процессор не имеет команды проверки
бита прямо в памяти). И не inline метод не имеет никакого преимущества.

HZ>     Тут разница половая: public в классе делаются функции, а не данные.
HZ> А на С
HZ> придется данные открывать. А если через функцию, то оверхед на вызов,
HZ> который при простом чтении переменной оказывается чересчур большим.
 Примерчик кода приведи. А то у меня EC++ нет.
а gcc для inline объём явно больше. Кстати, gcc ещё иногда любит
в полном соответствии со стандартом расширять char до int при вычислениях.
Тоже неблагоприятно на коде сказывается.

class foo {
  uchar ch;
public:
  foo(uchar _ch) { ch=_ch; }
  bool IsChar0() { return ch==0; }
  bool IsChar0Proc();
  bool IsBit3() { return bool(ch & (1<<3)); }
  bool IsBit3proc();
};

bool foo::IsChar0Proc() { return ch==0; }
bool fooIsBit3proc() { return bool(ch & (1<<3)); }

foo ff(5);

uchar moo1() {
  uchar cc=0;

  if( ff.IsChar0() ) ++cc;
  if( ff.IsBit3() ) ++cc;
  return cc;
}

uchar moo2() {
  uchar cc=0;

  if( ff.IsChar0Proc() ) ++cc;
  if( ff.IsBit3proc() ) ++cc;
  return cc;
}

и аналогичное для C

static uchar ch=5;
uchar IsChar0() { return ch==0; }
uchar IsBit3() { return ch & (1<<3); }

uchar moo() {
  uchar cc=0;

  if( IsChar0() ) ++cc;
  if( IsBit3() ) ++cc;
  return cc;
}

wbr,
--
/* Oleksandr Redchuk, Brovary, Ukraine */
/* real '\x40' real '\x2E' kiev '\x2E' ua     */


ICC AVR и стpоки
Sep 2003 18:26:59 +0000 (UTC):

[...]

HZ>>     Вопрос-то был: "Почему в С++ нет модулей?".
OR>  если в большинстве случаев достаточно их.

    Но зачем при наличии классов вводить еще и модули? Если достаточно
модульной функциональности, то и использовать класс не во всю мощь, а
ограниченно - как пространство имен. Или даже просто пространства имен и юзать.

HZ>> конкретное действие. Только на С будет оверхед на вызов, а в плюсах эту
HZ>> функцию
HZ>> просто делаешь инлайновой. Т.е. эффективность как при прямом обращении,
OR>  А вот это (эффективность инлайновых функций) очень зависит
OR> от того, на каком процессоре и какое действие производится.
OR> Ну по скорости вопросов нет, inline быстрее, а вот по объёму
OR> ещё вопрос. Даже на if( flag) при флаге равном "единице обработки"
OR> (байт/слово). А если flag - битовое поле или if (flag & 0x20),

    А какая разница флаг или нет. Загружается переменная из ОЗУ и дальше
логическая операция. Загрузка в любом случае одинакова, а разница в подходах
только в ней.

OR> то inline по объёму проиграет (если процессор не имеет команды проверки
OR> бита прямо в памяти). И не inline метод не имеет никакого преимущества.

    Не понял. Пример кода можно привести, где это проявится?

HZ>>     Тут разница половая: public в классе делаются функции, а не данные.
HZ>> А на С
HZ>> придется данные открывать. А если через функцию, то оверхед на вызов,
HZ>> который при простом чтении переменной оказывается чересчур большим.
OR>  Примерчик кода приведи. А то у меня EC++ нет.
OR> а gcc для inline объём явно больше.

    Что, и для однократного применения?

OR> Кстати, gcc ещё иногда любит в полном соответствии со стандартом расширять
OR> char до int при вычислениях. Тоже неблагоприятно на коде сказывается.

    ИАР это тоже делает, но оптимизатор после убирает лишнее. Был даже случай в
версии 2.25B, когда выражение

        byte1 = byte2 << 4;

    приводило к тому, что byte2 расширялось до инта, и затем оба байта
двигались на 4 бита. На это было указано. Они сказали, что так положено в
соответствии со стандартом, и это не баг. Но приняли к сведению, что
оптимизатор не на высоте. В 2.25С это пофиксили и оно стало компилироваться в
положенные

        swap r16
        andi r16,0xf0


OR> class foo {
OR>   uchar ch;

[...]

    Изволь.

    Файл "slon.h"

========================================
typedef unsigned char uchar;

class foo {
  uchar ch;
public:
  foo(uchar _ch) { ch=_ch; }
  bool IsChar0() { return ch==0; }
  bool IsChar0Proc();
  bool IsBit3() { return bool(ch & (1<<3)); }
  bool IsBit3proc();
};

uchar IsChar0();
uchar IsBit3();
bool fooIsBit3proc();
========================================


    Файл "slon1.cpp"

========================================
#include "slon.h"

static uchar ch=5;

uchar IsChar0() { return ch==0; }
uchar IsBit3() { return ch & (1<<3); }
bool fooIsBit3proc() { return bool(ch & (1<<3)); }
========================================

    Файл "slon.cpp"

========================================
#include "slon.h"

bool foo::IsChar0Proc() { return ch==0; }

foo ff(5);

uchar moo1() {
  uchar cc=0;

  if( ff.IsChar0() ) ++cc;
  if( ff.IsBit3() ) ++cc;
  return cc;
}


uchar moo() {
  uchar cc=0;

  if( IsChar0() ) ++cc;
  if( IsBit3() ) ++cc;
  return cc;
}
========================================


    Результаты компиляции.

    С++ вариант.

----------------------------------------
 uchar cc=0;

 if( ff.IsChar0() ) ++cc;
9100....                   LDS     R16,ff
2300                       TST     R16
F411                       BRNE    ??moo1_1
E001                       LDI     R16,1
C001                       RJMP    ??moo1_2
       ??moo1_1:
E000                       LDI     R16,0
 if( ff.IsBit3() ) ++cc;
       ??moo1_2:
....                       LDI     R30,LOW(ff)
....                       LDI     R31,(ff) >> 8
8110                       LD      R17,Z
FD13                       SBRC    R17,3
9503                       INC     R16
 return cc;
9508                       RET
----------------------------------------

    На мой взгляд лучше бы он вместо первого lds'а сразу бы загрузил указатель,
как во втором случае. Т.ч. тут парням еще есть над чем работать.


    С вариант.

----------------------------------------
938A                       ST      -Y,R24
 uchar cc=0;

 if( IsChar0() ) ++cc;
....                       RCALL   ??IsChar0
2300                       TST     R16
F011                       BREQ    ??moo_1
E081                       LDI     R24,1
C001                       RJMP    ??moo_2
       ??moo_1:
E080                       LDI     R24,0
 if( IsBit3() ) ++cc;
       ??moo_2:
....                       RCALL   ??IsBit3
2300                       TST     R16
F009                       BREQ    ??moo_3
9583                       INC     R24
 return cc;
       ??moo_3:
2F08                       MOV     R16,R24
9189                       LD      R24,Y+
9508                       RET
----------------------------------------

    И еще плюс сами функции:

----------------------------------------
uchar IsChar0() { return ch==0; }
        ??IsChar0:
 9100....                   LDS     R16,ch
 2300                       TST     R16
 F411                       BRNE    ??IsChar0_1
 E001                       LDI     R16,1
 9508                       RET
        ??IsChar0_1:
 E000                       LDI     R16,0
 9508                       RET



uchar IsBit3() { return ch & (1<<3); }
        ??IsBit3:
 9100....                   LDS     R16,ch
 7008                       ANDI    R16,0x08
 9508                       RET
----------------------------------------

    Суди сам.

    Все же оптимизатор у ИАРа неплох! Тут было заявление, что скоро gcc догонит
IAR. Очень сомневаюсь, что это произойдет скоро, и даже сомневаюсь, что это
вообще произойдет - ИАР тоже на месте не стоит.


...so long!

### Земля вращается вокруг своей оси - это позволяет нам измерять время суток.



Re: ICC AVR и стpоки
Hello Harry.

24 Sep 03 21:59, Harry Zhurov wrote to Oleksandr Redchuk:

 HZ>>> Т.е. сделать именно то, что на ++ получается нативно. И после
 HZ>>> этого еще не считать ++ную модель лучшей, чем сишную!
 OR>>  И необходимость писать в классах слова private - это
 OR>> то, что на ассемблере получается нативно.
 HZ>     В классах писать private не надо - объявляешь приватное сразу, потом
 HZ> пишешь public для открытого и вуаля. :)  Т.ч. все нативно. :))

темнишь :)
хоpоший стиль ввеpхy pазместить public, а ниже него - private

Alexey


ICC AVR и стpоки
Alexey Musin wrote to Harry Zhurov on Thu, 25 Sep 2003 11:48:10 +0400:

HZ>>>> Т.е. сделать именно то, что на ++ получается нативно. И после
HZ>>>> этого еще не считать ++ную модель лучшей, чем сишную!
OR>>>  И необходимость писать в классах слова private - это
OR>>> то, что на ассемблере получается нативно.
HZ>>     В классах писать private не надо - объявляешь приватное сразу, потом
HZ>> пишешь public для открытого и вуаля. :)  Т.ч. все нативно. :))

AM> темнишь :)
AM> хоpоший стиль ввеpхy pазместить public, а ниже него - private

    Это с чего ты взял? Этот стиль у всех свой, и можно долго спорить, какой
лучше и правильнее.

...so long!

### "Доярка сошла с трибуны, и на неe тотчас же влез председатель." (с) Из
школьного сочинения.



Re: ICC AVR и стpоки
Hello "Harry.

24 Sep 03 17:34, you wrote to me:

 AB>> Вообще-то я спрашивал почему не пройдет.
 HZ>     Потому что, например, если есть объявленный пользователем
 HZ> копирующий оператор присваивания, то этот оператор подразумевает
 HZ> определенную семантику
 HZ> копирования, а простое побитовое копирование имеет вполне определенную
 HZ> семантику клонирования, что позволяет создавать объекты неразрешенным
 HZ> способом. Или если есть приватные поля, то доступ к ним должен быть
 HZ> только через определенный интерфейс, и если просто побитово
 HZ> копировать, то это значит получить к ним доступ в обход системы типов,
 HZ> что есть еще более грязный хак.

Hе. Hе так. Hе пройдет это тогда, когда на этот объект есть ссылки из других
объектов, взаимодействующих с ним.

 AB>> В приведенном тобой примере - пройдет.
 AB>> Hо ты сделал правильное приведение, не так ли?

 HZ>     Это слишком простой пример.

Вот к нему я и прицепился. Плохие примеры мы тут все приводим. (и не только в
этом треде)

 HZ> А представь себе, что копирование
 HZ> производится в одной единице трансляции, а приведение в другой.

Что есть единица трансляции?

Alexey


ICC AVR и стpоки
Alexey Boyko wrote to "Harry Zhurov" <Harry Zhurov on Thu, 25 Sep 2003 12:46:42
+0400:

AB>>> Вообще-то я спрашивал почему не пройдет.
HZ>>     Потому что, например, если есть объявленный пользователем
HZ>> копирующий оператор присваивания, то этот оператор подразумевает
HZ>> определенную семантику
HZ>> копирования, а простое побитовое копирование имеет вполне определенную
HZ>> семантику клонирования, что позволяет создавать объекты неразрешенным
HZ>> способом. Или если есть приватные поля, то доступ к ним должен быть
HZ>> только через определенный интерфейс, и если просто побитово
HZ>> копировать, то это значит получить к ним доступ в обход системы типов,
HZ>> что есть еще более грязный хак.

AB> Hе. Hе так. Hе пройдет это тогда, когда на этот объект есть ссылки из
AB> других объектов, взаимодействующих с ним.

    Это почему же? Вот есть у тебя объект А. И есть объект Б, который
ссылается/работает с А. Если ты склонировал (путем побайтового копирования) А1
из А, то сам по себе А не изменился, и все "взаимоотношения" с Б остались на
прежнем уровне. А1, конечно, хотя и точная копия А, не может, в общем случае,
быть заменой А - это ведь другой объект.

    А я имел в виду другое. Вот есть объект А, у которого есть, например,
закрытые поля и определенный пользователем оператор присваивания и/или
определенный пользователем конструктор (копирования). Объект содержит закрытое
поле Flag - флаг/признак какого-то события. Этот флаг по (замыслу)
устанавливается только с помощью функции-члена void SetFlag(), которая
вызывается в строго определенных условиях, которые нужно зафиксировать путем
установки этого флага внутри объекта. Такая вот семантика задумана.

    И наш определенный пользователем оператор присваивания/конструктор
копирования при копировании данных объекта А в А1 копирует все поля, кроме поля
Flag - таков замысел: в новом объекте этот флаг будет установлен тоже точно так
же при возникновении тех самых определенных условий. В этом весь смысл. И
разработчик типа (класса), закладывая такую функциональность, предполагает
вполне определенное поведение - значение флага может быть изменено только с
помощью специальных функций-членов и никак иначе, - в противном случае
произойдет скрытное изменение семантики типа.

    А если копировать просто побайтово, то даже при правильном приведении типов
возможно это самое скрытное изменение семантики и, как следствие,
непредсказуемое поведение программы. Поэтому копирование не-POD типов с помощью
простого побайтового копирования является дырой в системе типов, по какой
причине оно и запрещено. И нарушение оного запрета - _очень_ грязный хак,
использование которого есть _очень_ плохой стиль!

[...]

HZ>> А представь себе, что копирование
HZ>> производится в одной единице трансляции, а приведение в другой.

AB> Что есть единица трансляции?

    Ну, это, в контексте С/С++, исходный файл (.с, .срр), который подается на
вход компилятору (заголовки, ессно, единицами трансляции не являются).


...so long!

### Нельзя же все ломать, надо на чем-то и сидеть.



Re: ICC AVR и стpоки
Hello "Harry.

24 Sep 03 17:34, you wrote to me:

 AB>> Hа классах есть только один способ и оптимизировать там нечего.
 AB>> Только на компилятор приходится надеятся.
 HZ>     С чего ты это взял?

ru.embedded почитал ;)

 HZ> ### Брюки важнее жены, потому что существует немало мест, куда можно
 HZ> пойти без жены.

;)

Alexey


Re: ICC AVR и стpоки
Hello "Harry.

24 Sep 03 17:34, you wrote to me:

 AB>> По индексу в массиве. Одномерные массивы не есть чем-то очень
 AB>> сложным и тяжелым для понимания.
 HZ>     А они в С/С++ только одномерными и бывают. int A[5][4] - это тоже
 HZ> одномерный массив размером [5]*[4].

??? чего-то тебя не в ту степь понесло.

 AB>> А так руками нужно описывать разные классы. Если в программу с
 AB>> массивами нужно добавить еще одно значение, нужно просто удлиннить
 AB>> массивы,
 HZ>     Hе, не все так безоблачно. Придется объявить функцию и поместить
 HZ> указатель на нее в _строго_ _определенное_ место в массиве, и не дай
 HZ> Бог ошибиться. А еще учти, что функция не одна, их несколько - в нашем
 HZ> небольшом примере их было три. Т.е. нужно создать три функции и
 HZ> поместить указатели на них в три разных массива по одинаковому
 HZ> индексу. Все это руками. И не ошибиться, т.к. компилятор это не сможет
 HZ> проверить. Короче, куча манипуляций, требующая предельного внимания.

Вижу, ты очень сильно заплюсовался. Hикаких функций писать я не предлагал.
В массивах max, min, delta я предлагал хранить числа, а не адреса функций.

 AB>> а на С++ - создать новый класс. Сколько еще строк понадобится?
 HZ>     А ты что, трудоемкость в строках измеряешь?

В конце концов все сводится к количеству строк.

 HZ> Если только ради
 HZ> виртуальных функций, то строк не больше понадобится - в случае ручной
 HZ> организации тоже писанины есть: вписывать в массивы указатели,
 HZ> прописывать до этого прототипы. По количеству писанины оно где-то
 HZ> соизмеримо, а вот по безопасности и удобству виртуальные функции
 HZ> рулят.

Оно-то конечно да. Если создавать на Си массивы указателей на функции, то или
застрелиться или перейти на С++. Hо я предлагал не создавать функции.

 AB>> Вообще-то меня С++ не устраивает, потому-что с ним получается
 AB>> многовато указателей на функции,
 HZ>     Это где это там оно появляется?

Вместе с виртуальными методами.

 AB>> с которыми АВРу не очень удобно работать.
 HZ>     А это еще почему? И кому тогда удобно?

ldd ZL, Y+N
ldd ZH, Y+N+1
icall

(это если Y свободный)

против:

rcall

Hа ARM:

косвенный
mov     LR, PC
ldr     PC, [R0, #N]

против:

bl


Alexey


ICC AVR и стpоки
Alexey Boyko wrote to "Harry Zhurov" <Harry Zhurov on Thu, 25 Sep 2003 13:04:12
+0400:

AB>>> По индексу в массиве. Одномерные массивы не есть чем-то очень
AB>>> сложным и тяжелым для понимания.
HZ>>     А они в С/С++ только одномерными и бывают. int A[5][4] - это тоже
HZ>> одномерный массив размером [5]*[4].

AB> ??? чего-то тебя не в ту степь понесло.

    Может и не в ту, это ты потом еще раз реши. Давай разберемся.

    Да, слово "многомерный" массив часто употребляют, имея в виду массивы вида:

        int A[n][m];

    Это бывает удобно, и чаще всего функциональность такого массива
соответствует функциональности двумерного массива - поясню: возможно, тут есть
некоторая неразбериха в терминах, что понимать под двумерным массивом?!

    Двумерный массив - это массив из элементов, каждый из которых определяется
двумя координатами (аргументами). Это как значения функции двух переменных,
вернее, табличное задание такой функции. Соответственно, любой элемент должен
быть задан двумя координатами, и попытка задания только одной координаты
(аргумента) должно приводить к ошибке вида: "Ошибка: попытка получить элемент
по одной координате. Массив не содержит таких элементов, каждый элемент
определяется двумя аргументами". Т.е. если есть _двумерный_ массив:

        int A[n][m];

    то любой элемент этого массива описывается как

        A[i][j];

    а выражение:

        A[i];

    просто не имеет смысла! Вообще!!

    Теперь рассмотрим массивы языков С/С++. Что означает объявление:

        int A[n][m];

    Оно означает массив _массивов_ элементов типа int. И, соответственно,
выражение:

        A[i];

    означает _указатель_ _на_ _массив_ _элементов_ _типа_ _int_. Т.е. это
выражение, в отличие от предыдущего случая, уже имеет вполне определенный
смысл, хотя ошибки, обычно, это не устраняет - если написать так:

        int x = A[2];

    то получишь ошибку вида: "Невозможно преобразовать int* в int".

    Зато можно обращаться с этим массивом, например, так:

        int x = **A;        // извлечение первого элемента из А

        int y = **(A + 1);  // извлечение первого элемента из второго
                            // подмассива массива А

        int x = *(*A + 2);  // извлечение третьего элемента из первого
                            // подмассива массива А


    Согласись, что довольно странный синтаксис для работы с двумерным
массивом!? Но зато вполне соответствующий массиву массивов.

    Кстати, еще момент: вот второй пример из приведенных выше:

        int y = **(A + 1); // извлечение первого элемента из второго
                           // подмассива массива А


    Будь А полноценным двумерным массивом - т.е. законченным, целостным
объектом, то выражение:

        А + 1

    означало бы адрес следующего такого двумерного массива, первый элемент
которого вычислялся бы по адресу:

        &A + sizeof(A)

    Но реально это не так, и выражение:

        А + 1

    указывает на второй подмассив, адрес которого вычисляется как:

        &A + sizeof(*A)

    Это происходит потому, что А - это не двумерный массив, а массив массивов,
и имя массива при операциях адресной арифметики (а также при передаче в
качестве аргумента функции) неявно преобразовывается в указатель на первый
элемент этого массива. Таким образом, в выражении:

        А + 1

    А имеет тип int (*)[m], т.е. указатель на _массив_ из m интов - указатель
на первый элемент массива. А этот первый элемент, в свою очередь, является тоже
массивом, что и подтверждает то, что A[n][m] - это массив массивов.

    Надеюсь, ты не будешь спорить с тем, что двумерный массив и массив
массивов - это разные вещи? Причем, "разность" их не терминологическая (тогда
можно было бы называть и так, и так безо всяких последствий), а принципиальная,
проявляющаяся в разном поведении, которое подробно рассмотрено на примере выше.

    Ну, и, наконец, массив массивов - это _ОДНОМЕРНЫЙ_ массив из элементов,
которые также являются массивами (а могут быть элементами любого другого типа -
целые, структуры, объекты классов и т.д.). И никаких многомерных массивов в
С/С++ не было и нет.

    Вот теперь ты снова реши, в ту ли степь меня понесло или нет?! :)



AB>>> А так руками нужно описывать разные классы. Если в программу с
AB>>> массивами нужно добавить еще одно значение, нужно просто удлиннить
AB>>> массивы,
HZ>>     Hе, не все так безоблачно. Придется объявить функцию и поместить
HZ>> указатель на нее в _строго_ _определенное_ место в массиве, и не дай
HZ>> Бог ошибиться. А еще учти, что функция не одна, их несколько - в нашем
HZ>> небольшом примере их было три. Т.е. нужно создать три функции и
HZ>> поместить указатели на них в три разных массива по одинаковому
HZ>> индексу. Все это руками. И не ошибиться, т.к. компилятор это не сможет
HZ>> проверить. Короче, куча манипуляций, требующая предельного внимания.

AB> Вижу, ты очень сильно заплюсовался. Hикаких функций писать я не предлагал.
AB> В массивах max, min, delta я предлагал хранить числа, а не адреса функций.

    Ну, тогда я вообще ничего не понял - как ты собираешься реализовать ту
функциональность, которая была приведена в том примере:

 // ----------------------------------
    ...
    if( keySelect.IsClick() ) CurrentParameter++;
    if( keyPlus.IsClick()   ) CurrentParameter->Increase();
    if( keyMinus.IsClick()  ) CurrentParameter->Decrease();
    ...
 // ----------------------------------

    Как ты предлагаешь достичь того же без функций, а только с помощью
какого-то массива?


AB>>> а на С++ - создать новый класс. Сколько еще строк понадобится?
HZ>>     А ты что, трудоемкость в строках измеряешь?

AB> В конце концов все сводится к количеству строк.

    :) Ну хорошо, что хоть не к ж..почасам! :))


AB>>> с которыми АВРу не очень удобно работать.
HZ>>     А это еще почему? И кому тогда удобно?

AB> ldd ZL, Y+N
AB> ldd ZH, Y+N+1
AB> icall

AB> (это если Y свободный)

    А и не обязательно его использовать для загрузки адреса в Z. Есть еще много
подходящих способов.

AB> против:

AB> rcall

    Во-первых, первый и второй варианы предоставляют весьма различную
функциональность, поэтому говорить, что первый вариант отстойный, и надо
пользоваться вторым, т.к. он эффективнее, не слишком разумно. Они не лучше или
хуже друг друга, они просто разные.

    Во-вторых, много команд в первом варианте берется из-за того, что
процессор-то 8-разрядный, а адреса-то 16-разрядные. И во втором случае у тебя
размер "прыжка" всего +-4 килобайта, в отличие от первого, где адрес
полноценный. Если сравнивать честно, то нужно использовать не rcall, а call,
который тоже тащит полный адрес и занимает места соответственно. Т.ч. по
эффективности оно, в этом случае, отличается всего в полтора раза.



...so long!

### На экзамене по теории вероятностей: "Девушка, какова вероятность того, что
выйдя сейчас на улицу, вы встретите зеленого бегемота? - 0.5! - Почему же??? -
Ну, либо встречу, либо нет!"



Re: ICC AVR и стpоки
Hello Dmitry.

24 Sep 03 19:00, you wrote to me:

 >> По сравнению, с основным кодом ядра линукса - да.
 DF> Hет, с моим кодом.
 >> Вообще-то для avr-g++ поддержка С++ занимает много меньше.
 DF> результаты 'wc -l соответсвующие-исходники' в студию.

К сожалению, я не очень в курсе. Hо насколько я понял, достаточно было
в линкерный скрипт добавить секции .ctors .dtors

 DF> Во 1-х, это зависит от целевой платформы,
 DF> во 2-х, хоть я и провожу аналогию между поддержкой C++ для
 DF> модулей ядра линукс и настоящей вделанной платформой, они все-таки
 DF> отличаются. в 3-х, в отличие от g++, в случае ядра линукс, нужно
 DF> прилагать немало усилий для обхода ограничений этой среды,
 DF> использованию C++ активно сопротивляющейся, а потому там около
 DF> половины объема исходников занимают всякие макросы и условия.

Вот вот. Пример неудачный.

Alexey


Site Timeline