Изучение основных принципов организации и обслуживания аппаратных прерываний в ОС DOS и QNX, страница 3

      mov   al, #2            ;

      mov   cl, al            ;

      and   cl, 0f            ;маскирование для выделения младшего разряда

      add   cl, 030           ;преобразование его в ASCII код

      sar   al, 4       ;сдвиг на 4 разряда

      mov   ch, al           

      and   ch, 0f            ;маскирование

      add   ch, 030           ;преобразование в ASCII код

      print #1, ch            ;запись результата в

      print #1+2, cl    ;видеобуфер

      pop   cx, ax            ;восстановление ресурсов

#em

      jmp   main

old_addr    dd    ?

main:

      ;сохраняем адрес старого обработчика (прерывание №8, от таймера)

      mov   ax, 035 by 8

      int   021

      mov w       old_addr, bx

      mov w old_addr+2, es

      ;загружаем адрес нового обработчика (прерывание №8, от таймера)

      lea   dx, timerIsr

      mov   ax, 025 by 8

      int   021  

      ;ждем нажатия клавиши

wait_esc:

      mov   ah, 0

      int   016

      cmp   ah, 1

      jne   wait_esc

      ;восстанавливаем старый обработчик

      lds   dx, old_addr

      mov   ax, 025 by 8

      int   021

      int   020

;собственный обработчик

timerIsr:

      push  ax, ds, es

      ;читаем часы

      mov   al, 4

      out   70h, al

      in    al, 71h

      ;печатаем часы

      print_sm 0, al

      print 4, ':'

      ;читаем минуты

      mov   al, 2

      out   70h, al

      in    al, 71h

      ;печатаем минуты

      print_sm 6, al

      print 10, ':'    

      ;читаем секунды

      mov   al, 0

      out   70h, al

      in    al, 71h

      ;печатаем секунды

      print_sm 12, al  

      pop   ax, ds, es

      ;переход на системный обработчик (cs - нужно??..)

      cs jmp      old_addr

Результаты испытаний:

3.3. Транзитная программа вывода текущего времени или даты в зависимости от выбранной клавиши с выходом по клавише.

Текст программы для QNX:

#include <stdio.h>

//для работы с прерываниями

#include <sys/neutrino.h>

//для обработки ошибок

#include <errno.h>

//для работы с сигналами

#include <signal.h>

//для работы с портом клавиатуры

#include <hw/inout.h>

#include <time.h>

//обработчик прерывания от клавиатуры

const struct sigevent* klav_int (void *area, int id);

void SIGUSR1_date(int signo);

void SIGUSR2_time(int signo);

struct sigevent klav_exit;

struct sigevent klav_date;

struct sigevent klav_time;

int main (void) {

      int inter_id;

      //обработчики сигналов

      signal (SIGUSR1, SIGUSR1_date);

      signal (SIGUSR2, SIGUSR2_time);

      //запрос на использование привиллегированного ввода/вывода

      //(для возможности использования прерываний)

      ThreadCtl(_NTO_TCTL_IO,0);

      //макрос для определения типа  "сигнал" структуры sigevent

      SIGEV_SIGNAL_INIT(&klav_exit,SIGKILL);

      SIGEV_SIGNAL_INIT(&klav_date,SIGUSR1);

      SIGEV_SIGNAL_INIT(&klav_time,SIGUSR2);

      //подключние обработчика прерывания

      inter_id=InterruptAttach(1, klav_int, NULL,0,0);

      //проверка на наличие ошибок

      if (inter_id == -1) {

            printf("%s\n",strerror(errno));

            return 1;