|
|
  |
Новичок на С, Помогите разобраться со структурой проекта |
|
|
|
Mar 19 2006, 13:05
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
osnwt спасибо за расширенный ответ. Детали и нюансы не почерпнёшь в мануалах. Там всё лаконично. Массив пересчёта я поместил в const __flash, бузусловно. Использовать 256 байт озу под это для меня слишком расточительно. Помещать Вам на рассмотрение ещё и фрагменты текста, по-моему это уж слишком.  Это уж самом-самом крайнем случае. Буду разбираться сам. Ваши советы мне помогли обрести уверенность. Я теперь больше доверяю компилятору и меньше себе.  Если что-то не так, - более детально разбираю программу. На счёт "легендарных" 11 байт. Ещё раз внимательно всё просмотрел (в который уже раз). У меня в программе очень много различных данных находится в sram. И разнотипных к тому же. Чё делает компилятор? - Он выбирает группу переменных (возможно использующихся в одном месте) и для обращения к переменным использует одно имя. А к остальным переменным обращается LDD Rx, Z+ (смещение в группе). Вот так и получилось 11 байт.  На самом деле это определённое количество переменных начинающихся с переменной "flag". В моём случае вычисление типа: Oport0 &= ((EkrToPort[*AdrShowEkr++ ^ Cycl_Ekr] & 0xf) | (EkrToPort[*AdrShowEkr++ ^ Cycl_Ekr] & 0xf0)); Заняло больше места чем l = (EkrToPort[*AdrShowEkr++ ^ Cycl_Ekr] & 0xf); Oport0 &= (l | (EkrToPort[*AdrShowEkr++ ^ Cycl_Ekr] & 0xf0)); (l - переменная локальная)
|
|
|
|
|
Mar 19 2006, 14:32
|

Частый гость
 
Группа: Свой
Сообщений: 175
Регистрация: 26-01-06
Из: Sevastopol
Пользователь №: 13 664

|
Цитата(SasaVitebsk @ Mar 19 2006, 15:05)  В моём случае вычисление типа: Oport0 &= ((EkrToPort[*AdrShowEkr++ ^ Cycl_Ekr] & 0xf) | (EkrToPort[*AdrShowEkr++ ^ Cycl_Ekr] & 0xf0)); Заняло больше места чем l = (EkrToPort[*AdrShowEkr++ ^ Cycl_Ekr] & 0xf); Oport0 &= (l | (EkrToPort[*AdrShowEkr++ ^ Cycl_Ekr] & 0xf0)); (l - переменная локальная) Хочу заметить, что первое (сложное) выражение, помимо того, что не очень наглядно, еще и неоднозначно с точки зрения порядка вычислений (иногда при этом можно получить и разную длину кода). Использованное там выражение *p++ имеет побочный эффект в виде инкремента указателя. В выражении e1 | e2 порядок вычисления выражений e1 и e2 вообще не определен (в отличие от e1 || e2, где вычисление идет слева направо - смысл операций, разумеется, разный). Потому в общем случае компилятор может сначала посчитать правое выражение, а потом левое. Очевидно, что результаты будут различные, так как *p++ (где p - это EkrToPort) даст разные результаты в этих двух случаях. Потому в таких случаях особенно важно писать однозначно и наглядно.
|
|
|
|
|
Mar 19 2006, 18:38
|

Частый гость
 
Группа: Свой
Сообщений: 175
Регистрация: 26-01-06
Из: Sevastopol
Пользователь №: 13 664

|
Цитата(osnwt @ Mar 19 2006, 16:32)  *p++ (где p - это EkrToPort) Ошибка: имелось в виду AdrShowEkr в выражении Код Oport0 &= ((EkrToPort[*AdrShowEkr++ ^ Cycl_Ekr] & 0xf) | (EkrToPort[*AdrShowEkr++ ^ Cycl_Ekr] & 0xf0));
|
|
|
|
|
Mar 19 2006, 20:27
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Я это обнаружил с самого начала, но решил посмотреть как это сделает компилятор. Потом убрал чтобы не было неоднозначности. Написанная мной подпрограмма прерывания на ASMе оказалась быстрее примерно в четыре раза. Я конечно ещё поэкспериментирую с СИ (программой прерывания), но вероятней всего в конечном варианте будет программа на асемблере. (Самый быстрый вариант на СИ тоже оставлю для возможного перехода на другой МП) Я приступил к отладке, поскольку в настоящий момент начинаю "терять из под контроля программу".  (Не знаю как у кого, а у меня при большой длине проги наступает такой момент, когда она живёт своей жизнью) После того как я отлажу (в симуляторе) некоторые независимые части, то начну её дописывать. Осталось процентов 20-25. И вот сейчас у меня непонятная ошибка. TekAdrActive = LastAdrActive = malloc(SIZE_FREE); // Âûäåëèòü ïàìÿòü При отладке в указатели заносится значение при SIZE_FREE менее 10. Фишка в том, что я пишу под atmega2560 (sram 8k). Компилятор выдаёт следующие значения занятой программы. // // 43 bytes in segment ABSOLUTE // 2 668 bytes in segment CODE // 3 002 bytes in segment FARCODE // 7 bytes in segment INITTAB // 12 bytes in segment INTVEC // 855 bytes in segment NEAR_Z // // 5 670 bytes of CODE memory (+ 19 bytes shared) // 855 bytes of DATA memory (+ 43 bytes shared) И ещё указатель на свободный адрес она выдаёт типа 229h. Может быть там и есть дырка байт 10.  Но потом идут массивы и прочее. Короче менее 5bfh этот адрес не должен быть. Где-то ошибка. Может быть это связано с сегментами? Дело в том что я с ними не работал и пока убей-непонимаю зачем они нужны (применительно к AVR. На процессоре 80x8х когда-то сталкивался под ассемблером. Там это очевидно). Помогите разобраться.
|
|
|
|
|
Mar 19 2006, 23:04
|

