|
|
  |
Вопрос по недокументированной команде ATtiny13., Откуда у ATtiny13 команда jmp ? |
|
|
|
Apr 6 2009, 09:06
|

Местный
  
Группа: Свой
Сообщений: 208
Регистрация: 6-07-04
Из: Полтава
Пользователь №: 279

|
Во избежание открытия в ветке дискуссии по поводу, кошерно ли рестартовать не через watchdog, а переходом по адресу 0, хотел бы заметить, в моём конкретном случае - вполне кошерно. Рестарт происходит по нажатию и отпусканию кнопки путем вывода контроллера из режима глубокой спячки, все необходимое подготовлено перед вводом в спячку. Перейду к сути. Имеем предельно простую подпрограмму прерывания: Код #pragma vector= INT0_vect __interrupt void Int0(void) { while(!BUTTON); __indirect_jump_to(0); } Генерируется код: Код 18 __interrupt void Int0(void) \ Int0: 19 { \ 00000000 93FA ST -Y, R31 \ 00000002 93EA ST -Y, R30 20 while(!BUTTON); \ ??Int0_0: \ 00000004 9BB1 SBIS 0x16, 0x01 \ 00000006 CFFE RJMP ??Int0_0 21 __indirect_jump_to(0); \ 00000008 E0E0 LDI R30, 0 \ 0000000A E0F0 LDI R31, 0 \ 0000000C 9409 IJMP \ 0000000E REQUIRE _A_PINB 22 } Все выполняется верно (и в железе тоже). Пишу с ассемблерной вставкой: Код #pragma vector= INT0_vect //В выключеном состоянии ~1...1,5 мкА __interrupt void Int0(void) { while(!BUTTON); asm("jmp 0"); // Не "rjmp 0", а именно "jmp 0" ! } Генерируется код: Код 18 __interrupt void Int0(void) \ Int0: \ ??Int0_0: 19 { 20 while(!BUTTON); \ 00000000 9BB1 SBIS 0x16, 0x01 \ 00000002 CFFE RJMP ??Int0_0 21 asm("jmp 0"); \ 00000004 940C0000 jmp 0 22 } И, как ни странно, все выполняется (и в железе тоже). В таком случае возникает вопрос, откуда у ATtiny13 появилась выполняемая в реале команда "jmp", отсутствующая в наборе команд для этого конкретного контроллера?
|
|
|
|
|
Apr 6 2009, 10:41
|

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

|
Цитата(kv_addr @ Apr 6 2009, 12:06)  В таком случае возникает вопрос, откуда у ATtiny13 появилась выполняемая в реале команда "jmp", отсутствующая в наборе команд для этого конкретного контроллера? Возникает также и другой вопрос: Если поставить asm("jmp random") что-нибудь изменится? Или МК будет тоже резетиться.
|
|
|
|
|
Apr 6 2009, 11:25
|

Местный
  
Группа: Свой
Сообщений: 208
Регистрация: 6-07-04
Из: Полтава
Пользователь №: 279

|
Цитата(defunct @ Apr 6 2009, 13:41)  Возникает также и другой вопрос: Если поставить asm("jmp random") что-нибудь изменится?
Или МК будет тоже резетиться. Компилятор будет ругаться. В ассемблерной вставке можно использовать только предопределенные символы и явные параметры. PS: Но вопрос о недокументированной команде остался в силе. PPS: Кстати, в своё время знал о недокументированных командах Z80 и иногда использовал их для трюков.
|
|
|
|
|
Apr 6 2009, 15:50
|

Местный
  
Группа: Свой
Сообщений: 208
Регистрация: 6-07-04
Из: Полтава
Пользователь №: 279

|
Цитата(Taradov Alexander @ Apr 6 2009, 16:53)  Под "random", если я правильно понял понимается любое число. Смысл в том, что ресет потому и происходит, что такой инструкции нет. Практика - критерий истины. Пишем еще кусок кода с известной точкой входа, и там зацикливаемся: Код #pragma vector= INT0_vect __interrupt void Int0(void) { while(!BUTTON); asm("jmp 10"); }
#pragma vector= ANA_COMP_vect __interrupt void Test(void) { DDRB = 0x08; PORTB_Bit3 = 0; while(1) PORTB_Bit3 = !PORTB_Bit3; } Компилируем, прошиваем. По нажатию и отпусканию кнопки на PB3 при помощи бациллоскопа наблюдаем красивый меандр. Команда jmp 10 отрабатывается безукоризненно.  Ваша гипотеза - ошибочна.
|
|
|
|
|
Apr 6 2009, 16:04
|
Гуру
     
Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047

