4. Зарезервированные слова. Для совместимости с ассемблером используется 41 зарезервированное слово, имеющее область действия только в asm-операторах. Эти слова имеют приоритет над именами пользователя, например:
Var Ch:char;
...
asm
mov Ch,1
end;
Здесь единица загружается в регистр процессора Ch, а не в ячейку памяти с именем Ch. Для указания описанного имени, совпадающего с зарезервированным словом, надо использовать перед именем символ «&»:
asm
mov &Ch,1
end;
5. Выражения. Использование выражений существенно отличается в Паскале и ассемблере. В Паскале упоминание переменной понимается как ее содержимое, а в asm-операторах обозначает адрес или константу. Поэтому оператор для х,
asm
mov AX, x+4
end;
описанного как переменная, не помещает значение х+4 в АХ, а загружает в регистр значение слова, хранящегося по адресу, на 4 байта большему х. Для увеличения х на 4 выполняются действия:
asm
mov AX, x
add AX,4
end;
Но записывать константы возможно следующим образом:
Const x=10;
y=20;
Var z:integer;
...
asm
mov z, x+y
end;
6. Есть 3 специальных переменных, одна из которых, @Result, обозначает переменную с результатом функции. Например, функция
Function Sum(x, y:integer):integer;
Begin
Sum:=x+y;
end;
эквивалентна
Function Sum(x, y:integer):integer;
Begin
asm
mov ax, x
add ax, y
mov @Result, ax
end;
end;
Для чисто ассемблерных подпрограмм может использоваться директива assembler. Это позволяет записывать подпрограммы полностью на языке ассемблера, с отсутствием операторных скобок и единственным asm-оператором:
Function LongMul(x, y:integer):longint; assembler;
asm
mov ax, x
imul y
end;
Использование @Result здесь не допускается, так как компилятор не образует переменную для результата функции. Обмен данными производится через регистры.
§8.2. Доступ к аппаратуре
Доступ к памяти
В Турбо Паскале можно напрямую обращаться к ячейкам памяти, организованным в три типа предопределенных одномерных массивов и представляющих элементы различного формата:
Mem – Byte,
MemW – Word,
MemL – Longint.
Для доступа к элементам массивов используется специальный синтаксис, состоящий из номера сегмента и номера ячейки памяти, оба типа Word:
Mem[$0040:$0049]:=7;
Data := MemW[Seg(V):Ofs(V)];
Обращение к оперативной памяти по физическим адресам обычно используется для доступа к системной информации DOS и BIOS и разрешено только в однопользовательских операционных системах, например MS-DOS.
Доступ к портам ввода-вывода
В процессорах фирмы Intel используется изолированный ввод-вывод. То есть область адресов памяти отделена от области внешних устройств. Все подключаемые внешние устройства с точки зрения процессора выглядят одинаково и являются портами ввода-вывода.
Для доступа к этим портам используются два предопределенных массива
Port, PortW
соответственно с типами byte и word.
Когда элементу массива Port или PortW присваивается значение, это действие интерпретируется как вывод значения в порт.
Когда элемент массива выступает как операнд в выражении, то доступ к порту понимается как ввод с порта. Например:
{ Разрешение дальнейшей работы контроллера прерываний }
Port[$20]:=$20;
{ Установка в 1 заданных линий порта }
PortW[Base]:=PortW[Base] or Maska;
{ Ожидание установки в 0 старшей линии порта }
While (Port[$82] and $80)=0 do;
Пример доступа к порту клавиатуры для управления движением курсора.
Program Kyrsor;
{ Демонстрационный пример доступа к порту клавиатуры для управления движением курсора }
Uses Crt; { используется для создания задержки }
Var Mode, { записываемый в порт байт }
Ch:byte; { число, читаемое с клавиатуры }
Begin
Writeln(' Выберите режим ввода символов:');
Writeln(' Задержка перед первым повторением:');
Writeln(' 1 - 250 мс');
Writeln(' 2 - 500 мс');
Writeln(' 3 - 750 мс');
Writeln(' 4 - 1 с');
Repeat
Read(Ch);
Until Ch in [1..4];
Case Ch of
1: Mode:=0;
2: Mode:=$20;
3: Mode:=$40;
4: Mode:=$60;
end;
Writeln(' Частота перемещения, раз/сек:');
Writeln(' 1 - 30');
Writeln(' 2 - 20');
Writeln(' 3 - 10');
Writeln(' 4 - 5');
Writeln(' 5 - 2');
Repeat
Read(Ch);
Until Ch in [1..5];
Case Ch of
2: Mode:=Mode or 4;
3: Mode:=Mode or $0a;
4: Mode:=Mode or $14;
5: Mode:=Mode or $1f;
end;
{ Команда на установку режима }
Port[$60]:=$f3;
{ Задержка на восприятие }
Delay(10);
{ Код режима }
Port[$60]:=Mode;
end.
Работа по прерываниям
Программный интерфейс DOS и BIOS организован в виде обращения к процедурам по прерываниям.
Прерыванием является указание процессору на то, что произошло какое-либо событие и требуется его обработка, называемая реакцией на прерывание.
Прерывания делятся на внешние по отношению к процессору, например от часов реального времени, и внутренние, например деление на ноль или переполнение. Более того, любое прерывание можно вызвать командой
INT n
где n - номер прерывания, обычно обозначается в шестнадцатеричной системе счисления (с буквой Н в конце числа).
Реакцией процессора на прерывание является выполнение подпрограммы, адрес начала которой, или вектор прерывания, находится в таблице, номер строки которой и есть номер прерывания. Максимальное количество прерываний для процессоров Intel – 256.
К подпрограммам DOS и BIOS доступ осуществляется по прерываниям. Связано это с тем, что в разных версиях адреса начала различных подпрограмм могут начинаться с разных адресов. А так как таблицу векторов прерываний формирует сама ОС, то достаточно только зафиксировать назначение строк таблицы, а ее содержание может изменяться.
В IBM-совместимых компьютерах не все вектора прерываний распределены между событиями и устройствами. Неиспользуемые номера и предназначены для обращения к подпрограммам ОС.
Так как свободных прерываний не много, то по одному вектору может вызываться несколько подпрограмм. Номер подпрограммы, называемый функцией или службой прерывания, передается в качестве параметра, записываемого в регистр АН. Например, наиболее часто используемое прерывание DOS 21Н имеет 87 служб.
Подпрограммы DOS имеют более высокий уровень обработки информации и часто дополнительно используют прерывания BIOS.
Основные прерывания DOS:
21Н – общие функции DOS;
25Н – безусловное чтение с диска;
26Н – безусловная запись на диск.
Основные прерывания BIOS:
10Н – работа с видеосистемой;
12Н – получение размера основной памяти;
13Н – работа с дисками;
14Н – работа с последовательными портами;
15Н – разнообразные службы;
16Н – работа с клавиатурой;
17Н – работа с принтером;
19Н – перезагрузка компьютера;
1АН – работа с часами реального времени.
Иногда возникает ситуация, когда в программе необходимо определить собственные алгоритмы реакции на прерывания от внешних устройств или операционной системы, отменив при этом стандартные реакции.
Процедура, которая будет обслуживать прерывание, должна иметь директиву interrupt и строго фиксированный список параметров:
Procedure <имя> (Flags,
CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP:Word);
interrupt;
Допускается отсутствие или задание отдельных параметров. Содержимое регистров процессора передается в процедуру в качестве параметров, поэтому их можно изменять.
Собственно переопределение некоторого прерывания производится обращением к процедуре модуля DOS:
SetIntVec (IntNo:byte; Vector:Pointer);
IntNo – номер прерывания, которое необходимо переопределить;
Vector – адрес новой процедуры обработки прерывания, которая будет запускаться автоматически.
При завершении программы желательно восстанавливать все переопределения, которые делались программой, включая и старые обработчики прерываний. Для сохранения предыдущей реакции, то есть адреса начала подпрограммы, используется процедура
GetIntVec (IntNo:byte; Var Vector:Pointer);
которая присваивает второму параметру адрес текущей реакции на прерывание с номером IntNo.
Таким образом, несколько программ могут работать с одним прерыванием: сначала срабатывает новый обработчик, затем управление передается следующему, расположенному по адресу Vector.
Программы, обрабатывающие прерывания, являются специфическими, так как обращение к ним происходит не из сегмента программ, а из таблицы прерываний. Поэтому для них необходимо указывать дальний (межсегментный) вызов директивой компилятора {$F+}.
Пример. Обработка прерывания, возникающего при нажатии клавиш Ctrl-Break.
Program Ctrl_Break;
{ Демонстрационный пример обработки прерывания,
возникающего при нажатии клавиш Ctrl-Break }
Uses Dos;
Const BreakFlag:boolean=False;
Var IntSt:pointer; { Адрес стандартного обработчика }
{$F+}
Procedure CtBr; interrupt;
Begin
BreakFlag:=true;
end;
{$F-}
Begin
{ Запоминаем адрес стандартной реакции }
GetIntVec($1b, IntSt);
SetIntVec($1b,@CtBr);
Writeln('Для окончания нажмите Ctrl-Break');
Repeat
Until BreakFlag;
{ Восстанавливаем первоначальный адрес реакции }
SetIntVec($1b, IntSt)
end.
Контрольные вопросы
1. Что такое «ассемблер»?
2. Что такое «макроассемблер»?
3. В каких случаях используется язык Ассемблер?
4. Что такое «встроенный ассемблер»?
5. Что такое «OBJ-файл»?
6. Какова структура asm-оператора?
7. Как в asm-операторах записываются комментарии?
8. Каков общий вид команды ассемблера (asm-оператора)?
9. Все ли регистры можно изменять в asm-операторах?
10. Как записываются локальные и глобальные метки в asm-операторах?
11. Какие коды инструкций (команд) используются во встроенном ассемблере?
12. Как обозначаются имена, совпадающие с зарезервированными словами?
13. Как в asm-операторах Паскаля в выражениях трактуется имя переменной?
14. Как в asm-операторах обозначается переменная с результатом функции?
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Основные порталы (построено редакторами)
