Консультация № 176893
24.02.2010, 16:41
43.02 руб.
0 0 0
Мультизадачность. Модифицировать программу, приведенную в электронном приложении. Подключить задачу, которая при нажатии клавиши F1 приостанавливает выполнение всех задач и возобновляет их выполнение при нажатии клавиши F2.


Приложение:

;программа демонстрирует одновременное выполнение
;трех простых задач в защищенном режиме. Для ее работы необходи-
;мо наличие процессора i80386 или выше.
; Рассмотрим работу программы по шагам.
; - Инициализация GDT и трех LDT (каждая задача имеет свою
;локальную таблицу). На этом этапе в таблицы заносятся адреса
;используемых сегментов (вся остальная информация занесена при
;трансляции).
; - Сохраняются состояния контроллеров прерываний и адрес
;возврата после останова процессора (в программе используется
;способ возврата в реальный режим с использованием аппаратного
;сброса процессора; BIOS передает управление по адресу содержа-
;щемуся в ячейках 0040:0067h и восстанавливает состояние конт-
;роллеров прерываний ).
; - Перепрограммирование контроллеров прерываний. Аппаратным
;прерываниям IRQ0-IRQ7 соответствуют вектора INT20h-INT27h, а
;IRQ8-IRQ15 - вектора INT30h-INT37h.
; - Размаскируются прерывания от таймера и клавиатуры (IRQ0 и
;IRQ1). Обработчик прерывания таймера - планировщик задач (см.
;ниже). Обработчик прерывания клавиатуры передает управление на
;точку выхода из защищенного режима, т.е. при нажатии любой кла-
;виши программа завершает работу и корректно выходит в DOS.
; - Переход в защищенный режим и настройка сегментных регист-
;ров.
; - В LDTR загружается селектор LDT первой задачи, а в TR -
;селектор TSS первой задачи.
; - Передача управления процедуре PUBLIC_CODE. Она является
;общей для первой и второй задач (т.е. эти задачи выполняют один
;и тот же код, но имеют разные сегменты данных). Таким образом,
;мы запустили Задачу, и теперь при передаче управления другой
;задаче ее состояние полностью сохранится в сегменте TSS.
; - При возникновении прерывания таймера управление получает
;планировщик задач (он описан в IDT как шлюз задачи). Пданиров-
;щик находит в списке задач адрес селектора TSS для следующей
;задачи, очищает ее бит Занятости и, адресуя селектор TSS, пе-
;реключается на новую задачу. Этот процесс повторяется примерно
;18 раз в секунду. О частоте переключения задач можно судить по
;частоте щелчков (для наглядности планировщик перед переключени-
;ем задачи выдает короткий щелчок).

.386P
BIOS_DATA_SEG SEGMENT USE16 AT 0040h
ORG 0067h
io_rom_init Dw ?
io_rom_seg Dw ?
BIOS_DATA_SEG ENDS

CSEG SEGMENT USE16 PARA PUBLIC 'CODE'
ASSUME CS:CSEG
ORG 100h
Start: jmp Main

inta00 Equ 020h
inta01 Equ 021h ;контроллер 8259 #1
intb00 Equ 0A0h
intb01 Equ 0A1h ;контроллер 8259 #2
status_port Equ 064h ;порт сотстояния 8042
key_port_a Equ 060h ;порты коптроллера
key_port_b Equ 061h ;клавиатуры
cmos_port Equ 070h ;порт обращения к cmos памяти

Code_Seg_Access Equ 10011010b ;байт права доступа для
;сегмента кода
Data_Seg_Access Equ 10010011b ;байт права доступа для
;сегмента данных

Task_Seg_State Equ 10001001b ;байт прав доступа для
;свободного TSS 386
Ldt_Seg_Access Equ 10000010b ;байт прав доступа для LDT
Task_Gate Equ 10000101b ;шлюз задачи
Trap_Gate Equ 10000111b ;шлюз спец. прерывания
int_gate Equ 10000110b ;шлюз прерывания
shut_cmd Equ 0FEh ;команда 8042 отключения
;компьютера
;*********************************************************
;* макрокоманда межсегментного перехода *
;* Jump_Offset - смещение *
;* Jump_Segment - сегмент *
;*********************************************************
JUMPFAR MACRO Jump_Offset,Jump_Segment
Db 0eah
Dw (offset Jump_Offset)
Dw Jump_Segment
ENDM
;********************************************************
;* макрокоманда заполнения дескриптора *
;* Seg_Addr - сегмент *
;* Offset_Addr - смещение *
;* Descr - дескриптор *
;********************************************************
FILLDESCR MACRO Seg_Addr,Offset_Addr,Descr
mov dx,Seg_Addr
mov cx,offset Offset_Addr
call _Form_24bit_Address
mov &descr.base_lo_word,dx
mov &descr.base_hi_byte,cl
ENDM

EXCEPT_PROC MACRO Ex_Number
pusha
push Ex_Number
jmp report_exc
ENDM
DESCRIPTOR STRUC
seg_limit Dw 0 ; Длина сегмента
base_lo_word Dw 0 ; Физ. адрес
base_hi_byte Db 0
acces_rights Db 0 ; Байт прав доступа
Db 0
base_top_byte Db 0 ; Физ. адрес
DESCRIPTOR ENDS

IDT_DESCRIPTOR STRUC
int_offset Dw 0 ; Точка входа
int_Selector Dw 0 ; Селектор дескриптора в GDT
Db 0
int_ss Db 0 ; Вид обработчика прерывания
Dw 0
IDT_DESCRIPTOR ENDS

Tss_Stencil386 STRUC ; Шаблон сегмента TSS i386
LINK Dw 0 ; селектор возврата
Dw 0
ESP0 Dd 0 ; значение ESP для стека
; уровня 0
SS0 Dw 0 ; значение SS для стека
Dw 0 ; уровня 0
ESP1 Dd 0 ; значение ESP для стека
; уровня 1
SS1 Dw 0 ; значение SS для стека
Dw 0 ; уровня 1
ESP2 Dd 0 ; значение ESP для стека
; уровня 2
SS2 Dw 0 ; значение SS для стека
Dw 0 ; уровня 2
CR3_ Dd 0 ; значение регистра CR3
EIP_ Dw 0 ; значение регистра EIP
Dw 0
EFLAGS Dd 0 ; значение регистра EFLAGS
EAX_ Dd 0 ; значение регистра EAX
ECX_ Dd 0 ; значение регистра ECX
EDX_ Dd 0 ; значение регистра EDX
EBX_ Dd 0 ; значение регистра EBX
ESP_ Dd 0 ; значение регистра ESP
EBP_ Dd 0 ; значение регистра EBP
ESI_ Dd 0 ; значение регистра ESI
EDI_ Dd 0 ; значение регистра EDI
ES_ Dw 0 ; значение регистра ES
Dw 0
CS_ Dw 0 ; значение регистра CS
Dw 0
SS_ Dw 0 ; значение регистра SS
Dw 0
DS_ Dw 0 ; значение регистра DS
Dw 0
FS_ Dw 0 ; значение регистра FS
Dw 0
GS_ Dw 0 ; значение регистра GS
Dw 0
LDTR_ Dw 0 ; значение регистра LDTR
Dw 0
Dw 0 ; бит 0 - бит ловушки Т
BaseMapIO Dw 104 ; относительный адрес БКВВ
Tss_Stencil386 ENDS

EVEN
; *************** Глобальная дескрипторная таблица ************
Gdt Label Word
Gdt0 Descriptor<>
;*************************************************************
;* описание GDT как сегмента данных
;*************************************************************
Gdt_Desc Equ (($-gdt)/8)*8+0000000000000000b
Gdt_Pointer Descriptor <gdt_leng-1,,,data_seg_access,>
;*************************************************************
;* дескриптор описывающий CSEG как сегмент кода
;*************************************************************
System_Code Equ (($-gdt)/8)*8+0000000000000000b
Gdt2 Descriptor<cseg_leng,,,code_seg_access,>
;*************************************************************
;* дескриптор описывающий CSEG как сегмент данных
;*************************************************************
System_Data Equ (($-gdt)/8)*8+0000000000000000b
Gdt3 Descriptor<cseg_leng,,,data_seg_access,>
;*************************************************************
;* дескриптор описывающий CSEG как сегмент данных
;*************************************************************
System_Stack Equ (($-gdt)/8)*8+0000000000000000b
Gdt4 Descriptor<0fffeh,,,data_seg_access,>
;*************************************************************
;* дескриптор описывающий IDT как сегмент данных
;*************************************************************
Idt_Pointer Descriptor<idt_leng-1,,,data_seg_access>
;*************************************************************
;* дескриптор описывающий видеопамять как сегмент данных
;*************************************************************
Video_Desc Equ (($-gdt)/8)*8+0000000000000000b
GDT5 Descriptor<1000h,8000h,0bh,data_seg_access>
;*************************************************************
;* cелектор дескриптора TSS для планировщика
;*************************************************************
Sheduler_Tss_Selector Equ (($-gdt)/8)*8+0000000000000000b
GDT6 Descriptor<103,,,Task_seg_state>
;*************************************************************
;* cелектор дескриптора TSS для первой задачи
;*************************************************************
Task1_Tss_Selector Equ (($-gdt)/8)*8+0000000000000000b
GDT7 Descriptor<103,,,Task_seg_state>
;*************************************************************
;* cелектор дескриптора TSS для второй задачи
;*************************************************************
Task2_Tss_Selector Equ (($-gdt)/8)*8+0000000000000000b
GDT8 Descriptor<103,,,Task_seg_state>

