Перейти к содержанию

    

Проблема с условием

Поскольку было объяснение, что писалось на конкурс уложить код в 1К, то допустимы и приветствуются любые извращения. Классические принципы здесь не нужны.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Про CPU с различными подходами в копировании char не знал, спасибо. Интересно конечно, как это может так быть - ведь копируются 8 бит все равно...

Загляните как-нить в листинг Cortex-M3/4 кода и сравните команды LDRB и LDRSB например. Поймёте почему.

Для этого имхо и ввели дополнительный чекбокс в IAR "signed/unsigned char".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Загляните как-нить в листинг Cortex-M3/4 кода и сравните команды LDRB и LDRSB например. Поймёте почему.

Для этого имхо и ввели дополнительный чекбокс в IAR "signed/unsigned char".

Сходу не получилось заставить компилятор сгенерировать LDRSB...

Использую armcc в составе Keil. Оптимизация 0. Галка "Plain Char is Signed" сброшена.

Код

volatile signed char a = 10;
volatile signed char b = 20;
volatile signed char c;

int main(void)
{
    c = a - b;
    
    while(1);
}

формирует следующий листинг

0x080002E0 4805      LDR           r0,[pc,#20]
0x080002E2 7800      LDRB          r0,[r0,#0x00]; загрузили a
0x080002E4 4905      LDR           r1,[pc,#20]
0x080002E6 7809      LDRB          r1,[r1,#0x00]; загрузили b
0x080002E8 1A40      SUBS          r0,r0,r1     ; вычли
0x080002EA B240      SXTB          r0,r0        ; ИМХО, лишнее, т.к. SUBS работает 32-битными числами
0x080002EC 4904      LDR           r1,[pc,#16]
0x080002EE 7008      STRB          r0,[r1,#0x00]; загружаем результат в переменную c

В случае, если переменные объявить без спецификатора signed (то есть с unsigned) то листинг тот же самый, но без SXTB

 

С оптимизацией -O3 для signed/unsigned листинг одинаковый:

0x0800028C 4803      LDR           r0,[pc,#12]
0x0800028E 7801      LDRB          r1,[r0,#0x00]
0x08000290 7842      LDRB          r2,[r0,#0x01]
0x08000292 1A89      SUBS          r1,r1,r2
0x08000294 7081      STRB          r1,[r0,#0x02]

Изменено пользователем Arlleex

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Сходу не получилось заставить компилятор сгенерировать LDRSB...

Использую armcc в составе Keil. Оптимизация 0. Галка "Plain Char is Signed" сброшена.

Всего лишь оптимизация умного компилятора :rolleyes:

Вы сами подумайте: раз Вы результат обратно сокращаете до 8 бит, то зачем тогда старшие биты вычислять? А если их вычислять не нужно, то можно ограничиться командами LDRB как более "дешёвыми". :laughing:

Тест Ваш построен некорректно. Для корректности теста сделайте int volatile c. Тогда, думаю, увидите LDRSB.

Ну и для теста можно одно из a или b сделать отрицательным.

 

0x080002EA B240 SXTB r0,r0 ; ИМХО, лишнее, т.к. SUBS работает 32-битными числами

Хоть это и лишнее, но это был намёк компилятора, что он заметил достаточность использования 8-бит для результата и поэтому не стал заморачиваться с правильным расширением входных аргументов. :rolleyes:

 

PS: Код теста не совсем корректный, так как должен вызвать warning "undefined behavior".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Тест Ваш построен некорректно. Для корректности теста сделайте int volatile c. Тогда, думаю, увидите LDRSB.

Точно! И вправду LDRB заменились на LDRSB... Просто с расширением знака. Все четко по описанию команды загрузки с расширением знака :rolleyes:

Единственное, что отмечу. Разницы в количестве тактов выполнения не заметно... То есть по факту выполняются они одинаково по времени, только лишь представление числа в памяти нужным образом расширяется или нет, вот и вся разница, вроде как.

 

PS: Код теста не совсем корректный, так как должен вызвать warning "undefined behavior".

Из-за int перед main() и отсутствия возвращаемого результата? Тогда не неопределенное поведение, а что-то типа "недостижимый участок кода" и "отсутствие возвращаемого значения в функции, которая возвращает int"... Но Keil не паникует, кстати... :laughing:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Единственное, что отмечу. Разницы в количестве тактов выполнения не заметно... То есть по факту выполняются они одинаково по времени, только лишь представление числа в памяти нужным образом расширяется или нет, вот и вся разница, вроде как.

Конечно разницы в тактах нет при условии наличия команды в кеше/конвеере CPU. Но в реальном МК команду ещё нужно выбрать из памяти, а ширина шины к памяти программ не бесконечна, как и скорость последней.

Так что по времени выполнения - Вы не правы.

 

Из-за int перед main() и отсутствия возвращаемого результата?

Нет. Из-за того, что в одном выражении используются две volatile-переменные. Порядок чтения которых внутри выражения неопределён. А volatile подразумевает строгость в порядке доступа.

 

Но Keil не паникует, кстати... :laughing:

А зря. IAR реагирует на подобные выражения: "undefined behavior".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Конечно разницы в тактах нет при условии наличия команды в кеше/конвеере CPU. Но в реальном МК команду ещё нужно выбрать из памяти, а ширина шины к памяти программ не бесконечна, как и скорость последней.

Так что по времени выполнения - Вы не правы.

Открыл TRM на Cortex-M3. Вижу, что CPI на LDRB и на LDRSB одинаковы и составляют 2 такта. Одинакова и их синтаксическая запись. Существуют как 16-битные, так и 32-битные версии обеих команд. При всех прочих равных условиях время выполнения LDRB и LDRSB одинаково.

То, что команду нужно выбрать из памяти - это понятно. Но LDRB нужно выбрать точно так же, как и LDRSB в одном и том же коде. Ничем не отличается.

Другое дело, если мы говорим о том, что загружать значение как оно есть и лишь потом программно еще расширять знак. Там да, несколько команд нужно: тот же LDRB + расширение знака, если требуется.

 

Нет. Из-за того, что в одном выражении используются две volatile-переменные. Порядок чтения которых внутри выражения неопределён. А volatile подразумевает строгость в порядке доступа.

Да, в упор не увидел очевидное... Жаль Keil не ругнулся никак даже при установке "All Warnings" в настройках компилятора :crying:

Изменено пользователем Arlleex

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Открыл TRM на Cortex-M3. Вижу, что CPI на LDRB и на LDRSB одинаковы и составляют 2 такта. Одинакова и их синтаксическая запись. Существуют как 16-битные, так и 32-битные версии обеих команд. При всех прочих равных условиях время выполнения LDRB и LDRSB одинаково.

А Вы когда-нибудь пробовали заглядывать в листинг? И сколько вы там видели LDRB разной длины и сколько LDRSB? :laughing:

Формы-то может и есть, тут вопрос в количестве....

Попробуйте в .asm-файле ввести 2 такие команды и скомпилить:

LDRB     R0, [R0, #0]
LDRSB     R0, [R0, #0]

А потом попробуйте поизменять регистры от R0 до R7 и посмотреть что получается.

А теперь загляните в листинги и увидите, что большинство обращений к памяти как раз подобные формы команд: косвенная с константным смещением.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
А Вы когда-нибудь пробовали заглядывать в листинг? И сколько вы там видели LDRB разной длины и сколько LDRSB? :laughing:

Формы-то может и есть, тут вопрос в количестве....

Мда, в листинге действительно LDRSB используются всегда 32-битные, очевиден проигрыш... Причем какие бы регистры не использовали - младшие или старшие - все равно берется команда Thumb-2 (32 бит). А вот LDRB, при использовании младших регистров в качестве операндов, компилируется в 16-битной Thumb форме; при использовании старших регистров - законно Thumb-2.

 

P.S. Почитал тут в мануале.

Если запись команды LDRSB использует форму с непосредственным смещением от базового регистра, то такая команда существует только 32-битная. Для LDRB такая команда есть в 16 битах, только там непосредственное значение ограничено 5 битами. Теперь все понятно!

 

jcxz, благодарю за полезную информацию :rolleyes:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Во времена настали: раздел про AVR, а тут про приготовление ARMов.

Изменено пользователем Obam

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Во времена настали: раздел про AVR, а тут про приготовление ARMов.

А что - AVR ещё жив? :rolleyes:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти