Консультация № 181212
10.12.2010, 20:19
120.61 руб.
0 2 1
Здравствуйте, уважаемые эксперты! Прошу Вас ответить на следующий вопрос: реализовать функцию 6 прерывания int 30h. В приложении модуль на Pascal (используются ассемблерные вставки). Там функция 6 реализована, однако, преподаватель сказал что реализована она "коряво", прошу Вас предложить вариант получше. Искренне благодарю за помощь!

Приложение:
{---Модуль содержит константы, типы переменных, переменные,---}
{------процедуры и функции для работы в защищенном режиме-----}
unit prot; {12-11-09}
interface
const

aa:longint=$123;
hex_tabl:array[0..15] of char='0123456789ABCDEF';
scan:byte=0; { Значение скан-кода нажатой клавиши }
modeVA:byte=0; { Цветное изображение экрана }
{ =1: черно-белое }
first:byte=1; { Первая запись в массив screen }
save_on:byte=0; { Признак перезаписи массива в файл }
{=============Селекторы дескрипторов таблицы GDT==============}

{--------------Селекторы дескрипторов сегментов---------------}

code_sel =$18; { кода программы, }
PROT_sel =$20; { кода модуля PROT, }
stack_sel:word =$28; { стека, }
data_sel :word =$30; { данных, }
real_sel :word =$38;
text_sel :word =$40; { видеопамяти текстового режима, }
mem_sel :word =$48; { расширенной памяти, }
graph_sel:word =$50; { видеопамяти графического режима, }
CONF_sel =$58; { кода модуля CONF, }
USER_sel =$60; { кода модуля USER, }
DEB_sel =$68; { кода модуля DEB, }
data3_sel:word =$70; { данных пользователя. }
{--------------Селекторы дескрипторов TSS задач---------------}

main_sel =8; { MAIN, }
v_main_sel:word=8; { MAIN, }
exc12_sel =$10; { EXC12_TASK, }
keyb_sel =$78; { KEYB_TASK, }
passw_sel =$80; { PASSW_TASK, }
date_sel =$88; { DATE_TASK, }
time_sel =$90; { TIME_TASK, }
color_sel =$98; { COLOR_TASK, }
sound_sel =$A0; { SOUND_TASK, }
duration_sel =$A8; { DURATION_TASK, }
user_check_sel =$B0; { USER_CHECK_TASK, }
vm86_sel =$B8; { SWITCH_VM86_TASK }
stack_TSS_sel
:word =$C0; { и стека TSS }
{-------------Селектор дескриптора шлюза вызова---------------}

gate_sel =$C8;
{------------------Селектор дескриптора LDT-------------------}

LDT_sel:word =$D0;
{====Селектор сегмента данных таблицы LDT задачи PASSW_TASK===}

dataLDT_sel:word=4;
{================Биты и байты доступа сегментов===============}

{-------------------Биты доступа сегментов--------------------}
present =$80; { P=1 : сегмент есть в памяти }
no_sys =$10; { S=1 : сегмент несистемный }
exe =$08; { E=1 : сегмент выполняемый }
down =$04; { ED=1: сегмент расширяется вниз }
wr_ena =$02; { W=1 : разрешена запись в сегмент }
rd_ena =$02; { R=1 : разрешено чтение из сегмента }
{------------------Байт доступа сегмента кода-----------------}

acc_code =present OR no_sys OR exe OR rd_ena;
{----------------Байт доступа сегмента данных-----------------}

acc_data=present OR no_sys OR wr_ena;
{----------------Байт доступа сегмента стека -----------------}

acc_stack=present OR no_sys OR wr_ena OR down;
{------------Байты доступа обработчиков прерывания------------}

acc_int_16=present OR $06; { 16-разрядного }
acc_int =present OR $0E; { 32-разрядного }
{------------Байты доступа обработчиков ловушки---------------}

acc_trap_16=present OR $07; { 16-разрядного }
acc_trap =present OR $0F; { 32-разрядного }
{-------------------Байты доступа TSS-------------------------}

acc_TSS_16=present OR $01; { 16-разрядного }
acc_TSS =present OR $09; { 32-разрядного }
{-----------------Байты доступа шлюзов вызова-----------------}

acc_call_16=present OR $04; { 16-разрядного }
acc_call =present OR $0C; { 32-разрядного }

{------------------Байт доступа шлюза задачи------------------}

acc_task=present OR $05;
{---------------------Байт доступа LDT------------------------}
acc_LDT=present OR 2;
type
{-------Структура дескриптора сегмента таблиц GDT и LDT-------}
t_dt=record
lim_l, { граница сегмента (биты 15-0) }
base_l :word; { базовый адрес сегмента (биты 15-0) }
base_h, { базовый адрес сегмента (биты 23-16) }
acc, { байт доступа }
lim_h, { G,D,0,X и граница сегмента (биты 19-16) }
base_hh:byte { базовый адрес сегмента (биты 31-24) }
end;
{-----------Структура данных регистров GDTR и IDTR------------}

t_dtr=record
lim :word; { граница и }
base :longint; { базовый адрес таблицы }
end;
{------Структура дескриптора таблицы IDT и шлюза вызова-------}

t_idt=record
ofs_l, { смещение (биты 15-0) }
sel :word; { селектор }
par, { число параметров }
acc :byte; { байт доступа }
ofs_h :word { смещение (биты 31-16) }
end;
{=======Структура TSS для МП 80386 и последующих моделей======}

t_tss=record
link, { Селектор возврата }
{---------------------Указатели стека-------------------------}

esp0,ss0, { кольца 0 }
esp1,ss1, { кольца 1 }
esp2,ss2, { кольца 2 }
{------------------Регистры микропроцессора-------------------}

cr3,eip,eflags,eax,ecx,edx,ebx,esp,ebp,esi,edi,
es,cs,ss,ds,fs,gs,ldt:longint;
bit_t, { Бит ловушки задачи }
adr_BKVV:word; { Смещение поля БКВВ }
sys_inf:string; { Поле для системной информации }
{ BK_VM86:array[0..31] of byte;}
BKVV:array[0..31] of byte; { БКВВ }
byte_end:byte; { Байт завершения TSS }
end;
{=======Структура TSS для задачи виртуального режима VM86=====}

t_tssVM=record
link, { Селектор возврата }
{---------------------Указатели стека-------------------------}

esp0,ss0, { кольца 0 }
esp1,ss1, { кольца 1 }
esp2,ss2, { кольца 2 }
{------------------Регистры микропроцессора-------------------}

cr3,eip,eflags,eax,ecx,edx,ebx,esp,ebp,esi,edi,
es,cs,ss,ds,fs,gs,ldtr:longint;
bit_t, { Бит ловушки задачи }
adr_BKVV:word; { Смещение БКВВ }
{-----Битовая карта перенаправления программных прерываний----}
BK_VM86:array[0..31] of byte;
{--------------Битовая карта ввода-вывода (БКВВ)--------------}
BKVV:array[0..1023*8] of byte;
byte_end:byte; { Байт завершения TSS }
end;
var
www:byte;
main_tss, { Сегменты состояния задач MAIN и }
exc12_tss: t_tss; { EXC12_TASK }
exc12_stack:array[0..255] of byte; { стек задачи exc12 }
screen: { Массив для сохранения значений }
array[0..3999] of word; { двух экранов видеопамяти }
offs_ekr:word;
di_,cx_:word; { Переменные для хранения значений }
dh_,dl_:byte; { регистров DI, CX, DH та DL }
gdt:array[0..22] of t_dt; { Таблица GDT }
idt:array[0..255] of t_idt; { Таблица IDT }
gdtr, { Содержимое GDTR }
idtr, { Содержимое IDTR для работы в защищенном режиме }
idtr_r { и для работы в реальном режиме }
:t_dtr;
s:string;
eip_:longint;
ofs_end_prot, { Смещение и селектор меток }
sel_end_prot, { end_prot }
ofs_ret_real,
sel_ret_real:word; { и ret_real }
{----------Переменные для хранения значений регистров---------}
{---------------------реального режима:-----------------------}

