реклама на сайте
подробности

 
 
> Как портабельно получить DDRx через PORTx?, Или игры с SFR-ами на IAR
osnwt
сообщение Mar 2 2006, 10:12
Сообщение #1


Частый гость
**

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



При портировании AVR-USB драйвера с GCC на IAR вылезла небольшая проблема с точки зрения эффективности кода. Автор оригинала использует следующие конструкции, которые нормально проходят в GCC:

Код
#define USB_CFG_IOPORT          PORTD
...
#define USBIN       (*(&USB_CFG_IOPORT - 2))    /* input port for USB bits */
#define USBDDR      (*(&USB_CFG_IOPORT - 1))    /* data direction for USB bits */


Под IAR это все транслируется, но превращается вот в такой вот кошмар:

Код
// USBDDR |= 0x10;
// USB_CFG_IOPORT |= 0x10;
        IN R16, 0x11
        ORI R16, 0x10
        OUT 0x11, R16

        SBI 0x12, 0x04


То есть, непосредственное обращение к регистру использует SBI, а обращение к указанной конструкции - последовательность команд, не считая определение константным выражением.

Перепробовал несколько идей - не помогло. Изменить определение самого порта с PORTx на просто x с последующей конкатенацией префиксов с именем порта не подходит, так как автор ориентируется в первую очередь на GCC и едва ли согласится радикально менять код, конфигурируемый пользователем.

Для себя-то я могу выйти из положения. Но работая совместно с Кристианом над официальным портом для IAR, хотелось предложить что-то более-менее портабельное без ухода от выбранного им способа определения портов.

Нет у кого идей? Подходит вариант с условной компиляцией (то есть, для именно IAR можно использовать тут __io и тому подобные специфические конструкции). Важно лишь, чтобы раскрывались они в конечном итоге в SBI, а не чтение-модификацию-запись покомандно.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 9)
andrvisht
сообщение Mar 3 2006, 11:30
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064



Цитата(osnwt @ Mar 2 2006, 14:12) *
Нет у кого идей? Подходит вариант с условной компиляцией (то есть, для именно IAR можно использовать тут __io и тому подобные специфические конструкции). Важно лишь, чтобы раскрывались они в конечном итоге в SBI, а не чтение-модификацию-запись покомандно.

Идея впринципе одна, ASM.
Причина такого кода заключена в том что сам порт обьявлен как __io а это означает что порт обьявляется как volatile
Сделано это для того чтобы при оптимизации его (порт) не выкинули. А поскольку он может измениться неведомо компилятору то он его перед изменением и вычитывает. Вот такая вот причина....
А для того чтобы было SBI CBI используй
PORTD_Bit0 = 1; // SBI
PORTD_Bit0 = 0; // CBI
и вкл Enable Bit Difinitions в Genera/ System
Go to the top of the page
 
+Quote Post
osnwt
сообщение Mar 3 2006, 12:02
Сообщение #3


Частый гость
**

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



Цитата(&-rey @ Mar 3 2006, 13:30) *
Идея впринципе одна, ASM.

Идеи не понял - при чем тут ASM? unsure.gif

Цитата
Причина такого кода заключена в том что сам порт обьявлен как __io а это означает что порт обьявляется как volatile

Осмелюсь напомнить, что и PORTD объявлен точно также.

Цитата
А поскольку он может измениться неведомо компилятору то он его перед изменением и вычитывает.

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

Цитата
А для того чтобы было SBI CBI используй
PORTD_Bit0 = 1; // SBI
PORTD_Bit0 = 0; // CBI
и вкл Enable Bit Difinitions в Genera/ System

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

Тем более, что для заданного вопроса эта конструкция неприменима в принципе. Я ведь спрашивал не про замену (PORTD |= 0x10) - это как раз транслируется оптимально в sbi без всяких PORTD_Bit4 = 1 (IAR достаточно разумен для такой оптимизации). А про замену для (*(&PORTD-1) |= 0x10) как эквивалента (DDRD |= 0x10). Это к вопросу об исходной постановке задачи wink.gif.

(Расшифровка: PORTD для IAR - это переменная с модификатором __io, находящаяся по фиксированному адресу (порта), являющемуся тем самым адресом этой переменной. Операция получения адреса &PORTD дает нам этот самый адрес. Вычитая из него единицу, получаем адрес DDRD. А далее используем *(адрес DDRD) для работы, собственно, с самим значением. Все формально правильно, но IAR не воспринимает полученное значение как константное выражение адреса __io порта. Добавление всяких модификаторов типа const или __io с разными приведениями типа мне не помогло. Возможно, я не всё попробовал. В этом и состоял исходный вопрос, а не в том, как избавиться от чтения-модификации-записи - где IAR считает нужным, он это делает и сам. А вот как ему помочь в данном случае?).

