Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Odd address trap и LPC23xx
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
VslavX
У меня в тестовой прошивке есть такой небольшой чудный кусочек кода:
Код
{
    ungigned long *p;
    dprintf("\r\nNon aligned DWORD read.. ");
    dflush();
    p = (unsigned long*)(0x209 + LPC_ISRAM);
    dprintf("%08X", *p);
}


Назначение этого кусочка - протестировать работу соответствующего обработчика исключения. Код прекрасно отработал на S3C44BOX, S3C2410, IXP42x, SAM7xx, PXA2xx/3xx и много лет все было чудесно. И вот, "понимаете, в машине в которой мы ехали, случайно, совершенно случайно, оказался цемент" ©. Я "совершенно случайно" запустил этот код на LPC2388, и... не увидел свой любимый "ODD ADDRESS TRAP".
Смотрим документацию, "усер мануал" на LPC23xx вообще не содержит слова "unaligned". В-общем, красота - при невыравненном адресе - на LPC23xx читается/пишется переставленный мусор, и все это МОЛЧА. Такая низость в самом деле имеет место, или я чего-то недопонимаю?
aaarrr
Цитата(VslavX @ Jan 15 2009, 21:43) *
Такая низость в самом деле имеет место, или я чего-то недопонимаю?

Имеет, еще на LPC21xx налетал. Впрочем, это не низость, а скорее вариант нормы smile.gif
VslavX
Цитата(aaarrr @ Jan 15 2009, 21:37) *
Имеет, еще на LPC21xx налетал. Впрочем, это не низость, а скорее вариант нормы smile.gif

Я бы сказал, что это - весьма и весьма "нетрадиционный" "вариант нормы". Норма - это список ARM-ом в моем первом посте. А так выглядит как очередная подляна от NXP, причем - совершенно необъяснимая sad.gif. Само исключение есть, генерируется извне ядра контроллером шины, почему бы не проконтроллировать еще и адрес - непонятно sad.gif.
P.S. Надо будет на их новые Кортексы глянуть - может там исключение добавили.
abcdefg
Цитата(VslavX @ Jan 15 2009, 23:08) *
P.S. Надо будет на их новые Кортексы глянуть - может там исключение добавили.


в кортексах вообще нет проблемы обращения к невыравненным адресам
amw
Цитата(VslavX @ Jan 15 2009, 20:43) *
У меня в тестовой прошивке есть такой небольшой чудный кусочек кода:
Код
{
    ungigned long *p;
    dprintf("\r\nNon aligned DWORD read.. ");
    dflush();
    p = (unsigned long*)(0x209 + LPC_ISRAM);
    dprintf("%08X", *p);
}


Назначение этого кусочка - протестировать работу соответствующего обработчика исключения. Код прекрасно отработал на S3C44BOX, S3C2410, IXP42x, SAM7xx, PXA2xx/3xx и много лет все было чудесно. И вот, "понимаете, в машине в которой мы ехали, случайно, совершенно случайно, оказался цемент" ©. Я "совершенно случайно" запустил этот код на LPC2388, и... не увидел свой любимый "ODD ADDRESS TRAP".
Смотрим документацию, "усер мануал" на LPC23xx вообще не содержит слова "unaligned". В-общем, красота - при невыравненном адресе - на LPC23xx читается/пишется переставленный мусор, и все это МОЛЧА. Такая низость в самом деле имеет место, или я чего-то недопонимаю?

Да есть такая фигня при чтении.
Посмотрите еще и запись.
VslavX
Цитата(abcdefg @ Jan 16 2009, 09:35) *
в кортексах вообще нет проблемы обращения к невыравненным адресам

Угу, спасибо - заинтересовался и посмотрел, наконец, описание M3 - ничего, вкусненько. Будем ждать LPC17xx.
meister
Цитата(VslavX @ Jan 15 2009, 22:43) *
В-общем, красота - при невыравненном адресе - на LPC23xx читается/пишется переставленный мусор, и все это МОЛЧА. Такая низость в самом деле имеет место, или я чего-то недопонимаю?


У меня есть файл arm7tdmi_instruction_set_reference.pdf, там написано следующее:

Код
If the memory address is not word-aligned, the value read is rotated right by 8 times
the value of bits [1:0] of the memory address. If R15 is specified as the destination, the
value is loaded from memory and written to the PC, effecting a branch.
VslavX
Код
If the memory address is not word-aligned, the value read is rotated right by 8 times
the value of bits [1:0] of the memory address. If R15 is specified as the destination, the
value is loaded from memory and written to the PC, effecting a branch.

Именно это я подразумевал под словом "переставленный". Для ARM7TDMI, который работает только в LE - будет такой вариант как Вы отцитировали. Для старших ARM-ов работающих в BE/LE вполне могут быть и отличия.
В любом случае - в результате невыравненного доступа получаем отнюдь не тот результат какой ожидали, а поскольку исключения нет - то "дорогая не узнает, какой у парня был конец" ©. Очень весело отлавливать такие проблемы при портировании 200К строк С-шного кода с 8-битника, например. NXP - "низачот", первый раз такой облом вижу. В 70-ых на PDP такое счастье как OAT было, а вот в 21-ом веке - не судьба.
meister
Цитата(VslavX @ Jan 16 2009, 13:02) *
В любом случае - в результате невыравненного доступа получаем отнюдь не тот результат какой ожидали


А Вы ожидайте "правильный" (в соответсвии с абзацем, который я процитировал). Вдруг Вам так и надо было. "Такие дела" ©.
zltigo
Цитата(VslavX @ Jan 16 2009, 12:02) *
Очень весело отлавливать такие проблемы при портировании 200К строк С-шного кода с 8-битника, например.

Вообще-то "это отлаживать" - Вам "низачет", ибо нужно не с последствиями бороться а банально этои 200К строк (кстати для 8bit это число строк кода СИЛЬНО СИЛЬНО надуманное - "урежте осетра" как минимум на порядок, тогда еще где-то в 64-128K бинарника поверю ) хоть мельком, но просмотреть. И вообще с этим хорошие компиляторы хорошо справляются - warning-ов хватает, если, конечно перворначальный код не совсем через заденпроходное отверстие писан, но незачем такое и портировать.
Цитата
NXP - "низачот", первый раз такой облом вижу. В 70-ых на PDP такое счастье как OAT было, а вот в 21-ом веке - не судьба.