;*************************************************************
;* cелектор дескриптора TSS для третьей задачи
;*************************************************************
Task3_Tss_Selector Equ (($-gdt)/8)*8+0000000000000000b
GDT100 Descriptor<103,,,Task_seg_state>
;*************************************************************
;* cелектор дескриптора LDT для первой задачи
;*************************************************************
Task1_Ldt_Selector Equ (($-gdt)/8)*8+0000000000000000b
GDT10 Descriptor<Task1_LDT_len,,,ldt_seg_access>
;*************************************************************
;* cелектор дескриптора LDT для второй задачи
;*************************************************************
Task2_Ldt_Selector Equ (($-gdt)/8)*8+0000000000000000b
GDT11 Descriptor<Task2_LDT_len,,,ldt_seg_access>
;*************************************************************
;* cелектор дескриптора LDT для третьей задачи
;*************************************************************
Task3_Ldt_Selector Equ (($-gdt)/8)*8+0000000000000000b
GDT110 Descriptor<Task3_LDT_len,,,ldt_seg_access>
;*************************************************************
;* дескриптор данных для списка задач
;*************************************************************
Task_List_desc Equ (($-gdt)/8)*8+0000000000000000b
GDT12 Descriptor<Task_List_len,,,data_seg_access>
;*************************************************************
;* дескриптор сегмента кода для задач 1 и 2
;*************************************************************
PublicCode_desc Equ (($-gdt)/8)*8+0000000000000000b
GDT14 Descriptor<PublicCode_len,,,code_seg_access>
;*************************************************************
;* дескриптор сегмента кода для задачи 3
;*************************************************************
Task3Code_desc Equ (($-gdt)/8)*8+0000000000000000b
GDT15 Descriptor<Task3code_len,,,code_seg_access>
Gdt_Leng Equ $ - GDT

EVEN
;************** Таблица дескрипторов прерываний ***************
Idt Label Word
;*************************************************************
;* обработчики особых ситуаций
;*************************************************************
ex0 idt_Descriptor<offset ex0_proc,System_Code,0,trap_gate,0>
ex1 idt_Descriptor<offset ex1_proc,System_Code,0,trap_gate,0>
ex2 idt_Descriptor<offset ex2_proc,System_Code,0,int_gate,0>
ex3 idt_Descriptor<offset ex3_proc,System_Code,0,trap_gate,0>
ex4 idt_Descriptor<offset ex4_proc,System_Code,0,trap_gate,0>
ex5 idt_Descriptor<offset ex5_proc,System_Code,0,trap_gate,0>
ex6 idt_Descriptor<offset ex6_proc,System_Code,0,trap_gate,0>
ex7 idt_Descriptor<offset ex7_proc,System_Code,0,trap_gate,0>
ex8 idt_Descriptor<offset ex8_proc,System_Code,0,int_gate,0>
ex9 idt_Descriptor<offset ex9_proc,System_Code,0,int_gate,0>
ex10 idt_Descriptor<offset ex10_proc,System_Code,0,trap_gate,0>
ex11 idt_Descriptor<offset ex11_proc,System_Code,0,trap_gate,0>
ex12 idt_Descriptor<offset ex12_proc,System_Code,0,trap_gate,0>
ex13 idt_Descriptor<offset ex13_proc,System_Code,0,trap_gate,0>
ex14 idt_Descriptor<offset ex14_proc,System_Code,0,trap_gate,0>
ex15 idt_Descriptor<offset ex15_proc,System_Code,0,trap_gate,0>
idt_Descriptor 16 dup(<>)
;*************************************************************
;* прерывание от таймера
;*************************************************************
int32 Idt_Descriptor<0,Sheduler_Tss_Selector,0,Task_gate,0>
;*************************************************************
;* прерывание от клавиатуры
;*************************************************************
int33 Idt_Descriptor<offset keyboard,System_Code,0,int_gate,0>
Idt_Descriptor 6 dup(<offset dummy1,System_Code,0,int_gate,0>)
;**** ********************************************************
;* прерывание аналог INT 10h
;*************************************************************
int40 Idt_Descriptor<offset int40_proc,System_Code,0,int_gate,0>
Idt_Descriptor 7 dup(<>)
Idt_Descriptor 8 dup(<offset dummy2,System_Code,0,int_gate,0>)
Idt_Leng Equ $ - IDT ; Длина IDT

i8259_1 Db ?
i8259_2 Db ?
Task_Counter Dw ? ; Номер текущей задачи
exc_mess Db 'EXCEPTION : $'
exc_mess_len Equ 12
masm51
;*************************************************************
;* заполнение TSS для всех задач
;*************************************************************
;-------------------------------------------------------------
; IP=offset start_shed EFLAGS=00000000h SP=80h
; ES=gdt_desc CS=system_code SS=system_stack
; DS=Task_List_desc FS=system_data
;-------------------------------------------------------------
Sheduler_TSS TSS_stencil386<,,,,,,,,,,,,offset start_shed,,\
00000000h,,,,,80h,,,,gdt_desc,,\
system_code,,system_stack,,\
Task_List_desc,,System_Data,,,,\
>
;--------------------------------------------------------------
; EFLAGS=00000200h SP=80h
; ES=TASK1_data CS=PublicCode_desc SS=Task1_stack
; DS=Task1_data FS=system_data LDTR=Task1_Ldt_selector
;--------------------------------------------------------------
Task1_TSS TSS_stencil386<,,,,,,,,,,,,,,00000200h,,,,,80h,,\
,,Task1_data,,PublicCode_desc,,\
Task1_stack,,Task1_data,,,,\
System_Data,,Task1_Ldt_Selector\
>
;--------------------------------------------------------------
; EFLAGS=00000200h SP=80h
; ES=TASK2_data CS=PublicCode_desc SS=Task2_stack
; DS=Task2_data FS=system_data LDTR=Task2_Ldt_selektor
;--------------------------------------------------------------

Task2_TSS TSS_stencil386<,,,,,,,,,,,,,,00000200h,,,,,80h,,\
,,Task2_data,,PublicCode_desc,,\
Task2_stack,,Task2_data,,,,\
System_Data,,Task2_Ldt_Selector\
>
;--------------------------------------------------------------
; EFLAGS=00000200h SP=80h
; ES=TASK3_data CS=PublicCode_desc SS=Task3_stack
; DS=Task3_data FS=system_data LDTR=Task3_Ldt_selector
;--------------------------------------------------------------
Task3_TSS TSS_stencil386<,,,,,,,,,,,,,,00000200h,,,,,80h,,\
,,Task3_data,,Task3code_desc,,\
Task3_stack,,Task3_data,,,,\
System_Data,,Task3_Ldt_Selector\
>
;*************************************************************
;* локальная дескрипторная таблица для Task1
;*************************************************************
Task1_LDT Label Word
Task1_data Equ (($-Task1_ldt)/8)*8+0000000000000100b
t1LDT1 Descriptor<DataS4Task1_len,,,data_seg_access>
Task1_stack Equ (($-Task1_ldt)/8)*8+0000000000000100b
t1LDT2 Descriptor<80h,,,data_seg_access>
Task1_LDT_len Equ $-Task1_LDT
;*************************************************************
;* локальная дескрипторная таблица для Task2
;*************************************************************
Task2_LDT Label Word
Task2_data Equ (($-Task2_ldt)/8)*8+0000000000000100b
t2LDT1 Descriptor<DataS4Task2,,,data_seg_access>
Task2_stack Equ (($-Task2_ldt)/8)*8+0000000000000100b
t2LDT2 Descriptor<80h,,,data_seg_access>
Task2_LDT_len Equ $-Task2_LDT
;*************************************************************
;* локальная дескрипторная таблица для Task3
;*************************************************************

Task3_LDT Label Word
Task3_data Equ (($-Task3_ldt)/8)*8+0000000000000100b
t3LDT1 Descriptor<DataS4Task3,,,data_seg_access>
Task3_stack Equ (($-Task3_ldt)/8)*8+0000000000000100b
t3LDT2 Descriptor<80h,,,data_seg_access>
Task3_LDT_len Equ $-Task3_LDT

StackTask1 Dw 80h dup(0) ; стек для Task1
StackTask2 Dw 80h dup(0) ; стек для Task2
StackTask3 Dw 80h dup(0) ; стек для Task3

;*************************************************************
;* сегмент данных для Task1
;*************************************************************
DataS4Task1 Label Byte
X Db 20 ;координаты для
Y Db 5 ;вывода на экран
titl Db 'Task1' ;заголовок
ascii_count Dw 3030h ;счетчик
Datas4Task1_len Equ $-DataS4Task1

;*************************************************************
;* сегмент данных для Task2
;*************************************************************
DataS4Task2 Label Byte
Db 50 ; координата X
Db 5 ; координата Y
Db 'Task2' ; заголовок
Dw 3030h ; счетчик
DataS4Task2_len Equ $-DataS4Task2

;*************************************************************
;* сегмент данных для Task3
;*************************************************************
DataS4Task3 Label Byte
Db 1 ; X
Db 10 ; Y
Db 'Демонстрация мультизадачности на примере '
Db 'одновременного выполнения трех задач$'
DataS4Task3_len Equ $-DataS4Task3

;*************************************************************
;* список переключаемых задач
;*************************************************************
Task_List Label Word
Dw 0
Dw Task1_Tss_Selector
Dw 0
Dw Task2_Tss_Selector
Dw 0
Dw Task3_Tss_Selector
Task_List_len Equ $-Task_List

MAIN PROC
Assume ds:Cseg
call Init_Tab ; Инициализация GDT.
call _Set_Protected_Mode ; Переход в защищенный
; режим.
mov ax,Task1_Tss_Selector ; Загрузка селектора TSS
ltr ax ; первой задачи в TR
mov ax,Task1_Ldt_Selector ; Загрузка селектора LDT
lldt ax ; первой задачи в LDTR
mov ax,Task1_Data ; Настройка регистров
mov ds,ax ; DS и ES на область
mov es,ax ; данных первой задачи
mov ax,Task1_Stack ; Настройка на область
mov ss,ax ; стека первой задачи
mov sp,60h
jmp PublicCode ; Ближний переход на
; CS:PublicCode (переклю-
; чение на первую задачу)
;**************************** Планировщик ********************
; Сюда произойдет передача управления при первом прерывании от
; системного таймера.
SHEDULER label byte
start_shed:
xor si,si
mov bx,fs:[task_counter] ; Считаем номер активной на
; момент прерывания задачи
inc bx
cmp bx,3
jne save_counter ; Вычислим номер новой
xor bx,bx ; активной задачи и
save_counter:
mov fs:[task_counter],bx ; сохраним его
shl bx,2
mov di,[bx+2] ; Сброс бита BUSY в байте
add di,5 ; прав доступа дескриптора
and es:byte ptr[di],0fdh ; TSS новой задачи
mov al,20h ; Выдача в PIC команды
out 20h,al ; завершения аппаратного
; прерывания
call Beep ; Короткий щелчок
jmp ds:Dword ptr [bx] ; Переключение на следующую
; задачу
;Сюда будет передаваться управление при прерывании от таймера
jmp short start_shed
Sheduler_len Equ $ - Sheduler

Main_2: mov al,Shut_Cmd ; Команда отключения
out Status_Port,al ; возврат в реальный режим
Main_1: hlt ; Останов процессора
jmp short Main_1

;*** Сюда BIOS передаст управление после сброса процессора ***
Real: mov dx,cs ;настройка сегментных
mov ds,dx ;регистров на адреса
mov ss,dx ;в реальном режиме
call _A20_Close ;закрытие шины А20
mov al,[i8259_1] ;востановление
out inta01,al ;состояния контроллеров
mov al,[i8259_2] ;прерываний
out intb01,al
sti
int 20h ; Выход в DOS
MAIN ENDP
;*************************************************************
;* обработчики особой ситуации просто выдают на экран ее номер
;*************************************************************
ex0_proc : Except_Proc '0'
ex1_proc : Except_Proc '1'
ex2_proc : Except_Proc '2'
ex3_proc : Except_Proc '3'
ex4_proc : Except_Proc '4'
ex5_proc : Except_Proc '5'
ex6_proc : Except_Proc '6'
ex7_proc : Except_Proc '7'
ex8_proc : Except_Proc '8'
ex9_proc : Except_Proc '9'
ex10_proc: Except_Proc 'A'
ex11_proc: Except_Proc 'B'
ex12_proc: Except_Proc 'C'
ex13_proc: Except_Proc 'D'
ex14_proc: Except_Proc 'E'
ex15_proc: Except_Proc 'F'
Report_Exc:
pop ax
push ds ax
mov ax,system_data
mov ds,ax
mov dh,0fh
mov cx,exc_mess_len
mov si,offset exc_mess
mov bh,14h
mov bl,17h
call writexy ; выдача сообщения 'EXEPTION'
pop ax ; извлекаем номер
mov bx,1423h ; особой ситуации
call Print_Char ; и вывод его на экран
pop ds
popa
iret
DUMMY1 PROC ; 'Заглушка' для первого
push ax ; контроллера прерываний
mov al,20h
out 20H,al
pop ax
iret
DUMMY1 ENDP

DUMMY2 PROC
push ax ; 'Заглушка' для второго
mov al,20h ; контроллера прерываний
out 20H,al
out 0A0H,al
pop ax
iret
DUMMY2 ENDP

KEYBOARD PROC ; Обработчик прерывания
jmp main_2 ; клавиатуры
KEYBOARD ENDP

;*************************************************************
;* выдача щелчка
;*************************************************************
BEEP PROC
push ax bx cx
in al,key_port_b
push ax
mov cx,80
beep0: push cx
and al,11111100b
out key_port_b,al
mov cx,60
id_1: loop id_1
or al,00000010b
out key_port_b,al
mov cx,60
id_2: loop id_2
pop cx
loop beep0
pop ax
out key_port_b,al
pop cx bx ax
ret
BEEP ENDP
Columns Db 80d
Rows Db 25d
Text_buf Db ' '
Cur_pos Db 0
Cur_line Db 0

;*************************************************************
;* вывод на экран
;* AX=01 символа в AH
;* AX=02 слова в DX
;*************************************************************
INT40_PROC PROC
push ds
push system_data
pop ds
cmp ah,01
je int_40_01
cmp ah,02
je int_40_02
iret
int_40_01: call print_char
jmp Int_40_Exit
int_40_02: mov ax,dx
call print_word
jmp Int_40_Exit
int_40_Exit: pop ds
iret
INT40_PROC ENDP

;-------------------------------------------------------------
; Вывод на экран символа из AL
; (x,y) = (bl,bh)
;-------------------------------------------------------------
PRINT_CHAR PROC
push di dx es
push video_desc
pop es
mov dx,bx
call set_addr
stosb
pop es dx di
ret
PRINT_CHAR ENDP

;-------------------------------------------------------------
; Преобразование байта в символьный формат
; ВХОД : AL - входной байт
; ВЫХОД : DX - выходное слово
;-------------------------------------------------------------
TABL Db '0123456789ABCDEF'
BYTE_TO_HEX PROC
push cx bx
mov bx, offset TABL
push ax
and al,0fh
xlat
mov dl,al
pop ax
mov cl,4
shr al,cl
xlat
mov dh,al
pop bx cx
ret
BYTE_TO_HEX ENDP
;--------------------------------------------------------------
; Вывод на экран содержимого AX
; (x,y) = (bl,bh)
;--------------------------------------------------------------
PRINT_WORD PROC
assume gs:cseg
push ax bx dx ax
mov cl,8
rol ax,cl
call byte_to_hex
mov [text_buf],dh
mov [text_buf+1],dl
pop ax
call byte_to_hex
mov [text_buf+2],dh
mov [text_buf+3],dl
mov si, offset text_buf
mov dh,70h
mov cx,4
call writexy
pop dx bx ax
ret
PRINT_WORD ENDP
;--------------------------------------------------------------
; Процедура подсчитывает смещение от начала видеопамяти
; Вход : DH - строка
; DL - колонка
; Выход: DI - смещение
; Used : Columns - количество столбцов на экране
;--------------------------------------------------------------
SET_ADDR PROC
push dx ax
xor di,di
mov al,dh
xor ah,ah
mul columns
xor dh,dh
add ax,dx
shl ax,1
mov di,ax
pop ax dx
ret
SET_ADDR ENDP
;-------------------------------------------------------------
;Перепрограммирование контроллера прерываний
; Вход : начальные номера прерываний :
; BH - IRQ0
; BL - IRQ8
;-------------------------------------------------------------
_SET_IRQ PROC
mov ah,bh
mov dx,Inta00
call Si_1
mov ah,bl
mov dx,Intb00
Si_1: mov al,11h
out dx,al
jmp short $+2
mov al,ah
inc dx
out dx,al
jmp short $+2
mov al,4
out dx,al
jmp short $+2
mov al,1
out dx,al
jmp short $+2
mov al,0ffh
out dx,al
dec dx
ret
ENDP
;-------------------------------------------------------------
;Вход: DX содержит номер сегмента
; CX содержит внутрисегментное смещение
;Выход: DX содержит значение BASE_LO_WORD
; CX содержит значение BASE_HI_BYTE
;-------------------------------------------------------------
_FORM_24BIT_ADDRESS PROC
push ax
rol dx,4
mov ax,dx
and dl,0f0h
and ax,0fh
add dx,cx
mov cx,ax
adc cl,ch
pop ax
ret
ENDP
;*************************************************************
;* открытие линии A20
;*************************************************************
_A20_OPEN PROC
mov ah,0dfh
call _Gate_A20
ret
ENDP
;*************************************************************
;* закрытие линии A20
;*************************************************************
_A20_CLOSE PROC
mov ah,0ddh
call _Gate_A20
ret
ENDP

;-------------------------------------------------------------
;Управление прохождением сигнала A20
; ВХОД: (AH)=0DDH A20 всегда равен 0
; (AH)=0DFh адресный разряд A20 открыт
; ВЫХОД: (AL)=0 8042 принял команду
; (AH)=2 сбой
;-------------------------------------------------------------
_GATE_A20 PROC
cli
call _Empty_8042
jnz ga_1
mov al,0d1h
out Status_Port,al
call _Empty_8042
jnz ga_1
mov al,ah
out Key_Port_a,al
call _Empty_8042
ga_1: ret
ENDP

;-------------------------------------------------------------
;Ждать пока буфер 8042 не опустеет
;Вход: нет
;Выход:(AL)=0 буфер пуст
; (AL)=2 не пуст
;-------------------------------------------------------------
_EMPTY_8042 PROC
push cx
sub cx,cx
emp_1: in al,status_port
and al,00000010b
loopnz emp_1
pop cx
ret
ENDP

;*************************************************************
;* инициализация защищенного режима
;*************************************************************
_SET_PROTECTED_MODE PROC
push ax bx
call _A20_Open
in al,inta01 ; сохранение состояния
mov [i8259_1],al ; контроллеров прерывания
in al,intb01
mov [i8259_2],al
mov bx,bios_data_seg
mov es,bx
mov [es:io_rom_seg],cs ;адрес возврата в
mov [es:io_rom_init],offset real ;реальный режим

mov al,08fh ;подготовка к
out cmos_port,al ;сбросу процессора
jmp short $+2
mov al,5
out cmos_port+1,al
cli ;перпрограммирование
mov bh,32d ;конролеров
mov bl,48d ;прерываний
call _Set_Irq

in al,inta01
and al,0fch ; Разрешить прерывания
out inta01,al ; таймера и клавиатуры

lgdt [Qword Ptr Gdt_Pointer] ; загрузка GDTR
lidt [Fword Ptr Idt_Pointer] ; загрузка IDTR
mov eax,cr0
or ax,1
mov cr0,eax ;переход в защищенный режим
jumpfar Spm_2,System_Code ; настройка CS на
; сегмент кода

