Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос по недокументированной команде ATtiny13.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
kv_addr
Во избежание открытия в ветке дискуссии по поводу, кошерно ли рестартовать не через 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", отсутствующая в наборе команд для этого конкретного контроллера?
defunct
Цитата(kv_addr @ Apr 6 2009, 12:06) *
В таком случае возникает вопрос, откуда у ATtiny13 появилась выполняемая в реале команда "jmp", отсутствующая в наборе команд для этого конкретного контроллера?

Возникает также и другой вопрос:
Если поставить
asm("jmp random")
что-нибудь изменится?

Или МК будет тоже резетиться.
kv_addr
Цитата(defunct @ Apr 6 2009, 13:41) *
Возникает также и другой вопрос:
Если поставить
asm("jmp random")
что-нибудь изменится?

Или МК будет тоже резетиться.


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

PS: Но вопрос о недокументированной команде остался в силе.

PPS: Кстати, в своё время знал о недокументированных командах Z80 и иногда использовал их для трюков. wink.gif
ataradov
Под "random", если я правильно понял понимается любое число. Смысл в том, что ресет потому и происходит, что такой инструкции нет.
kv_addr
Цитата(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 отрабатывается безукоризненно. smile.gif

Ваша гипотеза - ошибочна.
rx3apf
Цитата(kv_addr @ Apr 6 2009, 13:06) *
В таком случае возникает вопрос, откуда у ATtiny13 появилась выполняемая в реале команда "jmp", отсутствующая в наборе команд для этого конкретного контроллера?

Отсутствие команды в даташите не означает, что ее нет в "железе". Что-то мне помнится, что у mega8 такая команда была и работала. И вдруг очередная версия компилятора начала на нее ругаться - гляжу в даташит, а ее (jmp) уже и нет... За давностью не поручусь за подробности, может быть, то была не M8. Но в каком-то из мелких камней я это встречал.
kv_addr
Цитата(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". В более поздних ревизиях дейташитов этой команды в списке уже нет.
defunct
Цитата(kv_addr @ Apr 6 2009, 18:50) *
Ваша гипотеза - ошибочна.

Это не страшно, главное что Ваша подтверждена. laughing.gif
Заманчиво конечно, но наверное не стоит расчитывать, что во всех ревизиях чипа недокументированная инструкция будет поддерживаться. При какой-нить очередной оптимизации могут и выкинуть.
kv_addr
Цитата(defunct @ Apr 7 2009, 03:32) *
Это не страшно, главное что Ваша подтверждена. laughing.gif
Заманчиво конечно, но наверное не стоит расчитывать, что во всех ревизиях чипа недокументированная инструкция будет поддерживаться. При какой-нить очередной оптимизации могут и выкинуть.

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

Обнаружил в процессе поиска наиболее компактного варианта программного ресета.

Но вот "rjmp" побороть не смог. Как указать в ассемблерной вставке относительному переходу скакнуть по абсолютному адресу способа не нашел.

Зато обнаружил, что __indirect_jump_to(0), в отличие от asm("ldi r30,0\n ldi r31,0\n ijmp"), подавляет генерацию бесполезной reti, а __noreturn убирает столь же бесполезное в этом случае сохранение регистровой пары z.
ReAl
Цитата(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>
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.