PS. Почему-то, когда задаются банальные вопросы типа "как объявить переменную по фиксированному адресу", сразу же следует море правильных и не очень ответов. Стоит спросить что-то менее тривиальное - и полная тишина. Почти полная, в данном случае, так как одна попытка ответить все же была (хоть и не на тот вопрос) unsure.gif.

PPS. Не считая мелких нюансов, связанных с оптимизацией C-кода под gcc-avr, и не столь эффективную компиляцию под IAR, официальный порт avr-usb для IAR, можно сказать, уже готов. Еще пара мелких штришков по документации, и он может появиться на официальной странице проекта.

Сообщение отредактировал osnwt - Mar 3 2006, 12:07
Go to the top of the page
 
+Quote Post
andrvisht
сообщение Mar 3 2006, 13:08
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064



Цитата(osnwt @ Mar 3 2006, 16:02) *
Идеи не понял - при чем тут ASM? unsure.gif

Возможно я не совсем понял вопроса. sad.gif
Попробую изложить как я понял ...
конструкция типа
Код
(PORTD |= 0x10)
- это транслируется оптимально
А
Код
(*(&PORTD-1) |= 0x10)
как эквивалента
Код
(DDRD |= 0x10)
приводит к выше упомянутому коду....
Теперь если я врубился попробую снова smile.gif
когда мы пишем PORTD то компилятор точно знает что от него требуется и генерит то чего мы ждем от него.
например если написать
Код
(PORTD |= 0x30)

то это уже разложится на
Код
    000096   B302             IN      R16,PORTD
    000098   6300             ORI     R16,0x30
    00009A   BB02             OUT     PORTD,R16

когда (&PORTD-1) то он знает лишь то что PORTD у нас __io (volatile) и более ничего, поэтому поступает с ним соответственно.
собственно поэтому я и предложил решать это ASM вставкой, хотя я тоже не в восторге от такого подхода sad.gif
хотя если мотреть на то что он знает что мы обращаемся к DDRD
Код
  *(&PORTD - 1) |= 0x10;
    00009C   B301             IN      R16,DDRD
    00009E   6100             ORI     R16,0x10
    0000A0   BB01             OUT     DDRD,R16