Тут странное дело - когда давно поверял работу своего обработчика exception на чем-то вроде LPC2114 - точно работало, а потом на свежих чипах как-то исчезло, хотя недавно переписывал слегка и некоторым удивлением обнаружил, что на одном из китов с LPC2148 тоже отработал!
defunct
Цитата(zltigo @ Jan 16 2009, 11:58) *
(кстати для 8bit это число строк кода СИЛЬНО СИЛЬНО надуманное - "урежте осетра" как минимум на порядок, тогда еще где-то в 64-128K бинарника поверю )

Я прочитал как 200KB smile.gif
200K строк действительно многовато.


Цитата
И вообще с этим хорошие компиляторы хорошо справляются - warning-ов хватает, если, конечно перворначальный код не совсем через заденпроходное отверстие писан, то незачем такое и портировать.

Компиляторы не помогут когда адрес вычисляется диамически. sad.gif
Например, сравнение IPшника приятого пакета с сетевой маской.
zltigo
Цитата(defunct @ Jan 16 2009, 13:20) *
Компиляторы не помогут когда адрес вычисляется диамически. sad.gif
Например, сравнение IPшника приятого пакета с сетевой маской.

Отнюдь. В реальности буфера под фреймы выделяются выровненые а нормальная разборка ведется по наложенной структуре. При работе с невыровнеными элемсентами структуры полусите предупреждение. Есть масса более ветвистых протоколов, то там в основном и разборка побайтовая. Если кто-то нагородил нечто непотребное в стиле "я пишу на любом языке, как в машинных кодах", то, простите, портировать такое просто не надо - проблемы будут по любому.
VslavX
Цитата(zltigo @ Jan 16 2009, 11:58) *
Вообще-то "это отлаживать" - Вам "низачет", ибо нужно не с последствиями бороться а банально этои 200К строк (кстати для 8bit это число надуманное)

Увы, не надуманное. "У меня линейка есть" - поэтому я абсолютно спокоен. smile.gif
Самый старый проект был начат в 1992-ом, пережил asm x86, BCC3.1, Watcom, IAR AVR 1.30, IAR MSP, Softune LX16, GCC ARM, GCC PPC, сотни две вариаций и моделей, десяток языков (рус, укр, англ, нем, ...), сотни флагов условной компиляции. Так что 200К - это весьма и весьма скромно, могу Вас заверить. Много лет это "утаптывали ногами" в 128К меги - ей просто не было даже близкой конкуренции по цене, и там _очень_ много финтов направленных на "лишь бы влезло" и "хто украл 10 байт RAMы" - хроника одного байта - во всей красе. На проектах на ARM-ах - еще веселее - 200K - " это только лицо" ©, т.е. приложение. Сейчас моя "зона ответственности" - системный софт - HAL + TN + TCP + FAT + USB-host за 100К грозит играючи перейти. Впрочем, сложность - понятие относительное, посмотрим на исходники Линукса - там никакой "линейки" хватит.

Цитата(zltigo @ Jan 16 2009, 11:58) *
хоть мельком, но просмотреть. И вообще с этим хорошие компиляторы хорошо справляются - warning-ов хватает, если, конечно перворначальный код не совсем через заденпроходное отверстие писан, но незачем такое и портировать.

Да это все понятно, компилятором ловится 95% проблем, потом на других ARM-платформах отловили еще 3-4%. А вот вчера меня программеры ткнули носом в листинг - "ldrh R0, [R4, #0x209]" и спросили - "почему бнопня лезет?". И пришлось мне, "случайно, совершенно случайно", стряхнуть пыль с теста обработчика исключения. Профтыкал-с, признаю. И вот этот оставшийся 1% - самое трудное. В сумме несколько десятков человек тестировало пару месяцев изделие, а вот на баг только вчера попали sad.gif.

Цитата(zltigo @ Jan 16 2009, 11:58) *
Тут странное дело - когда давно поверял работу своего обработчика exception на чем-то вроде LPC2114 - точно работало, а потом на свежих чипах как-то исчезло, хотя недавно переписывал слегка и некоторым удивлением обнаружил, что на одном из китов с LPC2148 тоже отработал!

Да, интересно. Само исключение есть, и работает - я ж обработчик таки при написании проверял. (как оказалось по черновым тестам - записью невыравненного слова во флеш - по адресу 1) . Но, судя по доке, возникает при обращении к несуществующей памяти и при записи во флэшку. Есть плата на свежем 2148revB и есть китовая от MT на 2148rev- - попробую на них.

P.S. Таки купили Вы меня на "надуманное", ну и ладно, сделаю вид что провокации не было cheers.gif

Цитата(defunct @ Jan 16 2009, 12:20) *
Компиляторы не помогут когда адрес вычисляется диамически. sad.gif
Например, сравнение IPшника приятого пакета с сетевой маской.

IP-шник - неудачный пример. И вообще протоколы для "внешних сношений". Если учитывать endianess, то разбор такой структуры все равно макросами надо делать, и в них aligment учесть. У меня, например, в TCP в итоге получилось 4 варианта макроса считывания поля IP - BE/LE + aligned/unaligned.
А вот со своими внутренними структурами - там да, некоторый unaligned трабл у прикладников был. Вот еще беспокойство есть насчет оставшегося 1% sad.gif. Предполагался сценарий - "odd address trap" -> "bug report" -> e-mail -> база ошибок. Увы, мечты были грубо разрушены злобным NXP smile.gif
meister
Цитата(zltigo @ Jan 16 2009, 13:58) *
Тут странное дело - когда давно поверял работу своего обработчика exception на чем-то вроде LPC2114 - точно работало


