Смекни!
smekni.com

DOS-extender для компилятора Borland C++ (стр. 5 из 7)

init_gdt_descriptor(&gdt[2], MK_LIN_ADDR(_DS, 0),

0xffffL, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);

init_gdt_descriptor(&gdt[3],

MK_LIN_ADDR(_DS, &task_1_tss),

(unsigned long)TSS_SIZE-1, TYPE_TSS_DESCR | SEG_PRESENT_BIT);

init_gdt_descriptor(&gdt[4],

MK_LIN_ADDR(_DS, &task_2_tss),

(unsigned long)TSS_SIZE-1, TYPE_TSS_DESCR | SEG_PRESENT_BIT);

init_gdt_descriptor(&gdt[5],

MK_LIN_ADDR(_DS, &main_tss),

(unsigned long)TSS_SIZE-1, TYPE_TSS_DESCR | SEG_PRESENT_BIT);

// Инициализируем TSS для задач TASK_1, TASK_2

init_tss(&task_1_tss, CODE_SELECTOR, DATA_SELECTOR, task_1_stack+

sizeof(task_1_stack), task1);

init_tss(&task_2_tss, CODE_SELECTOR, DATA_SELECTOR, task_2_stack+

sizeof(task_2_stack), task2);

// Инициализируем элемент 6 таблицы GDT -

// дескриптор для сегмента видеопамяти

// Определяем видеорежим

r.h.ah = 15;

int86(0x10, &r, &r);

// Инициализация для монохромного режима

if (r.h.al == MONO_MODE)

init_gdt_descriptor(&gdt[6], MONO_VID_MEM,

3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);

// Инициализация для цветного режима

else if (r.h.al == BW_80_MODE || r.h.al == COLOR_80_MODE)

init_gdt_descriptor(&gdt[6], COLOR_VID_MEM,

3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);

else

{

printf("\nИзвините, этот видеорежим недопустим.");

exit(-1);

}

// Инициализация элементов 7 и 8 таблицы GDT

init_gdt_descriptor(&gdt[7],

MK_LIN_ADDR(_DS, &idt),

(unsigned long)IDT_SIZE-1,

TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);

init_gdt_descriptor(&gdt[8],

MK_LIN_ADDR(_DS, &keyb_task_tss),

(unsigned long)TSS_SIZE-1,

TYPE_TSS_DESCR | SEG_PRESENT_BIT);

// Инициализация TSS для задачи KEYB_TASK

init_tss(&keyb_task_tss, CODE_SELECTOR, DATA_SELECTOR,

keyb_task_stack + sizeof(keyb_task_stack), keyb_task);

// Инициализация элемента 9 таблицы GDT

init_gdt_descriptor(&gdt[9],

MK_LIN_ADDR(_DS, &keyb_tss),

(unsigned long)TSS_SIZE-1,

TYPE_TSS_DESCR | SEG_PRESENT_BIT);

// Инициализация TSS для задачи KEYB обработки ввода с клавиатуры

init_tss(&keyb_tss, CODE_SELECTOR, DATA_SELECTOR,

keyb_stack + sizeof(keyb_stack), Keyb_int);

// Инициализация элемента 10 таблицы GDT

init_gdt_descriptor(&gdt[10],

MK_LIN_ADDR(_DS, &flipflop_tss),

(unsigned long)TSS_SIZE-1,

TYPE_TSS_DESCR | SEG_PRESENT_BIT);

// Инициализация TSS для задачи FLIP_TASK

init_tss(&flipflop_tss, CODE_SELECTOR, DATA_SELECTOR,

flipflop_stack + sizeof(flipflop_stack), flipflop_task);

// Загрузка регистра IDTR

load_idtr(MK_LIN_ADDR(_DS, &idt), IDT_SIZE);

// Вход в защищённый режим

protected_mode(MK_LIN_ADDR(_DS, &gdt), sizeof(gdt),

CODE_SELECTOR, DATA_SELECTOR);

}

4.4 Файл TASKS.C. Содержит функции задач.

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include <mem.h>

#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] = '&bsol;';

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;

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] = '&bsol;';

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 <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#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 задач, участвующих в процессе разделения времени, возвращая селектор той задачи, которая должна стать активной. В самом конце обработки аппаратного прерывания таймера происходит переключение именно на эту задачу.

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include "tos.h"

// -------------------------------------------

// Модуль обслуживания таймера

// -------------------------------------------

#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. Обработка исключений.

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include "tos.h"

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. Заглушки для аппаратных прерываний.

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include "tos.h"

// Заглушки для необрабатываемых

// аппаратных прерываний.

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. Ввод символа с клавиатуры.

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include "tos.h"

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