Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Странное поведение JMP
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Student2
Мне надо было сделать 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?
Student2
Мне надо было сделать 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.
=GM=
Может так?

GOTO desiredAddress;

и сишный эквивалент конструкции
.ORG 0x0200
desiredAddress:
Сергей Борщ
Код
extern void Application();
__C_task void main(void)
{
    ....
        Application();
    ....
}
Линкеру объявить символ Application равный 0x200 - в командной строке или скрипте дописать -DApplication=200
rezident
Student2, если вы изобретаете бутлоадер с проверкой на валидность прикладной задачи, то сообщаю по секрету, что бутлоадер пишется и компилируется отдельно от нее и управление бутлоадеру передается еще ДО вызова main в функции типа __low_level_init или как-то похоже. Почитайте документацию на компилятор.
Student2
Цитата(Сергей Борщ @ Oct 30 2009, 16:17) *
Код
extern void Application();
__C_task void main(void)
{
    ....
        Application();
    ....
}
Линкеру объявить символ Application равный 0x200 - в командной строке или скрипте дописать -DApplication=200


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

А что тут загадочного? В первом случае компилятор предусматривает возврат, во втором - нет, т.к. вызов стоит в самом конце main. Т.е. "jump xxx" используется как более оптимальный аналог "call xxx; ret".
Сергей Борщ
Цитата(demiurg_spb @ Oct 30 2009, 19:32) *
Сергей, можете объяснить почему так происходит? Т.е. почему в этом случае генрится jmp а не icall.
Я не знаю, почему ИАР генерит ICALL для перехода по фиксированному адресу, заданному константой. Это очевидная недоработка и вопрос к его создателям. RJMP тоже сюрприз для меня, объянение aaarrr вполне правдоподобно. Обычно компилятор всталяет ®CALL, мы ведь описали Application() как обычную функцию.
demiurg_spb
Цитата(Сергей Борщ @ Oct 30 2009, 20:30) *
Я не знаю, почему ИАР генерит ICALL для перехода по фиксированному адресу, заданному константой. Это очевидная недоработка и вопрос к его создателям.
Если я правильно помню, то avr-gcc ведёт себя так же.
Цитата
RJMP тоже сюрприз для меня, объяснение aaarrr вполне правдоподобно. Обычно компилятор вставляет ®CALL, мы ведь описали Application() как обычную функцию.
Вот и я сильно удивился. Хорошо когда среди нас много догадливых сотоварищей:-)
SysRq
Если пишу (WinAVR):
Код
__attribute__((noreturn)) void testing_workmode(void)
{
}
То вызов транслируется в:
Код
rcall    .-1268  ; 0x130a4 <testing_workmode>

Где я ошибаюсь, почему тоже call? unsure.gif
AHTOXA
Потому что (имхо) noreturn влияет на формирование пролога и эпилога функции (убирает сохранение используемых регистров), и не влияет на способ вызова этой функции. Она может быть вообще в другом модуле, и вызывающая функция понятия не имеет, что вызываемая - noreturn.
Для проверки напишите
Код
__attribute__((noreturn)) void f2(void)
{
    for (;;);
}
__attribute__((noreturn)) void f1(void)
{
     f2();
}

И получите warning на f1, что типа noreturn-функция похоже делает return.
Student2
Программа сейчас работает, но возникла вот такая проблема поддержки и структурной чистотой - адрес установлен в линкере и он не виден из компилятора. Если хочу использовать то же значение 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;
Сергей Борщ
Цитата(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;
примерно так.
defunct
Цитата(Student2 @ Oct 30 2009, 14:53) *
Мне надо было сделать JMP к адресу 0200. Код такой:

asm( "jmp 0x200"); - поймет любой компилятор AVR.
Альтернативно можно определить макрос, который при переносе с платформы на платформу можно легко изменять:

#define GoToApplication() asm("jmp 0x200")

main
{
...
GoToApplication();
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.