§ Зачем нужны прерывания

Процессор - это сложное устройство, фактически, изолированное от внешнего мира. Он работает, выполняет некоторые операции. Но вот появляется устройство, которое дергает процессор за ногу и говорит "Я сделаль!". Процессор напряженно размышляет о смысле бытия, и вдруг понимает, что кто-то его дергает за ногу. Он смотрит, кто это делает, а это номер 8-й. Тогда процессор останавливает свои насущные дела и сохраняет флаги, сохраняет место, где он остановился и вызывает прерывание номер 8 (допустим). Всего 256 прерываний в процессоре предусмотрено, из них 16 базовых аппаратных, но вообще их можно намного больше сделать специальными методами. Но пока что их 16.
Напишем общую процедуру вызова прерывания по номеру
void interrupt(uint8_t int_id) {

    push(get_flags());
    push(regs16[REG_CS]);
    push(reg_ip);

    // CS:IP копируется из памяти
    reg_ip = rd(4*int_id, 2);
    regs16[REG_CS] = rd(4*int_id+2, 2);

    flags.i = 0;
    flags.t = 0;
}
Как видно, сначала в стек сохраняются флаги, потом текущий регистр CS, IP. Далее из памяти, начиная с 0 позиции, копируются IP,CS. Каждый адрес прерывания в 16-битном режиме занимает 4 байта памяти, потому они и располагаются последовательно один за одним, занимая ровно 1024 байта нижней области памяти.
Еще очень важный момент. В процессоре есть отладочные прерывания, и вот, если установлен TF=1 и IF=1, то после выполнения каждой инструкции будет вызываться прерывание 1:
if (flags.i && flags.t) interrupt(1);

§ Инструкции прерываний

Теперь напишем код для всех инструкции так называемых "программных прерываний" (software interrupt)
// INT3, INT i8, INTO
case 0xCC: interrupt(3); break;
case 0xCD: interrupt(fetch(1)); break;
case 0xCE: if (flags.o) interrupt(4); break;
case 0xF1: interrupt(1); break;
int 1 или 3 просто вызывает 1 или 3 прерывание, int i8 вызывает прерывание под номером, который следует за опкодом (1 байт), а into вызывает 4-е прерывание тогда, когда флаг OF=1.
После вызова прерывания, необходимо выйти из прерывания, для этого используется инструкция IRET:
case 0xCF:

    i_op1 = pop();
    i_op2 = pop();
    set_flags(pop());
    regs16[REG_CS] = i_op2;
    reg_ip = i_op1;
    break;
Последовательно выбирается из стека сначала значение IP, потом CS, и, в самом конце, обновляет флаги.
В действительности, с кодами прерываний тут всё. Теперь все зависит от аппаратуры, которая работает извне процессора, такая как таймер, клавиатура, диски, мышь и прочее.
Как и ранее, коды можно найти по ссылке.
Следующий материал