real_cs, { CS, }
real_ds, { DS, }
real_ss, { SS, }
real_es, { ES и }
real_sp:word; { SP }
subf, { Номер подфункции }
mode, { Режим работы МП: 0/1 (реальный/защищенный) }
left_shift:byte; { Состояние клавиши Left Shift: }
{ 0/1 (отпущена/нажата) }
{==========Объявление функций и процедур модуля PROT===========}

function hex(p:longint):string;
procedure wait_;
procedure get_time;
procedure init_gdt(sel:word;limit,base:longint;
acc_,byte_6:byte);
procedure init_gdtr(sel:word);
procedure init_idt(i:byte;ofs_:longint;sel_:word;acc_:byte);
procedure init_idtr;

procedure pic(mode:byte);
procedure init_tss (var tss:t_tss; cs,ds,es,ip,sp:word);
procedure set_unr(s_reg:byte;limit,base:longint;byte_6:byte);
procedure save_ekran;
procedure save_scr;
procedure exc_00;
procedure exc_01;
procedure exc_02;
procedure exc_03;
procedure exc_04;
procedure exc_05;
procedure exc_06;
procedure exc_07;
procedure exc_08;
procedure exc_10;
procedure exc_11;
procedure exc12_task;
{ procedure exc_12;}
procedure exc_13;
procedure exc_14;
procedure exc_16;
procedure exc_17;
procedure exc_18;
procedure PIC_1;
procedure PIC_2;
procedure keyb;
procedure int_30h;
procedure int_32h;
procedure int_33h;

implementation
const
s_err:string='Runtime error: исключение ';
s_e:string='error: ';
s_reg:array[0..7] of string=
(' EAX ',' ECX ',' EDX ',' EBX ',
' ESP ',' EBP ',' ESI ',' EDI ');
s_sreg:array[0..6] of string=(' EIP ',' CS ',' SS '
,' ES ',' DS ',' FS ',' GS ');
s_CR0:array[0..1] of string=
('PCN A W NETEMP',
'GDW резерв M P резерв ETSMPE');
s_CR0n:string='CR0:';
s_CR4n:string='CR4:';
s_CR4:array[0..2] of string=
( ' PPMPP TPV',
' Зарезервировано CGCASDSVM',
' EEEEEEDIE');
s_EFLAGSn:string='EFLAGS:';
s_EFLAGS:array[0..2] of string=
(' VV ',
' IIIAVR NIPODITSZ A P C',
' резерв DPFCMF0TOLFFFFFF0F0F1F');
var i:byte;
j:word;

{===========Описание функций и процедур модуля PROT===========}

