§ Зачем нужны прерывания
Процессор - это сложное устройство, фактически, изолированное от внешнего мира. Он работает, выполняет некоторые операции. Но вот появляется устройство, которое дергает процессор за ногу и говорит "Я сделаль!". Процессор напряженно размышляет о смысле бытия, и вдруг понимает, что кто-то его дергает за ногу. Он смотрит, кто это делает, а это номер 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, и, в самом конце, обновляет флаги.
В действительности, с кодами прерываний тут всё. Теперь все зависит от аппаратуры, которая работает извне процессора, такая как таймер, клавиатура, диски, мышь и прочее.
Как и ранее, коды можно найти по ссылке.
Следующий материал