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

Странное поведение JMP

Мне надо было сделать 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?

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


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

Мне надо было сделать 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.

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


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

Может так?

 

GOTO desiredAddress;

 

и сишный эквивалент конструкции

.ORG 0x0200

desiredAddress:

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


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

extern void Application();
__C_task void main(void)
{
    ....
        Application();
    ....
}

Линкеру объявить символ Application равный 0x200 - в командной строке или скрипте дописать -DApplication=200

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


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

Student2, если вы изобретаете бутлоадер с проверкой на валидность прикладной задачи, то сообщаю по секрету, что бутлоадер пишется и компилируется отдельно от нее и управление бутлоадеру передается еще ДО вызова main в функции типа __low_level_init или как-то похоже. Почитайте документацию на компилятор.

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


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

extern void Application();
__C_task void main(void)
{
    ....
        Application();
    ....
}

Линкеру объявить символ Application равный 0x200 - в командной строке или скрипте дописать -DApplication=200

 

Спасибо Сергей,!

Сейчас вижу RJMP и все работает как надо. Видно что у вас большой опыт в программирование!

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

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


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

extern void Application();

....

Линкеру объявить символ Application равный 0x200 - в командной строке или скрипте дописать -DApplication=200

Сергей, можете объяснить почему так происходит? Т.е. почему в этом случае генрится jmp а не icall. Спасибо!

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


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

Сергей, можете объяснить почему так происходит? Т.е. почему в этом случае генрится jmp а не icall. Спасибо!

А что тут загадочного? В первом случае компилятор предусматривает возврат, во втором - нет, т.к. вызов стоит в самом конце main. Т.е. "jump xxx" используется как более оптимальный аналог "call xxx; ret".

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


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

Сергей, можете объяснить почему так происходит? Т.е. почему в этом случае генрится jmp а не icall.
Я не знаю, почему ИАР генерит ICALL для перехода по фиксированному адресу, заданному константой. Это очевидная недоработка и вопрос к его создателям. RJMP тоже сюрприз для меня, объянение aaarrr вполне правдоподобно. Обычно компилятор всталяет ®CALL, мы ведь описали Application() как обычную функцию.

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


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

Я не знаю, почему ИАР генерит ICALL для перехода по фиксированному адресу, заданному константой. Это очевидная недоработка и вопрос к его создателям.
Если я правильно помню, то avr-gcc ведёт себя так же.

RJMP тоже сюрприз для меня, объяснение aaarrr вполне правдоподобно. Обычно компилятор вставляет ®CALL, мы ведь описали Application() как обычную функцию.
Вот и я сильно удивился. Хорошо когда среди нас много догадливых сотоварищей:-)

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


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

Если пишу (WinAVR):

__attribute__((noreturn)) void testing_workmode(void)
{
}

То вызов транслируется в:

rcall    .-1268  ; 0x130a4 <testing_workmode>

Где я ошибаюсь, почему тоже call? :unsure:

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


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

Потому что (имхо) noreturn влияет на формирование пролога и эпилога функции (убирает сохранение используемых регистров), и не влияет на способ вызова этой функции. Она может быть вообще в другом модуле, и вызывающая функция понятия не имеет, что вызываемая - noreturn.

Для проверки напишите

__attribute__((noreturn)) void f2(void)
{
    for (;;);
}
__attribute__((noreturn)) void f1(void)
{
     f2();
}

И получите warning на f1, что типа noreturn-функция похоже делает return.

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


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

Программа сейчас работает, но возникла вот такая проблема поддержки и структурной чистотой - адрес установлен в линкере и он не виден из компилятора. Если хочу использовать то же значение 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;

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


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

Программа сейчас работает, но возникла вот такая проблема поддержки и структурной чистотой - адрес установлен в линкере и он не виден из компилятора.
Почему? Преркрасно виден. Вы же получали адрес функции Application(). Вы можете этот адрес привести к любому нужному типу:
extern void Application();
__C_task void main(void)
{
    ....
        Application();
        uint16_t Size_Area = (uint16_t)Application;
    ....
}

__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;

примерно так.

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


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

Мне надо было сделать JMP к адресу 0200. Код такой:

asm( "jmp 0x200"); - поймет любой компилятор AVR.

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

 

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

 

main

{

...

GoToApplication();

}

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


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

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...