{-------------Преобразование данных в 16-ричную форму---------}
function hex(p:longint):string;
var s:string;
begin
s:=''; {'h';}
repeat
s:=hex_tabl[p and $f]+s;
p:=p shr 4
until p=0;
hex:=s
end;{hex}
{-----Ожидание нажатия клавиши (в scan - скан-код нажатия)----}
procedure wait_;assembler;
asm
mov scan,0
@w: cmp scan,0
jz @w
test scan,80h
jnz @w
{ db 66h}
{ iret}
end;
procedure get_time;assembler;
asm
nop
mov ax,100h
{ mov bx,2F09h {2F0Bh} {2103h}
int 30h { Установка маркера в точку экрана (33,3) }
mov cx,3 { Три цикла определения и вывода времени }
mov al,4 { в формате чч:мм:сс }
@2:push cx
push ax
out 70h,al
in al,71h { В AL - значение часов/минут/секунд }
mov cl,1dh { Видео-атрибут }
mov dl,al
sub di,2
mov ax,300h
int 30h { Вывод на экран значения часов/минут/секунд }
pop ax
pop cx
cmp cx,1 { В третьем цикле не надо выводить ":" }
jz @1
push cx
push ax
mov ah,2
sub di,2
mov cl,1dh
mov dl,3ah
int 30h { Вывод на экран символа ":" }
pop ax
sub al,2
pop cx
loop @2
@1:
db 66h { Использовался 32-разрядный вызов процедуры; }
{ команды RETF нет, так как она подставляется транслятором }
end;
{------------Формирование дескриптора таблицы GDT-------------}
procedure init_gdt(sel:word;limit,base:longint;acc_,
byte_6:byte);
begin
with gdt[sel shr 3] do begin
if limit>$FFFFF then begin
limit:=limit shr 12;
byte_6:=byte_6 or $80;
end;
lim_l :=limit;
base_l :=base;
base_h :=base shr 16;
acc :=acc_;
lim_h :=limit shr 16 or byte_6;
base_hh:=base shr 24;
end
end; {init_dt}
{------Формирование данных регистра GDTR и его загрузка-------}
procedure init_gdtr(sel:word);
begin
gdtr.lim:=sel+7;
gdtr.base:=longint(seg(gdt)) shl 4+ofs(gdt);
asm
db 0fh,01h,16h { LGDT gdtr: }
dw gdtr { загрузка атрибутов GDT в GDTR из gdtr }
end
end; {init_gdtr}
{------------Формирование дескриптора таблицы IDT-------------}
procedure init_idt(i:byte;ofs_:longint;sel_:word;acc_:byte);
begin
with idt[i] do begin
ofs_l:=ofs_;
sel:=sel_;
par:=0;
acc:=acc_;
ofs_h:=ofs_ shr 16;
end
end; {init_idt}
{-----------Запрет внешних аппаратных прерываний,-------------}
{-----сохрание содержимого регистра IDTR реального режима,----}
{-------формирование данных регистра IDTR и его загрузка------}
{---------------для работы в защищенном режиме----------------}
procedure init_idtr;
begin
asm
cli { Запрет маскируемых и }
mov al,80h { немаскируемых }
out 70h,al { прерываний }
db 0fh,1,0eh { SIDT idtr_r: }
dw idtr_r { Сохранение атрибутов IDT в idtr_r }
end;
idtr.lim:=sizeof(idt)-1;
idtr.base:=longint(seg(idt)) shl 4+ofs(idt);
asm
db 0fh,01h,1eh { LIDT idtr: }
dw idtr { Загрузка атрибутов IDT в IDTR из idtr }
end;
end;{init_idtr}
{------------Программирование ведущего и ведомого-------------}
{--------------контроллеров прерываний для работы-------------}
{------в реальном (mode=0) и защищенном (mode=1) режимах------}
procedure pic(mode:byte);
var k1,k2:byte;
begin
if mode=0 then begin k1:=8; k2:=$70 end
else begin k1:=$20; k2:=$28 end;
port[$20]:=$11; { 1-й ПКП: ICW1 }
port[$21]:=k1; { 1-й ПКП: ICW2 }
port[$21]:=4; { 1-й ПКП: ICW3 }
port[$21]:=1; { 1-й ПКП: ICW4 }
port[$a0]:=$11; { 2-й ПКП: ICW1 }
port[$a1]:=k2; { 2-й ПКП: ICW2 }
port[$a1]:=2; { 2-й ПКП: ICW3 }
port[$a1]:=1; { 2-й ПКП: ICW4 }
end;{pic}
{------------Формирование TSS для 32-разрядных МП-------------}
procedure init_tss(var tss:t_tss; cs,ds,es,ip,sp:word);
begin
tss.cs:=cs;
tss.ds:=ds;
tss.es:=es;
tss.ss:=ds;
tss.eip:=ip;
tss.esp:=sp;
tss.eflags:=$200;
tss.bit_t:=0;
tss.byte_end:=$ff
end;{init_tss}

{---------------Для работы в режиме "Unreal"------------------}
{---для заданного сегментного регистра указываются параметры--}
{--связанного с ним сегмента памяти, которые могут отличаться-}
{----от параметров реального режима: граница сегмента и его---}
{----базовый адрес могут быть увеличены до величины 4 ГБ-1----}
procedure set_unr(s_reg:byte;limit,base:longint;byte_6:byte);
begin
{------------------Формирование таблицы GDT-------------------}

{ нуль-дескриптор: }
init_gdt(0,0,0,0,0);
{ дескриптор сегмента данных: }

init_gdt(8,limit,base,acc_data,byte_6);
{----------Создание данных и загрузка регистра GDTR-----------}
init_gdtr(8);
{---------------Запрет аппаратных прерываний------------------}
asm
cli { маскируемых }
mov al,80h
out 70h,al { и немаскируемых }
{-----------------Переход в защищенный режим------------------}

db 0fh,20h,0c0h { MOV EAX,CR0 }
or al,1
db 0fh,22h,0c0h { MOV CR0,EAX }
{-------Загрузка селектора в заданный сегментный регистр------}
mov ax,8 { Селектор сегмента }
cmp s_reg,0 { ES? }
jnz @3
mov es,ax { MOV ES,AX }
jmp @k
@3:cmp s_reg,3 { DS? }
jnz @4
mov ds,ax { MOV DS,AX }
jmp @k
@4:cmp s_reg,4 { FS? }
jnz @5
db 8eh,0e0h { MOV FS,AX }
jmp @k
@5:cmp s_reg,5 { GS? }
jnz @k
db 8eh,0e8h { MOV GS,AX }
{-----------------Возврат в реальный режим--------------------}

@k:db 0fh,20h,0c0h { MOV EAX,CR0 }
and al,not 1
db 0fh,22h,0c0h { MOV CR0,EAX }
{--------------------Разрешение прерываний-------------------}
sti { маскируемых }
mov al,0Dh
out 70h,al { и немаскируемых }
end;
end;{set_unr}

{---------Сохранение изображения экрана в массиве screen-------}
procedure save_ekran;assembler;
asm
cmp scan,0E0h { Если два первых скан-кода клавиши }
mov scan,al
jnz @3 { являються кодами E0h и 2Ah, т.е. }
cmp al,2Ah { нажата клавиша "Print Screen", то }
jnz @3
mov save_on,1 { установить признак сохранения екрана }
cmp first,1
jz @1
add offs_ekr,2400 { Изменить смещение массива и }
mov ax,700h { сохранить помощью функции 7 INT 30h }
mov bx,0 { текущее содержимое области экрана }
mov dx,4F18h { с координатами: (0,0) и (79,24), }
int 30h { т.е. весь экран в массиве screen }
jmp @end
@1:
mov first,0
@2: jmp @end
@3:
cmp al,0E0h { Если скан-код нажатой клавиши равен E0h }
jnz @end
cmp first,1 { и сброшен признак сохранения экрана - }
jnz @end
mov ax,700h { с помощью функции 7 INT 30h сохранить }
mov bx,0 { текущее содержимое области экрана }
mov dx,4F18h
int 30h
cmp save_on,0 { Признак сохранения екрана установлен? }
jnz @1 { Если нет - }
mov save_on,1 { установить признак сохранения екрана }
add offs_ekr,2400 { и изменить смещение массива }
jmp @end { для сохранения 2-го экрана, }
(*
@1: { если да - }
mov ax,700h { с помощью функции 7 INT 30h сохранить }
mov bx,0 { текущее содержимое области экрана }
mov dx,4F18h { с координатами: (0,0) и (79,24), }
int 30h { т.е. весь экран в массиве screen }
jmp @end

@2:
cmp al,0E0h { Если скан-код нажатой клавиши равен E0h }
jnz @end
cmp save_on,0 { и сброшен признак сохранения экрана - }
jnz @end
mov ax,700h { с помощью функции 7 INT 30h сохранить }
mov bx,0 { текущее содержимое области экрана }
mov dx,4F18h
int 30h *)
@end:
end;{save_ekran}

{-----Сохранение значения массива ekran на магнитном диске----}
procedure save_scr;
const s_arr:string='Введите имя массива для сохранения экрана';
var
save_scr_:string;
ekr:file of word;
k:integer;
begin
if boolean(save_on) then begin
{ asm
mov ax,0b800h
mov es,ax
mov ax,102h
mov cl,70h
mov bx,16h
int 30h
end; }
writeln('Введите имя массива для сохранения экрана');
readln(save_scr_);
if save_scr_<>'' then begin
save_scr_:='EKRAN/'+save_scr_;
assign(ekr,save_scr_);
rewrite(ekr);
for k:=0 to 3999 do write(ekr,screen[k]);
end;
end;
end;

{----------Обработчики исключений 0-8, 10-14, 16-18-----------}
{---(процедуры exc_00-exc_08, exc_10-exc_14, exc_116-exc_18)--}
{-------выводят на экран номер исключения, адрес команды------}
{--------------и завершают выполнение программы---------------}

procedure exc_00;assembler; { Обработчик исключения 0: }
asm { деление на 0 }
mov ah,1 { Функция 1 прерывания 32h: }
mov dx,100h { вывод на экран номера исключения (0) }
int 32h { и адреса команды }
db 0ffh,2eh { Межсегментный переход }
dw ofs_end_prot { на метку end_prot: }
end;
procedure exc_01;assembler; { Обработчик исключения 1: }
asm { - при TF=1 регистра EFLAGS; }
mov ah,1 { - при T=1 сегмента TSS; }
mov dx,101h { - по контрольным точкам программы; }
int 32h { - по контрольным точкам данных; }
db 0ffh,2eh { - по контрольным точкам УВВ; }
dw ofs_end_prot { - при защите регистров отладки }
end;
procedure exc_02;assembler; { Обработчик исключения 2: }
asm { немаскируемое прерывание (NMI) }
mov ah,1
mov dx,102h
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure exc_03;assembler; { Обработчик исключения 3: }
asm { по команде INT 3 }
mov ah,1
mov dx,103h
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure exc_04;assembler; { Обработчик исключения 4: }
asm { по команде INTO при OF=1 }
mov ah,1
mov dx,104h
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure exc_05;assembler; { Обработчик исключения 5: }
asm { выход за пределы диапазона }
mov ah,1 { при выполнении команды BOUND }
mov dx,105h
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure exc_06;assembler; { Обработчик исключения 6: }
asm { неверный код операции }
mov ah,1 { или адресации }
mov dx,106h
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure exc_07;assembler; { Обработчик исключения 7: }
asm { недоступно устройство FPU }
mov ah,1
mov dx,107h
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure exc_08;assembler; { Обработчик исключения 8: }
asm { двойная ошибка }
mov ah,1
mov dx,108h
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure exc_10;assembler; { Обработчик исключения 10: }
asm { недоступен TSS }
mov ah,1
mov dx,10Ah
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure exc_11;assembler; { Обработчик исключения 11: }
asm { недоступен сегмент }
mov ah,1
mov dx,10Bh
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
{--Задача EXC12_TASK: обработчик исключения 12: ошибка стека--}
procedure exc12_task;assembler;
asm
@12:
mov ah,1
mov dx,0Ch
int 32h
mov scan,0
@w:cmp scan,0 { Задержка до нажатия любой клавиши }
jz @w
test scan,80h
jnz @w
{----------Анализ бита P дескриптора сегмента стека:----------}
{----------------если сброшен - восстановить------------------}

mov bx,offset main_tss
mov bx,[bx+80] { Из TSS читается селектор стека }
test byte ptr [offset gdt+bx+5],80h
jnz @1
or byte ptr [offset gdt+bx+5],80h
jmp @end
{------Если бит P не сброшен - изменить указатель стека-------}
@1:
mov bx,offset main_tss
mov ax,0fffh { Значение 0FFFh }
mov [bx+56],ax { заносится в поле ESP сегмента TSS }
{--------------и завершить выполнение программы---------------}

mov ax,ofs_end_prot { Смещение метки end_prot }
mov [bx+32],ax { заносится в поле EIP сегмента TSS }
@end:
db 66h
iret
jmp @12
end;{exc12_task}
procedure exc_13;assembler; { Обработчик исключения 13: }
asm { нарушение общей защиты }
{---Анализ вызова обработчика прерывания 13 для определения,--}
{--------это исключение 13 или возврат из режима VM8086-------}
push ax
push ds
mov ax,30h
mov ds,ax
mov bp,sp
mov ax, [bp+12]
cmp ax,real_cs { Если селектор CS в стеке является }
pop ds { базовым адресом реального режима - }
pop ax
jnz @err
db 0eah { тогда: переключение на задачу MAIN }
dw 0 { для выхода из режима VM8086, }
dw main_sel
@err:
mov ah,1 { иначе: вывод на экран сообщения о том, }
mov dx,10Dh { что возникло исключение 13 }
int 32h
db 0ffh,2eh { и завершение программы }
dw ofs_end_prot
end;
procedure exc_14;assembler; { Обработчик исключения 14: }
asm { недоступна страница }
mov ah,1
mov dx,10Eh
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure exc_16;assembler; { Обработчик исключения 16: }
asm { ошибка FPU при NE=1 регистра CR0 }
mov ah,1
mov dx,110h
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure exc_17;assembler; { Обработчик исключения 17: }
asm { ошибка выравнивания данных }
mov ah,1
mov dx,111h
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure exc_18;assembler; { Обработчик исключения 18: }
asm { ошибка функционирования узлов МП и МПС }
mov ah,1
mov dx,112h
int 32h
db 0ffh,2eh
dw ofs_end_prot
end;
procedure keyb;assembler; { Обработчик прерываний }
asm { от клавиатуры: }
pusha
mov al,20h
out 20h,al
in al,60h { Чтение скан-кода нажатия/отжатия клавиши }
cmp modeVA,1
jz @save
mov scan,al
jmp @scan
{---------С помощью процедуры save_ekran определяется,--------}
{-------------нажата ли клавиша "Print screen":---------------}
{--если да - сохранить изображение экрана в переменной screen-}

@save:
db 9ah { 16-разрядный вызов }
dw offset save_ekran { процедуры save_ekran }
dw PROT_sel
{----------Анализ скан-кодов нажатых и отжатых клавиш---------}

@scan:
cmp scan,2Ah { Нажата клавиша "левый Shift"? }
jnz @k1 { Если да - }
mov left_shift,1 { установить признак нажатия клавиши }
jmp @end
@k1:
cmp scan,0AAh { Отжата клавиша "левый Shift"? }
jnz @k2 { Если да - }
mov left_shift,0 { сбросить признак нажатия клавиши }
jmp @end
@k2:
cmp left_shift,1 { Если нажаты клавиши "левый Shift" }
jnz @end
cmp scan,0C5h { и "Pause/Break", тогда выполняется }
jnz @end
db 0ffh,2eh { межсегментный переход на метку end_prot }
dw ofs_end_prot { для срочного завершения программы }
@end:popa
db 66h
iret
end;{keyb}
{---------Обработчики-заглушки аппаратных прерываний,---------}
{----------поступающих на 1-й контроллер прерываний-----------}

procedure PIC_1;assembler;
asm
push ax
mov al,20h
out 20h,al { Сброс бита регистра ISR 1-го ПКП }
pop ax
db 66h
iret
end;
{---------Обработчики-заглушки аппаратных прерываний,---------}
{----------поступающих на 2-й контроллер прерываний-----------}

procedure PIC_2;assembler;
asm
push ax
mov al,20h { Сброс бита регистра ISR }
out 20h,al { 1-го и }
out 0a0h,al { и 2-го контроллеров прерываний }
pop ax
db 66h
iret
end;
{-----------Обработчик программного прерывания 30h------------}
{------выполняет вывод данных на экран в текстовом режиме-----}
{------------Переменная modeVA задает режим вывода:-----------}
{-------modeVA=0: цвет символов и их фона задается------------}
{---------------как видеоатрибут в регистре CL;---------------}
{-------modeVA=1: символы черного цвета на белом фоне,--------}
{-----------------общий фон экрана - серый--------------------}

procedure int_30h;assembler;
{ Назначение регистров:}
{ AH - номер функции }
{ Al - номер подфункции }
{ BL - номер строки экрана }
{ BH - номер столбца экрана }
{ DL/DX/EDX - значение данных }
{ (байта/слова/двойного слова) }
{ CL - видеоатрибут символов }
{ SI - смещение строки символов }
asm { DI - смещение ячейки видеопамяти }

cmp ah,0
jz @f0
cmp ah,1
jz @f1
cmp ah,2
jz @f2
cmp ah,3
jz @f3
cmp ah,4
jz @f4
cmp ah,5
jz @f5
cmp ah,6
jz @f6
cmp ah,7
jz @f7
cmp ah,8
jz @f8
jmp @end
{-----Функция 0: установка назначения бита 7 видеоатрибута----}
{----------------(с сохранением всех регистров)---------------}
{ AL=0 - режим мерцания символа }
@f0: { AL=1 - режим 16-битного фона }
{ cmp modeVA,0
jnz @end }
push ax
push dx
mov ah,al
mov dx,3DAh
in al,dx { Разрешить запись адреса (индекса) регистра }
mov al,10h
mov dx,3c0h { Записать адрес (10h) }
out dx,al { регистра управления режимом }
cmp ah,0
jnz @01
mov al,8 { режим с мерщанием символа }
jmp @02
@01:
mov al,0 { режим 16-цветного фона }
@02:
mov dx,3c0h
out dx,al { Задать указанный режим }
mov al,20h
mov dx,3c0h
out dx,al { Разрешить вывод на экран }
pop dx
pop ax
jmp @end
{-----Функция 1: установка маркера в заданную точку экрана----}
{-----------(с сохранением всех регистров, кроме DI)----------}
{ AL=0 - без изменения экрана }
{ AL=1 - с очисткой до конца строки }
{ AL=2 - с очисткой до конца экрана }
{ (в CL - цвет фона экрана) }
@f1: { AL=3 - c подсветкой маркера }
push ax
push cx
push dx
push bx
push si
mov subf,al { Сохранение номера подфункции }
{------------------Установка маркера на экране----------------}
mov al,bl
mov dl,80
mul dl
shr bx,8
add ax,bx
mov dx,ax { В DX - номер места маркера }
shl ax,1
mov di,ax
mov si,ax { В DI,SI - адрес маркера }
cmp subf,0
jz @pop
cmp subf,3
jz @3
{-----------Определение числа стираемых символов--------------}
mov ax,dx
mov dh,0
mov dl,80
sub dl,bl { В DL - число стираемых символов в строке }
cmp subf,1
jz @clear
cmp subf,2
jnz @pop
mov dx,ax
mov ax,2000
sub ax,dx
mov dx,ax { В DX - число стираемых символов на экране }
{---------------------Очистка экрана--------------------------}
@clear:
mov al,20h { ASCII-код пробела }
cmp modeVA,0
jz @12
mov ah,70h { Серый фон }
jmp @121
@12:
mov ah,cl { Фон задается регистром CL }
@121:
mov cx,dx
@wxy_:
stosw
loop @wxy_
mov di,si
jmp @pop
{-----------------Установка подсветки маркера-----------------}
@3:
mov dx,3d4h
mov al,0fh
out dx,al
mov dx,3d5h
mov al,bl
out dx,al
mov dx,3d4h
mov al,0eh
out dx,al
mov dx,3d5h
mov al,bh
out dx,al
@pop:
pop si
pop bx
pop dx
pop cx
pop ax
jmp @end
{---------------Функция 2: вывод символа на экран-------------}
@f2:
mov al,dl
cmp modeVA,0
jz @21
mov ah,0f0h
jmp @22
@21:
mov ah,cl
@22:
stosw
add di,2
jmp @end
{------Функция 3: вывод данных на экран в 16-ричной форме-----}
{ AL=0 - вывод байта }
{ AL=1 - вывод слова }
@f3: { AL=2 - вывод двойного слова }
lea bx,hex_tabl
cmp modeVA,0
jz @31
mov ah,0f0h
jmp @32
@31:
mov ah,cl
@32:
cmp al,0
jz @8
cmp al,1
jz @16
add di,14
mov cx,8
jmp @1
@8:add di,2
mov cx,2
jmp @1
@16:add di,6
mov cx,4
@1:push cx
@lp:mov al,dl
and al,0fh
db 66h
shr dx,4
xlat
stosw
sub di,4
loop @lp
pop cx
shl cx,1
add cx,4 {2}
add di,cx
jmp @end
{----------Функция 4: вывод строки символов на экран----------}
@f4:
cmp modeVA,0
jz @41
mov ah,0f0h
jmp @42
@41:
mov ah,cl
@42:
mov bx,si
inc si
mov cl,[bx]
cmp cl,0
jz @end
xor ch,ch
@wxy:
lodsb
stosw
loop @wxy
jmp @end
{-------Функция 5: вывод данных на экран в двоичной форме-----}
{ AL=0 - вывод байта }
{ AL=1 - вывод слова }
@f5: { AL=2 - вывод двойного слова }
lea bx,hex_tabl
cmp modeVA,0
jz @51
mov ah,0f0h
jmp @52
@51:
mov ah,cl
@52:
cmp al,0
jz @8_2
cmp al,1
jz @16_2
mov cx,8
jmp @2
@8_2:
mov cx,2
jmp @2
@16_2:
mov cx,4
@2:push cx
push cx
shl cx,3
sub cx,2
add di,cx { di+cx*8-2 }
pop cx
@lp_1:push cx
xor ah,8
mov cx,4
@lp_2:mov al,dl
and al,01h
db 66h
shr dx,1
xlat
stosw
sub di,4
loop @lp_2
pop cx
loop @lp_1
pop cx
shl cx,3
add cx,2 { di+cx*8+2 }
add di,cx
jmp @end
{-----Функция 6: вывод данных на экран в десятичной форме-----}
{ AL=0 - вывод байта }
{ AL=1 - вывод слова }
@f6: { AL=2 - вывод двойного слова }
push bp
push cx
mov bp, sp
db 66h
mov cx, 0CA00h { Заносим 1 000 000 000 }
dw 3B9Ah { в ECX }
lea bx, hex_tabl
cmp al,1
jne @6_1
db 66h
and dx, 0FFFFh
dw 0000h
db 66h
mov cx, 2710h { Заносим 10 000 }
dw 0000h { в ECX }
@6_1: cmp al,0
jne @6_b
db 66h
and dx, 000FFh
dw 0000h
db 66h
mov cx, 0064h { Заносим 100 }
dw 0000h { в ECX }
jmp @6_b
@osn: dw 0Ah
dw 0h
@6_b: {add di,2}
db 66h
mov ax, dx
@procsym:
db 66h
xor dx, dx
db 66h
div cx
mov ah, [ss:bp]
xlat
stosw
db 66h
mov ax,cx
db 66h
mov cx,dx
db 66h
xor dx, dx
db 66h
div word [@osn]
db 66h
xchg ax, cx
cmp cx, 0
jne @procsym
db 66h
mov dx,bx
pop cx
pop bp
jmp @end
{-----Функция 7: Работа с прямоугольной областью экрана,------}
{----------------ограниченной координатами:-------------------}
{--------(X1,Y1) - левый верхний угол области экрана;---------}
{--------(X2,Y2) - правый нижний угол области экрана----------}
@f7: { AL=0: сохранить в памяти }
push ax { AL=1: восстановить на экране }
push bx { BX - (X1,Y1) }
push dx { DX - (X2,Y2) }
mov al,bl
mov dl,80
mul dl
shr bx,8
add ax,bx
shl ax,1
mov di,ax { В DI - адрес левого верхнего угла области }
mov si,di
xor cx,cx
pop dx
pop bx
pop ax
sub dh,bh { X2-X1 }
inc dh
mov dh_,dh
sub dl,bl { Y2-Y1 }
inc dl
mov dl_,dl
mov cl,dl
mov cx_,cx
mov bx,offset screen
add bx,offs_ekr
@l2:
push cx
xor cx,cx
mov cl,dh
@l1:
push cx
cmp al,0
push ax
jz @sto
mov ax,[bx]
mov es:[di],ax
jmp @m
@sto:
mov ax,es:[di]
mov [bx],ax
@m:
pop ax
add di,2
add bx,2
pop cx
loop @l1
add si,160
mov di,si
pop cx
loop @l2
jmp @end
{---Функция 8: вывод строки из массива символов на экран-----}
@f8:
mov ah,cl
inc si
mov cx,dx
@wxy8:
lodsb
stosw
loop @wxy8
jmp @end
@end:iret
end;
{-----------Обработчик программного прерывания 31h------------}
{----------Вывод данных на экран в графическом режиме---------}

procedure int_31h;assembler;
{--------------Функция 1: вывод на экран пиксела--------------}
{ BX - номер столбца (x) }
{ CX - номер строки (y) }
{ EDX - 32-разрядный цвет пикселя (0RGB) }
asm
mov ax,640 { Число пикселей в строке }
db 66h
and bx,0FFFFh
dw 0
db 66h
push dx
mul cx { Произведение - в DX:AX }
db 66h
shl dx,16
mov dx,ax { Произведение - в EDX }
db 66h
add dx,bx
db 66h
shl dx,2
db 66h
mov di,dx { В DI - адрес пикселя в видеопамяти }
db 66h
pop dx
{ db 66h}
{ mov dx,0FF00h
dw 0h }
db 66h,67h,26h,89h,17h { MOV ES:[EDI],EDX }
db 66h
iret
end;


{------------Обработчик программного прерывания 32h-----------}
{-------Вывод на экран служебной и отладочной информации------}

procedure int_32h;assembler;
{ Назначение регистров: }
{ AH - номер функции }
{ BH/BL - номер столбца/строки экрана }
{ Для функции 1 координаты курсора заданы по умолчанию: }
{ BL=17, BH=1 }
asm
{------Задание в переменной mode режима работы процессора-----}
db 66h
push ax
db 0fh,20h,0c0h { MOV EAX,CR0 }
test al,1 { Анализ режима работы МП: }
jnz @pm
mov mode,0 { реальный режим }
jmp @beg
@pm:mov mode,1 { защищенный режим }
@beg:
{ mov mode,0}
db 66h
pop ax
cmp ah,1
jnz @mark
{----Задание для функции 1 координат маркера по умолчанию:----}
mov bl,9 {17 { строка 17, }
mov bh,1 { столбец 1 }
push dx
push dx
@mark:pusha
mov ax,101h { Установка маркера в точку экрана с }
mov cl,0
int 30h { координатами, заданными в BH/BL }
mov bp,sp { с очисткой строки }
mov [bp],di
popa
cmp ah,1
jz @f1
cmp ah,2
jz @f2
cmp ah,3
jz @f3
cmp ah,4
jz @f4
cmp ah,5
jz @f5
cmp ah,6
jz @f6
cmp ah,7
jz @f7
jmp @end

{-------------------------Функция 1:--------------------------}
{----Вывод на экран сообщения "Runtime error: исключение",----}
{---номера исключения и (при необходимости) адреса команды,---}
{---при выполнении которой (при отказе) или после выполнения--}
{------------которой (при ловушке) возникло исключение--------}
@f1: { Назначение регистров:}
{ DL - номер исключения }
{ DH - 1/0: с выводом/ }
{ без вывода адреса команды }
mov ah,4 { Функция 4: }
mov si, offset s_err
mov cl,1bh
int 30h { вывод на экран строки s_err }
mov ax,300h { Функция 3, подфункция 0: }
mov cl,1ch
pop dx
int 30h { вывод на экран номера исключения }
pop dx
mov bp,sp
{------------Анализ номера возникшего исключения:-------------}
{--если он равен одному из номеров 0,1,2,3,4,5,6,7,16 или 18,-}
{----------то код ошибки в стек не заносился и поэтому--------}
{---------------очистки стека делать не нужно-----------------}
cmp dl,0
jz @3
cmp dl,1
jz @3
cmp dl,2
jz @3
cmp dl,3
jz @3
cmp dl,4
jz @3
cmp dl,5
jz @3
cmp dl,6
jz @3
cmp dl,7
jz @3
cmp dl,16
jz @3
cmp dl,18
jz @3
{-----------------Очистка стека от кода ошибки----------------}
db 66h
mov ax,[bp+8]
db 66h
mov [bp+12],ax
db 66h
mov ax,[bp+4]
db 66h
mov [bp+8],ax
db 66h
mov ax,[bp]
db 66h
mov [bp+4],ax
add sp,4
mov bp,sp

{----Если при обработке возникшего исключения нужен анализ----}
{------кода ошибки, то вместо вызова прерывания INT 32h-------}
{-----необходимо использовать собственные средства анализа,---}
{----например, как это сделано в обработчике исключения 11----}
{-----------------программы P_INT (раздел 5)------------------}
@3:

cmp dh,0
jz @end

{------Вывод на экран адреса (селектор:смещение) команды,-----}
{-----------------которая вызвала исключение------------------}

mov ah,2
mov cl,1bh
mov dl,28h
int 30h { Вывод на экран символа "(" }
sub di,2
mov ax,301h
mov cl,1eh
db 66h
mov dx,[bp+16] { Чтение из стека CS }
int 30h { Вывод на экран значения CS }
sub di,2
mov ah,2
mov cl,1eh
mov dl,3ah
int 30h { Вывод на экран символа ":" }
sub di,2
mov ax,302h
mov cl,1eh
db 66h
mov dx,[bp+12] { Чтение из стека EIP }
int 30h { Вывод на экран значения EIP }
sub di,2
mov ah,2
mov cl,1bh
mov dl,29h
int 30h { Вывод на экран символа ")" }
jmp @end

{------------------------Функция 2:----------------------------}
{----------------Вывод на экран значений РОН:------------------}
{------------EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI------------}
{ }
{-----Особенность этой функции: перед ее вызовом необходимо----}
{---------сохранить в стеке значения регистров AX и BX,--------}
{-----------а после вызова функции - их восстановить-----------}
{------------(см. обработчик ислючения 0 модуля PROT)----------}
{ В AL - режим вывода значений регистров }
{ AL=0: вывод в одну строку }
@f2: { AL=1: вывод в две строки }
{--------Сохранить параметры вызова прерывания INT 32h:-------}
push ax { режим вывода и }
push bx { координаты вывода }
mov bp,sp
cmp mode,0
{-------Восстановить исходные значения регистров AX и BX------}
{---------для реального и защищенного режимов работы МП-------}
jnz @pm1
mov ax,[bp+12]
mov bx,[bp+10]
jmp @@1
@pm1:mov ax,[bp+18]
mov bx,[bp+16]
@@1:
db 66h
pusha { Сохранить РОНы для вывода на экран }
mov bp,sp
mov bx,[bp+32] { Восстановить координаты места экрана }
mov ax,100h
int 30h { Установить маркер }
{------Вывод массива строк наименований регистров (s_reg)-----}
lea bx,s_reg
mov cx,8
@as:push cx
push bx
mov ah,4
mov cl,1ah
mov si,bx
int 30h
add di,2
pop bx
add bx,256
pop cx
cmp cx,5
jnz @l
mov ax,[bp+34] { Анализ режима вывода: }
cmp al,0 { AL=0: в одну строку }
jz @l
add di,408 { AL=0: в две строки }
@l:loop @as
mov ax,[bp+34]
cmp al,0 { Анализ режима вывода }
jnz @l3
add di,142
jmp @l4
@l3:add di,142
@l4:mov cx,8
@l1:
db 66h
pop dx { Чтение из стека значения очередного РОНа }
push cx
push di
mov cl,1bh
mov ax,302h
int 30h { Вывод на экран значения очередного РОНа }
pop di
sub di,18
pop cx
cmp cx,5
jnz @l2
mov bp,sp
mov ax,[bp+18]
cmp al,0 { Анализ режима вывода }
jz @l2
sub di,408
@l2:loop @l1
pop bx
pop ax
jmp @end
{--------------------------Функция 3:-------------------------}
{----------Вывод на экран значений счетчика команд EIP--------}
{--------и сегментных регистров CS, SS, ES, DS, FS и GS-------}
{ Назначение регистров: AL - номер подфункции }
{------AL=0: вывод значений собственно регистров EIP и CS-----}
{------AL=1: вывод "теневых" значений регистров EIP и CS------}
{----В случае AL=1 перед вызовом функции необходимо задать:---}
{ в CX - значение CS }
@f3:
cmp al,0
jz @01
push cx
cmp mode,0
jz @31
db 66h
@31:push dx
@01:
push ax
{-----------------Вывод массива строк s_sreg------------------}
lea bx,s_sreg
mov cx,7
{ add di,160}
@as1:push cx
push bx
mov ah,4
mov cl,1ah
mov si,bx
int 30h
add di,2
pop bx
add bx,256
pop cx
loop @as1
add di,82
pop ax
cmp al,0
jnz @02
mov bp,sp
cmp mode,0
jz @32
db 66h
@32:mov dx,[bp]
{ mov cur_adr,dx}
mov cl,1bh
mov ax,302h
int 30h { Вывод на экран значения EIP }
cmp mode,0
jnz @pm2
mov dx,[bp+2]
jmp @33
@pm2:mov dx,[bp+4]
{ mov cur_sel,dx}
@33:mov cl,1bh
mov ax,301h
int 30h { Вывод на экран значения CS }
jmp @ss
@02:cmp mode,0
jz @34
db 66h
@34:pop dx
mov cl,1bh
mov ax,302h
int 30h { Вывод на экран "теневого" значения EIP }
pop dx
mov cl,1bh
mov ax,301h
int 30h { Вывод на экран "теневого" значения CS }
@ss:
mov dx,ss
mov cl,1bh
mov ax,301h
int 30h { Вывод на экран значения SS }
mov dx,es
mov cl,1bh
mov ax,301h
int 30h { Вывод на экран значения ES }
mov bp,sp
mov dx,ds
mov cl,1bh
mov ax,301h
int 30h { Вывод на экран значения DS }
db 8ch,0e2h { MOV DX,FS }
mov cl,1bh
mov ax,301h
int 30h { Вывод на экран значения FS }
db 8ch,0eah { MOV DX,GS }
mov cl,1bh
mov ax,301h
int 30h { Вывод на экран значения GS }
jmp @end

{------Функция 4: Вывод на экран наименований и значений------}
{------------битов (флагов) регистра управления CR0-----------}
{ Назначение регистров: AL - номер подфункции }
{-------AL=0: вывод в двоичном виде значений битов CR0--------}
{-------AL=1: вывод наименований и значений битов CR0--------}
@f4:
cmp al,0
jz @val
{------------------Вывод массива строк s_CR0------------------}
lea bx,s_CR0
mov cx,2
@as2:push cx
push bx
mov ah,4
mov cl,1dh
mov si,bx
int 30h
add di,96
pop bx
add bx,256
pop cx
loop @as2
sub di,8
@val:
mov ah,4
mov cl,1ah
mov si,offset s_CR0n { Вывод строки "CR0:" }
int 30h
db 0fh,20h,0c2h { MOV EDX,CR0 }
mov cl,1bh
mov ax,502h
int 30h { Вывод на экран значений разрядов CR0 }
jmp @end

{------Функция 5: Вывод на экран наименований и значений------}
{------------битов (флагов) регистра управления CR4-----------}
@f5:
{------------------Вывод массива строк s_CR4------------------}
lea bx,s_CR4
mov cx,3
@as3:push cx
push bx
mov ah,4
mov cl,1dh
mov si,bx
int 30h
add di,96
pop bx
add bx,256
pop cx
loop @as3
sub di,8
mov ah,4
mov cl,1ah
mov si,offset s_CR4n { Вывод строки "CR4:" }
int 30h
db 0fh,20h,0e2h { MOV EDX,CR4 }
mov cl,1bh
mov ax,502h
int 30h { Вывод на экран значений разрядов CR4 }
jmp @end
{------Функция 6: Вывод на экран наименований и значений------}
{----------------битов (флагов) регистра EFLAGS---------------}
@f6:
{----------------Вывод массива строк s_EFLAGS-----------------}
lea bx,s_EFLAGS
mov cx,3
@as4:push cx
push bx
mov ah,4
mov cl,1dh
mov si,bx
int 30h
add di,96
pop bx
add bx,256
pop cx
loop @as4
sub di,14
mov ah,4
mov cl,1ah
mov si,offset s_EFLAGSn
int 30h { Вывод строки "EFLAGS:" }
db 66h
pushf
db 66h
pop dx
mov cl,1bh
mov ax,502h
int 30h { Вывод на экран значений разрядов EFLAGS }
jmp @end
{---------Функция 7: Вывод на экран содержимого стека---------}
{ Назначение регистров: AL - номер подфункции }
{ AL=0: 16-розрядный стек }
{ AL=1: 32-розрядный стек }
{ CX - число элементов стека }
@f7:
mov bp,sp
mov si,0
cmp al,0
jnz @732
@716: push cx
push si
mov dx,[bp+si]
mov ax,301h
mov cl,1bh
int 30h
add di,150
pop si
add si,2
pop cx
loop @716
jmp @end
@732: push cx
push si
db 66h
mov dx,[bp+si+12]
mov ax,302h
mov cl,1bh
int 30h
add di,142
pop si
add si,4
pop cx
loop @732
jmp @end
@end:
cmp mode,0
jz @iret
db 66h
@iret:iret
end;{int_32nh}
{----------Обработчик программного прерывания 33h------------}
{----------------Ввод данных с клавиатуры:--------------------}
procedure int_33h;assembler;
asm
{-----------Анализ наличия данных в буфере клавиатуры---------}
db 64h
mov si,[1ch] { В SI - адрес начала данных }
@wait:
db 64h
cmp si,[1ch]
jz @wait
cmp ah,2
jnz @end
{-----------------------Чтение символа------------------------}
db 64h
mov dx,[si] { В DL - ASCII-код, в DH - скан-код }
{--------Коррекция начала данных в буфере клавиатуры----------}
db 64h
add si,2
mov [1ah],si
@end:
db 66h
iret
end;{int_32h}
{==============Секция инициализации модуля PROT===============}
begin
{---Формирование дескрипторов сегментов базовой таблицы GDT,--}
{---------которые являются общими для всех программ,----------}
{----------------работающих в защищенном режиме---------------}
{ Нуль-дескриптор }
init_gdt(0,0,0,0,0);
{ Дескриптор сегмента кода модуля PROT: }
init_gdt(PROT_sel,$ffff,longint(CSeg) shl 4,acc_code,0);
{ Дескриптор сегмента стека: }
init_gdt(stack_sel,0,longint(Sseg) shl 4,acc_stack,0);
{ Дескриптор сегмента данных: }
init_gdt(data_sel,$ffff,longint(Dseg) shl 4,acc_data,0);
{ Дескриптор сегмента данных реального режима: }
init_gdt(real_sel,$ffff,longint(Dseg) shl 4,acc_data,0);
{ Дескриптор сегмента видеопамяти для текстового режима: }
init_gdt(text_sel,4000-1,$b8000,acc_data,0);
{-----------------------Дескрипторы TSS-----------------------}
{ Задачи MAIN: }
init_gdt(main_sel,sizeof(t_tss)-1,
longint(Dseg) shl 4+ofs(main_tss),acc_TSS,0);

{ задачи EXC12_TASK: }
init_gdt(exc12_sel,sizeof(t_tss)-1,
longint(Dseg) shl 4+ofs(exc12_tss),acc_TSS,0);
{==================Формирование таблицы IDT===================}

{------Дескрипторы шлюзов обработчиков исключений 0-18:-------}
init_idt(0,ofs(exc_00),PROT_sel,acc_trap);
init_idt(1,ofs(exc_01),PROT_sel,acc_trap);
init_idt(2,ofs(exc_02),PROT_sel,acc_trap);
init_idt(3,ofs(exc_03),PROT_sel,acc_trap);
init_idt(4,ofs(exc_04),PROT_sel,acc_trap);
init_idt(5,ofs(exc_05),PROT_sel,acc_trap);
init_idt(6,ofs(exc_06),PROT_sel,acc_trap);
init_idt(7,ofs(exc_07),PROT_sel,acc_trap);
init_idt(8,ofs(exc_08),PROT_sel,acc_trap);
init_idt(10,ofs(exc_10),PROT_sel,acc_trap);
init_idt(11,ofs(exc_11),PROT_sel,acc_trap);
init_idt(12,0,exc12_sel,acc_task);
init_idt(13,ofs(exc_13),PROT_sel,acc_trap);
init_idt(14,ofs(exc_14),PROT_sel,acc_trap);
init_idt(16,ofs(exc_16),PROT_sel,acc_trap);
init_idt(17,ofs(exc_17),PROT_sel,acc_trap);
init_idt(18,ofs(exc_18),PROT_sel,acc_trap);
{--------------Дескрипторы шлюзов обработчиков----------------}
{---------------внешних аппаратных прерывания:----------------}

{-----Дескриптор шлюза обработчика прерывания от таймера:-----}
init_idt($20,ofs(PIC_1),PROT_sel,acc_int);
{---Дескриптор шлюза обработчика прерывания от клавиатуры:----}
init_idt($21,ofs(keyb),PROT_sel,acc_int);
{----Дескрипторы шлюзов обработчиков прерываний IRQ2-IRQ7:----}
for i:=2 to 7 do
init_idt($20+i,ofs(PIC_1),PROT_sel,acc_int);
{---Дескрипторы шлюзов обработчиков прерываний IRQ8-IRQ15:----}
for i:=8 to 15 do
init_idt($20+i,ofs(PIC_2),PROT_sel,acc_int);
{---Дескрипторы шлюза обработчика программного прерывания:----}

init_idt($30,ofs(int_30h),PROT_sel,acc_trap_16);
init_idt($31,ofs(int_31h),PROT_sel,acc_trap);
init_idt($32,ofs(int_32h),PROT_sel,acc_trap);
for i:=$33 to 255 do init_idt(i,0,0,0);
{---------Формирование сегмента TSS задачи EXC12_TASK---------}
init_tss(exc12_tss,PROT_sel,data_sel,text_sel,
ofs(exc12_task),ofs(exc12_stack)+sizeof(exc12_stack));
end.

Обсуждение

давно
Старший Модератор
31795
6196
10.12.2010, 22:06
общий
функции №№5,6 практически у Вас выполняют одну и туже работу:
Код:
mov ax,number
xor cx,cx
@@01:
xor dx,dx
div word [ @osn ]
push dx
inc cx
;проверяем ах = 0
or ax,ax
jnz @@01
@@02:
pop ax
add al,30h
;тут запись-вывод
loop @@02

Получаете остаток от деления и записываете его в стек, а из стека извлекаете уже цифры в нужном порядке.
По поводу:
{ AL=0 - вывод байта }
{ AL=1 - вывод слова }
{ AL=2 - вывод двойного слова }

Я бы поэксперементировал с таким кодом:
Код:
begin
asm
;заполнение регистра единицами
mov cl,1{0,1,2}
mov ax,8
shl ax,cl
mov cx,ax
xor bx,bx
@@01:
stc
rcl bx,1
loop @@01
;
;дальше контроль - вывод
mov cx,16
@@02:
xor al,al
shr bx,1
adc al,30h
int 29h
loop @@02
end;
readln;
end.


итог:
функция №5 ставите основание 2, и записываете в регистр(к примеру EBX) нужное количество "1", после этого AND EAX,EBX и вывод значения в ЕАХ
функция №6 ставите основание 10, и см. выше
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
7438
7205
18.12.2010, 02:56
общий
это ответ
Здравствуйте, Alexkharkov!
Вот Вам реализация функций 5 и 6
В функции 5 сдвигаем edx влево так, чтобы наше число стало на левом крае регистра,
затем выводим по тетрадам (раз Вам так хочется менять атрибут у тетрад), начиная со старшего бита
В функции 6 мы сначала обнуляем старшие ненужные биты, сдвигая влево/вправо на число ненужных бит,
затем формируем в стеке последовательность цифр, как остатки от деления на 10 нашего числа,
ну и, наконец, выводим на экран цифры из стека в обратном порядке.

[code h=200]{-------Функция 5: вывод данных на экран в двоичной форме-----}
{ AL=0 - вывод байта }
{ AL=1 - вывод слова }
@f5: { AL=2 - вывод двойного слова }
cmp modeVA,0 { определимся с атрибутом }
jz @51
mov ah,0f0h { для ч/б }
jmp @52
@51:
mov ah,cl { заданный атрибут }
@52:
mov cl,al { размерность данных }
mov bx,8 { 8 бит на байт }
shl bx,cl { всего бит }
mov cx,32 { максимум бит }
sub cx,bx { число "лишних" бит слева }
db 66h
shl dx,cl { сдвинем edx влево, убрав все лишние }
mov cx,bx { сколько выводим бит }
shr cx,2 { сколько тетрад }
@lp_1:push cx { цикл вывода тетрад }
xor ah,8 { "помигаем" атрибутом для тетрад }
mov cx,4 { число бит в тетраде }
@lp_2: { цикл вывода терады, начиная со ст бита }
mov al,0 { обнулим }
db 66h { сдвинем edx на 1 бит влево, }
shl dx,1 { при этом старший бит будет в C }
adc al,'0' { al = 0+'0'+C (в итоге '0' или '1') }
stosw { пишем }
loop @lp_2 { биты тетрады }
pop cx { счетчик тетрад }
loop @lp_1 { по всем }
add di,2 { пропустим одно знакоместо (если надо) }
jmp @end

{-----Функция 6: вывод данных на экран в десятичной форме-----}
{ AL=0 - вывод байта }
{ AL=1 - вывод слова }
@f6: { AL=2 - вывод двойного слова }
cmp modeVA,0 { определимся с атрибутом }
jz @61
mov bl,0f0h { для ч/б }
jmp @62
@61:
mov bl,cl { заданный атрибут }
@62:
mov cl,al { размерность данных }
mov ax,8 { 8 бит на байт }
shl ax,cl { всего бит }
mov cx,32 { максимум бит }
sub cx,ax { число "лишних" бит слева }
db 66h
shl dx,cl { сдвинем edx влево, убрав все лишние }
db 66h
shr dx,cl { вернем обратно, при этом вместо лишних будут 0 }
db 66h
mov ax,dx { наше число }
xor cx, cx { число цифр }
db 66h
mov si, 10 { будем делить на dword 10 }
dw 0
@6_1: { цикл получения цифр }
db 66h
xor dx,dx { подготавливаемся к делению }
db 66h
div si { edx:eax / 10 }
push dx { сохраним остаток - очередную младшую цифру }
inc cx { считаем }
db 66h
test ax,ax { eax != 0 ? }
jnz @6_1 { т.е. еще есть десятичные разряды? }
@6_2: { цикл вывода цифр в обратном порядке }
pop ax { извлекаем из стека }
mov ah, bl { атрибут }
or al, '0' { 0-9 -> '0'-'9' }
stosw { пишем }
loop @6_2 { по всем }
add di,2 { пропустим одно знакоместо (если надо) }
jmp @end

end[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа