Функции обработки машинных слов Lo, Hi и Swap




Среди прочих специальных средств низкого уровня Турбо Паскаль предоставляет несколько удобных функций для работы над отдельными байтами машинных слов. Некоторые системные переменные и функции Турбо Паскаля возвращают два однобайтовых значения, объединенных в тип Word. Для их «распаковки» как раз подходят описываемые здесь функции. Их три (табл. 14.1).

Таблица 14.1

Функция: Тип Возвращаемое значение
Hi(X): Тип-X Старший байт аргумента X
Lo(X): Тип-X Младший байт аргумента X
Swap(X): Тип-X Число с переставленными старшим и младшим байтами

Аргумент X имеет тип Word или Integer (2-байтовый целый), и возвращаемое значение имеет тот же тип, что и X.

Любое число типа Word раскладывается на два слагаемых из значений своих байтов по правилу (для типа Integer эта формула не подходит)

X:= Hi(X) * 256 + Lo(X);

Функция Swap возвращает число типа Word или Integer в зависимости от типа аргумента X, в котором старший и младший байты поменялись местами. Следует быть осторожным при использовании функции с аргументом типа LongInt. В версии 5.5 Турбо Паскаля компилятор «ничего не имеет против» таких вызовов, но возвращаемое значение при счете усекается до типа Word, меняя его иной раз до неузнаваемости.

Вставки машинного кода в программе

Оператор inline

Несмотря на то, что средствами Турбо Паскаля можно сделать практически все, не всегда полученный результат будет максимально {304} эффективным по быстродействию, если сравнивать с грамотно написанной программой на ассемблере. Другой вопрос, за сколько дней и ночей будет написан и отлажен ассемблерный текст, а за сколько — программы на Турбо Паскале. Все это верно и для других языков. В последних версиях языка Си можно просто писать вставки на ассемблере посреди текста Си-программ. Довольно похожим способом решена проблема включения машинных команд в текст программ на Турбо Паскале. Правда, в текущих версиях языка для того надо употреблять не мнемонические команды языка ассемблера, а их аналоги в машинном коде. Оператор вставки машинного кода записывается с помощью зарезервированного слова inline и списка кодов, разделенных косой чертой:

inline (Код1/ Код2/ Код3/.../ КодN);

Встретив такой оператор, компилятор прекращает на время генерировать код и вставляет Код1, Код2 и другие из оператора inline без каких-либо особых преобразований, а затем снова начинает преобразовывать предложения Турбо Паскаля в выполнимый код. Это более гибкий способ, чем компоновка объектного файла директивой {$L ИмяФайла}, поскольку позволяет вставлять в программу «чисто ассемблерные» отдельные операторы, в то время как {$L...} позволяет лишь использовать внешние процедуры и функции. Программирование в чистых машинных кодах, как это требует формат inline, — занятие не для начинающих. Не имея большого опыта работы с ассемблерами для процессоров семейства 8086/286, лучше избегать применения оператора inline, тем более, что необходимость в нем возникает не так уж часто. В книге Дж.Дунтемана [5], посвященной подобным вопросам, приводится такой список задач, требующих прямого использования машинных кодов:

1. Процедуры обработки прерываний.

2. Резидентные программы.

3. Организация многозадачных режимов.

Дж. Дунтеман характеризует эти задачи как задачи «не для малодушных», особенно третью. Код в операторе inline — это либо константа, либо имя переменной. Константа должна быть целым положительным числом типа Byte или Word и может быть записана как в десятичном, так и в шестнадцатеричном формате. Пример: оператор

inline($CD / 05); { Мнемоника -> INT 05H }

это то же самое, что вызов прерывания 05 (печать с экрана). Если значение константы попадает в диапазон 0...255, то она хранится {305} как однобайтовый код. Если же оно превосходит 255, то хранится как слово (два байта). В последнем случае код хранится по машинному правилу: младший байт (Lo(Word)) предшествует старшему (Hi(Word)). Можно явно заказывать формат хранения кода, используя перед константой знаки «<» и «>». Если константа записана с предшествующим знаком «<», то от нее будет взят только младший байт. Но если ей предшествует знак «>», то она будет записана в двух байтах, например:

inline(>1) даст два байта кода: $01 и $00.

Размер хранения кодов важен для организации переходов внутри оператора inline.

Если вместо константы стоит имя переменной, то оно трактуется как слово (два байта) — смещение в сегменте хранения этой переменной. Таким образом, переменная в inline задает адрес в сегменте DS (DSeg) или SS (SSeg) первого байта своего значения. Если же нужен не первый байт значения, а, например, третий, то можно указать это, дописав к переменной константу — смещение от ее первого байта, например:

inline(.../ XVar+2 /...);

Адрес первого байта XVar может быть записан как XVar+0. Смещение от начала переменной может быть и отрицательным, достаточно заменить знак «+» на «-».

Внутри кодов inline могут быть доступны значения глобальных переменных и типизированных констант (они хранятся в сегменте DS), а также, если inline стоит внутри тела процедуры или функции, становятся доступными локальные переменные этих процедур и их переменные параметры. Подробное изложение техники обращения к ним, соглашений о размещении и размерах локальных переменных, способах передачи значений в процедуры, функции и обратно заняло бы слишком много места (не считая таблицы машинных кодов для 8088/86/286). Подробно вопросы интерфейса с ассемблерными программами и работа с inline рассматривается в гл. 15 справочного руководства по Турбо Паскалю 5.0 [2] и в уже упоминавшейся книге [5] (с оговорками, ибо она написана для версии 3.0). Здесь же мы дадим один последний совет начинающим любителям машинных кодов: во избежание фатальных последствий запрещено модифицировать кодами оператора inline регистры процессора ВР, SP, SS и DS. Остальные — можно. {306}



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2022-11-01 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: