Реферат по предмету "Информатика"


DOS-extender для компилятора Borland C

--PAGE_BREAK--

Рис. 3. Формат элементов дескрипторной таблицы прерываний IDT.

Расположение определяется содержимым 5-байтового внутреннего регистра процессора IDTR. Формат регистра IDTR полностью аналогичен формату регистра GDTR, для его загрузки используется команда LIDT. Так же, как регистр GDTR содержит 24-битовый физический адрес таблицы GDT и её предел, так и регистр IDTR содержит 24-битовый физический адрес дескрипторной таблицы прерываний IDT и её предел.
Регистр IDTR программа загружает перед переходом в защищённый режим, в функции protected_mode() модуля TOSSYST.ASM при помощи вызова функции set_int_ctrlr(), описанной в файле TOSSYST.ASM.
Для обработки особых ситуаций — исключений — разработчики процессора i80286 зарезервировали 31 номер прерывания. Каждому исключению соответствует одна из функций exception_XX() из модуля EXCEPT.C. Собственно, описав реакцию программы на каждое исключение можно обрабатывать любые ошибки защищенного режима. В моем случае достаточно завершать программу при возникновении любого исключения с выдачей на экран номера возникшего исключения. Поэтому функции exception_XX() просто вызывают prg_abort(), описанной там же, и передают ей номер возникшего исключения. Функция prg_abort() переключает процессор в реальный режим, выводит сообщение с данными возникшего исключения и завершает работу программы.
Теперь разберемся с аппаратными прерываниями, которые нас не интересуют в данной программе, однако это не мешает им происходить. Для этого в модуле INTPROC.C описаны две функции заглушки iret0() и iret1(), которые собственно ничего не делают кроме того, что выдают на контроллеры команды конца прерывания. Функция iret0() относится к первому контроллеру (Master), а вторая – ко второму (Slave).
 Неплохо было бы включить в программу поддержку программного прерывания 30h, чтобы можно было получать данные с клавиатуры. Это реализовано в модуле KEYBOARD.ASM, в функции Int_30h_Entry(). В IDT помещается вентиль программного прерывания, который вызывает данную функцию в момент прерывания 30h.
После запуска программа переходит в защищённый режим и размаскирует прерывания от таймера и клавиатуры. Далее она вызывает в цикле прерывание int 30h (ввод символа с клавиатуры), и выводит на экран скан-код нажатой клавиши и состояние переключающих клавиш (таких, как CapsLock, Ins, и т.д.). Если окажется нажатой клавиша ESC, программа выходит из цикла.

 Обработчик аппаратного прерывания клавиатуры — процедура с именем Keyb_int из модуля KEYBOARD.ASM. После прихода прерывания она выдаёт короткий звуковой сигнал (функция beep() из модуля TOSSYST.ASM), считывает и анализирует скан-код клавиши, вызвавшей прерывание. Скан-коды классифицируются на обычные и расширенные (для 101-клавишной клавиатуры). В отличие от прерывания BIOS INT 16h, мы для простоты не стали реализовывать очередь, а ограничились записью полученного скан-кода в глобальную ячейку памяти key_code. Причём прерывания, возникающие при отпускании клавиш, игнорируются.

Запись скан-кода в ячейку key_code выполняет процедура Keyb_PutQ() из модуля KEYBOARD.ASM. После записи эта процедура устанавливает признак того, что была нажата клавиша — записывает значение 0FFh в глобальную переменную key_flag.

Программное прерывание int 30h опрашивает состояние key_flag. Если этот флаг оказывается установленным, он сбрасывается, вслед за чем обработчик int 30h записывает в регистр AX скан-код нажатой клавиши, в регистр BX — состояние переключающих клавиш на момент нажатия клавиши, код которой передан в регистре AX.

 Ну и последнее, требующееся прерывание – это аппаратное прерывание таймера. Обработка этого прерывания реализована в функции Timer_int() модуля TIMER.C. Эта функция служит для переключения процессора между задачами. Более подробно я рассмотрю ее работу в следующей главе курсового проекта.
 Структура элемента дескрипторной таблицы прерываний IDT описана в файле tos.inc:
STRUC idtr_struc

 idt_len dw 0

 idt_low dw 0

 idt_hi db 0

 rsrv db 0

ENDS idtr_struc
3.5 Реализация мультизадачности.
 Я пошел в данном курсовом проекте самым простым способом – реализации мультизадачности через аппаратный таймер компьютера. Реализация более сложных алгоритмов явно тянет на дипломный проект.

 Как известно, таймер вырабатывает прерывание IRQ0 примерно 18,2 раза в секунду. Можно использовать данный факт для переключения между задачами, выделяя каждой квант времени. Я не буду здесь реализовывать механизм приоритетов задач. Все выполняемые задачи имеют равный приоритет.

 Для реализации разделения ресурсов компьютера между задачами и их взаимодействию друг с другом и средой исполнения (можно даже ее назвать операционной системой), я реализовал механизм семафоров.

 В моем случае семафор представляет собой ячейку памяти, отражающая текущее состояние ресурса — свободен или занят.

 Я иду еще на одно упрощение — не создаю здесь таблицы LDT для каждой задачи. Все-таки это не настоящая ОС, а ее так скажем, модель.

 Настоящие многозадачные ОС квантуют время не на уровне программы, а на уровне задачи, так как каждая программа может иметь несколько параллельно выполняющихся потоков. Я не буду здесь организовывать механизм потоков. Это, я думаю, простительно, так как он не реализован полностью даже в Linux. Буду исходить из предпосылки, что одна программа равна одной задаче.
3.5.1 Контекст задачи.

Для хранения контекста неактивной в настоящей момент задачи процессор i80286 использует специальную область памяти, называемую сегментом состояния задачи TSS (Task State Segment). Формат TSS представлен на рис. 4.



Рис. 4. Формат сегмента состояния задачи TSS.

Сегмент TSS адресуется процессором при помощи 16-битного регистра TR (Task Register), содержащего селектор дескриптора TSS, находящегося в глобальной таблице дескрипторов GDT (рис. 5).



Рис. 5. Дескриптор сегмента состояния задачи TSS.

Многозадачная операционная система для каждой задачи должна создавать свой TSS. Перед тем как переключиться на выполнение новой задачи, процессор сохраняет контекст старой задачи в её сегменте TSS.

Сегмент состояния задачи описан в файле tos.h:

typedef struct tss

{

 word link; // поле обратной связи
 word sp0; // указатель стека кольца 0

 word ss0;

 word sp1; // указатель стека кольца 1

 word ss1;

 word sp2; // указатель стека кольца 1

 word ss2;
 word ip; // регистры процессора

 word flags;

 word ax;

 word cx;

 word dx;

 word bx;

 word sp;

 word bp;

 word si;

 word di;

 word es;

 word cs;

 word ss;

 word ds;

 word ldtr;

} tss;
3.5.2 Переключение задач.
 В качестве способа переключения между задачами выберем команду JMP. Неудобство в этом случае представляет то, что если, к примеру, задача 1 вызвала задачу 2, то вернуться к задаче 2 можно только вызвав снова команду JMP и передав ей TSS задачи 1.

Реализация альтернативного метода через команду CALL позволяет создавать механизм вложенных вызовов задач, но выглядит гораздо более трудоемким и требует организации вентилей вызова задач.
Функция переключения задач называется jump_to_task() и реализована в модуле TOSSYST.ASM:
PROC _jump_to_task NEAR

 push bp

 mov bp,sp

 mov ax,[bp+4]; получаем селектор

 ; новой задачи

 mov [new_select],ax; запоминаем его
 jmp [DWORD new_task]; переключаемся на

 ; новую задачу

 pop bp

 ret

ENDP _jump_to_task
Переключение задач происходит в функции Timer_int() из модуля TIMER.C. Эта функция вызывается по прерыванию таймера. Выбор какая задача получит процессор в данный момент решает диспетчер задач, организованный как функция dispatcher(), описанная в модуле TIMER.C. Диспетчер работает по самому простому алгоритму – по кругу переключает процессор между задачами.

3.5.3 Разделение ресурсов.
 Разделение ресурсов для задач организовано в файле SEMAPHOR.C. Сам семафор представляет собой целое 2-х байтное число (int). В принципе можно было обойтись и одним битом, но это требует несколько более сложного кода.

 Так как операционная система у меня получается ну очень крошечная, я думаю будет достаточно предположить, что максимальное количество семафоров в системе будет равно 5. Поэтому в файле SEMAPHOR.C задан статический массив из 5 семафоров:
word semaphore[5];
 Работа задач с семафорами организуется при помощи 3-х функций:
sem_clear() – процедура сброса семафора,

sem_set() – процедура установки семафора,

sem_wait() – процедура ожидания семафора.
 
3.5.4 Задачи.
 Исполняющиеся задачи организованы как просто функции, в модуле TASKS.C.
Задача task1() выполняется единократно, после чего передает управление операционной системе.

Задачи task2() и flipflop_task() работают в бесконечных циклах, рисуя на экране двигающиеся линии, тем самым обозначая свою работу. Задача flipflop_task() работает с меньшим периодом и только тогда, когда установлен семафор 1.

Задача keyb_task() вводит символы с клавиатуры и отображает скан-коды нажатых клавиш, а также состояние переключающих клавиш на экране. Если нажимается клавиша ESC, задача устанавливает семафор номер 0. Работающая параллельно главная задача ожидает установку этого семафора. Как только семафор 0 окажется установлен, главная задача завершает свою работу и программа возвращает процессор в реальный режим, затем передаёт управление MS-DOS.
4. Полные исходные тексты программы.
4.1 Файл TOS.INC. Определение констант и структур для модулей, составленных на языке ассемблера.
CMOS_PORT equ 70h

PORT_6845 equ 63h

COLOR_PORT equ 3d4h

MONO_PORT equ 3b4h

STATUS_PORT equ 64h

SHUT_DOWN equ 0feh

INT_MASK_PORT equ 21h

VIRTUAL_MODE equ 0001

A20_PORT equ 0d1h

A20_ON equ 0dfh

A20_OFF equ 0ddh

EOI equ 20h

MASTER8259A equ 20h

SLAVE8259A equ 0a0h

KBD_PORT_A equ 60h

KBD_PORT_B equ 61h
L_SHIFT equ 0000000000000001b

NL_SHIFT equ 1111111111111110b

R_SHIFT equ 0000000000000010b

NR_SHIFT equ 1111111111111101b
L_CTRL equ 0000000000000100b

NL_CTRL equ 1111111111111011b

R_CTRL equ 0000000000001000b

NR_CTRL equ 1111111111110111b
L_ALT equ 0000000000010000b

NL_ALT equ 1111111111101111b

R_ALT equ 0000000000100000b

NR_ALT equ 1111111111011111b
CAPS_LOCK equ 0000000001000000b

SCR_LOCK equ 0000000010000000b

NUM_LOCK equ 0000000100000000b

INSERT equ 0000001000000000b
STRUC idtr_struc

 idt_len dw 0

 idt_low dw 0

 idt_hi db 0

 rsrv db 0

ENDS idtr_struc
4.2 Файл TOS.H. Определение констант и структур для модулей, составленных на языке Си.
#define word unsigned int
// Селекторы, определённые в GDT
#define CODE_SELECTOR 0x08 // сегменткода

#define DATA_SELECTOR 0x10 // сегментданных
#define TASK_1_SELECTOR 0x18 // задачаTASK_1

#define TASK_2_SELECTOR 0x20 // задачаTASK_2

#define MAIN_TASK_SELECTOR 0x28 // главнаязадача
#define VID_MEM_SELECTOR 0x30 // сегментвидеопамяти

#define IDT_SELECTOR 0x38 // талицаIDT
#define KEYBIN_TASK_SELECTOR 0x40 // задачавводасклавиатуры

#define KEYB_TASK_SELECTOR 0x48 // задачаобработки

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

#define FLIP_TASK_SELECTOR 0x50 // задачаFLIP_TASK
// Байтдоступа
typedef struct

{

 unsigned accessed: 1;

 unsigned read_write: 1;

 unsigned conf_exp: 1;

 unsigned code: 1;

 unsigned xsystem: 1;

 unsigned dpl: 2;

 unsigned present: 1;

}ACCESS;
// Структура дескриптора
typedef struct descriptor

{

 word limit; // Предел (размер сегмента в байтах)

 word base_lo; // Базовый адрес сегмента (младшее слово)

 unsigned char base_hi; // Базовый адрес сегмента (старший байт)

 unsigned char type_dpl; // Поле доступа дескриптора

 unsigned reserved; // Зарезервированные16 бит

}descriptor;
// Структура вентиля вызова, задачи, прерывания,

// исключения
typedef struct gate

{

 word offset;

 word selector;

 unsigned char count;

 unsigned char type_dpl;

 word reserved;

} gate;
// Структура сегмента состояния задачи TSS
typedef struct tss

{

 word link; // поле обратной связи
 word sp0; // указатель стека кольца 0

 word ss0;

 word sp1; // указатель стека кольца 1

 word ss1;

 word sp2; // указатель стека кольца 1

 word ss2;
 word ip; // регистры процессора

 word flags;

 word ax;

 word cx;

 word dx;

 word bx;

 word sp;

 word bp;

 word si;

 word di;

 word es;

 word cs;

 word ss;

 word ds;

 word ldtr;

}tss;
// Размеры сегментов и структур
#define TSS_SIZE (sizeof(tss))

#define DESCRIPTOR_SIZE (sizeof(descriptor))

#define GATE_SIZE (sizeof(gate))

#define IDT_SIZE (sizeof(idt))
// Физические адреса видеопамяти для цветного

// и монохромного видеоадаптеров
#define COLOR_VID_MEM 0xb8000L

#define MONO_VID_MEM 0xb0000L
// Видеоржеимы
#define MONO_MODE 0x07 // монохромный

#define BW_80_MODE 0x02 // монохромный, 80 символов

#define COLOR_80_MODE 0x03 // цветной, 80 символов
// Значения для поля доступа
#define TYPE_CODE_DESCR 0x18

#define TYPE_DATA_DESCR 0x10

#define TYPE_TSS_DESCR 0x01

#define TYPE_CALL_GATE 0x04

#define TYPE_TASK_GATE 0x85

#define TYPE_INTERRUPT_GATE 0x86

#define TYPE_TRAP_GATE 0x87
#define SEG_WRITABLE 0x02

#define SEG_READABLE 0x02

#define SEG_PRESENT_BIT 0x80
// Константы для обработки аппаратных

// прерываний
#define EOI 0x20

#define MASTER8259A 0x20

#define SLAVE8259A 0xa0
// Макро для формирования физического

// адреса из компонент сегменоного адреса

// исмещения
#define MK_LIN_ADDR(seg,off) (((unsigned long)(seg))
// Тип указателя на функцию типа void без параметров
typedef void (func_ptr)(void);
4.3 Файл TOS.H. Основной файл программы.
#include

#include

#include

#include

#include «tos.h»
// --------------------------------

// Определения вызываемых функций

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

void Init_And_Protected_Mode_Entry(void);
void protected_mode(unsigned long gdt_ptr, unsigned int gdt_size,

 word cseg, word dseg);
word load_task_register(word tss_selector);

void real_mode(void);

void jump_to_task(word tss_selector);

void load_idtr(unsigned long idt_ptr, word idt_size);

void Keyb_int(void);

void Timer_int(void);

void Int_30h_Entry(void);
extern word kb_getch(void);

void enable_interrupt(void);
void task1(void);

void task2(void);

void flipflop_task(void);

void keyb_task(void);
void init_tss(tss *t, word cs, word ds,

 unsigned char *sp, func_ptr ip);
void init_gdt_descriptor(descriptor *descr, unsigned long base,

 word limit, unsigned char type);
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); }
    продолжение
--PAGE_BREAK--void iret0(void);

void iret1(void);
// --------------------------------------

// Глобальная таблица дескрипторов GDT

// --------------------------------------
descriptor gdt[11];
// --------------------------------------

// Дескрипторная таблица прерываний IDT

// --------------------------------------
gate idt[] =

