Atmega собирает и ретранслирует вызовы прерывания

Мне нравится собирать все возможные прерывания и передавать их в альтернативную таблицу прерываний обработчика, которую может установить пользователь.

Для этого я должен:
1) собрать все/любые запросы на прерывание
2) определить, откуда произошло прерывание
3) ретранслировать вызов на другой стол, указанный пользователем.

Если вы знакомы с прерываниями, то знаете, что если вы регистрируете одну функцию для всех обработчиков прерываний, то нет способа идентифицировать источник прерывания. Но регистрация уникального обработчика прерывания, который несет информацию об источнике и вызывает другую функцию для отправки вызова, для каждого прерывания — это пустая трата места в коде. Например: atmega328 имеет 24 обработчика прерываний. Каждый из них, скомпилированный с помощью avr-gcc, занимает 76 байт.


Но у меня есть идея, как можно зарегистрировать одну функцию-обработчик и идентифицировать источник:

00000000 <__vectors>:
   0:   0c 94 34 00     jmp 0x68    ; 0x68 <__ctors_end>
   4:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
   8:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
   c:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>

Если я определяю обработчик прерывания (даже если он умещается в 4 байта), помещается инструкция jmp. Если его можно заменить, например, на вызов 0xa2 (который может уместиться в 4 байта), его можно использовать для идентификации адреса источника прерывания.

Поскольку call хранит адрес возврата, функция, запущенная по адресу 0xa2, может прочитать этот адрес и тем самым идентифицировать вызывающего абонента. Затем добавьте дополнительный pop (извлекает адрес стека, накопленный вызовом в таблице прерываний) и reti (для возврата из прерывания обработчик) после тела функции.

Если это может работать теоретически, для достижения этого остается только один вопрос:

Как заменить инструкции jmp на call в таблице прерываний?

, 👍0


2 ответа


Лучший ответ:

1

Таблица векторов прерываний предоставлена среда выполнения C. Это обычно не предназначено для переопределения пользовательским кодом. Вы можете, однако, сделать это, если вы замените всю среду выполнения C на свою собственную и скомпилируете свой скетч с параметром -nostartfiles.

Я играл в эту игру, когда пытался точно оценить прерывание задержки. См. подробности в этом ответе (ответ длинный, но вы можете сразу перейти к последнему разделу).

,

1

Ответ, который я принял, является правильным ответом на проблему, которую я задал. Однако замена среды выполнения C требует присоединения и поддержки большого количества файлов crt.S, изначально связанных с GCC. Чтобы избежать этого, я «несколько раз спал над этой проблемой» и нашел другое решение.

После компиляции хост-приложения, которое должно перенаправлять вызовы прерывания (исходник скрипта). Я написал утилиту, которая перезаписывает все переходы прерываний в начале ihex (source) со смещением к целевому приложению.

Хорошо, это решение не собирает, не идентифицирует и не ретранслирует входящие прерывания, а просто ретранслирует их. Поскольку нет целевого приложения, ничто не разрешает эти прерывания и не вызывает ошибки. Это решение также не требует дополнительного места для кода.

,