"Работало", это как, DABT? В том абзаце, что я привел, ничего про DABT написано не было, там написано, что работает, но "специфически".
zltigo
Цитата(VslavX @ Jan 16 2009, 14:03) *
Самый старый проект был начат в 1992-ом, пережил asm x86, BCC3.1, Watcom, IAR AVR 1.30, IAR MSP, Softune LX16, GCC ARM, GCC PPC, сотни две вариаций и моделей.....

Все верно, у меня практически такие-же вещи по полной программе, НО все это не делалось единовременно вдруг с 8 на 32. При переходе ровным счетом ни одной проблемы в работе, именно с выравниванием не вызвало. Все отсеялось в процессе портирования при работе с исходниками.
Цитата
На проектах на ARM-ах - еще веселее - 200K - " это только лицо" ©, т.е. приложение.

Посторяю - 200K чего? Кода или сишных строк??? Вот прям сейчас сижу в начале обычного проекта: ARM 94 файла 40767 текстовых строк из них всего 21943 стороки с кодом. Бинарник 134504 байта. Процентов 15% пришло с 8bit. Еще 20% вообще сразу живут на всех платформах. Будет развиваится и раздуваться еще несколько лет. Естественно есть и уже перевалившие за 300K бинарника. Говорите, что у Вас "200К строк С-шного кода" причем, как ранее говорили, для чего-либо врезультате влезающего в AVR128 и затем портированых? Так вот не верю.
Цитата
P.S. Таки купили Вы меня на "надуманное", ну и ладно, сделаю вид что провокации не было cheers.gif

Никаких провокаций - просто удивился. Полагаю обосновано.
defunct
Цитата(zltigo @ Jan 16 2009, 12:30) *
Отнюдь. В реальности буфера под фреймы выделяются выровненые а нормальная разборка ведется по наложенной структуре.

