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

Процессор - это сложное устройство, фактически, изолированное от внешнего мира. Он работает, выполняет некоторые операции. Но вот появляется устройство, которое дергает процессор за ногу и говорит "Я сделаль!". Процессор напряженно размышляет о смысле бытия, и вдруг понимает, что кто-то его дергает за ногу. Он смотрит, кто это делает, а это номер 8-й. Тогда процессор останавливает свои насущные дела и сохраняет флаги, сохраняет место, где он остановился и вызывает прерывание номер 8 (допустим). Всего 256 прерываний в процессоре предусмотрено, из них 16 базовых аппаратных, но вообще их можно намного больше сделать специальными методами. Но пока что их 16.
Напишем общую процедуру вызова прерывания по номеру
1void interrupt(uint8_t int_id) {
2
3    push(get_flags());
4    push(regs16[REG_CS]);
5    push(reg_ip);
6
7    // CS:IP копируется из памяти
8    reg_ip = rd(4*int_id, 2);
9    regs16[REG_CS] = rd(4*int_id+2, 2);
10
11    flags.i = 0;
12    flags.t = 0;
13}
Как видно, сначала в стек сохраняются флаги, потом текущий регистр CS, IP. Далее из памяти, начиная с 0 позиции, копируются IP,CS. Каждый адрес прерывания в 16-битном режиме занимает 4 байта памяти, потому они и располагаются последовательно один за одним, занимая ровно 1024 байта нижней области памяти.
Еще очень важный момент. В процессоре есть отладочные прерывания, и вот, если установлен TF=1 и IF=1, то после выполнения каждой инструкции будет вызываться прерывание 1:
1if (flags.i && flags.t) interrupt(1);

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

Теперь напишем код для всех инструкции так называемых "программных прерываний" (software interrupt)
1// INT3, INT i8, INTO
2case 0xCC: interrupt(3); break;
3case 0xCD: interrupt(fetch(1)); break;
4case 0xCE: if (flags.o) interrupt(4); break;
5case 0xF1: interrupt(1); break;
int 1 или 3 просто вызывает 1 или 3 прерывание, int i8 вызывает прерывание под номером, который следует за опкодом (1 байт), а into вызывает 4-е прерывание тогда, когда флаг OF=1.
После вызова прерывания, необходимо выйти из прерывания, для этого используется инструкция IRET:
1case 0xCF:
2
3    i_op1 = pop();
4    i_op2 = pop();
5    set_flags(pop());
6    regs16[REG_CS] = i_op2;
7    reg_ip = i_op1;
8    break;
Последовательно выбирается из стека сначала значение IP, потом CS, и, в самом конце, обновляет флаги.
В действительности, с кодами прерываний тут всё. Теперь все зависит от аппаратуры, которая работает извне процессора, такая как таймер, клавиатура, диски, мышь и прочее.
Как и ранее, коды можно найти по ссылке.
Следующий материал