Прерывание -- это механизм, осуществляющий прекращение исполнения основного кода и передачу управления по заданному адресу (вектору прерывания) при возникновении какого-либо события. Этим событием может быть поступление внешнего сигнала от порта ввода-вывода или периферийного устройства, аппаратный сбой или программная ошибка (например, деление на ноль или попытка обращения к памяти по неразрешенному адресу), или выполнение специальной команды запроса прерывания. Особым видом прерывания является аппаратный сброс.
При поступлении прерывания обычно происходит следующее. Процессор останавливает исполнение кода и помещает содержимое счетчика команд на верхушку стека, а затем загружает в счетчик команд адрес в таблице векторов, соответствующий данному прерыванию. Таблица векторов представляет собой кусок памяти, заполненный командами безусловного перехода к адресам обработчиков прерываний, и исполнив одну из этих команд, процессор перепрыгивает на нужный обработчик прерывания. Первоочередной задачей его является как можно скорее запретить все другие прерывания и сохранить содержимое регистров процессора на стеке. После завершения своей работты обработчик снимает со стека и восстанавливает содержимое регистров и разрешает прерывания, а затем команда reti берет со стека адрес, на котором случилось прерывание, и помещает его в счетчик команд. После этого продолжается исполнение основного кода, как будто ничего и не случилось.
Что такое стек? Это некоторая область памяти и регистр -- указатель стека. Когда мы помещаем что-либо на стек (условно -- команда push), мы записываем это что-то по адресу, соответствующему указателю стека и автоматически уменьшаем содержимое регистра на длину машинного слова, который теперь указывает на следующую "чистую" ячейку памяти. Чтобы снять что-то со стека, мы увеличиваем адрес на длину машинного слова и копируем содержимое ячейки по получившемуся адресу в соответствующий регистр.
Выше описано использование стека при возникновении прерываний. Но стек удобно использовать в первую очередь при вызове подпрограмм. При вызове подпрограмм (команда call) происходит то же самое, что при прерывании: адрес, с которого произошел вызов, кладется на стек. Перед этим на стек можно положить данные, которые далее будут использоваться подпрограммой. Временные переменные, используемые только подпрограммой, тоже часто хранят на стеке. После завершения подпрограммы, как и при завершении обработчика прерывания, восстанавливаются регистры и вызывается команда ret, которая передает управление на следующую после вызова команду, взяв адрес опять-таки из стека. Разумеется, чтобы это сработало, надо, чтобы подпрограмма, завершаясь, корректно "убрала за собой", восстановив не только регистры, но и указатель стека. Вернуть результат исполнения можно опять-таки через стек.