CODE_SELECTOR, DATA_SELECTOR); }
4.4 Файл TASKS.C. Содержит функции задач.
#include #include #include #include #include #include "tos.h" #include "screen.h"
word dispatcher(void);
// Номер текущей строки для вывода на экран extern unsigned int y;
// Задача TASK_1 void task1(void) { while(1) { vi_print(0,y++, " Запущена задача TASK_1, "
" возврат управления главной задаче", 0x70); jump_to_task(MAIN_TASK_SELECTOR);
// После повторного запуска этой задачи // снова входим в цикл. } }
// Задача TASK_2 long delay_cnt1 = 0l; word flipflop1 = 0; void task2(void) { char Buf[B_SIZE + 1]; // Буфер вывода задачи 2 static TLabel Label1; static TLabel Label2;
memset(Buf, ' ', B_SIZE); Buf[B_SIZE] = 0;
Label1.Pos = 0; Label1.Dir = 1;
Buf[Label1.Pos] = '/';
Label2.Pos = B_SIZE; Label2.Dir = 0; Buf[Label2.Pos] = '';
vi_print(30, 15, "Работает задача 2:", 0x7f);
while (1) { // Периодически выводим на экран движки, // каждый раз переключая // семафор номер 1. Этот семафор однозначно // соответствует выведенной на экран строке. asm sti if (delay_cnt1 > 150000l) { asm cli
StepLabel(&Label1, &Label2, Buf);
if (flipflop1)
{ vi_print(5, 16, Buf, 0x1f); sem_clear(1);
} else
{ vi_print(5, 16, Buf, 0x1f); sem_set(1);
} flipflop1 ^= 1; delay_cnt1 = 0l; asm sti } delay_cnt1++; } }
word flipflop = 0; long delay_cnt = 0l;
// Эта задача также периодически выводит на экран // с меньшим периодом. Кроме того, эта задача // работает только тогда, когда установлен // семафор номер 1. void flipflop_task(void) { char Buf[B_SIZE + 1]; // Буфер вывода задачи 2 static TLabel Label1; static TLabel Label2;
Label1.Pos = 0; Label1.Dir = 1; Buf[Label1.Pos] = '/';
vi_print(30, 12, "Работает задача 0:", 0x7f);
while(1) { asm sti if (delay_cnt > 20000l ) { sem_wait(1); // ожидаем установки семафора asm cli
StepLabel(&Label1, &Label2, Buf); vi_print(5, 13, Buf, 0x1f); flipflop ^= 1; delay_cnt = 0l; asm sti } delay_cnt++; } }
word keyb_code;
extern word keyb_status;
// Эта задача вводит символы с клавиатуры // и отображает скан-коды нажатых клавиш // и состояние переключающих клавиш на экране. // Если нажимается клавиша ESC, задача // устанавливает семафор номер 0. // Работающая параллельно главная задача // ожидает установку этого семафора. Как только // семафор 0 окажется установлен, главная задача // завершает свою работу и программа возвращает // процессор в реальный режим, затем передаёт // управление MS-DOS. void keyb_task(void) { vi_print(32, 20, " Key code: .... ", 0x20); vi_print(32, 21, " Key status: .... ", 0x20); while(1) { keyb_code = kb_getch(); vi_put_word(45, 20, keyb_code, 0x4f); vi_put_word(45, 21, keyb_status, 0x4f); if ((keyb_code & 0x00ff) == 1) sem_set(0); } }
4.5 Файл SEMAPHOR.C. Содержит процедуры для работы с семафорами.
#include #include #include #include #include "tos.h"
// Массив из пяти семафоров
word semaphore[5];
// Процедура сброса семафора. // Параметр sem - номер сбрасываемого семафора void sem_clear(int sem) { asm cli semaphore[sem] = 0; asm sti }
// Процедура установки семафора // Параметр sem - номер устанавливаемого семафора void sem_set(int sem) { asm cli semaphore[sem] = 1; asm sti }
// Ожидание установки семафора // Параметр sem - номер ожидаемого семафора void sem_wait(int sem) { while (1) { asm cli // проверяем семафор if (semaphore[sem]) break;
asm sti // ожидаем установки семафора asm nop asm nop } asm sti }
4.6 Файл TIMER.C. Процедуры для работы с таймером и диспетчер задач.
Cодержит обработчик аппаратного прерывания таймера, который периодически выдаёт звуковой сигнал и инициирует работу диспетчера задач. Диспетчер задач циклически перебирает селекторы TSS задач, участвующих в процессе разделения времени, возвращая селектор той задачи, которая должна стать активной. В самом конце обработки аппаратного прерывания таймера происходит переключение именно на эту задачу.
// ------------------------------------------- // Модуль обслуживания таймера // -------------------------------------------
#define EOI 0x20 #define MASTER8259A 0x20
extern void beep(void); extern void flipflop_task(void); void Timer_int(void); word dispatcher(void);
word timer_cnt;
// ------------------------------------------ // Обработчик аппаратного прерывания таймера // ------------------------------------------
void Timer_int(void) { asm pop bp
// Периодически выдаём звуковой сигнал
timer_cnt += 1; if ((timer_cnt & 0xf) == 0xf) { beep(); }
// Выдаём в контроллер команду конца // прерывания asm mov al,EOI asm out MASTER8259A,al
// Переключаемся на следующую задачу, // селектор TSS которой получаем от // диспетчера задач dispatcher()
jump_to_task(dispatcher()); asm iret }
// -------------------------------------- // Диспетчер задач // --------------------------------------
// Массив селекторов, указывающих на TSS // задач, участвующих в параллельной работе, // т.е. диспетчеризуемых задач
word task_list[] = { MAIN_TASK_SELECTOR, FLIP_TASK_SELECTOR, KEYBIN_TASK_SELECTOR, TASK_2_SELECTOR };
word current_task = 0; // текущая задача word max_task = 3; // количество задач - 1
// Используем простейший алгоритм диспетчеризации - // выполняем последовательное переключение на все // задачи, селекторы TSS которых находятся // в массиве task_list[].
word dispatcher(void) { if (current_task < max_task) current_task++; else current_task = 0; return(task_list[current_task]); }
4.7 Файл EXCEPT.C. Обработка исключений.
void prg_abort(int err);
// Номер текущей строки для вывода на экран
extern unsigned int y;
// Обработчики исключений
void exception_0(void) { prg_abort(0); } void exception_1(void) { prg_abort(1); } void exception_2(void) { prg_abort(2); } void exception_3(void) { prg_abort(3); } void exception_4(void) { prg_abort(4); } void exception_5(void) { prg_abort(5); } void exception_6(void) { prg_abort(6); } void exception_7(void) { prg_abort(7); } void exception_8(void) { prg_abort(8); } void exception_9(void) { prg_abort(9); } void exception_A(void) { prg_abort(0xA); } void exception_B(void) { prg_abort(0xB); } void exception_C(void) { prg_abort(0xC); } void exception_D(void) { prg_abort(0xD); } void exception_E(void) { prg_abort(0xE); } void exception_F(void) { prg_abort(0xF); } void exception_10(void) { prg_abort(0x10); } void exception_11(void) { prg_abort(0x11); } void exception_12(void) { prg_abort(0x12); } void exception_13(void) { prg_abort(0x13); } void exception_14(void) { prg_abort(0x14); } void exception_15(void) { prg_abort(0x15); } void exception_16(void) { prg_abort(0x16); } void exception_17(void) { prg_abort(0x17); } void exception_18(void) { prg_abort(0x18); } void exception_19(void) { prg_abort(0x19); } void exception_1A(void) { prg_abort(0x1A); } void exception_1B(void) { prg_abort(0x1B); } void exception_1C(void) { prg_abort(0x1C); } void exception_1D(void) { prg_abort(0x1D); } void exception_1E(void) { prg_abort(0x1E); } void exception_1F(void) { prg_abort(0x1F); }
// ------------------------------ // Аварийный выход из программы // ------------------------------
void prg_abort(int err) { vi_print(1, y++,"ERROR!!! ---> Произошло исключение", 0xc);
real_mode(); // Возвращаемся в реальный режим
// В реальном режиме выводим сообщение об исключении
gotoxy(1, ++y); cprintf(" Исключение %X, нажмите любую клавишу", err); getch();
textcolor(WHITE); textbackground(BLACK); clrscr(); exit(0); }
4.8 Файл INTPROC.C. Заглушки для аппаратных прерываний.
// Заглушки для необрабатываемых // аппаратных прерываний.
void iret0(void) { // первый контроллер прерываний asm { push ax mov al,EOI out MASTER8259A,al pop ax pop bp iret } }
// ----------------------------------------------------------- // второй контроллер прерываний void iret1(void) { asm { push ax mov al,EOI out MASTER8259A,al out SLAVE8259A,al pop ax pop bp iret } }
4.9 Файл KEYB.C. Ввод символа с клавиатуры.
extern word key_code;
// Функция, ожидающая нажатия любой // клавиши и возвращающая её скан-код
unsigned int kb_getch(void) { asm int 30h return (key_code); }
4.10 Файл KEYBOARD.ASM. Процедуры для работы с клавиатурой.
IDEAL
MODEL SMALL RADIX 16
P286 include "tos.inc"
; ------------------------------------------ ; Модуль обслуживания клавиатуры ; ------------------------------------------
PUBLIC _Keyb_int, _Int_30h_Entry, _key_code, _keyb_status EXTRN _beep:PROC DATASEG
_key_flag db 0
_key_code dw 0 ext_scan db 0
_keyb_status dw 0
CODESEG
PROC _Keyb_int NEAR cli
call _beep
push ax mov al, [ext_scan] cmp al, 0 jz normal_scan1 cmp al, 0e1h jz pause_key
in al, 60h
cmp al, 2ah jz intkeyb_exit_1 cmp al, 0aah jz intkeyb_exit_1
mov ah, [ext_scan] call Keyb_PutQ
mov al, 0 mov [ext_scan], al jmp intkeyb_exit
pause_key:
in al, 60h cmp al, 0c5h jz pause_key1 cmp al, 45h jz pause_key1
jmp intkeyb_exit
pause_key1: mov ah, [ext_scan] call Keyb_PutQ
normal_scan1: in al, 60h cmp al, 0feh jz intkeyb_exit cmp al, 0e1h jz ext_key cmp al, 0e0h jnz normal_scan
ext_key: mov [ext_scan], al jmp intkeyb_exit
intkeyb_exit_1: mov al, 0 mov [ext_scan], al jmp intkeyb_exit
normal_scan: mov ah, 0 call Keyb_PutQ
intkeyb_exit: in al, 61h mov ah, al or al, 80h out 61h, al xchg ah, al out 61h, al mov al,EOI out MASTER8259A,al
Страницы: 1, 2, 3, 4