|
Странное поведение JMP |
|
|
|
Oct 30 2009, 12:53
|

Частый гость
 
Группа: Участник
Сообщений: 83
Регистрация: 4-08-09
Из: Болгария / София
Пользователь №: 51 737

|
Мне надо было сделать JMP к адресу 0200. Код такой: Код /*---------------------------------------------------------------------------*/ __C_task void main(void) /* the main code is here */ /*---------------------------------------------------------------------------*/ { Initialize();
if (testCode == 0) /* bad code */ { ((void (*)())0x200)(); /* jump to the fixed address (!!!! USES ICALL!!!!)*/ }
if (busReceiveByte() == seq1) {
if (busReceiveByte() == seq2) { loader(); } }
((void (*)())0x200)(); /*(!!!! USES IJMP!!!!) */
} Но на дизассемблере находил что первый JMP \"сделан\" из ICALL а второй из IJMP, что то вроде: Код LDI R30, 0x00 LDI R31, 0x02 ICALL
LDI R30, 0x00 LDI R31, 0x02 IJMP Мне хотелось как нибудь чтобы компилятор поставил RJMP и не мучил меня с IJMP. Конечно я совсем не согласен когда он огорчил меня с ICALL. Слово goto точно подходить для меня но как установить этикет по адресу 0x200?
|
|
|
|
|
 |
Ответов
(1 - 14)
|
Oct 30 2009, 13:00
|

Частый гость
 
Группа: Участник
Сообщений: 83
Регистрация: 4-08-09
Из: Болгария / София
Пользователь №: 51 737

|
Мне надо было сделать JMP к адресу 0200. Код такой: Код /*---------------------------------------------------------------------------*/ __C_task void main(void) /* the main code is here */ /*---------------------------------------------------------------------------*/ { Initialize();
if (testCode == 0) /* bad code */ { ((void (*)())0x200)(); /* jump to the fixed address (!!!! USES ICALL!!!!)*/ }
if (busReceiveByte() == seq1) {
if (busReceiveByte() == seq2) { loader(); } }
((void (*)())0x200)(); /*(!!!! USES IJMP!!!!) */
} Но на дизассемблере находил что первый JMP \"сделан\" из ICALL а второй из IJMP, что то вроде: Код LDI R30, 0x00 LDI R31, 0x02 ICALL
LDI R30, 0x00 LDI R31, 0x02 IJMP Мне хотелось как нибудь чтобы компилятор поставил RJMP и не мучил меня с IJMP. Конечно я совсем не согласен когда он огорчил меня с ICALL. Слово goto точно подходить для меня но как установить этикет по адресу 0x200? Камень - Tiny88.
|
|
|
|
|
Oct 30 2009, 14:45
|

Частый гость
 
Группа: Участник
Сообщений: 83
Регистрация: 4-08-09
Из: Болгария / София
Пользователь №: 51 737

|
Цитата(Сергей Борщ @ Oct 30 2009, 16:17)  Код extern void Application(); __C_task void main(void) { .... Application(); .... } Линкеру объявить символ Application равный 0x200 - в командной строке или скрипте дописать -DApplication=200 Спасибо Сергей,! Сейчас вижу RJMP и все работает как надо. Видно что у вас большой опыт в программирование!
Сообщение отредактировал Student2 - Oct 30 2009, 14:47
|
|
|
|
|
Oct 30 2009, 17:30
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(demiurg_spb @ Oct 30 2009, 19:32)  Сергей, можете объяснить почему так происходит? Т.е. почему в этом случае генрится jmp а не icall. Я не знаю, почему ИАР генерит ICALL для перехода по фиксированному адресу, заданному константой. Это очевидная недоработка и вопрос к его создателям. RJMP тоже сюрприз для меня, объянение aaarrr вполне правдоподобно. Обычно компилятор всталяет ®CALL, мы ведь описали Application() как обычную функцию.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 30 2009, 20:15
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(Сергей Борщ @ Oct 30 2009, 20:30)  Я не знаю, почему ИАР генерит ICALL для перехода по фиксированному адресу, заданному константой. Это очевидная недоработка и вопрос к его создателям. Если я правильно помню, то avr-gcc ведёт себя так же. Цитата RJMP тоже сюрприз для меня, объяснение aaarrr вполне правдоподобно. Обычно компилятор вставляет ®CALL, мы ведь описали Application() как обычную функцию. Вот и я сильно удивился. Хорошо когда среди нас много догадливых сотоварищей:-)
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Oct 30 2009, 20:28
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

|
Если пишу (WinAVR): Код __attribute__((noreturn)) void testing_workmode(void) { } То вызов транслируется в: Код rcall .-1268 ; 0x130a4 <testing_workmode> Где я ошибаюсь, почему тоже call?
|
|
|
|
|
Oct 30 2009, 20:36
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Потому что (имхо) noreturn влияет на формирование пролога и эпилога функции (убирает сохранение используемых регистров), и не влияет на способ вызова этой функции. Она может быть вообще в другом модуле, и вызывающая функция понятия не имеет, что вызываемая - noreturn. Для проверки напишите Код __attribute__((noreturn)) void f2(void) { for (;;); } __attribute__((noreturn)) void f1(void) { f2(); } И получите warning на f1, что типа noreturn-функция похоже делает return.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Nov 3 2009, 09:43
|

Частый гость
 
Группа: Участник
Сообщений: 83
Регистрация: 4-08-09
Из: Болгария / София
Пользователь №: 51 737

|
Программа сейчас работает, но возникла вот такая проблема поддержки и структурной чистотой - адрес установлен в линкере и он не виден из компилятора. Если хочу использовать то же значение 0200 для установки других параметров мне надо заново установит в файле параметр (например #define SIZE_AREA 0x200). Поддержка кода усложнена и возможность сделать ошибки больше потому что надо менять данные на 2 места . Я попробовал Код #define SIZE_AREA 0x200 ..... ((void (*)())SIZE_AREA)(); Все работает прекрасно но нахожу в дизассемблере Код LDI R30, 00 LDI R31, 02 IJMP В итоге 4 байта больше! Подскажите как вернут добрый RJMP на месте и вместе с тем установить адрес SIZE_AREA внутри С файла - т.е. был доступен внутри С файла для дополнительные операции как __root __flash uint16_t MARKER @ (SIZE_AREA-2) = 0x434C;
|
|
|
|
|
Nov 3 2009, 11:38
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Student2 @ Nov 3 2009, 12:43)  Программа сейчас работает, но возникла вот такая проблема поддержки и структурной чистотой - адрес установлен в линкере и он не виден из компилятора. Почему? Преркрасно виден. Вы же получали адрес функции Application(). Вы можете этот адрес привести к любому нужному типу: Код extern void Application(); __C_task void main(void) { .... Application(); uint16_t Size_Area = (uint16_t)Application; .... } Цитата(Student2 @ Nov 3 2009, 12:43)  __root __flash uint16_t MARKER @ (SIZE_AREA-2) = 0x434C; Вам надо в скрипте линкера создать новый сегмент для этих данных и заставить линкер правильно расположить его: Код -DApplication=200 -Z(CODE)MARKER_seg#0-(Application-1) Код #pragma segment = "MARKER_seg" #pragma location = "MARKER_seg" __root __flash uint16_t MARKER = 0x434C; примерно так.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Nov 4 2009, 00:10
|

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

|
Цитата(Student2 @ Oct 30 2009, 14:53)  Мне надо было сделать JMP к адресу 0200. Код такой: asm( "jmp 0x200"); - поймет любой компилятор AVR. Альтернативно можно определить макрос, который при переносе с платформы на платформу можно легко изменять: #define GoToApplication() asm("jmp 0x200") main { ... GoToApplication(); }
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|