- •Глава 1. Сведения о компиляторе
- •1.1.Введение
- •1.2. Основные вопросы
- •1.3. Описание компилятора и документация
- •1.4. Компилятор и другие средства разработки
- •1.5. Набор возможностей компилятора
- •1.5.1. Стандарт ANSI Си
- •1.5.2. Оптимизация
- •1.5.3. Поддержка стандартной ANSI библиотеки
- •1.5.4. Гибкие модели памяти
- •1.5.5. Драйвер компилятора
- •Глава 2. Отличия 16-битового компилятора от ANSI
- •2.1. Введение
- •2.2. Основные вопросы
- •2.3. Отличия ключевых слов
- •2.3.1. Определение атрибутов переменных
- •2.3.2. Определение атрибутов функций
- •2.3.3. Inline функции
- •2.3.4. Переменные в определенных регистрах
- •2.3.4.1. Определение глобальных регистровых переменных
- •2.3.4.2. Определение локальных регистровых переменных
- •2.3.5. Комплексные числа
- •2.3.6. Целые размером в двойное слово
- •2.3.7. Ссылки на тип с помощью typeof
- •2.4. Отличия операторов
- •2.4.1. Метки как значения
- •2.4.2. Условные операторы с опущенными операндами
- •2.4.3. Диапазоны case
- •2.5. Отличия выражений
- •2.5.1. Двоичные константы
- •Глава 3. Использование компилятора в командной строке
- •3.1. Введение
- •3.2. Основные вопросы
- •3.3. Обзор
- •3.4. Соглашение для имен файлов
- •3.5. Опции
- •3.5.1. Опции, специфические для устройств dsPIC
- •3.5.2. Опции для управления типом результатов
- •3.5.3. Опции для управления диалектом Cи
- •3.5.5. Опции для отладки
- •3.5.6. Опции для управления оптимизацией
- •3.5.7. Опции для управления препроцессором
- •3.5.8. Опции для ассемблера
- •3.5.9. Опции для компоновщика
- •3.5.10. Опции для поиска в каталогах
- •3.5.11. Опции для соглашений по генерации кода
- •3.6. Переменные окружения
- •3.7. Предопределенные имена макро
- •3.9. Компиляция нескольких файлов в командной строке
- •3.10. Особенные символы
- •Глава 4. Среда периода исполнения
- •4.1. Введение
- •4.2. Основные вопросы
- •4.3. Адресное пространство
- •4.4. Запуск и инициализация
- •4.5. Пространства памяти
- •4.6. Модели памяти
- •4.6.1. Ближние и дальние данные
- •4.6.2. Ближний и дальний код
- •4.7. Расположение кода и данных
- •4.8. Программный стек
- •4.9. Использование стека в Си
- •4.11. Соглашения по вызову функций
- •4.11.1. Параметры функции
- •4.11.2. Возвращаемое значение
- •4.12. Соглашения о регистрах
- •4.13. Двоичная инверсия и модульная адресация
- •4.14.1. Загрузочные и защищенные константы
- •4.14.2. Строковые константы как аргументы
- •4.14.3. Переменные с квалификатором const в безопасной Flash
- •4.14.4. Модель совместимости объектов
- •Глава 5. Типы данных
- •5.1. Введение
- •5.2. Основные вопросы
- •5.3. Представление данных
- •5.4. Целые
- •5.5. С плавающей точкой
- •5.6. Указатели
- •Глава 6. Дополнительные типы указателей Си
- •6.1. Введение
- •6.2. Управляющие PSV указатели
- •6.2.1. Определение данных для управления доступом PSV
- •6.2.2. Управляемый доступ PSV
- •6.2.3. Рассмотрение ISR
- •6.3. PMP указатели
- •6.3.1. Инициализация PMP
- •6.3.2. Объявление нового пространства памяти
- •6.3.3. Определение переменных в пространстве PMP
- •6.4. Внешние указатели
- •6.4.1. Объявление нового пространства памяти
- •6.4.2. Определение переменных во внешнем пространстве
- •6.4.3. Определение способа доступа к пространству памяти
- •6.4.3.2. Функции записи
- •6.4.4. Пример внешней памяти
- •Глава 7. Файлы поддержки устройства
- •7.1. Введение
- •7.2. Основные вопросы
- •7.3. Файлы заголовков процессора
- •7.4. Файлы определения регистров
- •7.5. Использование SFR
- •7.6. Использование макросов
- •7.6.1. Макросы настройки битов конфигурации
- •7.6.2. Макросы использования ассемблера inline
- •7.6.3. Макросы выделения памяти данных
- •7.6.4. Макросы объявления ISR
- •7.7. Адресация EEDATA из Си - только для dsPIC30F
- •7.7.1. Доступ к EEDATA через PSV
- •7.7.2. Доступ к EEDATA посредством команд TBLRDx
- •7.7.3. Дополнительные источники информации
- •Глава 8. Прерывания
- •8.1. Введение
- •8.2. Основные вопросы
- •8.3. Написание программы обработки прерывания
- •8.3.1. Рекомендации по написанию ISR
- •8.3.3. Кодирование ISR
- •8.3.4. Использование макросов для объявления простых ISR
- •8.4. Запись вектора прерывания
- •8.4.1. Вектора прерываний dsPIC30F (без SMPS)
- •8.4.3. Вектора прерываний PIC24F
- •8.4.4. Вектора прерываний dsPIC33F/PIC24H
- •8.5. Сохранение контекста в ISR
- •8.7. Вложенные прерывания
- •8.8. Разрешение/запрещение прерываний
- •8.9. Разделение памяти между основной программой и ISR
- •8.9.1. Разработка проблем
- •8.9.2. Разработка решений
- •8.9.3. Пример приложения
- •8.10. Использование PSV в ISR
- •Глава 9. Совместное использование ассемблера и Си
- •9.1. Введение
- •9.2. Основные вопросы
- •9.3. Смесь переменных и функций на ассемблере и Си
- •9.4. Использование ассемблера inline
- •Приложение A. Определяемое реализацией поведение
- •A.12. Квалификаторы
- •A.13. Деклараторы
- •A.14. Операторы
- •A.17. Сигналы
- •A.18. Потоки и файлы
- •A.20. Errno
- •A.22. Abort
- •A.23. Exit
- •A.24. Getenv
- •A.25. Система
- •A.26. Strerror
- •Приложение B. Встроенные функции
- •B.2. Список встроенных функций
- •Приложение C. Диагностика
- •Приложение D. Компиляторы Си PIC18 и PIC24/dsPIC
- •D.6. Использование стека
- •D.11. Банк доступа
- •D.12. Inline ассемблер
- •D.13. Прагмы
- •D.14. Модели памяти
- •D.15. Соглашения о вызове
- •D.16. Код запуска
- •D.17. Управляемые компилятором ресурсы
- •D.18. Оптимизация
- •D.20. Определяемое реализацией поведение
- •D.21. Битовые поля
Глава 4. Среда периода исполнения
больше. Если известно, что все функции в приложении — ближние, то для компиляции каждого модуля может быть использована опция командной строки по умолчанию -msmall-code, чтобы заставить компилятор генерировать более эффективную форму вызова функции.
Если эта опция по умолчанию неприемлема, доступны следующие альтернативы.
1. Возможно компилировать отдельные модули приложения с опцией командной строки -msmall-code. В этом случае вызовы функций только в таких модулях будут использовать более эффективную форму.
2. Если использована опция -msmall-code, компилятор можно заставить |
|
|
. |
использовать длинную форму вызова функции для отдельных функций, снабдив |
|
их атрибутом far. |
A |
|
3. Вместо применения опций командной строки, воздействующих на модуль
Опция командной строки -msmall-c de отличается от опции -msmall-data тем, что в первом случае компилятор не делает ничего особенного, чтобы проверить, расположены ли функции близко или далеко, тогда как в последнем случае компилятор разместит переменные в заданных секциях.
Компоновщик выдаст сообщение об ошибке, если функция, объявленная ближней, не может быть доступна одному из своих вызовов, использующему более эффективную форму.
целиком, можно заставить компилятор использовать более эффективную форму вызова, снабдив их объявленияWilsonи определения атрибутом near.
4.7.Расположение кода и данных
.text, а данные в ряд именованных секций, в зависимости от используемой модели
Как описано в п. 4.3. «Адресноеby пространство», компилятор помещает код в секцию
памяти и необходимости инициализации данных. Когда модули соединяются на этапеTranslatedкомпоновки, компоновщик определяет стартовые адреса различных секций на основании их атрибутов.
Отклонения могут появиться, когда некоторая функция или переменная должны располагаться по определенному адресу либо внутри заданного диапазона адресов. Наиболее простой путь достичь этого состоит в использовании атрибута address, описанного в п.2.3. «Отличия ключевых слов». Например, чтобы поместить функцию PrintString в адрес 0x8000 программной памяти:
int attribute ((address(0x8000))) PrintString(const char *s);
Аналогично, чтобы поместить переменную Mabonga в адрес 0x1000 памяти данных: int attribute ((address(0x1000))) Mabonga = 1;
Другой способ конкретного расположения кода или данных заключается в помещении функции или переменой в определенную пользователем секцию, и задании адреса этой секции в пользовательском сценарии компоновки. Это делается так:
1.Чтобы ввести определенную пользователем секцию, изменяется декларация кода или данных в исходном коде Си.
2.Чтобы определить начальный адрес пользовательской секции, вносятся соответствующие добавления в пользовательский сценарий компоновки.
Например, чтобы поместить функцию PrintString в адрес 0x8000 программной памяти сначала объявим ее соответствующим образом в исходном Си коде:
int __attribute__ ((__section__(“.myTextSection“))) PrintString(const char *s);
Атрибут секции определяет, что функция должна быть помещена в секцию с именем
.myTextSection, а не в секцию по умолчанию .text. Он не задает, где определенная пользователем секция будет располагаться. Это надо сделать в
© 2008 Microchip Technology Inc. |
DS51284H(ru) стр. 4-5 |
16-битовый компилятор Си. Руководство
пользовательском сценарии компоновки, как описано ниже. Беря за основу специфический для данного устройства сценарий компоновки, добавляем следующее определение секции:
.myTextSection 0x8000 :
{
|
*(.myTextSection); |
|
|
||
|
} >program |
|
|
|
|
|
Этим задается, что выходной файл должен содержать секцию с именем |
||||
|
.myTextSection, со стартовым адресом 0x8000 и содержащую все входные |
||||
|
секции с именем .myTextSection. Поскольку в данном примере есть только одна |
||||
|
функция PrintString в такой секции, она и расположится по адресу 0x8000 |
||||
|
программной памяти. |
|
|
A |
. |
|
|
|
|
||
|
Точно также, для размещения переменной |
|
|||
|
Mabonda в адресе 0x1000 памяти |
||||
|
данных, первым делом объявим переменную в исходном коде Си как: |
||||
|
int __attribute__((__section(“.myDataSection”))) Mabonda = 1; |
||||
|
Атрибут секции определяет, что переменная должна быть помещена в секцию с |
||||
|
именем .myDataSection, а не в секцию по умолчанию .data. Он не задает, где |
||||
|
определенная пользователем секция будет располагаться. Снова это надо сделать |
||||
|
в пользовательском сценарии компоновки, как описано ниже. Беря за основу |
||||
|
специфический для данного устройства сценарий компоновки, добавляем |
||||
|
следующее определение секции: |
|
|
||
|
.myDataSection 0x1000 : |
Wilson |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
*(.myDataSection); |
|
|
||
|
} >data |
by |
|
|
|
|
|
|
|
|
|
|
Этим задается, что выходной файл должен содержать секцию с именем |
||||
|
.myDataSection, со стартовым адресом 0x1000 и содержащую все входные |
||||
|
секции с именем .myDataSection. Поскольку в данном примере есть только одна |
||||
|
переменная Mabonda в такой секции, она и расположится по адресу 0x1000 памяти |
||||
|
данных. |
|
|
|
|
4.8. |
Программный стек |
|
|
|
|
|
В устройствах dsPIC регистр W15 выделяется для использования в качестве |
||||
|
программного указателя стека. Все операции процессора со стеком, включая вызов |
||||
|
функций, прерывания и исключения, используют программный стек. Стек растет |
||||
|
вверх, в сторону увеличения адресов памяти. |
|
|
||
|
Translated |
|
|
|
|
Устройства dsPIC также поддерживают определение переполнения стека. Если регистр предельного значения указателя стека, SPLIM, инициализирован, устройство будет определять переполнение при любой операции со стеком. Если происходит переполнение, процессор инициирует исключение по ошибке стека. По умолчанию это вызывает сброс процессора. Приложение может установить свой обработчик исключительных ситуаций, определив функцию обработки прерывания с именем _StackError. Подробнее см. главу 8 «Прерывания».
Стартовый модуль периода исполнения Си инициализирует указатель стека (W15) и регистр предельного значения указателя стека во время последовательности запуска и инициализации. Начальные значения обычно задаются компоновщиком, который выделяет максимально возможный объем от неиспользованной памяти данных. Расположение стека сообщается в выходном файле карты компоновки. Приложения могут гарантировать, что по крайней мере минимальный стек будет доступен, с помощью опции командной строки компоновщика --stack. Подробнее см. «MPLAB® Assembler, Linker and Utilities for PIC24 MCUs and dsPIC® DSCs User’s Guide» (DS51317).
DS51284H(ru) стр. 4-6 |
© 2008 Microchip Technology Inc. |
Глава 4. Среда периода исполнения
С другой стороны, стек заданного размера может быть выделен с помощью определенной пользователем секции в нестандартном сценарии компоновки. Для использования стартовым модулем периода исполнения определяются два символа: __SP_init и __SPLIM_init:
.stack : |
|
{ |
|
__SP_init = .; |
|
. += 0x100; |
|
__SPLIM_init = .; |
. |
. += 8; |
|
} >data |
|
__SP_init определяет начальную величинуA |
для указателя стека (W15), а |
Wilson |
|
__SPLIM_init определяет начальную величину для регистра предельного значения указателя стека (SPLIM). Величина SPLIM_init должна быть по крайней мере на 8 байтов ниже, чем физический предел стека, чтобы оставить место обработчику исключения по переполнению стека. Эта величина должна быть еще уменьшена, чтобы учитывать использование стека собственно обработчиком прерываний, если обработчик исключительной ситуации по ошибке стека установлен. Обработчик прерываний по умолчанию не требует дополнительного объема стека.
4.9.Использование стека в Си
Компилятор Си использует стек для: |
|
• |
by |
• |
Размещения автоматических переменных |
• Передачи аргументов функциям
•W15Translated— это указатель стека (SP). Он указывает на вершину стека, которая определяется как первый свободный адрес в стеке.
•W14 — это указатель фрейма (FP). Он указывает на текущий фрейм функции. Каждая функция, если требуется, создает новый фрейм на вершине стека, в котором располагаются автоматические и временные переменные. Опция
командной строки компилятора -fomit-frame-pointer может быть использована для ограничения использования FP.Сохранения состояния процессора в функциях обработки прерываний управленияРИС. 4-1. УКАЗАТЕЛИ СТЕКА И ФРЕЙМА
Стек растет |
|
|
|
SP (W15) |
|
|
|
||
в сторону |
|
|
|
|
|
|
|
|
|
увеличения |
Фрейм |
|
|
FP (W14) |
адреса |
|
|
||
функции |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Стартовые модули Си периода исполнения (crt0.o и crt1.o из libpic30.a) инициализируют указатель стека W15, устанавливая его на дно стека, и регистр указатель границы стека, устанавливая его на вершину стека. Стек растет вверх, и,
© 2008 Microchip Technology Inc. |
DS51284H(ru) стр. 4-7 |
16-битовый компилятор Си. Руководство
если он превышает значение указателя границы стека, происходит прерывание по ошибке стека.
Следующий рисунок иллюстрирует последовательность событий при вызове функции. Выполнение команд CALL или RCALL заносит адрес возврата в программный стек. См. рис. 4-2.
РИС. 4-2. КОМАНДЫ CALL ИЛИ RCALL
|
|
|
A |
. |
|
|
SP (W15) |
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
Адр.возвр.[23:16] |
|
|
|
|
|
|
|
Адр.возвр.[15:0] |
|
|
|
|
|
|
|
Wilson |
|
|
|
|
|
Стек растет |
|
Параметр 1 |
|
|
|
|
|
в сторону |
|
... |
|
|
|
|
|
увеличения |
|
Параметр n-1 |
|
|
|
|
|
адреса |
|
Параметр n |
|
|
|
|
|
|
|
Фрейм |
|
|
|
|
FP (W14) |
|
|
вызывающей |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
функции |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Теперь вызываемая функция может выделить пространство для своего локального |
|||||||
контекста (рис. 4-3) |
by |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
РИС. 4-3. РАСПРЕДЕЛЕНИЕ СТЕКА ВЫЗЫВАЕМОЙ ФУНКЦИЕЙ |
|||||||
|
|
|
|
|
|
|
|
Translated |
|
|
|
|
|
SP (W15) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Локальные и |
|
|
|
FP (W14) |
|
|
|
временные |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
переменные |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Предыдущий FP |
|
|
|
|
|
|
|
Адр.возвр.[23:16] |
|
|
|
|
|
|
|
Адр.возвр.[15:0] |
|
|
|
|
|
Стек растет |
|
Параметр 1 |
|
|
|
|
|
... |
|
|
|
|
|
||
в сторону |
|
|
|
|
|
||
увеличения |
|
Параметр n-1 |
|
|
|
|
|
адреса |
|
Параметр n |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Фрейм |
|
|
|
|
|
|
|
вызывающей |
|
|
|
|
|
|
|
функции |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DS51284H(ru) стр. 4-8 |
© 2008 Microchip Technology Inc. |
Глава 4. Среда периода исполнения
Наконец, в стек убираются используемые вызываемой функцией регистры (рис. 4-4)
РИС. 4-4. СОХРАНЕНИЕ РЕГИСТРОВ ВЫЗЫВАЕМОЙ ФУНКЦИЕЙ
|
|
|
|
Сохр. вызыва- |
|
|
|
|
|
SP (W15) |
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
[W14+n] доступ |
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
емой функцией |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
к локальному |
|
|
|
|
|
|
регистры |
|
|
|
|
|
|
|
|
|
|
|
|
. |
|
|
|
контексту |
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
Локальные и |
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
A |
|
|
|
FP (W14) |
|
||
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
временные |
|
|
|
|
|
||
|
|
|
|
|
|
|
|
[W14–n] доступ |
|
||
|
Стек растет |
|
|
переменные |
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||||
|
в сторону |
|
|
|
|
|
|
|
к параметрам |
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
Предыдущий FP |
|
|
|
|
|
|
|
|
увеличения |
|
|
Wilson |
|
|
|
|
|
функции в стеке |
|
|
|
|
Адр.возвр.[23:16] |
|
|
|
|
|
|||
|
адреса |
|
|
|
|
|
|
|
|
||
|
|
|
Адр.возвр.[15:0] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Параметр 1 |
|
|
|
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
|
Параметр n-1 |
|
|
|
|
|
|
|
|
|
|
|
Параметр n |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Фрейм |
|
|
|
|
|
|
|
|
|
|
|
вызывающей |
|
|
|
|
|
|
|
|
|
Сиby |
|
функции |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4.10. Использование хипа в |
|
|
|
|
|
|
|
|
|
||
долженTranslatedбыть создан. Если единственным используемым файлом является stdout, |
|||||||||||
Хип периода исполнения в Си — это неинициализированная область памяти данных, |
|||||||||||
которая используется для динамического выделения памяти с помощью функций |
|||||||||||
управления память из стандартных библиотек Си: calloc, malloc и realloc. Если |
|||||||||||
вы не используете эти функции, вам не потребуется выделять хип. По умолчанию хип |
|||||||||||
не создается. |
|
|
|
|
|
|
|
|
|
Если Вы хотите использовать динамическое выделение памяти непосредственно, вызывая одну из функций распределения памяти, или косвенно, используя функции ввода/вывода из стандартных библиотек Си, то хип должен быть создан. Чтобы создать хип, надо определить его размера в командной строке компоновщика с помощью опции --heap. Ниже приведен пример выделения 512 байтов для хипа с помощью командной строки:
pic30-gcc foo.c -Wl,--heap=512
Компоновщик располагает хип непосредственно под стеком.
Если вы используете функции ввода/вывода из стандартных библиотек Си, то хип то размер хипа может быть нулевым, т. е. используйте опцию командной строки:
-Wl,--heap=0
Если вы открываете файлы, тогда размер хипа должен включать 40 байтов для каждого одновременно открытого файла. При нехватке памяти хипа функция open будет возвращать признак ошибки. Для каждого файла, использующего буфер, требуется 514 байтов в пространстве хипа. При нехватке памяти хипа для буфера, файл будет открыт в небуферизованном режиме.
© 2008 Microchip Technology Inc. |
DS51284H(ru) стр. 4-9 |