Spm_2: mov ax,System_Stack ; Инициализация сегментных
mov ss,ax ; регистров
mov ax,System_Data
mov ds,ax
mov es,ax
mov gs,ax
pop bx ax
sti
ret
_SET_PROTECTED_MODE ENDP
;*************************************************************
;* заполнение дескрипторов в GDT базовыми адресами
;*************************************************************
INIT_TAB PROC
FillDescr CS, 0 , Gdt2
FillDescr CS, 0 , Gdt3
FillDescr SS, 0 , Gdt4
FillDescr CS, Gdt , Gdt_Pointer
FillDescr CS, IDT , IDT_POINTER
FillDescr CS, SHEDULER_TSS, GDT6
FillDescr CS, Task1_TSS , GDT7
FillDescr CS, Task2_TSS , GDT8
FillDescr CS, Task3_TSS , GDT100
FillDescr CS, Task1_LDT , GDT10
FillDescr CS, Task2_LDT , GDT11
FillDescr CS, Task3_LDT , GDT110
FillDescr CS, Task_List , GDT12
FillDescr CS, PublicCode , GDT14
FillDescr CS, Task3Code , GDT15
FillDescr CS, StackTask1 , t1LDT2
FillDescr CS, StackTask2 , t2LDT2
FillDescr CS, StackTask3 , t3LDT2
FillDescr CS, DataS4Task1 , t1LDT1
FillDescr CS, DataS4Task2 , t2LDT1
FillDescr CS, DataS4Task3 , t3LDT1
ret
INIT_TAB ENDP
;*************************************************************
;* процедура для задач Task1 и Task2
;*************************************************************
PublicCode Proc
Pc_begin: xor di,di
mov bh,byte ptr[di+1] ;координата Y
mov bl,byte ptr[di] ;координата X
mov si,02 ;заголовок задачи titl
mov cx,5
mov dh,00fh
call writeXY ;вывод заголовка
Pc_1: xor di,di
mov bh,byte ptr[di+1] ; Y
mov bl,byte ptr[di] ; X
add bh,2
inc bl
mov cx,2
mov si,07 ; смещение счетчика
; ascii_count
call writexy ;вывод содержимого счетчика
mov cx,6fffh
call delay ; задержка
mov cx,ds:[07] ; Ascii_count
xor cx,3030h
inc ch ; увеличение счетчика на 1
cmp ch,0ah
jne m2 ;счетчик = 100?
xor ch,ch ;да - начать работу сначала
inc cl ;нет- вывести новое
cmp cl,0ah ;содержимое счетчика
je Pc_3
m2: or cx,3030h
m1: mov ds:[07],cx
jmp Pc_1
Pc_3: jmp Pc_Begin
PublicCode Endp

;-------------------------------------------------------------
; Запись строки в видеопамять
; Вход : DS:SI - адрес строки
; CX - длина строки
; BH - строка
; BL - колонка
; DH - атрибут
; Used : переменная COLUMNS : количество столбцов на экране
;-------------------------------------------------------------
WRITEXY PROC
push di si
push es
push video_desc
pop es
xor di,di
mov dl,gs:[columns]
mov al,bh
mul dl
xor bh,bh
add ax,bx
shl ax,1
mov di,ax
mov ah,dh
w_l: lodsb
stosw
loop w_l
pop es
pop si di
ret
WRITEXY ENDP

;*************************************************************
;* задержка время в CX
;*************************************************************
DELAY PROC
Del_1: pusha
popa
loop Del_1
ret
DELAY ENDP

PublicCode_len Equ $-PublicCode

;*************************************************************
;* код задачи Task3
;*************************************************************
Task3code Proc
xor di,di
mov cx,word ptr [di] ; позиция
mov si,2 ; смещение стороки
T3_1: mov bx,cx
mov al,byte ptr [si]
inc si
cmp al,'$'
je T3_Exit ; вывод сообщения
mov ah,1 ; на экран с помощью
int 40d ; прерывания INT 40h
call T3_Delay ; задержка
inc cl
cmp cl,80
jne t3_2
xor cl,cl
inc ch
T3_2: jmp Short T3_1
xor dx,dx
T3_exit: mov ah,2
mov bx,0e25h
int 40d
inc dx
call T3_Delay
jmp Short T3_Exit
T3_delay: push cx
mov cx,09ffh
T3d_1: pusha
popa
loop t3d_1
pop cx
ret
Task3code Endp
Task3Code_len Equ $-Task3Code

Cseg_Leng Equ $
Cseg Ends
End Start

Обсуждение

Форма ответа