|
Вопрос по IAR, Настройки среды программирования |
|
|
|
 |
Ответов
(1 - 62)
|
Nov 8 2013, 18:35
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 8 2013, 22:19)  Подскажите, возможно ли настроить IAR так, чтобы он сделал компиляцию кода (например какой-то отдельной функции или всего кода) строго в определенный участок флешь памяти (от сих до сих, так сказать)? Дописать перед функцией pragma location, а в опциях линкера (ExtraOptions) определить это место, как сегмент. Например, так было достигнуто размещение функции ReadFuse() в загрузочной оласти: Код #pragma location="BOOT" void ReadFuse() { ... } Сам сегмент был определен так: Код -D_..X_FLASH_BOOT=F000 -Z(CODE)BOOT=_..X_FLASH_BOOT-_..X_FLASH_END Вместо BOOT можно написать какое-то другое слово, а вместо F000 другой адрес.
|
|
|
|
|
Nov 9 2013, 15:56
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 9 2013, 08:51)  Спасибо за ответ. Что значит 2 точки в коде: Код -D_..X_FLASH_BOOT=F000 -Z(CODE)BOOT=_..X_FLASH_BOOT-_..X_FLASH_END То есть задается только адрес начала размещения? Нет, здесь задается именно сегмент памяти от сих до сих, где будут размещены ВСЕ функции, которые к данному сегменту приписаны. Т.е. если у вас несколько функций приписаны к сегменту BOOT, то все они в него попадут друг за дружкой. И тогда строго формально нельзя будет предсказать, с какого адреса одна из тех функций начинается, хотя практически линкер укладывает их тела в тот сегмент в порядке упоминания в тексте программы. Поэтому, чтобы разместить функцию строго по определенному адресу, вам придется сделать уникальный сегмент только для нее! Тогда уж она точно окажется в том ряду первой и попадет на начало сегмента. Точки и подчеркивание, думаю, нечего не означают, просто придают именам уникальность, чтобы те случайно не совпали с именами каких-то объектов в программе. Т.е. _..X_FLASH_BOOT - это одно имя целиком, а директива D (от слова define) лишь приписывает ей значение. Само же определение сегмента задано во второй строке, после директивы Z. Вообще-то, я сама глубоко с этим не разбиралась, а просто механически переделала под свое имя (BOOT) определение какого-то другого сегмента в том же самом стиле (это видно в xcl-файле для данного типа МК). Рисковать не хотелось, а надо было сделать по-быстрому. Думаю, что в данном случае вполне годилось бы самое примитивное определение без всяких дефиниций: -Z(CODE)BOOT=F000-F100 где задается имя сегмента, а его границы выставлены прямо в числах. Определения имени границ сегментов нужны в файле конфигурации только затем, чтобы связать все сегменты в одну цепочку. Поэтому там каждое имя повторяется по меньшей мере 2 раза - в качестве конца предыдущего сегмента и начале последующего. Мой случай был в этом отношении примитивным, т.к. загрузочная область была заведомо пуста. В вашем случае дело может вылиться в то, что придется переписывать файл конфигурации под себя. Тогда его надо скопировать его в свой проект из: \Program Files\IAR Systems\Embedded Workbench 6.5\430\config\lnk430f5529.xcl (так этот файл называется для MSP430F5529, но у вас может быть другой МК) переключить проект на него вместо умолчания, а потом внести в него исправления. Редактировать исходный файл конфигурации нельзя, можно только копию! Проблема тут в том, что вся память уже поделена на сегменты! А потому свой сегмент придется буквально вклинивать между существующими, раздвинув в каком-то месте границы. Тут ситуация, как на политической карте мира - вам не создать нового государства, не потеснив в границах соседей, поскольку вся земля уже поделена. Однако разбираться в том файле, уж тем более редактировать его, довольно противно. А потому попытайте сначала самый легкий способ - на числах, вдруг сработает? Цитата(d7d1cd @ Nov 9 2013, 08:51)  А что будет, если скомпилированный код не умещается от указанного места расположения до конца флешь памяти? В этом случае линкер ошибку должен выдать. Примерно такую же, когда код слишком велик для памяти данного МК. Цитата(d7d1cd @ Nov 9 2013, 08:51)  При попытке компиляции IAR выдает ошибку Fatal Error[e163]: The command line symbol "_..X_FLASH_END" in -Z(CODE)BOOT=_..X_FLASH_BOOT-_..X_FLASH_END is not defined. Дефиниции границ сегментов могут довольно сильно отличаться по именам у разных МК. Советую вам найти xcl-файл именно для своего типа МК и сделать определение, подобное тому, как там определены сегменты кода.
|
|
|
|
|
Nov 9 2013, 17:31
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(Xenia @ Nov 9 2013, 19:56)  А потому попытайте сначала самый легкий способ - на числах, вдруг сработает? Определил сегмент так: Код -Z(CODE)BOOT=F002-F0FF И все получилось! Компилятор расположил код функции с адреса 0xF002. Спасибо. По расположению кода теперь разобрался. Есть другой вопрос. В функции я использую переменные. Как указать компилятору при определении переменной, что эта переменная должна быть физически расположена по адресу 0x0200, например? Или как указать, что массив данных должен начинаться с адреса 0x0421?
|
|
|
|
|
Nov 10 2013, 10:30
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Попытался указать переменной конкретный адрес. Ничего не получается. В опциях линкера я указал: Код -Z(DATA)VARIABLE=0200-020F В коде прописал: Код #pragma location = "VARIABLE" char data = 1; Однако при выполнении кода в симуляторе я вижу, что цифра 1 попадает в регистр R14, а не в диапазон 0x0200-0x020F. Ошибок нет. Что не так то опять? P.S. Посмотрел файл io430x24x.h. Есть там много строк, подобных этой: Код /* ADC12 Interrupt Flag */ __no_init volatile unsigned short ADC12IFG @ 0x01A4; Как я понимаю, здесь переменной ADC12IFG "назначается" адрес 0x01A4. Неужели я не могу так же в программе назначить свои переменные?
Сообщение отредактировал d7d1cd - Nov 10 2013, 11:41
|
|
|
|
|
Nov 10 2013, 12:25
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 10 2013, 14:30)  В коде прописал: Код #pragma location = "VARIABLE" char data = 1; Однако при выполнении кода в симуляторе я вижу, что цифра 1 попадает в регистр R14, а не в диапазон 0x0200-0x020F. Ошибок нет. Что не так то опять? Если у вас переменная в регистр попала, то это локальная переменная, объявленная внутри блока из фигурных скобок. Такие переменные называются "автоматическими", имеют ограниченное время жизни, а потому и располагаются на стеке или в регистрах. А чтобы застолбить переменную или массив в памяти, они должны быть глобальными, т.е. объявленными вне функций или с декларатором static. Цитата(d7d1cd @ Nov 10 2013, 14:30)  Посмотрел файл io430x24x.h. Есть там много строк, подобных этой: Код /* ADC12 Interrupt Flag */ __no_init volatile unsigned short ADC12IFG @ 0x01A4; Как я понимаю, здесь переменной ADC12IFG "назначается" адрес 0x01A4. Неужели я не могу так же в программе назначить свои переменные? А вы попробуйте. Думаю, что вполне можете и так. Только внутри фигурных скобок этого не делайте.
|
|
|
|
|
Nov 10 2013, 13:42
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Сделал объявление переменной глобально, то есть вне функции. Все хорошо, но работает только с атрибутом __no_init: Код #pragma location = "VARIABLE" __no_init volatile char data;
int main( void ) { data = 1; } Далее я попробовал сделать как в стандартном файле. Все тоже заработало, но тоже только с атрибутом __no_init: Код __no_init volatile char X @ 0x0210;
int main( void ) { data = 1; } В принципе то, что объявление переменных выше указанными способами не предусматривает их инициализации, мне и надо. По удобству я считаю, что второй способ лучше. С объявлением глобальных переменных тоже теперь ясно. А можно ли локальную переменную объявить так, чтобы она была связана с конкретным регистром?
|
|
|
|
|
Nov 10 2013, 13:53
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 10 2013, 17:42)  Все хорошо, но работает только с атрибутом __no_init В принципе то, что объявление переменных выше указанными способами не предусматривает их инициализации, мне и надо. По удобству я считаю, что второй способ лучше. С объявлением глобальных переменных тоже теперь ясно. Так оно и быть должно. Все обнуляемые переменные и массивы попадают в сегмент NEAR_Z (у других МК может называться по иному), который обнуляется при запуске (в процедуре startup). А раз у вас данные расположены в другом/самодельном сегменте, то инициализации они не получат. То, что аттрибут __no_init требуется синтаксически не знала (в старых версиях не был обязателен). Цитата(d7d1cd @ Nov 10 2013, 17:42)  А можно ли локальную переменную объявить так, чтобы она была связана с конкретным регистром? Полагаю, что нельзя.
|
|
|
|
|
Nov 10 2013, 14:53
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 10 2013, 18:04)  Хорошо. А возможно ли какой-то локальной переменной присвоить значение какого-то регистра? И еще: при объявлении локальной переменной ей назначается какой-то регистр. Возможно ли сделать так, чтобы значение этого регистра предварительно было сохранено в стеке, а после окончания работы функции восстановлено из него? На этот вопрос мне трудно дать конкретный ответ, т.к. нас с вами разделяют архитектуры: я - преимущественно AVR-щица, а вы - пользователь MSP430. Обмениваться опытом нам позволяет лишь общий компилятор IAR, и то лишь в той мере, в которой существует подобие между реализациями для этих двух архитектур. Согласно стандартам языка C/C++, вы имеете возможность добавить декларатор "register", если хотите, чтобы локальная переменная заводилась не на стеке, а в регистре: register char data; или char register data; Только эта декларация является лишь пожеланием, которое компилятор может проигнорировать, даже не выдав по этому поводу никакого сообщения. Что же касается массивов, то это почти безнадега. То, насколько у компилятора есть возможности удовлетворить данное пожелание, сильно зависит от числа свободных регистров в данной архитектуре. В архитектуре AVR имеется 32 регистра, и хотя младшие из них специализированы, то все равно остается дофига других. В таких случаях компилятор довольно охотно удовлетворяет просьбу "register", хотя и трудно заранее предвидеть, какой по номеру регистр он для этой цели выберет. А, скажем, на архитектуре x86 такие пожелания удовлетворяются крайне редко, т.к. там всего 7 регистров, причем, совсем не лишних. Поэтому мне трудно предсказать, насколько компилятор для MSP430 окажется покладистым. Еще в AVR-ном варианте есть возможность зарезервировать отдельные регистры (начиная с R15 и ниже) под глобальные переменные. Например: __regvar __no_init volatile long data@12; // data занимает 4 регистра: R12,R13,R14,R15 Но эти же же регистры приходится изымать из обращения в опциях проекта, чтобы компилятор их не использовал. При этом пользоваться можно только библиотекой clib (которая регистры R5-R15 либо не использует, либо сохраняет/восстанавливает их значения), а библиотекой dlib пользоваться нельзя.
|
|
|
|
|
Nov 10 2013, 14:57
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(SSerge @ Nov 10 2013, 18:45)  Оставьте эту работу компилятору, это его проблемы. Я понимаю, но у меня задача очень специфическая. Нашел я тут как делать вставки на ассемблере: Код int main( void ) { int AAA; asm("MOV.W R15, &AAA"); } Однако тут компилятор выдает ошибку: Цитата Error[Og005]: Unknown symbol in inline assembly: "AAA" Если же переменную ААА объявить глобально (вне функции main), то ошибки нет. Хотя в справке к IAR переменная объявлена локально. Почему же ошибка?
|
|
|
|
|
Nov 11 2013, 20:28
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(d7d1cd @ Nov 10 2013, 19:57)  Если же переменную ААА объявить глобально (вне функции main), то ошибки нет. Хотя в справке к IAR переменная объявлена локально. Почему же ошибка? Компилятор строку с inline assembler сам не разбирает. Он просто вставляет ее в текст объектного (ассемблерного) модуля. А поскольку в вашем примере переменная AAA в Си-шном модуле нигде более не используется, то оптимизатор компилятора выкидывает ее за ненадобностью. И вот когда объектный модуль попадает "на стол" к линкеру, то линкер приходит в недоумение, что это за объект AAA вдруг обнаружился? Т.к. компилятор про объект AAA ничего (адрес объекта) линкеру не сообщил и более того - совсем выкинул из программы. Вообще ассемблерные вставки в Си это перманентное зло. Если вам нужно что-то особенное, оптимизированные под свои задачи, то используйте отдельные законченные функции, полностью написанные на ассемблере. О том, как правильно писать такие функции и о правилах передачи аргументов в/из asm-функций из/в Си-функции, описано в документации. А вставлять отдельные ассемблерные команды посреди Си-шного исходника бросьте сразу, еще не начиная Ну и еще раз напомню про отличия типов переменных. Тип переменной влияет на ее размещение в памяти и область видимости. Переменные типа global (глобальная) и static (статическая) размещаются в памяти данных, т.е. под них выделяются ячейки памяти с постоянным адресом. Переменные типа auto (автоматическая или локальная) размещаются на стеке или в РОН (по усмотрению компилятора), но постоянного адреса в памяти они не имеют. Переменные типа register (регистровая) в принципе могут быть как глобальными (если объявлена вне функции с указанием конкретного регистра) так и локальными (объявлена без указания регистра внутри функции). Переменные типа register это тип данных с наиболее быстрым доступом. А для того, чтобы доступ к ним был быстрым, предполагается, что размещаться они должны в РОН. Но проблема состоит в том, что если заранее в опциях проекта для переменных типа register не зарезервировать конкретные регистры (в IAR EW430 возможно резервировать только R4 и R5), то компилятор обращается с ними очень вольно и в большинстве случаев пилюет на такую декларацию с высокой колокольни, трактуя локальные register как обычные переменные auto. Область видимости global - вся программа. Область видимости static - данный конкретный модуль или функция, если static объявлена внутри функции. Область видимости auto - функция или блок оператора в котором она объявлена.
|
|
|
|
|
Nov 12 2013, 09:33
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 12 2013, 09:02)  Хочется подробнее узнать про функции, написанные полностью на ассемблере. Как я полагаю в этих функциях для переменных можно будет использовать любые РОН, а не только R4 и R5. Подскажите ссылку на документацию (если возможно - на русском языке). IAR поддерживает сборку проекта, состоящего из C/C++ и ассеблерных файлов/модулей, различая их по расширению. Книжек о том, как програмировать на этих языках для MSP430, можно легко надыбать в интернете, но мой совет будет простой: написать на языке C функцию, нуждающуюся в переложении на ассемблер, в отдельном файле, откомпилировать проект с установкой, чтобы выдавало ассемблерный листинг. После чего редактируешь листинг по своему вкусу, использя те регистры, какие хочется, а затем подменяешь в проекте второй файл на асемблерный. Я, кстати, сама так МК-шному ассемблеру училась - книг не читала, а писала по образу и подобию того, как компилятор компилирует сишные образцы. Правда, к этому времени я на других ассемблерах уже умела программировать - это, видимо, тоже помогало. А из книг было достаточно таблицы инструкций и IAR-ского руководства EW430_AssemblerReference.pdf Думаю, что самая большая тут трудность не в том, чтобы на ассемблеру выучиться, а в том, чтобы соблюсти условности, позволяющие линкеру связывать объектные модули от двух разных языков. Т.к. проблема чаще возникает в том, что на ассемблере порой приходится искать доступ к глобальным переменным и массивам, определенным в сишной части проекта.
|
|
|
|
|
Nov 12 2013, 10:01
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(Xenia @ Nov 12 2013, 13:33)  ...написать на языке C функцию, нуждающуюся в переложении на ассемблер, в отдельном файле, откомпилировать проект с установкой, чтобы выдавало ассемблерный листинг. После чего редактируешь листинг по своему вкусу, используя те регистры, какие хочется, а затем подменяешь в проекте второй файл на ассемблерный. Если Вас не затруднит, можете сделать пошаговое описание выше сказанного? Просто я в IAR совсем новичок. Ранее программировал только на C++Builder. Например, на С написать функцию, которая принимает 2 параметра и возвращает сумму квадратов этих параметров. Как потом реализацию этой функции вывести в ассемблерный листинг?
|
|
|
|
|
Nov 13 2013, 10:53
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(d7d1cd @ Nov 13 2013, 14:19)  Скажите, что я не так делаю? Видимо, что-то не так  А что за ошибка? Я в ассемблере не слишком шарился, обычно си хватало. Есть пара проектов, но сейчас времени нет искать. Может, как-нибудь эту функцию надо глобально расшарить директивами? Типа паблик или что-то в этом роде РТФМ, там много интересного
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Nov 14 2013, 15:20
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(d7d1cd @ Nov 14 2013, 12:48)  Сделал я проект. Прикладываю его сюда. В этом проекте я получаю ассемблерный листинг, который потом не компилируется. Люди добрые, посмотрите, подскажите... В мнемонике ассемблера MSP430 нет команды ERROR. Она вставляется в листинг видимо как раз специально с той целью, чтобы этот asm потом не компилировали Я не знаю ни C++, ни как вставлять в проект для С++ ASM-функции. Специально только для этого курить документацию IAR мне лениво  Но вот мой вариант вашего проекта без каких-либо "плюсов", pure C т.с. Функция DivisionOnTwo вырезана из вашего листинга и оформлена как законченная самостоятельная ASM-функция, которая вызывается из Си-шного модуля. Проект компилируется без ошибок и даже работает (в симуляторе). Обратите внимание, что прототип функции DivisionOnTwo описан с квалификатором external.
|
|
|
|
|
Nov 14 2013, 17:28
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Спасибо всем за помощь! Наконец то я победил компилятор. Как мне подсказал rezident, необходимо функцию, которую надо переложить на ассемблер, написать в проекте на С (но не на С++). Тогда получается пригодный для компиляции ассемблерный листинг. Его я правлю как мне необходимо и добавляю к проекту на С++. Прототип функции, которая находится в ассемблере, необходимо объявить с квалификатором extern "C". Почитав руководство к компилятору, я узнал, что при передаче в функцию параметров, всегда используются конкретные регистры, так же, как и при возврате функциями каких-либо значений.
Сообщение отредактировал d7d1cd - Nov 15 2013, 07:49
|
|
|
|
|
Nov 17 2013, 09:56
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
И снова здравствуйте. Теперь я умею в одном проекте использовать код на С++ и на ассемблере. Но вот возник вопрос... У меня в проекте 3 функции, написанные на С++. Все они не принимают параметров и не возвращают их (работают с глобальными переменными). Вызываются они одна за другой. Настроив линкер, я указал, что функции у меня расположены в определенной области памяти. В отладчике я вижу, что мои функции расположились в указанной мной области памяти в таком же порядке, как происходит их вызов. Далее я самую первую функцию пишу на ассемблере, так же указав сегмент расположения этой функции. Порядок вызова функций я не меняю, однако после всего этого я вижу, что функция, написанная на ассемблере, расположилась в памяти после функций, написанных на С++ (хотя вызывается первая). Подскажите, почему эта функция на С++ была первая в памяти, а на ассемблере стала последней? И еще: конечно это не особо критично, но подскажите, возможно ли указать линкеру не только расположение функций, но и порядок их размещения в памяти?
|
|
|
|
|
Nov 17 2013, 10:47
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 17 2013, 13:56)  Подскажите, почему эта функция на С++ была первая в памяти, а на ассемблере стала последней? И еще: конечно это не особо критично, но подскажите, возможно ли указать линкеру не только расположение функций, но и порядок их размещения в памяти? У IAR компиляторы языка С/С++ и языка ассемблера раздельные! В вашем случае это icc430.exe и a430.exe. Поэтому сишные функции окажутся откомпилированными в одном объектном модуле, а ассемблерные функции в другом. А дальше все зависит от того, в каком порядке их соберет линкер. Видимо у него make такой, что первыми в очереди на сборку идут сишные модули, а ассемблерные за ними. Впрочем, попробуйте переставить порядок следования сишного и ассемблерного модулей в проекте. Если это у вас получится, то, вероятно, и порядок следования функций тоже изменится. P.S. А не все ли вам равно, в каком порядке функции следуют внутри сегмента кода? Зарекаться на этот порядок в проектах, в общем-то, неприлично.
|
|
|
|
|
Nov 17 2013, 11:08
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(Xenia @ Nov 17 2013, 14:47)  У IAR компиляторы языка С/С++ и языка ассемблера раздельные! В вашем случае это icc430.exe и a430.exe. Поэтому сишные функции окажутся откомпилированными в одном объектном модуле, а ассемблерные функции в другом. А дальше все зависит от того, в каком порядке их соберет линкер. Видимо у него make такой, что первыми в очереди на сборку идут сишные модули, а ассемблерные за ними.
Впрочем, попробуйте переставить порядок следования сишного и ассемблерного модулей в проекте. Если это у вас получится, то, вероятно, и порядок следования функций тоже изменится.
P.S. А не все ли вам равно, в каком порядке функции следуют внутри сегмента кода? Зарекаться на этот порядок в проектах, в общем-то, неприлично. Ну во поводу постскриптума: мне все равно, по сути... А поменяв порядок следования в Workspace, все получилось! Спасибо за совет. Пока делал это, обнаружил следующую проблему. В функции на С++, для которой указано конкретное расположение, используется операция деления. Из отладчика я увидел, что операция деления - это тоже функция. И ее линкер размещает не в моем сегменте. Как сделать так, чтобы было в моем?
|
|
|
|
|
Nov 17 2013, 12:01
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 17 2013, 15:08)  Пока делал это, обнаружил следующую проблему. В функции на С++, для которой указано конкретное расположение, используется операция деления. Из отладчика я увидел, что операция деления - это тоже функция. И ее линкер размещает не в моем сегменте. Как сделать так, чтобы было в моем? Функция деления выбирается из библиотеки. Компилятор ее не компилирует, т.к. библиотека уже находится в скомпилированном виде. А, значит, и сегмент у той функции такой, в каком компилировалась библиотека. И если сегменты вашего кода и библиотеки называются по разному, то и функциям никак не быть вместе. В тех же случаях, когда библиотечная функция обособлена (не вызывает в своем теле других библиотечных функций), то вы можете взять ее код из сорцов библиотеки и присоединить к своему коду. Тогда она откомпилируется вместе с вашим кодом и окажется вашем сегменте. А по правилам линковки библиотека линкуется последней, а потому к коду будет пришит вами скомпилированный экземпляр, а не библиотечный.
|
|
|
|
|
Nov 17 2013, 12:49
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(Xenia @ Nov 17 2013, 16:01)  ...вы можете взять ее код из сорцов библиотеки и присоединить к своему коду. Тогда она откомпилируется вместе с вашим кодом и окажется вашем сегменте. А по правилам линковки библиотека линкуется последней, а потому к коду будет пришит вами скомпилированный экземпляр, а не библиотечный. Как же мне это сделать (взять код из сорцов библиотеки), если, как Вы сказали, библиотека уже скомпилирована? Можно попросить привести примерчик?
|
|
|
|
|
Nov 17 2013, 13:13
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 17 2013, 16:49)  Как же мне это сделать (взять код из сорцов библиотеки), если, как Вы сказали, библиотека уже скомпилирована? Можно попросить привести примерчик? Если у вас полная версия, то исходники библиотек она тоже должна включать. Лежат тут: \IAR Systems\Embedded Workbench X.x\430\src\lib\ Только сам компиятор в эти исходники не лазает, а пользуется уже скомпилированным вариантом под конкретно ваш МК: \IAR Systems\Embedded Workbench X.x\430\lib\
|
|
|
|
|
Nov 22 2013, 07:29
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
И снова здравствуйте. Подскажите, пожалуйста, как в одном заголовочном файле объявить константы и для модуля С++ и для модуля на ассемблере? Пытался разместить в таком файле следующие константы: Код #define VAR (0x0200) __no_init volatile int Variable @ VAR; Если такой заголовочный файл добавить в модуль на С++, то компиляция ошибок не вызывает. А вот в модуле на ассемблере происходит ругань на вторую строку. Стандартные заголовочные файлы при их инклуде к модулю на любом языке при компиляции ошибок не создают. Я так же хочу сделать свой модуль...
|
|
|
|
|
Nov 22 2013, 11:23
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 22 2013, 11:29)  Подскажите, пожалуйста, как в одном заголовочном файле объявить константы и для модуля С++ и для модуля на ассемблере? Пытался разместить в таком файле следующие константы: Код #define VAR (0x0200) __no_init volatile int Variable @ VAR; Если такой заголовочный файл добавить в модуль на С++, то компиляция ошибок не вызывает. А вот в модуле на ассемблере происходит ругань на вторую строку. Стандартные заголовочные файлы при их инклуде к модулю на любом языке при компиляции ошибок не создают. Я так же хочу сделать свой модуль... Стандартные заголовочные файлы только потому "интернациональны", что содержат в себе условную компиляцию: Код #ifdef __IAR_SYSTEMS_ICC__ для C/C++ компилятора #endif
#ifndef __IAR_SYSTEMS_ASM__ для ассемблера #endif Тогда как определения констант через #define оба компилятора понимают одинаково хорошо (через один и тот же препроцессор текст проходит). Отсюда и рекомендация: определять общие константы через #define в начале хидера, а если приходится что-то добавлять специфическое, отчего у одного из компиляторов возникает несварение желудка, то ставите это под условие __IAR_SYSTEMS_ICC__или __IAR_SYSTEMS_ASM__. Поэтому ваш пример будет выглядеть как-то так: Код #define VAR 0x0200 #ifdef __IAR_SYSTEMS_ICC__ __no_init volatile int Variable @ VAR; #endif Тогда оба компилятора получат одинаковые знания про константу VAR, но ассемблер не увидит сишную строку, которая его станет раздражать.
|
|
|
|
|
Nov 23 2013, 18:01
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 23 2013, 20:53)  Спасибо. Есть еще вопрос по расположению кода. Есть 2 функции. Мне необходимо чтобы точки входа в эти функции располагались строго по определенным адресам (например, точка входа в первую функцию по адресу 0xFC60, во вторую - по адресу 0xFC64). Возможно ли такое? За чем дело стало? Повторите снова тот же приём. Вы же уже раньше определяли сегмент -Z(CODE)BOOT=F002-F0FF и у вас всё получилось. Так определите теперь две таких штуки. С разными именами сегментов, конечно. Вот только если точки входа так близко расположены: 0xFC60 и 0xFC64, вы врядли запихаете первую из функций в 4 байта. Следовательно у вас там есть место только для jmp-перехода. На C такого кода не написать, а на ассемблере - вполне. Напишите на ассемблере два джампа и вставьте пустые байты данных между ними, если это потребуется, чтобы второй джамп пришелся на 0xFC64. Тогда это будет всего один сегмент. Опять же на ассемблере гораздо проще расположить код в требуемых местах памяти. Тем не менее, сдается мне, что вы собираетесь таким вычурным способом писать таблицу прерываний для загрузочного режима  . И если моя догадка верна, то всего этого делать не надо. А надо создать другой проект под бутовую часть, т.е. писать загрузчик в чистом виде, так чтобы и таблица прерываний, и кодовый сегмент были в верхней памяти. А уж потом объедините нижнюю часть кода (от проекта приложения) и верхнюю часть кода (от проекта загрузчика) на уровне нех-прошивки или бинарного кода.
|
|
|
|
|
Nov 24 2013, 07:04
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Я пытался свою задачу выполнить следующим образом. В проекте на С++ в файле main я создал 2 функции. Для этих функций я задал сегмент расположения, который начинался с адреса 0xFC60. В телах этих функций я вызываю по 1 функции, которые содержат нужный рабочий код, и больше ничего. Сами эти функции я по порядку вызываю в функции main(). Выглядит это так: Код // Сегмент CODEPLACE начинается с адреса 0xFC60
#pragma location = "CODEPLACE" void _Function1() { Function1(); // Часть рабочего кода расположена в этой функции }
#pragma location = "CODEPLACE" void _Function2() { Function2(); // Часть рабочего кода расположена в этой функции }
int main() { _Function1(); // У этой функции адрес вызова всегда должен быть 0xFC60 _Function2(); // У этой функции адрес вызова всегда должен быть 0xFC64 } Все задуманное работает... но только в конфигурации Debug. В конфигурации Release линкер располагает мои функции _Function1() и _Function2() не в начале сегмента CODEPLACE, а в конце. Соответственно, при изменении рабочего кода, адреса этих функций меняются. Может как то можно решить эту проблему?
|
|
|
|
|
Dec 28 2013, 15:06
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Привет всем. Снова вопрос по среде программирования. Есть проект на ассемблере. В проекте 2 файла. Один главный, второй с функциями (умножение, деление и т. д.). Оба файла добавлены в проект. Из первого файла функции второго видно посредством PUBLIC и EXTERN-ов.
Теперь вопрос. Во втором файле много функций, но в первом файле используется, например, одна. Однако при компиляции проекта, в исполняемый файл попадают все функции из 2 файла (хотя, повторюсь, используется только одна). Возможно ли сделать так, чтобы в конечный файл прошивки компилировались только используемые функции?
|
|
|
|
|
Jan 1 2014, 13:25
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Разобрался в своем вопросе. Необходимо перед объявлением функции указать сегмент и флаг NOROOT: Код RSEG CODE:NOROOT
|
|
|
|
|
Jan 6 2014, 13:29
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Уже устал биться с линкером. Помогите... У меня в проекте на ассемблере 2 файла (1 и 2). В 1 основные функции программы, во 2 так сказать рутинные функции (умножение, деление и прочее). Функции из файла 2 вызываются в 1 файле посредством директив PUBLIC и EXTERN. XCL-файл я использую свой. Его содержимое, состоящее из одной строки, такое: Код -Z(CODE)CODE=FC60-FFDF,9668-97EB // Весь мой код должен быть в этих диапазонах адресов Перед каждой функцией в файлах 1 и 2 я указываю сегмент размещения. Делаю это вот так (на примере функции умножения): Код RSEG CODE:NOROOT:REORDER:SORT Mul16u16uTo32u: DINT NOP MOV R12, &MPY MOV R13, &OP2 MOV &RESLO, R12 MOV &RESHI, R13 EINT RET Все было хорошо, пока мой код был мал. Линкер его размещал начиная с адреса FC60. Я думал, что когда закончится место в диапазоне FC60-FFDF, то линкер начнет размещать код в диапазоне 9668-97EB. Однако этого не произошло. Когда размер скомпилированного кода стал превышать размер диапазона FC60-FFDF, то линкер выдал мне ошибку: Цитата Linking Error[e16]: Segment CODE (size: 0x384 align: 0x1) is too long for segment definition. At least 0x4 more bytes needed. The problem occurred while processing the segment placement command "-Z(CODE)CODE=FC60-FFDF,9668-97EB", where at the moment of placement the available memory ranges were "CODE:fc60-ffdf,CODE:9668-97eb" Reserved ranges relevant to this placement: 9668-97eb CODE fc60-ffdf CODE Error while running Linker Total number of errors: 1 Total number of warnings: 0 Я попробовал изменить порядок диапазонов адресов в XCL-файле. Однако это не помогло. Линкер выдает ту же ошибку. Что самое интересное, после изменения порядка адресов в XCL-файле, я убрал некоторые строки кода (чтобы "все стало помещаться"). После компиляции ошибки не стало, однако линкер все равно размещает код в диапазоне FC60-FFDF, хотя в XCL-файле этот диапазон прописан после диапазона 9668-97EB. Подскажите, что за напасть и как с ней бороться...  P.S. Для информации: CODE NOROOT, ROOT NOROOT means that the segment part is discarded by the linker if no symbols in this segment part are referred to. Normally, all segment parts except startup code and interrupt vectors should set this flag. The default mode is ROOT which indicates that the segment part must not be discarded.
REORDER, NOREORDER REORDER allows the linker to reorder segment parts. For a given segment, all segment parts must specify the same state for this flag. The default mode is NOREORDER which indicates that the segment parts must remain in order.
SORT, NOSORT SORT means that the linker sorts the segment parts in decreasing alignment order. For a given segment, all segment parts must specify the same state for this flag. The default mode is NOSORT which indicates that the segment parts are not sorted.
Сообщение отредактировал d7d1cd - Jan 6 2014, 13:35
|
|
|
|
|
Jan 6 2014, 14:59
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(rezident @ Jan 6 2014, 17:52)  Приложите в сообщению весь ваш XCL-файл полностью. Приложил...
|
|
|
|
|
Jan 6 2014, 15:46
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(SM @ Jan 6 2014, 19:30)  Сделайте еще одну секцию с кодом, с другим именем, и вынесете в нее часть кода. На сколько я знаю, нельзя одну секцию разделить на два диапазона адресов, должно быть две разные секции. Я понимаю, что можно так сделать. Но ведь хочется эту работу возложить на линкер. Тем более было тут сообщение уважаемого rezidenta: Цитата Вам просто нужно для сегмента CODE указать несколько диапазонов адресов, перечислив их через запятую. Вот там я пояснял как правильно отредактировать XCL-файл.
|
|
|
|
|
Jan 6 2014, 16:57
|
Гуру
     
Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881

|
Цитата(d7d1cd @ Jan 6 2014, 19:46)  Я понимаю, что можно так сделать. Но ведь хочется эту работу возложить на линкер. Вообще, обычно линкеры не могут сами разбивать секцию на части, потому что не знают, как это корректно делать, в каком месте. Возможно, конечно, у IAR есть подсекции функций, или еще какие то механизмы для указания линкеру, как ему можно разбить секцию, но я этих механизмов в рамках IAR-а не знаю. В любом случае, требуются какие то директивы/указания, в каком месте секции можно разрывать - линкер сам этого не знает, и поэтому ругается.
|
|
|
|
|
Jan 6 2014, 17:16
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(SM @ Jan 6 2014, 20:57)  Вообще, обычно линкеры не могут сами разбивать секцию на части, потому что не знают, как это корректно делать, в каком месте. Возможно, конечно, у IAR есть подсекции функций, или еще какие то механизмы для указания линкеру, как ему можно разбить секцию, но я этих механизмов в рамках IAR-а не знаю. В любом случае, требуются какие то директивы/указания, в каком месте секции можно разрывать - линкер сам этого не знает, и поэтому ругается. Тогда для чего придуманы флаги для директивы RSEG (REORDER, SORT)? Про NOROOT знаю для чего: если данный код не используется, то линкер не вставляет его в готовую прошивку.
|
|
|
|
|
Jan 6 2014, 19:17
|
Гуру
     
Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881

|
Цитата(d7d1cd @ Jan 6 2014, 21:16)  Тогда для чего придуманы флаги для директивы RSEG (REORDER, SORT)? Про NOROOT знаю для чего: если данный код не используется, то линкер не вставляет его в готовую прошивку. Я так подозреваю, что все это касается частей одной секции, располагающейся в разных объектных модулях - потому что куски одноименной секции точно можно перемешивать в порядке размещения, если они были скомпилированы из разных отдельных исходных файлов. Но именно подозреваю. Да и NOROOT тоже - о неиспользуемости кода линкер может судить только по одному принципу - что в модуле нет ни точки входа, и ни одного использованного PUBLIC-символа. Но, именно, в секции модуля, которая внутри каждого модуля едина. PS повторюсь, я не слышал, чтобы у IAR был механизм подсекций для процедур/функций - именно поэтому, вроде, на сколько я помню, секция внутри каждого модуля едина (для того и придумана, чтобы код/данные можно было прерывать, перемежать, в т.ч. в макросах, а потом все стало едиными цельными и гарантировано последовательными кусками), а вот куски секции, собираемые из разных модулей, линкер может менять местами, сортировать, выкидывать, и т.д.
|
|
|
|
|
Feb 27 2014, 16:09
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(rezident @ Feb 27 2014, 19:38)  Сделать что "это"? Переменные вы и так обязаны объявлять в своей программе. Я пишу на ассемблере. Чтобы разместить код функции по определенному адресу, я пишу: Код RSEG MySegment Mul16u16uTo32u: ... RET А в файле XCL или в опциях линкера и прописываю: Код -Z(CODE)MySegment=1200-1300 Так вот: нельзя ли обойтись без файла XCL и опций линкера и описание сегмента расположить в файле, где расположен код функции.
|
|
|
|
|
Feb 27 2014, 16:56
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(_Артём_ @ Feb 27 2014, 20:54)  Может и можно - посмотрите в документации есть ли у IAR директива ASEG или аналогичная. ASEG есть. И ASEGN есть. Какую директиву использовать? Не особо я силен в англицком. Подскажите в чем отличие этих директив друг от друга и от директивы RSEG? Вот их описание в документации: CODE Beginning an absolute segment Use ASEG to set the absolute mode of assembly, which is the default at the beginning of a module. If the parameter is omitted, the start address of the first segment is 0, and subsequent segments continue after the last address of the previous segment. Note: If a move of an immediate value to an absolute address, for example mov #0x1234, 0x300 is made in a relocatable or absolute segment, the offset is calculated as if the code begun at address 0x0000. The assembler does not take into account the placement of the segment.
Beginning a named absolute segment Use ASEGN to start a named absolute segment located at the address address. This directive has the advantage of allowing you to specify the memory type of the segment.
Beginning a relocatable segment Use RSEG to start a new segment. The assembler maintains separate location counters (initially set to zero) for all segments, which makes it possible to switch segments and mode anytime without having to save the current program location counter. Up to 65536 unique, relocatable segments can be defined in a single module.
Beginning a common segment Use COMMON to place data in memory at the same location as COMMON segments from other modules that have the same name. In other words, all COMMON segments of the same name start at the same location in memory and overlay each other. Obviously, the COMMON segment type should not be used for overlaid executable code. A typical application would be when you want several different routines to share a reusable, common area of memory for data. It can be practical to have the interrupt vector table in a COMMON segment, thereby allowing access from several routines. The final size of the COMMON segment is determined by the size of largest occurrence of this segment. The location in memory is determined by the XLINK -Z command; see the IAR Linker and Library Tools Reference Guide. Use the align parameter in any of the above directives to align the segment start address.
Сообщение отредактировал d7d1cd - Feb 27 2014, 17:28
|
|
|
|
|
Feb 27 2014, 17:23
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(d7d1cd @ Feb 27 2014, 20:56)  ASEG есть точно. Как ей правильно пользоваться? Ну вы спросили - вы же msp программируете, у меня и компилятора под них нет. В AVR так(для примера): Код ASEG INTVEC ORG 0h Для msp наверное что-то похожее, подробнее смотрите в Assembler Reference. P.S. Cо скриптом как-то правильнее...
|
|
|
|
|
Feb 28 2014, 13:39
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Вроде разобрался как использовать директиву ASEG: Код ASEG 0x1240; Указываю для функции Proc адрес начала 0х1240 Proc: CLR R12 CALL #Proc2 MOV R14, R12 RET Все вроде хорошо, но в XCL файле я мог указать диапазон адресов для сегмента. А здесь так видимо нельзя сделать. Или я не прав? P.S. Со скриптом - это с использованием XCL файла и директивы RSEG?
Сообщение отредактировал d7d1cd - Feb 28 2014, 13:40
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|