согласен что компилятор мог бы и подумать sad.gif(((
Go to the top of the page
 
+Quote Post
osnwt
сообщение Mar 3 2006, 13:36
Сообщение #5


Частый гость
**

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



Действительно, вопрос понят не совсем правильно.

Цитата
когда мы пишем PORTD то компилятор точно знает что от него требуется и генерит то чего мы ждем от него.
например если написать
Код
(PORTD |= 0x30)

то это уже разложится на
Код
    000096   B302             IN      R16,PORTD
    000098   6300             ORI     R16,0x30
    00009A   BB02             OUT     PORTD,R16

Когда мы пишем (PORTD |= 0x30), то компилятору в любом случае не остается ничего, кроме как представить это тремя командами (можно двумя, но это уже нюансы).

В данном случае везде используется вариант с установкой строго одного бита: (PORTD |= 0x10). И если PORTD - это стандартное определение порта, то будет sbi. Если вместо PORTD использовано стандартное определение DDRD, то тоже будет sbi. Но вот если использовано (применимое только к AVR) тайное знание того, что адрес DDRD = адрес PORTD-1, то как ни напиши - компилятор упорно не хочет использовать sbi, что приводит к замене одной команды тремя. Учитывая то, что это повторяется в коде несколько раз, мы заметно проигрываем в размере.

Вопрос состоял в том, как корректно получить экивалент стандартного определения порта DDRD, зная лишь базовый порт PORTD. Притом, так, чтобы компилятор понимал, что этот эквивалент - это точно такое же определение, как и его штатное, и работал с ним соответственно. Естественно, что всё это - константные выражения, адрес порта не меняется в run-time. От того и обидно, что мне пока не удалось этого сделать sad.gif

Цитата
когда (&PORTD-1) то он знает лишь то что PORTD у нас __io (volatile) и более ничего, поэтому поступает с ним соответственно.

А, вот что имелось в виду... Понятно. Фокус тут в том, можно ли каким-либо путем убедить компилятор, что (&PORTD-1), хоть это и адрес volatile переменной, но сам он является const-антой. А дальше - что это - константный адрес __io переменной, которая сама по себе volatile, но такие ведь все порты. Возможно, какими-то приведениями типов и можно это сделать, но я пока не преуспел.

Цитата
собственно поэтому я и предложил решать это ASM вставкой, хотя я тоже не в восторге от такого подхода sad.gif

Автор avr-usb - тем более. Он не склонен делать слишком много явно бросающихся в глаза модификаций текста для коммерческого компилятора, так как проект ориентирован (и сильно) на gcc-avr, и сильно под него оптимизирован без ассемблерных вставок. Заменить, скажем, __io(x) на пустую конструкцию для компиляции под gcc он согласится, а вот делать множество условных #if - нет, если в принципе проект собирается (а он собирается и работает). Но вопросы оптимизации формы представления - это уже вторично. Мне бы хоть под IAR понять, как выкрутиться из положения.

PS. После некоторого раздумья становится понятно, в чем может быть проблема (но не как ее решать). Ведь макро типа DDRD определяются через структуру, размещаемую по некоему фиксированному адресу в сегменте __io (образно говоря). В целом может быть так, что знание этого адреса во время трансляции штатных структур компилятору недоступно, а закладывается в информацию для линкера, который лишь на стадии линковки может прописать туда реальное значение, а также его же -1 - в те места, где на него ссылаются. Если так, то сделать более корректно и унифицированно не получится в принципе sad.gif

Так что желающим оптимизировать и это придется заняться hand job (ручной работой по коверканью исходников, а не тем, что часто под этим подразумевают wink.gif )

Сообщение отредактировал osnwt - Mar 3 2006, 13:42
Go to the top of the page
 
+Quote Post
_Bill
сообщение May 23 2006, 11:59
Сообщение #6


Местный
***

Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219



Цитата(osnwt @ Mar 2 2006, 13:12) *
Нет у кого идей? Подходит вариант с условной компиляцией (то есть, для именно IAR можно использовать тут __io и тому подобные специфические конструкции). Важно лишь, чтобы раскрывались они в конечном итоге в SBI, а не чтение-модификацию-запись покомандно.

Если gcc не умеет работать с портами, то я бы ввел условную трансляцию. Тем более, что наверняка есть еще отличия, не только при обращении к портам. Например, процедуры обработки прерываний по-разному описываются.
Go to the top of the page
 
+Quote Post
Guest_Гость_*
сообщение May 23 2006, 12:13
Сообщение #7





Guests






Цитата(_Bill @ May 23 2006, 14:59) *
Если gcc не умеет работать с портами, то я бы ввел условную трансляцию. Тем более, что наверняка есть еще отличия, не только при обращении к портам. Например, процедуры обработки прерываний по-разному описываются.

Вопрос был только по этому месту - остальные давно решены. Условная трансляция тут не поможет, так как вопрос в том, как полупортабельно получить адрес соседнего порта при том. что адреса SFR-ов - это вообще в принципе непортабельная штука с точки зрения C.

Используемая конструкция работает в обоих компиляторах. Проблема только в том, что у IAR получается избыточность в 2 байта кода. За малостью названного автор не стал что-то придумывать, так как основной прицел был GCC, а IAR - постольку-поскольку.
Go to the top of the page
 
+Quote Post
_Bill
сообщение May 23 2006, 13:04
Сообщение #8


Местный
***

Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219



Цитата(Гость @ May 23 2006, 15:13) *
Вопрос был только по этому месту - остальные давно решены. Условная трансляция тут не поможет, так как вопрос в том, как полупортабельно получить адрес соседнего порта при том. что адреса SFR-ов - это вообще в принципе непортабельная штука с точки зрения C.

Используемая конструкция работает в обоих компиляторах. Проблема только в том, что у IAR получается избыточность в 2 байта кода. За малостью названного автор не стал что-то придумывать, так как основной прицел был GCC, а IAR - постольку-поскольку.

Что значит "соседний порт"? Насколько необходима здесь эффективность? И вообще, переносимость и эффективность часто являются противоречивыми требованиями, и выбирать приходится что-то одно.
Go to the top of the page
 
+Quote Post
_Sam_
сообщение Oct 24 2006, 08:29
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 278
Регистрация: 18-01-05
Из: Санкт-Петербург
Пользователь №: 2 031



Мне тоже пришлось столкнутся с похожей проблемой и вот что я выяснил.

IAR не поддерживает указатели в __io области и по идее должен ругаться на такие финты... Однако этого не происходит.

В документации также сказано что
Цитата
An assignment to a bitfield always generates a write access, in
some cases also a read access. If only one bit is updated—set
or cleared—the sci/cbi instructions are executed.

Но это относится только к
Цитата
__io declared variables located in 0x–0x1F

указатели не являются located variable с точки зрения компилятора поэтому до уровня sci/cbi они и не оптимизируются!

Т.к. для операции разыменования указателя спецификаторы памяти в том числе и __io неприменимы, то данная задача в случае с IAR решения не имеет.
Go to the top of the page
 
+Quote Post
_Sam_
сообщение Oct 25 2006, 08:14
Сообщение #10


Местный
***

Группа: Свой
Сообщений: 278
Регистрация: 18-01-05
Из: Санкт-Петербург
Пользователь №: 2 031



Нарыл ещё кое-что интересное. Вам это наверное не очень поможет, потому что надо включать EC++, но может кому интересно будет.
Цитата
It is allowed to have a reference to a memory type as a template parameter, even if
pointers to that memory type are not allowed.

попробовал, с шаблонами действительно работает! т.е. в листинге появились команды sbi/cli вместо чтение-модификация-запись!
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 02:35
Рейтинг@Mail.ru


Страница сгенерированна за 0.01425 секунд с 7
ELECTRONIX ©2004-2016