Приветствую вас! При появлении запроса на прерывание (IRQ) в регистре запросов прерывания IRR контроллера 8259A устанавливается бит, соответствующий этому прерыванию. Если бит регистра обслуживаемых запросов ISR того же прерывания (и всех более приоритетных) сброшен и прерывание незамаскировано (в IMR или через cli), процессор подтверждает прерывание и соответствующий бит в IRR сбрасывается, а в ISR устанавливается. После отправки команды EOI сбрасывается и бит регистра ISR, разрешая процессору снова прерывать выполнение кода вызовом обработчика того же прерывания (и менее приоритетных). Соответственно, поскольку после подтверждения прерывания процессором бит в IRR сбрасывается, он в любом момент может быть установлен снова, а значит, если мы ещё не завершили обработку прерывания, по после отправки EOI и выполнения iret/sti обработчик будет вызван снова. Мне необходимо предотвратить эту ситуацию и сбросить соответствующий бит регистра IRR перед выходом из обработчика прерывания (iret), ну или перед отправкой EOI. Вопрос: как это сделать? Регистр IRR можно без проблем прочитать, интерфейс для этого есть, а вот с записью проблема... Вот тут написано: Значит, стало быть, каким-то образом IRQ может быть снято? Как это сделать, как сбросить бит регистра IRR? p.s. Вариант инициализации контроллера прошу не предлагать
Это надуманная проблема. IRR не надо сбрасывать. Когда вы сбрасываете ISR посылкой EOI, контроллер выполнит сброс проверит IRR и если там что-то есть то обнулит IRR и выставит ISR,
Тут борятся только организационно распорядительными методами: - обработчик прерывания должен быть как можно карочи. - DPC- в виндоусе, Interrupt Service Routin(ISR) - в FreeRtos. В обоих этих ОС есть очередь для вызова обработчиков прерываний. При приходе прерывания ОС определяет обработчик прерывания* и кладёт его в очередь. Посылает EOL контроллеру прерываний выполняет IRET, а при первом удобном** случае вызывается обработчик прерывания DPC или ISR. * Вернее тут два обработчика прерываний InteruptHandler. Первый тупо проверяет его ли железка вызвало прерывание или нет. А второй уже непосредственно обработчик. ** Удобным случаем является момент смены контекста потока. Signal/Slot, а так же при вызове сервиса ядра int 80h. Переводчик неправ. Снять можно только если IRR не настроен на режим защёлки. Одна беда так как ISA прерывания импульсные, поэтому IRR настроен на режим защёлки. Так что сбросить не получится без полной инициализации.
Он короткий, лишь в редких случаях он работает долго. Вот в этом случае и нужно сделать так, чтобы прерывание не повторялось после завершения текущего обработчика. Потому что полный сброс сбросит ВСЕ биты IRR, т.е. если я нажал на клавишу во время работы "долгого обработчика" IRQ 0, клавиша не сработает на выходе из прерывания. В принципе, я знаю, как сделать по-другому Изначально счётчик таймера настраивается на высокую частоту. А при долгой обработке в счётчик таймера записывается 0, а на выходе новое значение (оно всё равно перезаписывается каждый раз). 55 мс для этой "долгой обработки" хватит с лихвой (там и 1 мс хватит). Я просто подумал, что может есть вариант сбросить бит и всё.
Это надуманная проблема. Но если охота. Послал EOL не выходя из IRET читаешь ISR и если там есть ваш бит, то ещё раз шлёшь EOL. Перед чтением надобно выдержать паузу, 250 нс.
Почему надуманная? У меня на каждом вызове определённое действие выполняется, лишних вызовов быть не должно. EOL – это EOI ? А как в ISR выставится бит, если у меня прерывания запрещены (cli – это же то же самое, что маска IMR)? Его там не будет в любом случае. ISR перенимает бит из IRR только тогда, когда прерывания разрешены и нет маски в IMM, так ведь? А если я разрешу прерывания, то произойдёт "рекурсивный" вызов обработчика. Можно, конечно, отследить вложенность, но это уже нагромождение пойдёт...
Я, кстати, сейчас проверил эту тему. Действительно, так и есть. При входе в прерывание регистр ISR = 0, делаю приличную паузу, отправляю EOI, снова делаю паузу, читаю ISR = 0. Соответственно, IRR = 0 на входе, IRR = 1 на выходе (как и предполагалось). Так что, Pavia, такой вариант не прокатит... Спойлер: Код, если интересно... Код (Text): .MODEL Tiny .286 .CODE ORG 100h Start: First: push offset Intercept Delay proc mov bx,50 DelayBX: loop $ dec bx jnz DelayBX ret Delay endp Show proc mov al,00001010b ; чтение IRR call Show1 mov al,' ' int 29h mov al,00001011b ; чтение ISR call Show1 mov al,13 int 29h mov al,10 int 29h ret Show endp Show1 proc out 20h,al in al,20h mov cx,8 xchg dx,ax @@2: shl dl,1 mov al,'0' adc al,0 int 29h loop @@2 ret Show1 endp Handler: cmp byte ptr cs:First,0 je skip mov byte ptr cs:First,0 pusha call Show call Delay call Show mov al,20h out 20h,al ; EOI inc bx call DelayBX call Show popa skip: RealInt: db 0EAh RealAddr dw ?,? TSREnd = $ ORG $-4 Intercept: mov ax,3508h int 21h mov RealAddr[0],bx mov RealAddr[2],es mov ah,25h lea dx,Handler int 21h mov ah,49h mov es,ds:[2Ch] int 21h lea dx,TSREnd int 27h END Start Выдаёт 00000000 00000001 00000001 00000001 00000001 00000000 В DOSBox, правда, но и в реале, думаю, то же самое будет...