{

 // Обработчики исключений

 {(word)&exception_0, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 0

 { (word)&exception_1, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1

 { (word)&exception_2, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 2

 { (word)&exception_3, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 3

 { (word)&exception_4, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 4

 { (word)&exception_5, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 5

 { (word)&exception_6, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 6

 { (word)&exception_7, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 7

 { (word)&exception_8, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 8

 { (word)&exception_9, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 9

 { (word)&exception_A, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // A

 { (word)&exception_B, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // B

 { (word)&exception_C, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // C

 { (word)&exception_D, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // D

 { (word)&exception_E, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // E

 { (word)&exception_F, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // F

 { (word)&exception_10, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 10

 { (word)&exception_11, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 11

 { (word)&exception_12, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 12

 { (word)&exception_13, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 13

 { (word)&exception_14, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 14

 { (word)&exception_15, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 15

 { (word)&exception_16, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 16

 { (word)&exception_17, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 17

 { (word)&exception_18, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 18

 { (word)&exception_19, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 19

 { (word)&exception_1A, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1A

 { (word)&exception_1B, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1B

 { (word)&exception_1C, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1C

 { (word)&exception_1D, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1D

 { (word)&exception_1E, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1E

 { (word)&exception_1F, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1F
 // Обработчик прерываний таймера
 {(word)&Timer_int, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 20
 // { (word)&Keyb_int, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 21
 // Вентиль задачи, запускающейся по прерыванию от клавиатуры
 {0, KEYB_TASK_SELECTOR, 0, TYPE_TASK_GATE, 0 }, // 21
 // Заглушки для остальных аппаратных прерываний
 {(word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 22

 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 23

 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 24

 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 25

 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 26

 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 27

 { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 28

 { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 29

 { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2A

 { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2B

 { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2C

 { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2D

 { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2E

 { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2F
 // Обработчик для программного прерывания, которое

 // используется для ввода с клавиатуры

 {(word)&Int_30h_Entry, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 30
 // Вентиль задачи FLIP_TASK

 {0, FLIP_TASK_SELECTOR, 0, TYPE_TASK_GATE, 0 } // 31

};
// -------------------------------------------

// Сегменты TSS для различных задач

// -------------------------------------------
tss main_tss; // TSS главной задачи

tss task_1_tss; // TSS задачиTASK_1

tss task_2_tss; // TSS задачиTASK_2

tss keyb_task_tss; // TSS задачобслуживания

tss keyb_tss; // клавиатуры

tss flipflop_tss; // TSS задачиFLIP_TASK
// -------------------------------------------

// Стеки для задач

// -------------------------------------------
unsigned char task_1_stack[1024];

unsigned char task_2_stack[1024];

unsigned char keyb_task_stack[1024];

unsigned char keyb_stack[1024];

unsigned char flipflop_stack[1024];
word y=0; // номер текущей строки для вывода на экран
// -------------------------------------------

// Началопрограммы

// -------------------------------------------
extern int getcpu(void);
void main(void)

{

 // Очищаемэкран

 textcolor(BLACK);

 textbackground(LIGHTGRAY);

 clrscr();
 // Входим в защищённый режим процессора

 Init_And_Protected_Mode_Entry();
 // Выводим сообщение

 vi_hello_msg();
 y=3;

 vi_print(0, y++, " Установлен защищённый режим в главной задаче", 0x7f);
 // Загружаем регистр TR селектором главной задачи

 // т.е. задачи main()
 load_task_register(MAIN_TASK_SELECTOR);
 // Переключаемся на задачу TASK_1

 jump_to_task(TASK_1_SELECTOR);
 // После возврата в главную задачу выдаём сообщение

 vi_print(0, y++ ," Вернулись в главную задачу", 0x7f);
 // Запускаем планировщик задач
 vi_print(0, y++ ," Запущен планировщик задач", 0x70);

 enable_interrupt(); // разрешаем прерывание таймера
 // Ожидаем установки семафора с номером 0. После того,

 // как этот семафор окажется установлен, возвращаемся

 // в реальный режим.
 // Семафор 0 устанавливается задачей, обрабатывающей ввод с

 // клавиатуры, которая работает независимо от

 // главной задаче.
 vi_print(18, 24," Для возврата в реальный режим нажмите ESC", 0x70);
 sem_clear(0); // сброс семафора 0

 sem_wait(0); // ожидание установки семафора 0
 // Возврат в реальный режим, стирание экрана и

 // передача управления MS-DOS
 real_mode();

 textcolor(WHITE);

 textbackground(BLACK);

 clrscr();

}
// -----------------------------------

// Функция инициализации сегмента TSS

// -----------------------------------
void init_tss(tss *t, word cs, word ds,

 unsigned char *sp, func_ptr ip)

{

 t->cs = cs; // селектор сегмента кода

 t->ds = ds; // поля ds, es, ss устанавливаем

 t->es = ds; // на сегмент данных

 t->ss = ds;

 t->ip = (word)ip; // указатель команд

 t->sp = (word)sp; // смещение стека

 t->bp = (word)sp;

}
// -------------------------------------------------

// Функция инициализации дескриптора в таблице GDT

// -------------------------------------------------
void init_gdt_descriptor(descriptor *descr,

 unsigned long base,

 word limit,

 unsigned char type)

{

 // Младшее слово базового адреса

 descr->base_lo = (word)base;
 // Старший байт базового адреса

 descr->base_hi = (unsigned char)(base >> 16);
 // Поле доступа дескриптора

 descr->type_dpl = type;
 // Предел

 descr->limit = limit;
 // Зарезервированное поле, должно быть

 // сброшено в 0 всегда (для процессоров 286)

 descr->reserved = 0;

}
// -----------------------------------------------

// Инициализация всех таблиц и вход

// в защищённый режим

// -----------------------------------------------
void Init_And_Protected_Mode_Entry(void)

{

 union REGS r;
 // Инициализируем таблицу GDT, элементы с 1 по 5
 init_gdt_descriptor(&gdt[1], MK_LIN_ADDR(_CS, 0),

 0xffffL, TYPE_CODE_DESCR | SEG_PRESENT_BIT | SEG_READABLE);
 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

#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;
 memset(Buf, ' ', B_SIZE);

 Buf[B_SIZE] = 0;
 Label1.Pos = 0;

 Label1.Dir = 1;

 Buf[Label1.Pos] = '/';
    продолжение
--PAGE_BREAK-- Label2.Pos = B_SIZE;

 Label2.Dir = 0;

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

#include

#include

#include

#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

 current_task++;

 else

 current_task = 0;

 return(task_list[current_task]);

}
4.7 Файл EXCEPT.C. Обработка исключений.
#include

#include

#include

#include

#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

#include

#include

#include

#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

#include

#include

#include

#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

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
 mov al, 0

 mov [ext_scan], al

 jmp intkeyb_exit
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
 pop ax

 sti

 iret

 jmp _Keyb_int

ENDP _Keyb_int
PROC Keyb_PutQ NEAR
 push ax
 cmp ax, 002ah; L_SHIFT down

 jnz @@kb1

 mov ax, [_keyb_status]

 or ax, L_SHIFT

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb1:

 cmp ax, 00aah; L_SHIFT up

 jnz @@kb2

 mov ax, [_keyb_status]

 and ax, NL_SHIFT

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb2:

 cmp ax, 0036h; R_SHIFT down

 jnz @@kb3

 mov ax, [_keyb_status]

 or ax, R_SHIFT

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb3:

 cmp ax, 00b6h; R_SHIFT up

 jnz @@kb4

 mov ax, [_keyb_status]

 and ax, NR_SHIFT

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb4:

 cmp ax, 001dh; L_CTRL down

 jnz @@kb5

 mov ax, [_keyb_status]

 or ax, L_CTRL

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb5:

 cmp ax, 009dh; L_CTRL up

 jnz @@kb6

 mov ax, [_keyb_status]

 and ax, NL_CTRL

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb6:

 cmp ax, 0e01dh; R_CTRL down

 jnz @@kb7

 mov ax, [_keyb_status]

 or ax, R_CTRL

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb7:

 cmp ax, 0e09dh; R_CTRL up

 jnz @@kb8

 mov ax, [_keyb_status]

 and ax, NR_CTRL

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb8:

 cmp ax, 0038h; L_ALT down

 jnz @@kb9

 mov ax, [_keyb_status]

 or ax, L_ALT

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb9:

 cmp ax, 00b8h; L_ALT up

 jnz @@kb10

 mov ax, [_keyb_status]

 and ax, NL_ALT

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb10:

 cmp ax, 0e038h; R_ALT down

 jnz @@kb11

 mov ax, [_keyb_status]

 or ax, R_ALT

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb11:

 cmp ax, 0e0b8h; R_ALT up

 jnz @@kb12

 mov ax, [_keyb_status]

 and ax, NR_ALT

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb12:

 cmp ax, 003ah; CAPS_LOCK up

 jnz @@kb13

 mov ax, [_keyb_status]

 xor ax, CAPS_LOCK

 mov [_keyb_status], ax

 jmp keyb_putq_exit

@@kb13:

 cmp ax, 00bah; CAPS_LOCK down

 jnz @@kb14

 jmp keyb_putq_exit

@@kb14:

 cmp ax, 0046h; SCR_LOCK up

    продолжение
--PAGE_BREAK--


Не сдавайте скачаную работу преподавателю!
Данный реферат Вы можете использовать для подготовки курсовых проектов.

Поделись с друзьями, за репост + 100 мильонов к студенческой карме :

Пишем реферат самостоятельно:
! Как писать рефераты
Практические рекомендации по написанию студенческих рефератов.
! План реферата Краткий список разделов, отражающий структура и порядок работы над будующим рефератом.
! Введение реферата Вводная часть работы, в которой отражается цель и обозначается список задач.
! Заключение реферата В заключении подводятся итоги, описывается была ли достигнута поставленная цель, каковы результаты.
! Оформление рефератов Методические рекомендации по грамотному оформлению работы по ГОСТ.

Читайте также:
Виды рефератов Какими бывают рефераты по своему назначению и структуре.