|
Цитата(kv_addr @ Apr 6 2009, 13:06)  В таком случае возникает вопрос, откуда у ATtiny13 появилась выполняемая в реале команда "jmp", отсутствующая в наборе команд для этого конкретного контроллера? Отсутствие команды в даташите не означает, что ее нет в "железе". Что-то мне помнится, что у mega8 такая команда была и работала. И вдруг очередная версия компилятора начала на нее ругаться - гляжу в даташит, а ее (jmp) уже и нет... За давностью не поручусь за подробности, может быть, то была не M8. Но в каком-то из мелких камней я это встречал.
|
|
|
|
|
Apr 6 2009, 16:36
|

Местный
  
Группа: Свой
Сообщений: 208
Регистрация: 6-07-04
Из: Полтава
Пользователь №: 279

|
Цитата(rx3apf @ Apr 6 2009, 19:04)  Отсутствие команды в даташите не означает, что ее нет в "железе". Что-то мне помнится, что у mega8 такая команда была и работала. И вдруг очередная версия компилятора начала на нее ругаться - гляжу в даташит, а ее (jmp) уже и нет... За давностью не поручусь за подробности, может быть, то была не M8. Но в каком-то из мелких камней я это встречал. Меня заинтересовал сам факт. Про Z80 я уже писал. Кстати, несмотря на то, что казалось бы "jmp 0" должен давать одно слово выигрыша, все же идеологически правильный минимизированный вариант: Код #pragma vector= INT0_vect __interrupt __noreturn void Int0(void) { while(!BUTTON); __indirect_jump_to(0); } не проигрывает в объёме кода, потому как во втором случае компилятор не генерирует хвостовое "reti", четко понимая, что возвращаться некуда, а в первом не имеет об этом никакого представления и после "jmp 0" оставляет еще и "reti". PS: Да, еще кстати, в старом дейташите на Мегу8 (Rev. 2486I–AVR–12/02) обнаружил "jmp". В более поздних ревизиях дейташитов этой команды в списке уже нет.
|
|
|
|
|
Apr 7 2009, 06:20
|

Местный
  
Группа: Свой
Сообщений: 208
Регистрация: 6-07-04
Из: Полтава
Пользователь №: 279

|
Цитата(defunct @ Apr 7 2009, 03:32)  Это не страшно, главное что Ваша подтверждена. Заманчиво конечно, но наверное не стоит расчитывать, что во всех ревизиях чипа недокументированная инструкция будет поддерживаться. При какой-нить очередной оптимизации могут и выкинуть. Естественно, полагаться на такие трюки ни в коем случае нельзя, особливо в серии, очень может вылезти боком, но в качестве курьёза меня заинтересовало. Обнаружил в процессе поиска наиболее компактного варианта программного ресета. Но вот "rjmp" побороть не смог. Как указать в ассемблерной вставке относительному переходу скакнуть по абсолютному адресу способа не нашел. Зато обнаружил, что __indirect_jump_to(0), в отличие от asm("ldi r30,0\n ldi r31,0\n ijmp"), подавляет генерацию бесполезной reti, а __noreturn убирает столь же бесполезное в этом случае сохранение регистровой пары z.
|
|
|
|
|
Apr 7 2009, 13:33
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(kv_addr @ Apr 7 2009, 09:20)  Но вот "rjmp" побороть не смог. Как указать в ассемблерной вставке относительному переходу скакнуть по абсолютному адресу способа не нашел. Сделать его "неизвестным". Например, задать в скрипте линкера метку, равную 0, а в исходнике объявить как внешнюю. Как для иар-а не знаю, для avr-gcc так: Цитата .text : { PROVIDE (__reset_addr = 0) ; *(.vectors) Код __asm__ __volatile__ ( ".global __reset_addr\n\t" "rjmp __reset_addr" :: ); Цитата Disassembly of section .text:
00000000 <__reset_addr>: 0: 09 c0 rjmp .+18 ; 0x14 <__ctors_end> ... 74: c5 cf rjmp .-118 ; 0x0 <__reset_addr>
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|