Это мой код, и программист, а не компоновщик, должен знать, что происходит. У cortex-m есть разные таблицы векторов, и они могут быть довольно длинными, много-много отдельных векторов прерываний. Выше было просто прикосновение одного вкуса в один прекрасный день. Если вы никогда не будете использовать ничего, кроме вектора сброса, вам нужно сжечь больше областей памяти, создавая всю таблицу? возможно нет. Возможно, вы захотите сделать один достаточно глубоким, чтобы охватить неопределенные исключения и прерывания, и тому подобное, чтобы вы могли перехватить их с контролируемым зависанием. Если вам нужен только сброс и одно прерывание, но это прерывание находится довольно глубоко в таблице, вы можете создать огромную таблицу, чтобы покрыть оба, или, если хватит смелости, поместить некоторый код между ними, чтобы восстановить потерянное пространство.
Чтобы узнать / прочитать больше, вам нужно обратиться к техническому справочнику TRM для конкретных ядер cortex-m cortex-m0, cortex-m3 и cortex-m4, а также, возможно, ARM ARM для armv7-m. (cortex-m - это все семейство armv7-m). ARM ARM означает ARM Architectural Reference Manual, в котором в общих чертах рассказывается обо всей семье, но при этом не затрагиваются основные подробности, требующие ARM ARM и правильного TRM, обычно при программировании для ARM (если вам нужно получить что-то низкое. уровень вроде asm или конкретные регистры). Все это можно найти на веб-сайте infocenter.arm.com, где вы можете найти Архитектуру или процессоры серии Cortex-M.
Эти ядра достаточно новые, они, вероятно, не имеют большего числа оборотов. Для некоторых старых ядер лучше всего получить TRM для конкретного ядра. Возьмите, например, ARM11 Mpcore, если поставщик использовал версию 1.0 (r1p0) ядра, несмотря на устаревшие отметки в руководстве, вы хотите, по крайней мере, попытаться использовать руководство версии 1.0 вместо руководства версии 2.0, если есть различия. Поставщики не всегда говорят вам, какую версию они купили / использовали, так что это может быть проблемой при разборе того, как запрограммировать вещь или какие ошибки относятся к вам, а какие нет. (Linux полон ошибок, связанных с ARM, из-за непонимания этого, ошибок, примененных в целом или неверных данных, инструкций, используемых на неправильных ядрах или в неподходящее время, и т. Д.).
Я, вероятно, написал этот обработчик для cortex-m3, когда впервые получил его, а затем вырезал и вставлял кое-где, не удосужившись исправить или изменить его.
Ядро (CPU, логика) определенно знает, сколько поддерживаемых прерываний, и знает полный состав таблицы векторов. Могут быть управляющие сигналы на краю ядра, которые могут изменить такие вещи, и поставщик мог связать их одним способом или сделать их программируемыми и т. Д. Независимо от того, какая логика для этого ядра определенно знает, как выглядит векторная таблица как будто программист должен сделать так, чтобы код соответствовал аппаратному обеспечению по мере необходимости. Все это будет описано в TRM для этого ядра.
EDIT
Жестко закодированным в логике будет адрес или смещение для каждого из этих событий или прерываний. Поэтому, когда происходит прерывание или событие, он выполняет чтение памяти с этого адреса.
Это просто банк флэш-памяти, вы передаете ему адрес, строб чтения, и некоторые данные выходят. Эти биты ничего не значат, пока вы не поместите их в контекст. Вы можете вызвать цикл памяти по адресу 0x10, если вы создаете некоторый код, который выполняет инструкцию загрузки по этому адресу, или вы можете перейти к этому адресу, и цикл выборки считывает это местоположение в надежде найти инструкцию, и если событие имеет этот жестко закодированный адрес и чтение происходит по этому адресу, он надеется найти адрес для обработчика. но это всего лишь воспоминание. Так же, как файл в файловой системе, это просто байты на диске. Если это jpeg, то конкретный байт может быть пикселем, если файл на диске является программой, то байт со смещением может быть инструкцией. это просто байт.
Эти адреса генерируются непосредственно из логики. В наши дни логика написана с использованием языков программирования (обычно это verilog или vhdl или некоторый язык более высокого уровня, который выдает verilog или vhdl в качестве вывода). Не отличается от того, что если бы вы написали программу на своем любимом языке, вы можете буквально жестко закодировать какой-либо адрес
x = (unsigned int *)0x1234;
или вы можете выбрать использование структуры, массива или какого-то другого стиля программирования, но после компиляции он все равно приводит к некоторому фиксированному адресу или смещению:
unsigned int vector_table[256];
...
handler_address = vector_table[interrupt_base+interrupt_number];
...
Поэтому, как программист, на этом низком уровне вы должны знать, когда и когда аппаратное обеспечение будет считывать один из этих адресов и почему. если вы никогда не используете прерывания, потому что вы никогда не включаете никаких прерываний, то те области памяти, которые обычно могут содержать адреса обработчиков прерываний, теперь являются областями памяти, которые вы можете использовать для чего угодно. если, как вы видите во многих, почти во всех моих примерах, мне только нужен вектор сброса, остальное я не использую. Я мог бы случайно натолкнуться на неопределенный обработчик инструкций или прервать данные, если бы случайно выполнил не выровненный доступ, но обычно я не беспокоюсь об этом достаточно, чтобы разместить там обработчик. Я все равно собираюсь рухнуть / повиснуть, поэтому я разберусь с этой проблемой, когда доберусь туда, перейду этот мост, когда доберусь до него. Так что я обычно доволен минимальным для cortex-m адресом стека и адресом сброса:
.cpu cortex-m3
.thumb
.word 0x20002000 /* stack top address */
.word _start /* 1 Reset */
.thumb_func
.global _start
_start:
bl notmain
b hang
.thumb_func
hang: b .
И да, абсолютно я поместил двухсимвольную инструкцию bl notmain в ячейку памяти для NMI. если возникнет NMI, то процессор прочитает это местоположение, предположит, что это адрес для обработчика, попытается извлечь инструкцию по этому адресу, которая будет иметь кто знает что. Он может даже знать, прежде чем извлечь, что это неверный адрес и вызвать прерывание данных, которое в вышеупомянутом случае будет еще одним адресом куда-то, и это может превратиться в бесконечный цикл прерываний данных. Или если случайно одна из этих инструкций окажется похожей на адрес в нашей программе, то в основном она попадет прямо в середину программы, что довольно часто приводит к некоторому сбою. что такое авария? действительно? ЦП выполняет свою работу по чтению байтов из памяти и интерпретирует их как инструкции, если эти инструкции говорят, что они делают невыровненный доступ, или эти байты не являются действительными инструкциями или заставляют вас читать недопустимый адрес памяти, и вы возвращаетесь в таблицу векторов. Или вам может повезти, что испорченные адреса, которые пишутся или читаются при переходе в середину кодового пространства, приводят к удалению флэш-банка, выбрасыванию байта uart или изменению входного порта gpio на выходной порт (если вам действительно повезет, вы попытаетесь ударить его о землю или что-то еще, и вы расплавите чип).
Если бы я начал видеть странные вещи (и, надеюсь, не услышать, не понюхать или не увидеть, как чип тает), я мог бы добавить несколько десятков записей в таблицу векторов, которые указывают на зависание, или указать на обработчик, который выплевывает что-то из порта или включает gpio / led. если моя странность теперь становится включением этого светодиода или выводом uart в обработчике, тогда мне нужно разобраться, какое событие происходит, или, если я подумаю о последних нескольких изменениях в моем приложении, я могу понять, что у меня был не выровненный доступ или ветвь в сорняки и т. д.
Это возвращает нас к поговорке: «Компьютер не делает то, что вы хотите сделать, он делает то, что вы сказали сделать». Вы помещаете туда байты, и они интерпретируют их такими, какие они были, если вы не поместили правильные байты в нужное место (векторные адреса в нужное место, инструкции, которые делают правильные вещи, и правильные данные в нужном месте). может / потерпит крах.