Это все так, но давайте рассмотрим случай когда пакеты идут с разных интерфейсов. Eth и PPP-Link (у одного перед IP header'ом 14 байт eth заголовка, у второго длина ppp заголовка зависит от настроек канала и может быть от 1 байта и выше... И там и там "по-умолчанию" IP заголовок получается невыровненым относительно начала пакета. А мы хотим проверить по маске быстро (чтобы "одной" командой):

Код
*(U32 *)(packet + offset)   &  mask


Вот тут недостача align exception'а может сыграть злую шутку


Цитата
Если кто-то нагородил нечто непотребное в стиле "я пишу на любом языке, как в машинных кодах", то, простите, портировать такое просто не надо - проблемы будут по любому.

Я безотносительно, ни к чьему коду не привязываясь. Просто интересно получить ответы на следующие вопросы:

Что у NXP есть по поводу misalign'a - как они предлагают обрабатывать такие ситуации в run-time (какие-нить их доки на этот счет)?
Может быть есть сводка в каких NXP чипах align exception поддерживается, а в каких нет?
zltigo
Цитата(defunct @ Jan 16 2009, 16:27) *
Это все так, но давайте рассмотрим случай когда пакеты идут с разных интерфейсов.

Можно многое, что искусственно придумать и еще больше "реализовать" по дурному - не вопрос smile.gif. В данном конкретном случае сразу могу спросить, а какого они идут в один и тот-же буфер? Давайте не будем развивать эту тему. Я ведь тоже все это не просто так сказал - в частности протоколы, например, входящие в стеки SS7, ISDN, V5.2, ... реализовывалитсь на разных платформах, портировались, инкапсулировались а в них разборки на порядки сложнее и ветвистее нежели IP, пусть даже он Ethernet+VLAN и т.д.
GetSmart
Цитата(defunct @ Jan 16 2009, 19:27) *
Код
*(U32 *)(packet + offset)   &  mask


Вот тут недостача align exception'а может сыграть злую шутку

Для таких случаев нужно создавать дополнительный U32 (например U32ua) внутри pragma pack (1). Это конечно не совместимость снизу вверх, но так можно написать универсальный код, правильно работающий на 8, 16 и 32 платформах.
defunct
Цитата(zltigo @ Jan 16 2009, 15:38) *
В данном конкретном случае сразу могу спросить, а какого они идут в один и тот-же буфер?

Ну... потому что на IP уровне и те и те - IP. Да и чтоб расход памяти соптимизировать - пользовать один и тот же пул пакетов.

Цитата
Давайте не будем развивать эту тему.

ОК

Цитата(GetSmart @ Jan 16 2009, 15:43) *
Для таких случаев нужно создавать дополнительный U32 (например U32ua) внутри pragma pack (1).

Не, такое - не пойдет. Тормозить будет, т.к. будет LDRB вместо LDR.
Мы ж скорости хотим. smile.gif - если скорость не нужна можно везде все упаковать и будет ARM как восьмибитник работать.
GetSmart
Цитата(defunct @ Jan 16 2009, 19:49) *
Не, такое - не пойдет. Тормозить будет, т.к. будет LDRB вместо LDR.
Мы ж скорости хотим. smile.gif - если скорость не нужна можно везде все упаковать и будет ARM как восьмибитник работать.

Ещё как пойдёт. Только использовать его надо именно в местах разбора буферов, в которых есть хоть малейшая вероятность невыровненности данных. Для работы с обычными переменными (статика, локальные) надо применять тип без прагмы.
VslavX
Цитата(zltigo @ Jan 16 2009, 14:07) *
Все верно, у меня практически такие-же вещи по полной программе, НО все это не делалось единовременно вдруг с 8 на 32. При переходе ровным счетом ни одной проблемы в работе, именно с выравниванием не вызвало. Все отсеялось в процессе портирования при работе с исходниками.

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

Цитата(zltigo @ Jan 16 2009, 14:07) *
Посторяю - 200K чего? Кода или сишных строк??? Вот прям сейчас сижу в начале обычного проекта: ARM 94 файла 40767 текстовых строк из них всего 21943 стороки с кодом. Бинарник 134504 байта. Процентов

Дело было давно (в районе 2000-го) - из любопытства написал простой скриптик подсчета текстовых строк на Perl и прогнал на каталоге с исходниками для одной платформы (AVR, кажись). Тогда вышло около 150К - всех текстовых строк - с хидерами, C- кодом, комментариями, но без документации, makefiles и всяких вспомогательных скриптов (то отдельно все лежит). Сейчас не считал, по минимуму полагаю 200K.
Эти все 200К написаны прикладниками - без платформозависимого и системного кода, который пишу я. ИМХО, по стилю там тяжеловато - с комментами напряг, и макросов засилье изрядное, так что текст - "плотненький", сколько строк именно с кодом - не скажу, но тоже не менее 50%.

Цитата(zltigo @ Jan 16 2009, 14:07) *
несколько лет. Естественно есть и уже перевалившие за 300K бинарника. Говорите, что у Вас "200К строк С-шного кода" причем, как ранее говорили, для чего-либо врезультате влезающего в AVR128 и затем портированых?

Это где я говорил что все 200К строк исходников одновременно влезают в 128К? Я сказал, что в сумме есть 200К строк из которых получается сотня различных вариантов путем условной компиляции.

Цитата(zltigo @ Jan 16 2009, 14:07) *
Процентов 15% пришло с 8bit. Еще 20% вообще сразу живут на всех платформах

В-о-о-о-т. А у нас 75-90% пришло с 8-битника и эти же 75-90% живут на всех 8/32-битных платформах. Из оставшихся 10-25% для 32-битников - 80% (ОС, стеки) тоже живут на всех 32-битных платформах. Итого - у меня "не живущая" и заново пишущаяся для платформы часть составляет 2-5% - против Ваших 65%. Отсюда и Ваш совет - "при портировании надо пересмотреть код". Когда пишешь заново - не вопрос - само собой так получается, а вот когда оно уже написано, отлажено и работает - хто ж в здравом уме туда полезет?

Цитата(zltigo @ Jan 16 2009, 14:07) *
Так вот не верю.

Чему именно? Что бывают проекты где 75-90% процентов платформо-независимо и может жить на 8/16/32?


Цитата(defunct @ Jan 16 2009, 15:49) *
Не, такое - не пойдет. Тормозить будет, т.к. будет LDRB вместо LDR.
Мы ж скорости хотим. smile.gif - если скорость не нужна можно везде все упаковать и будет ARM как восьмибитник работать.

У меня эту проблему в общем случае решить не удалось. Для TCP/IP у меня такая реализация:
Код
LW_INLINE_FORCED
DWORD
lw_ipload(
    PLW_IP_ADDR ptr)
{
#if LW_ALIGNED_HDR
    //
    // Вариант перестановки для выравненного доступа
    //
    DWORD    v, t1, t2;

    v = *(PDWORD)ptr;

    t1 = v ^ ((v << 16) | v >> 16);        // t1 =  2143 ^ 4321
    t2 = (v >> 8) | (v << 24);            // t2 =  1432
    t1 = t1 & 0xFF00FFFF;                // t1 =  2043 ^ 4021
    return t2 ^ (t1 >> 8);                // 1432 ^ (0204 ^ 0402)
#else
    //
    // Вариант перестановки для невыравненного доступа
    //
    return  (DWORD)((PBYTE)ptr)[3]
         | ((DWORD)((PBYTE)ptr)[2] << 8)
         | ((DWORD)((PBYTE)ptr)[1] << 16)
         | ((DWORD)((PBYTE)ptr)[0] << 24);
#endif
}


Для PowerPC в bigendian это выглядит так:
Код
LW_INLINE_FORCED
DWORD
lw_ipload(
    PLW_IP_ADDR ptr)
{
    return *(PDWORD)ptr;
}


Если в проекте есть хоть один сетевой интерфейс для которого поле IP может быть невыравнено, то в кофигурации указан LW_ALIGNED_HDR нулевой. Но обычно есть только один ethernet, я стараюсь чтобы было выравнивание (гы, на SAM7X - получилось выровнять пакеты при приеме, на LPC - нет smile.gif) и работает выравненный вариант.

Пример работы с полем:
Код
{
    DWORD ip;

    ip = lw_ipload(&iphdr->ipsrc);
    //
    // Делаем с IP чего надо
    //
{


Но тут как раз проблема ловли исключений не так остро стоит - этот код свой и писался изначально под разные платформы с разной endianess и alignment. Проблема острее стоит в портированном "старье".
zltigo
Цитата(VslavX @ Jan 16 2009, 19:06) *
Чему именно?

Я более, чем четко сказал чему, что и подтвердилось. Если считать строки "по Вашему", то у меня их в одном из проектов и 500K, пожалуй наберется только это дутые строки. Из нуждающихся во внимательном портировании ни у Вас, ни у меня и десятка % не наберется. Тем более когда Вы ведете речь практически обо все совокупности наработанного из которого полагаю только 10-20% в конкретный проект ложатся. Порядка единиц процентов можно неспешно и глазками вычитать на предмет скользких мест.
Цитата
Что бывают проекты где 75-90% процентов платформо-независимо и может жить на 8/16/32?

У меня сейчас, пожалуй, поболе 99,9% не зависят от 8/16/32, ибо я говорил откуда пришли исходники, а не то, какими они стали.
Цитата
из любопытства написал простой скриптик подсчета текстовых строк на Perl и прогнал

Я в редактор скрипт встроил - всегда могу глянуть smile.gif


Цитата(VslavX @ Jan 16 2009, 19:23) *
У меня эту проблему в общем случае решить не удалось.

Для общего случая эта проблема решается через memcpy(). Причем для прилично писанных на ASM библиотек все получается вполне эффективно.
VslavX
Цитата(zltigo @ Jan 16 2009, 18:24) *
проект ложатся. Порядка единиц процентов можно неспешно и глазками вычитать на предмет скользких мест.

Мое мнение - можно вычитать на 99% smile.gif, вчерашний случай это подтвердил
А про неспешно - забудьте - еще в прошлом году уже все должно быть сделано.

Цитата(zltigo @ Jan 16 2009, 18:24) *
Я в редактор скрипт встроил - всегда могу глянуть smile.gif

Зачем? Это же смешно - строками меряться smile.gif. Я вот давно объем оценил и забыл, сейчас вот брякнул - и пожалел smile.gif. Я обычно объем архива смотрю - и прогресс виден и понятно когда снапшоты бэкапить пора.


Цитата(zltigo @ Jan 16 2009, 18:38) *
Для обшего случая эта проблема решается через memcpy(). Причем для прилично писанных на ASM библиотек все получается вполне эффективно.

А можно пример?
zltigo
Цитата(VslavX @ Jan 16 2009, 19:39) *
А можно пример?

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

Вот прям сейчас под руками получение контрольной суммы прошивки располагающейся по совершенно произвольному адресу:
memcpy( &crc, (BYTE *)crc_addr, 2 );
Естественно такое черевато:
crc = *((ushort *)crc_addr );
А такое мудрено:
crc = (((ushort)(*(((BYTE *)crc_addr)+1)))<<8) | (ushort)( *((BYTE *)crc_addr) );
Кстати, знаете почему я именно этот кусок привел smile.gif smile.gif smile.gif - Я НА ЭТО НАСТУПИЛ и запомнил. Наступил, сразу скажу, не при портировании, а при изучении ARM - первые шаги, загрузчик, контроль целостности... Наступил и запомнил smile.gif и теперь просто внимателен и осторожен.
Цитата(VslavX @ Jan 16 2009, 19:39) *
Зачем? Это же смешно - строками меряться smile.gif.

Упаси бог - Чисто для себя делалось - так сказать интегральная оценка.
defunct
Цитата(GetSmart @ Jan 16 2009, 16:16) *
Ещё как пойдёт.

Да не пойдет так! т.к. медленно.
Конкретно в этом случае ожидается, что данные в буфере выровнены. Если нет - тогда это критическая ситуация и проц должен дать мне фатальный эксепшин.

Цитата
Только использовать его надо именно в местах разбора буферов, в которых есть хоть малейшая вероятность невыровненности данных. Для работы с обычными переменными (статика, локальные) надо применять тип без прагмы.

Зачем замедлять работу программы лишними проверками и лишними побайтовыми операциями в критических для производительности местах?
Из-за "малейшей" вероятности делать код вчетверо медленнее - увольте. Мне лучше эксепшн smile.gif
VslavX
Цитата(zltigo @ Jan 16 2009, 19:01) *
memcpy( &crc, (BYTE *)crc_addr, 2 );
Естественно такое черевато:
crc = *((ushort *)crc_addr );
А такое мудрено:
crc = (((ushort)(*(((BYTE *)crc_addr)+1)))<<8) | (ushort)( *((BYTE *)crc_addr) );

Ну и - почему просто не написать:
Код
crc = lw_wload((ushort *)crc_addr);

где lw_wload - это макрос, аналогичный приведенному мной в посте выше и вырождающийся в один из Ваших вариантов. Если адрес произвольный и неизвестно, выравнен ли он при runtime, на этот случай есть макрос lw_wload_na() (na - not aligned). Все эти макросы компилируются в нормальный компактный код, да еще и обеспечивают конверсию BE/LE при необходимости. А вызов функции - всегда оверхед, и очень заметный, особенно для копирования 2/4 байт. Хотя бы посмотрите в листинг - сколько при вызове для ARM-а регистров сохраняться будет. Не-е-е - это не мой путь, точно. ИМХО, скопировать структуру целиком - еще можно, но это если памяти завались и скорость не волнует. А у меня так не бывает sad.gif

И все же:

1. Есть проект, состоит из двух частей - прикладной и системной
2. Системная часть - небольшой процент от проекта
- легко заменяется при смене аппаратной части на том же процессоре
3. Прикладная часть - большой процент от проекта и
- развивается долгий срок
- долгое время живет на 8-битной платформе
- долгое время компилируется одним и тем же компилятором
- значительная многовариантность
- значительная оптимизация по размеру кода и оперативной памяти, с учетом платформы и компилятора
4. Возникает необходимость смены платформы на 32-битную

И теперь, как автор системной части, я обязан обеспечить своим коллегам-прикладникам максимально безболезненные условия для портирования и отладки прикладной части. А я не могу сделать это в полном объеме, потому как NXP не удосужилась сделать простейшую и стандартную вещь. И что, мое возмущение неоправдано?
zltigo
Цитата(VslavX @ Jan 16 2009, 21:06) *
Ну и - почему просто не написать:

Когда это оправдано, естественно, используются разные способы и макросы однин из часто используемых. В данном случае Вы просили пример с memcpy() - я привел пример использования в загрузчике - совершенно не критичном по скорости месте. При копировании струкрур тоже весьма эффективно.
Цитата
но это если памяти завались и скорость не волнует.

Ну насчет размера кода то возможны и даже очень возможны варианты smile.gif
Цитата
А у меня так не бывает sad.gif

Посмею опять не поверить, основываясь на своих реалиях, что вcегда и везде дела обстят именно так smile.gif.
Цитата
И теперь, как автор системной части, я обязан обеспечить своим коллегам-прикладникам максимально безболезненные условия для портирования и отладки прикладной части. А я не могу сделать это в полном объеме, потому как NXP не удосужилась сделать простейшую и стандартную вещь.

Смотря как подходить к делу, сваять обработчик exception и умыть руки, предоставив возможность поэкспериментировать с наступанием на грабли в паркетно-домашних условиях? Но что делать при таком эмпирическом подходе к делу в реально-непаркетных условиях эксплуатации? Сделать из заказчика естествоиспытателя? В рабочей системе есть система фиксации и выкарабкивания нештатных сттуаций? Тогда какая особо разница, между вылетом и фиксацией факта разборки, например, странного пакета в конкретной ветке?
Цитата
И что, мое возмущение неоправдано?

Лучше, конечно, быть здоровым и богатым smile.gif.... А вообще, настаиваю, что лучше думать. Вы, например, настаиваете на необходимости максимально возможной производительности всегда и везде? Как тогда быть, напимер на 32bit x86, когда при "неправильном" доступе к памяти просто напросто молча получими торможение в разы sad.gif. Опять возмущаться sad.gif?
VslavX
Цитата(zltigo @ Jan 16 2009, 20:52) *
Посмею опять не поверить, основываясь на своих реалиях, что вcегда и везде дела обстят именно так smile.gif.

Гы, я обычно пишу системный код - то есть универсальные сервисы, которые будут использовать другие люди, иногда даже через несколько лет после написания. Поэтому вполне естественно заложить максимально возможное быстродействие и все доступные оптимизации. Вы гарантируете, что при использовании memcpy() у Вас не переполнится, к примеру стек? (а в многопоточке это будет естественно скопировать выравненную структуру в локальную переменную). Или прикладники не будут злоупотреблять частым вызовом функции? Хотя иногда так приятно себе сказать - "а вот таких гадских условий у нас в этой функции не будет никогда" и не писать какой-то противный кусок. В тех нечастых случаях, когда я себе такое позволяю, подстилается соответствующий ASSERT. А вообще - разочарован я Вашим примером использования memcpy(). Он, конечно, имеет право на жизнь, но я надеялся увидеть что-нить менее брутальное.

Цитата(zltigo @ Jan 16 2009, 20:52) *
Смотря как подходить к делу, сваять обработчик exception и умыть руки, предоставив возможность поэкспериментировать с

Это уже мои проблемы и мои фантазии какой обработчик написать, понадобится - буду эмулировать корректный доступ, потребуют - запишу проблему в лог, разрешат - отправлю баг-репорт по и-мейлу. Но на LPC23xx у меня нет выбора.

Цитата(zltigo @ Jan 16 2009, 20:52) *
максимально возможной производительности всегда и везде? Как тогда быть, напимер на 32bit x86, когда при "неправильном" доступе к памяти просто напросто молча получими торможение в разы sad.gif. Опять возмущаться sad.gif?

Ну это уже, имхо, передергивание - априори программу пытаемся написать правильно, доступ предполагаем корректный и по необходимости оптимизированный (если уж хотим избежать "торможения в разы"). Речь идет об исключении - когда что-то пошло нештатно. А насчет возмущения - есть стандартная, привычная и много раз использованная при отладке вещь - OAT/DABT, а теперь вот ее нет, а она реально полезна.
А думать - да, оно вредно обычно (а то опять не поверите smile.gif) не бывает.
zltigo
Цитата(VslavX @ Jan 16 2009, 22:28) *
Гы, я обычно пишу системный код - то есть универсальные сервисы, которые будут использовать другие люди, иногда даже через несколько лет после написания. Поэтому вполне естественно заложить максимально возможное быстродействие и все доступные оптимизации.


Абсолютно аналогично smile.gif

Цитата
А вообще - разочарован я Вашим примером использования memcpy(). Он, конечно, имеет право на жизнь, но я надеялся увидеть что-нить менее брутальное.

Пример, как пример. Один из варианов наряду с разнообразными (к сожалению разнообразными) макросами, какими-нибудь узкозаточенными intrinsic функциями типа memcpy_word_from_unaligned( dst, src ) представляющими собой усеченные memcpy(), где только dst гарантированно "хороший" адрес и прочими совершенно, напомню, не отрицаемыми мною решениями. Причем (действительно зачастую брутальный) memcpy() можно легко и гарантировнно безошибочно обернуть в любые макросы и ими сразу и без проблем обозначать проблемные места. C последующим обдумыванием и созданием более узкоспециализированных решений. 
GetSmart
Цитата(defunct @ Jan 17 2009, 00:01) *
Да не пойдет так! т.к. медленно.

Паранойя?! Вы ещё совсем недавно всё на AVR песали и не жаловались на быстродействие. LPC раз в 5 быстрее AVR, и если на нём побайтово из буфера собирать Long, то особых тормозов не будет заметно. Дальше спорить не буду. Я всё равно останусь при своём мнении.

А вообще, тут все забыли одну вещь касательно Data Abort при невыровненных словах. Где-то читал, что в LPC он возникает только если проц работает в USER MODE. Во всех остальных MODE, в частности в SYSTEM MODE он специально заблокирован, так как все остальные режимы предназначены для системы. Так что, господа песатели, отлаживайте свои проги в USER MODE, а когда уже всё отладите можете переносить код в другие режимы biggrin.gif
VslavX
Цитата(GetSmart @ Jan 17 2009, 07:12) *
А вообще, тут все забыли одну вещь касательно Data Abort при невыровненных словах. Где-то читал, что в LPC он возникает только если проц работает в USER MODE. Во всех остальных MODE, в частности в SYSTEM MODE он специально заблокирован, так как все остальные режимы предназначены для системы. Так что, господа песатели, отлаживайте свои проги в USER MODE, а когда уже всё отладите можете переносить код в другие режимы biggrin.gif

Совет хороший, и стал бы еще лучше если бы Вы его ссылкой подтвердили. А то документация производителя и google как-то скромно умалчивают про приведенные Вами факты.
GetSmart
Прямо скажу, я за 3 года об АРМах столько всего начитался, что уже не помню когда и где читал. Но скорее всего где-то в разделе об ограничениях USER MODE. Точно помню, что в этом режиме нельзя изменить младшие биты регистра флагов, отвечающих за текущий режим и за запрет прерываний. Мне сейчас лень искать всем желающим нужную им инфу. Подсказки я дал. Все желающие - на поиски!!!

А не вылетание в аборт при невыровненном чтении имеет свои плюсы. Жаль, что IAR это делать не умеет, но эта фича даёт возможность прочитать 32 бита с любого нечётного адреса всего за две команды LDR. Например читая слово с адреса 1 в регистр прочитаются правильно сразу три байта. Старший байт нужно будет прочитать в другой регистр из адреса 5. Потом по маске их объеденить. Браво LPC!!! smile.gif

Потестировал это дело на LPC2134/01 но не срабатывает исключение ни в SYSTEM, ни в USER. Абыдно sad.gif А может где-то флажок стоит, управляющий этой фичей.
defunct
Цитата(GetSmart @ Jan 17 2009, 07:12) *
Паранойя?! Вы ещё совсем недавно всё на AVR песали и не жаловались на быстродействие.

Я и до сих пор под AVR/C51 много чего пишу, и не жалуюсь на быстродействие. Но там у меня задачи нетребовательные к быстродействию.
Не понимаю, Вы пытаетесь защитить/оправдать остуствие exception'a в LPC?!

Цитата
LPC раз в 5 быстрее AVR, и если на нём побайтово из буфера собирать Long, то особых тормозов не будет заметно. Дальше спорить не буду. Я всё равно останусь при своём мнении.
В таком случае SAM7 "порвет" LPC по производительности (т.к. не нужно будет собирать Long побайтово).

Цитата
А вообще, тут все забыли одну вещь касательно Data Abort при невыровненных словах. Где-то читал, что в LPC он возникает только если проц работает в USER MODE. Во всех остальных MODE, в частности в SYSTEM MODE он специально заблокирован, так как все остальные режимы предназначены для системы.

Если можно - более подробно на этот счет. Где читали? ;>
zltigo
Цитата(defunct @ Jan 17 2009, 19:00) *
В таком случае SAM7 "порвет" LPC по производительности (т.к. не нужно будет собирать Long побайтово).

Вы, это, простите о чем???
defunct
Цитата(zltigo @ Jan 17 2009, 19:13) *
Вы, это, простите о чем???

О том что мне совесть не позволит в проц в котором нет exception'a вставить опасный код.

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

на SAM'е мне ничто не мешает там где нужна скорость написать:
*(U32 *)<произвольный адрес> = x;
т.к. есть полная уверенность в том, что даже если произвольный адрес неправильный я это не пропущу.

на LPC будет как минимум:

Код
if (<произвольный адрес> & 0x3)
{
   slow implementation
}
else
{
   fast
}
aaarrr
Цитата(defunct @ Jan 17 2009, 21:25) *
т.к. есть полная уверенность в том, что даже если произвольный адрес неправильный я это не пропущу.

А есть уверенность, что когда произвольный адрес станет неправильным от изменения совсем в другом месте, Вы этого не пропустите?
abcdefg
Цитата(defunct @ Jan 17 2009, 21:25) *
О том что мне совесть не позволит в проц в котором нет exception'a вставить опасный код.

на LPC будет как минимум:

Код
if (<произвольный адрес> & 0x3)
{
   slow implementation
}
else
{
   fast
}


Ну вообщем то так и делается smile.gif И не только для LPC
Например, в WinCE'шных драйверах упомянутого выше самсунга...
zltigo
Цитата(defunct @ Jan 17 2009, 20:25) *
О том что мне совесть не позволит в проц в котором нет exception'a вставить опасный код.


Ну и как это новое утверждение соотностится с Вашим предыдущим

Цитата
В таком случае SAM7 "порвет" LPC по производительности (т.к. не нужно будет собирать Long побайтово).


, которое и вызвало моой вопрос. Повторяю вопрос - как наличие exception приводит к результату "не нужно будет собирать Long побайтово"
VslavX
Цитата(defunct @ Jan 17 2009, 20:25) *
на LPC будет как минимум:

Код
if (<произвольный адрес> & 0x3)
{
   slow implementation
}
else
{
   fast
}

ИМХО, при неработающем исключении лучше бы написать так:
Код
{
   ASSERT(((DWORD)adr & (sizeof(DWORD)-1)) == 0, "Ugly unaligned pointer");
   fast implementation
}

ASSERT программно сгенерит недостающее исключение. Но беда в том, что я предпочитаю "традиционный вариант нормы" - то есть работающее исключение, и на такую подлянку никто не рассчитывал и, соответственно, этот ASSERT по коду не "раскидан".
defunct
Цитата(zltigo @ Jan 17 2009, 21:46) *
Ну и как это новое утверждение соотностится с Вашим предыдущим

ну.. так сказать "прямопропорционально". На SAM'е будет быстрый опасный код, на LPC - медленный и безопасный.

Цитата
Повторяю вопрос - как наличие exception приводит к результату "не нужно будет собирать Long побайтово"

Чтобы ответить на этот вопрос, позвольте мне определить рамки в которых плаваем. Дано:
1. буферы, содержащие некие типизированные данные, например IP заголовок;
2. предполагается, что для любого буфера, IP заголовок может находиться с произвольным смещением от начала буфера;
3. предполагается, что начало IP заголовка всегда на границе 32 бит. (напр, программируем DMA так, чтобы он нам клал пакет не с начала буфера, а с некоторого смещения, так чтобы IP заголовок получался выровненным).
(отступ от последнего условия - есть ситуация неординарная, возникающая возможно при фатальной ошибке программы).

Теперь собсно ответ на вопрос:
С наличием exception'a - я буду работать с полями IP заголовка как с U32 без проверок на выровненность.
Без exception'a мне придется либо предусмотреть его программную генерацию, либо - побайтовую сборку/копирование полей с требуемым выравниванием. Оба варианта будут пагубно сказываться на быстродействии (лишний код и все-таки).

Цитата
ИМХО, при неработающем исключении лучше бы написать так:
...
ASSERT(((DWORD)adr & (sizeof(DWORD)-1)) == 0, "Ugly unaligned pointer");

Согласен, однако это не сделает реализацию такой же быстрой как без assert'a sad.gif
Проверка останется все равно.
GetSmart
Цитата(defunct @ Jan 18 2009, 06:44) *
Согласен, однако это не сделает реализацию такой же быстрой как без assert'a sad.gif
Проверка останется все равно.

С такой паранойей надо писать на ассемблере и ничего не бояться biggrin.gif Т.к. любители структурированного программирования на Си без забот выносят часть кода в отдельную процедуру, что сказывается на быстродействии ещё хуже чем сборка одного Long побайтово. А уж если программа написана на C++, то жаловаться на замедление просто смешно.

Дам бесплатный совет. В режиме отладки ставьте ASSERT или любую проверку. В режиме Release уберите проверки и получите быстродействие ещё больше чем в SAM7, т.к. проц быстрее. Но даже если LPC будет собирать Long побайтово, то по скорости он всё равно (!) не уступит SAM7. Хочу подчеркнуть, что я предлагал собирать побайтово Long только для быстрой проверки какого-либо условия в буфере. Если же нужно выгребать множество слов из буфера, то как правильно писал zltigo, сперва нужно через memcpy скопировать буфер и выровнять его начало. Можно даже не тратить дополнительную память и скопировать внутри текущего буфера на 1, 2 или 3 байта назад. Или вперёд.

Как там говорится: в чужом глазу соринку... в своём глазу бревно...
zltigo
Цитата(GetSmart @ Jan 17 2009, 10:52) *
А не вылетание в аборт при невыровненном чтении имеет свои плюсы. Жаль, что IAR это делать не умеет, но эта фича даёт возможность прочитать.....



Сейчас попробовал переписать один относительно критичный кусочек работающий (никаих проблем не было - компилятор, естественно, сам разруливал) в кольцевом буфере с 16bit данными под описаный стиль "корреция результата после чтения по невыровненному адресу" результат мне понравился. Если до этого я в принципе пребывал на позициях - особо без разницы есть аборт или нет, то теперь чаша весов (если действительно требуется выжимать быстродействие) склоняется к безабортовому варианту.
aaarrr
Цитата(zltigo @ Jan 18 2009, 14:17) *
Если до этого я в принципе пребывал на позициях - особо без разницы есть аборт или нет, то теперь чаша весов (если действительно требуется выжимать быстродействие) склоняется к безабортовому варианту.

А оптимальное решение где-то посередине: на ARM920, 926 и т.п. генерация аборта включается битом в CP15. Здесь могли бы сделать так же.
zltigo
Цитата(aaarrr @ Jan 18 2009, 14:10) *
генерация аборта включается битом в CP15. Здесь могли бы сделать так же.

Ну без вариантов smile.gif вот оно счастье!
VslavX
Имхо, это уж совсем клиническая ситуация - "невыровненный кольцевой буфер 16-битных слов" - такого я еще не встречал.

Moderator:

Извините! Совершенно случайно промахнулся и отредактировал Ваш пост удалив большую его часть sad.gif sad.gif sad.gif...

VslavX:

Да ничего страшного, бывает.
Если найдется время - таки фрагменты листингов выложите, плз - интересно, неужели "в самом деле все качели погорели" ? smile.gif
Я над темой доступа к невыравненым данным немало размышлял, может тут что новое любопытное появится.
zltigo
Цитата
Имхо, это уж совсем клиническая ситуация - "невыровненный кольцевой буфер 16-битных слов" - такого я еще не встречал.

Ну маленько не так написал sad.gif - буфер само-собой выровненный, а слова лежащие в нем, естественно, уже нет. Буфера обслуживают 16bit SPI, протокол старинный и тоже 16bit - пришел из 70x годов с машины которая про 8bit вобще не знала smile.gif
VslavX
Мне правда интересно. На ARM-е можно любой невыравненный USHORT (16-битное целое) загрузить за 3 инструкции
Код
ldrb R1, [R0, #0]
ldrb R2, [R0, #1]
orr  R1, R1, R2, shl #8

Как можно грузить быстрее - ума не приложу laughing.gif . Если даже воспользоваться изращенным способом загрузки от NXP - то все равно нужна проверка, что 16-битное не пересекает границу 32-битного слова.
Вот я такой тестик запустил:
Код
{
    BYTE a[8];
    DWORD i;
    for(i=0; i<sizeof(a); i++) a[i] = (BYTE)(i+1);
    dprintf("\r\n%08X %08X %08X %08X",
                *((PDWORD)&a[0]),
                *((PDWORD)&a[1]),
                *((PDWORD)&a[2]),
                *((PDWORD)&a[3]));
}

Результат: 04030201 01040302 02010403 03020104
То есть, действительно имеет место циклический сдвиг - так еще (дополнительно к проверке вмещения в одно слово) и старшие биты чистить надо. Не понимаю, где тут можно выиграть blink.gif
zltigo
Цитата(VslavX @ Jan 18 2009, 15:30) *
Не понимаю, где тут можно выиграть blink.gif


У меня память под буфера внешняя и замена одного из двух ldrb из внешней памяти банальным tst регистр,#0x3 мне и понравилась, хотя и те-же "три инструкции", как понравилось и использование (кусочек на ASM) только одного регистра вместо 2 ( у Вас даже 3x ).
VslavX
Цитата(zltigo @ Jan 18 2009, 15:53) *
У меня память под буфера внешняя и замена одного из двух ldrb из внешней памяти банальным tst регистр,#0x3 мне и понравилась, хотя и те-же "три инструкции", как понравилось и использование (кусочек на ASM) только одного регистра вместо 2 ( у Вас даже 3x ).

Ну, допустим, доступ к внешней памяти медленный. Но ведь если, например, младшие два бита адреса равны 0x03, то все равно надо читать два раза из памяти - два последовательных DWORD/WORD-a. И дополнительная проверка на равенство этих битов адреса на 0x03 с последующим ветвлением/пропуском тоже нужна. Где собак зарыт?
P.S. Переписал свой тестик на использование 16-битных невыравненных слов - там еще результаты мрачней. Ну никак за одно обращение два слова (16 или 32-битных) не читается.
P.P.S. "Листинг, сестра, листинг" smile.gif
zltigo
Цитата(VslavX @ Jan 18 2009, 16:29) *
Ну, допустим, доступ к внешней памяти медленный. Но ведь если, например, младшие два бита адреса равны 0x03, то все равно надо читать два раза из памяти - два последовательных DWORD/WORD-a.


В этом моем случае - нет - все двухбайтовое. 0x3 я просто так использовал. Ну а в случае реального смещения на байт речь уже идет о той-же двухкратно разнице - 2 или 4 обращения.

Цитата
И дополнительная проверка на равенство этих битов адреса на 0x03


Одна команда

Цитата
с последующим ветвлением/пропуском тоже нужна. Где собак зарыт?


Для ARM без ветвления smile.gif

Цитата
P.P.S. "Листинг, сестра, листинг" smile.gif

Код
tst      R0,#0x3
ldrh     R0,[R0, #+0]
lsrne    R0,R0,#+8

вместо
Код
ldrb     R1,[R0, #+0]
ldrb     R0,[R0, #+1]
orr      R0,R1,R0, lsl #+8
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.