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

 
 
> Странное поведение JMP
Student2
сообщение Oct 30 2009, 12:53
Сообщение #1


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

Группа: Участник
Сообщений: 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?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 14)
Student2
сообщение Oct 30 2009, 13:00
Сообщение #2


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

Группа: Участник
Сообщений: 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.
Go to the top of the page
 
+Quote Post
=GM=
сообщение Oct 30 2009, 13:10
Сообщение #3


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Может так?

GOTO desiredAddress;

и сишный эквивалент конструкции
.ORG 0x0200
desiredAddress:


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 30 2009, 14:17
Сообщение #4


Гуру
******

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



Код
extern void Application();
__C_task void main(void)
{
    ....
        Application();
    ....
}
Линкеру объявить символ Application равный 0x200 - в командной строке или скрипте дописать -DApplication=200


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 30 2009, 14:23
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Student2, если вы изобретаете бутлоадер с проверкой на валидность прикладной задачи, то сообщаю по секрету, что бутлоадер пишется и компилируется отдельно от нее и управление бутлоадеру передается еще ДО вызова main в функции типа __low_level_init или как-то похоже. Почитайте документацию на компилятор.
Go to the top of the page
 
+Quote Post
Student2
сообщение Oct 30 2009, 14:45
Сообщение #6


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

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Oct 30 2009, 16:32
Сообщение #7


неотягощённый злом
******

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



Цитата(Сергей Борщ @ Oct 30 2009, 17:17) *
[code]extern void Application();
....
Линкеру объявить символ Application равный 0x200 - в командной строке или скрипте дописать -DApplication=200
Сергей, можете объяснить почему так происходит? Т.е. почему в этом случае генрится jmp а не icall. Спасибо!


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Oct 30 2009, 16:44
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(demiurg_spb @ Oct 30 2009, 19:32) *
Сергей, можете объяснить почему так происходит? Т.е. почему в этом случае генрится jmp а не icall. Спасибо!

А что тут загадочного? В первом случае компилятор предусматривает возврат, во втором - нет, т.к. вызов стоит в самом конце main. Т.е. "jump xxx" используется как более оптимальный аналог "call xxx; ret".
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 30 2009, 17:30
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Oct 30 2009, 20:15
Сообщение #10


неотягощённый злом
******

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



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


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
SysRq
сообщение Oct 30 2009, 20:28
Сообщение #11


Чайник, 1 литр
****

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



Если пишу (WinAVR):
Код
__attribute__((noreturn)) void testing_workmode(void)
{
}
То вызов транслируется в:
Код
rcall    .-1268  ; 0x130a4 <testing_workmode>

Где я ошибаюсь, почему тоже call? unsure.gif
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Oct 30 2009, 20:36
Сообщение #12


фанат дивана
******

Группа: Свой
Сообщений: 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.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Student2
сообщение Nov 3 2009, 09:43
Сообщение #13


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

Группа: Участник
Сообщений: 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;
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 3 2009, 11:38
Сообщение #14


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
defunct
сообщение Nov 4 2009, 00:10
Сообщение #15


кекс
******

Группа: Свой
Сообщений: 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();
}
Go to the top of the page
 
+Quote Post

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

 


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


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