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