Sys_Programming / LAB4
.DOC
ЛАБОРАТОРНАЯ РАБОТА №4
Цель работы: изучить правила работы с командой Ассемблера XLAT.
Теоретическая часть
Команда XLAT (кодирование AL
XLAT [адрес_таблицы_перекодировки]
Логика: AL = (BX)+(AL)
Команда XLAT переводит байт, согласно таблице преобразований. Указатель 256-байтовой таблицы преобразований находится в BX. Байт, который нужно перевести, расположен в AL. После выполнения команды XLAT байт в AL заменяется на байт, смещенный на AL байтов от начала таблицы преобразований.
Таблица преобразований может содержать менее 256 байтов. Операнд, т.е. адрес_таблицы_перекодировки, является необязательным, поскольку указатель таблицы должен быть загружен в BX еще до начала выполнения команды.
Следующий пример иллюстрирует перевод десятичного числа (от 0 до 15) в соответствующую "цифру" шестнадцатеричной системы счисления:
Сегмент данных:
HEX_TABLE DB '0123456789ABCDEF'
Сегмент кода:
LEA BX,HEX_TABLE ;указатель таблицы засылаем в BX,
MOV AL,DECIMAL_DIGIT ;а переводимую цифру - в AL
XLAT HEX_TABLE ;переводим
. ;теперь в AL находится ASCII-код
. ;соответствующей цифры
. ;шестнадцатеричной системы
Выполнение лабораторной работы
Задача: Необходимо ввести с клавиатуры двузначное шестнадцатеричное число и, используя таблицу перекодировки, перевести его в двоичное и десятичное.
Для шестнадцатеричных цифр имеются следующие правила кодировки (табл. 4.1).
| 
				 Символ шестнадцатиричной цифры  | 
			
				 ASCII-код (двоичное представление)  | 
			
				 Двоичная тетрада  | 
		
| 
				 0  | 
			
				 30h (0011 0000)  | 
			
				 0000  | 
		
| 
				 1  | 
			
				 31h (0011 0001)  | 
			
				 0001  | 
		
| 
				 2  | 
			
				 32h (0011 0010)  | 
			
				 0010  | 
		
| 
				 3  | 
			
				 33h (0011 0011)  | 
			
				 0011  | 
		
| 
				 4  | 
			
				 34h (0011 0100)  | 
			
				 0100  | 
		
| 
				 5  | 
			
				 35h (0011 0101)  | 
			
				 0101  | 
		
| 
				 6  | 
			
				 36h (0011 0110)  | 
			
				 0110  | 
		
| 
				 7  | 
			
				 37h (0011 0111)  | 
			
				 0111  | 
		
| 
				 8  | 
			
				 38h (0011 1000)  | 
			
				 1000  | 
		
| 
				 9  | 
			
				 39h (0011 1001)  | 
			
				 1001  | 
		
| 
				 A,a  | 
			
				 41h (0100 0001) , 61h (0110 0001)  | 
			
				 1010  | 
		
| 
				 B,b  | 
			
				 42h (0100 0010) , 61h (0110 0010)  | 
			
				 1011  | 
		
| 
				 C,c  | 
			
				 43h (0100 0011) , 61h (0110 0011)  | 
			
				 1100  | 
		
| 
				 D,d  | 
			
				 44h (0100 0100) , 61h (0110 0100)  | 
			
				 1101  | 
		
| 
				 E,e  | 
			
				 45h (0100 0101) , 61h (0110 0101)  | 
			
				 1110  | 
		
| 
				 F,f  | 
			
				 46h (0100 0110) , 61h (0110 0110)  | 
			
				 1111  | 
		
Для решения поставленной задачи нам, в первую очередь, необходимо составить таблицу перекодировки (tab1 в листинге 4.1).
Листинг 4.1.
- 
PAGE 60,132
 - 
TITLE Лабораторная работа №4
 - 
;Программа преобразования двузначного шестнадцатеричного числа
 - 
;в десятичное представление с использованием команды XLAT
 - 
;Вход: исходное шестнадцатеричное число; вводится с клавиатуры
 - 
;Выход: результат преобразования в регистре AL
 - 
;-------Сегмент данных---------------------
 - 
DATASG SEGMENT PARA 'Data'
 - 
message DB "Введите две шестнадцатиричные цифры,$"
 - 
tab1 DB 30h dup (0),0,1,2,3,4,5,6,7,8,9, 7h dup (0)
 - 
DB 0ah,0bh,0ch,0dh,0eh,0fh, 1ah dup (0)
 - 
DB 0ah,0bh,0ch,0dh,0eh,0fh, 99h dup (0)
 - 
DATASG ENDS ;Конец сегмента данных
 - 
;------------------------Сегмент стека---------------------
 - 
STK SEGMENT STACK
 - 
DB 256 DUP ('?') ;сегмент стека
 - 
STK ENDS ;Конец сегмента стека
 - 
;------------------------Сегмент кода---------------------
 - 
CODE SEGMENT PARA PUBLIC 'CODE'
 - 
MAIN PROC FAR ;начало процедуры MAIN
 - 
ASSUME CS:CODE, DS:DATASG, SS:STK
 - 
MOV AX,DATASG ;адрес сегмента данных в регистр АХ
 - 
MOV DS,AX ;AX в DS
 - 
LEA BX,tab1 ;загрузка адреса строки байт в регистр ВХ
 - 
MOV AH,9 ;функция DOS 09h - вывод строки на дисплей
 - 
MOV DX,offset message ;адрес выводимой строки
 - 
int 21h ;вызов DOS
 - 
SUB AX,AX ;очистить регистр АХ
 - 
MOV AH,1h ;функция DOS 01h - ввод символа с клавиатуры
 - 
int 21h ;вызов DOS: вводим первую цифру в AL
 - 
XLAT ;перекодировка первого введенного символа в AL
 - 
MOV DL,AL
 - 
SHL DL,4 ;сдвиг DL влево для освобождения места для
 - 
;младшей цифры
 - 
int 21h ;вызов DOS: ввод второго символа в AL
 - 
XLAT ;перекодировка второго введенного символа в AL
 - 
ADD AL,DL ;складываем для получения результата
 - 
MOV AX,4C00h ;завершение работы программы
 - 
int 21h ;вызов DOS
 - 
MAIN ENDP ;конец процедуры MAIN
 - 
CODE ENDS ;конец сегмента кода
 
END MAIN ;конец программы с точкой входа MAIN
Обсудим этот момент подробнее. Прежде всего нужно определится со значениями тех байтов, которые вы будете изменять. В нашем случае это символы шестнадцатиричных цифр. Поэтому мы конструируем в сегменте данных таблицу, в которой на места байтов, соответствующих символам шестнадцатиричных цифр, помещаем их новые значения, то есть двоичные эквиваленты шестнадцатиричных цифр. Например: для ASCII-кода шестнадцатиричной цифры ‘В’ его значение должно стоять на 66(42h) месте в таблице tab1.
Строки 10-12 листинга 4.1 демонстрируют, как это сделать. Байты этой таблицы, смещения которых не совпадают со значениями кодов шестнадцатиричных цифр, нулевые. Действительно, до 30h (48) ASCII-кодов нет (см. табл.4.1) и у нас стоят нули (30h dup (0)). Следует учесть, что до 30h (48) номера таблицы именно 48 нолей, так как нумерация начинается с 0. Дальше от 30h до 39h идут шестнадцатиричные цифры 0 .. 9. Затем до 41h символов нет. Это составляет: 41h - 39h = 7h=7D нулей. Далее от 41h до 46h идут большие буквы от ‘А’ до ‘F’. Далее 61h - 41h = 1Ah=26 нулей и от 61h до 66h малые буквы от ‘a’ до ‘f’. И большие и маленькие буквы имеют одно и то же двоичное значение (например, ‘A’ и ‘a’ имеют одно и то же значение 0ah = 0000 1010). Желательно определить все 256 байт таблицы. Дело в том, что если мы ошибочно поместим в AL код символа, отличный от символа шестнадцатиричной цифры, то после выполнения команды XLAT получим непредсказуемый результат. В случае листинга 4.1 это будет ноль, что не совсем корректно, так как непонятно, что же в действительности было в AL: код символа «0» или что-то другое. Поэтому, наверное, есть смысл здесь поставить «защиту от дурака», поместив в неиспользуемые байты таблицы какой-нибудь определенный символ (например ?). После каждого выполнения XLAT нужно просто будет контролировать значение в AL на предмет совпадения с этим символом, и если оно произошло, выдавать сообщение об ошибке.
После того как таблица составлена, с ней можно работать. В сегменте команд, после обычной процедуры загрузки адреса сегмента данных в регистр DS (строки 22-23), командой LEA загружаем адрес таблицы в регистр ВХ (<24>). Просмотрите это в отладчике с помощью окна Watches и дампа распределения памяти Dump. Далее, в строках 25-27 выводим на экран приглашение к вводу шестнадцатеричных цифр. Для этого в регистр AH помещаем номер функции DOS 9 (09h-вывод строки символов на дисплей), в регистр DX адрес строки message и вызываем прерывание 21h. Очищаем регистр АХ и помещаем в АН номер функции 01h (ввод символа с клавиаторы) и прерывание 21h. После выполнения функции 01h в регистре AL будет введеный символ (проверьте это с помощью отладчика). Команда XLAT по номеру ВХ+AL определит в таблице двоичное значение первого введенного символа. Он будет иметь вид 0nh (или 0000 nnnn в двоичном виде, т.е. старший полубайт будет равен нулю). Младший полубайт необходимо где-то запомнить. Для этого мы пересылаем его в регистр DL (<32>) и сдвигаем на 4 разряда влево (<33>), подготавливая место для следующей цифры. В DL будет (nnnn 0000). Далее вызываем 21h (<35>) для ввода второго символа в AL (в АН по-прежнему находится 1h). После XLAT (<36>) в AL будет (0000 mmmm). Складывая AL и DL, получим в AL окончательный результат (nnnn mmmm). Его можно посмотреть при помощи отладчика.
Для закрепления знаний и исследования трудных моментов выполните программу из листинга 4.1 под управлением отладчика.