Частый гость
 
Группа: Свой
Сообщений: 175
Регистрация: 26-01-06
Из: Sevastopol
Пользователь №: 13 664

|
Цитата(SasaVitebsk @ Mar 19 2006, 22:27)  TekAdrActive = LastAdrActive = malloc(SIZE_FREE); // Âûäåëèòü ïàìÿòü
При отладке в указатели заносится значение при SIZE_FREE менее 10. Фишка в том, что я пишу под atmega2560 (sram 8k). Компилятор выдаёт следующие значения занятой программы. ... Может быть это связано с сегментами? Дело в том что я с ними не работал и пока убей-непонимаю зачем они нужны (применительно к AVR. На процессоре 80x8х когда-то сталкивался под ассемблером. Там это очевидно). Помогите разобраться. Каждый байт кода или данных помечается, как располагаемый в определенном именованном сегменте. Имеется некоторое количество предопределенных сегментов, используемых компилятором. Можно также создавать свои собственные. Раскладыванием сегментов по адресам занимается линкер под управлением файла конфигурации *.lnk. По умолчанию в IAR среда определяет основные размеры областей, а дальше используется файл конфигурации для соответствующего контроллера. Там указано, что сегмент такой-то занимает адреса такие-то. Это делается (по умолчанию) с учетом заданных в конфигурации проекта размеров стеков, кучи и т.п. При работе с *alloc функциями надо выделить достаточный размер "кучи" (heap) в конфигурации проекта. А потом посмотреть, где линкер разместит сегменты HEAP и NEAR_HEAP. Если выделяемый адрес не попадает в эти области, то что-то не так с программой. Подробнее RTFM по линкеру, там все хорошо расписано. В данном случае сегменты не имеют ничего общего с сегментами x86, это просто средство управления распределением адресов под код и данные при окончательной компоновке.
|
|
|
|
|
Mar 22 2006, 12:29
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Спасибо. Сегодня ине глючит у меня. Поэтому топик попал дважды да не весь.  Передаю вторую часть Подскажите спецы (IAR). Более сложный вопрос.  Переменные объявлены следующим образом: void static *AdrActiveKom[MAX_ACTIVE_KOM+1]; // Адреса указателей на начало активных команд uint8_t i, j, c, *adrnpict; Имею такой цикл (или он меня  ) j= (uint8_t *)AdrActiveKom[i+1]-(uint8_t *)AdrActiveKom[i]; // Высчитать длину команды for(adrnpict=(AdrActiveKom[i]);adrnpict<(AdrActiveKom[NumbActiveKom+1]-j);adrnpict++) *adrnpict = *(adrnpict+j);// перенесли команду Если цикл описать так, то синтаксич. ошибка несовместимости типов, а если так как ниже то всё OK j= (uint8_t *)AdrActiveKom[i+1]-(uint8_t *)AdrActiveKom[i]; // Высчитать длину команды for(adrnpict=((uint8_t *)AdrActiveKom[i]);adrnpict<((uint8_t *)AdrActiveKom[NumbActiveKom+1]-j);adrnpict++) *adrnpict = *(adrnpict+j);// перенесли команду Но при вычислениях (не в теле цикла, а при выч. переменных цикла) компилятор использует адреса а не содержимое массива. Можно конечно поизголятся используя адресную арифметику, но я хочу выяснить где у меня ошибка? Что я не правильно понимаю? С уважением.
|
|
|
|
|
Mar 22 2006, 13:09
|

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

|
Цитата(SasaVitebsk @ Mar 22 2006, 14:29)  Можно конечно поизголятся используя адресную арифметику, но я хочу выяснить где у меня ошибка? Ошибка на стадии проектирования.. Я извиняюсь, но алгоритм у Вас если мягко сказать - очень замороченный. Что приводит к просто ужасной реализации в коде. Задача вроде бы простая - скопировать тело команды в буфер команды, соответственно должна решаться простым способом даже без вычисления длины команды. Пока не поздно упрощайте алгоритм (если уже не поздно..)..
|
|
|
|
|
Mar 22 2006, 20:42
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Всё ещё сложнее чем Вы думаете.  И вто же время достаточно симпатично в реализации. На самом деле команд много и поступают непрерывно. Команды имеют переменную длину и структуру. Заносятся последовательно и там проблем не возникает. Исполняются только те команды которым подошло время. Т.н. активные. Исполняются пока не завершится время исполнения. С исполнением тоже проблем нет. То что Вы видите, - это не занесение в буфер а "смерть" команды. Т.е. она отработала, и её надо выкинуть из буфера. Я конечно могу просто удалить указатель на данную команду, но тогда в памяти появится "дырка". Короче стандартная ситуация "сборки мусора", которая, как говорят, эффективно решена в UNIX, но плохо в Windows.  Известно и её решение в файловой системе диска начиная с FAT. По известной причине данные решения я применить не могу.  Поэтому я переписываю все команды следующие за удаляемой на место начиная с освобождённого. А также пересчитываю массив указателей на начало команд и уменьшаю их число. Всё это на PC работает и здесь ошибки нет, но компилятор почему-то не верно компилирует (точнее не так как я от него хочу).
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|