3.1. Записать в текстовом редакторе NORTON следующую программу в EXE-формате:
.286
TITLE CALLPR (EXE) Вызов процедур
;-------------------------------------------------------
STACKSG SEGMENT PARA STACK 'Stack'
DW 32 DUP(?)
STACKSG ENDS
;-------------------------------------------------------
CODESG SEGMENT PARA 'Code'
BEGIN PROC FAR
ASSUME CS:CODESG,SS:STACKSG
PUSH DS;Записать DS в стек
SUB AX,AX;Записать в стек
PUSH AX;нулевой адрес
CALL B10;Вызвать В10
MOV DS,AX;в регистр DS
MOV AX,0250;Переслать 0250 в АХ
ADD AX,0125;Прибавить 0125 к АХ
MOV CX,AX;Записать сумму в CX
RET;Вернуться в DOS
BEGIN ENDP
;--------------------------------------------------------
B10 PROC
CALL C10;Вызвать С10
SUB AX,AX
SUB CX,CX
RET;Вернуться в вызывающую программу
B10 ENDP
;---------------------------------------------------------
C10 PROC
ADD AX,1
MOV BX,AX
INC BX
RET;Вернуться в вызывающую программу
C10 ENDP
;-----------------------------------------------------------
CODESG ENDS
END BEGIN
Команда CALL автоматически записывает в стек относительный адрес команды, следующий непосредственно за командой CALL, уменьшая при этом указатель вершины стека. В вызываемой процедуре команда RET использует этот адрес для возврата в вызывающую процедуру и при этом автоматически увеличивается указатель вершины стека.
При передаче управления в ЕХЕ-программу в регистрах микропроцессора устанавливаются следующие значения:
DS и ES: Адрес префикса программного сегмента - область в 256 (100Н) байт, которая предшествует выполняемому программному модулю в памяти.
CS: Адрес точки входа в программу (адрес первой выполняемой команды).
IP: Нуль.
SS: Адрес сегмента стека.
SP: Относительный адрес, указывающий на вершину стека.
3.2. Выполните ассемблирование программы callpr.asm с получением листинга. Запишите листинг в отчет. Выполните компоновку программы.
3.3. Вызовите отладчик DEBUG для пошагового выполнения программы. С помощью команды R просмотрите начальное состояние регистров микропроцессора. С помощью команды D SS:00 просмотрите сегмент стека. Параграфы, отведенные под стек должны быть обнулены. Определите адрес по которому кончается стек и сравните этот адрес с содержимым указателя вершины стека SP. Введите команду Т,
после чего выполнится первая команда PUSH. Определите, как изменилось содержимое указателя вершины стека SP. Проверьте записалось ли содержимое регистра DS в стек, просмотрев еще раз сегмент стека.
Обратите внимание, слова в стек записываются в обратной последовательности, например, 00 07 записывается в виде 07 00. Отладчик DEBUG при использовании его для просмотра стека заносит в стек другие значения, включая содержимое IP, для собственных нужд.
3.4. Продолжая пошаговый режим выполните вторую команду PUSH. Определите, как изменилось содержимое указателя вершины стека и проверьте записался ли нулевой результат из регистра АХ в стек, еще раз просмотрев сегмент стека.
3.5. Выполните команду CALL B10. Определите, как изменилось содержимое указателя вершины стека и какое новое число записалось в стек. Это число является адресом возврата после окончания процедуры CALL B10. Найдите этот адрес по листингу программы и определите команду на которую перейдет микропроцессор после окончания процедуры CALL B10. Сама команда CALL B10 вызывает процедуру B10, первой командой которой является команда CALL C10.
3.6. Выполните команду CALL C10. Определите, как изменилось содержимое указателя вершины стека и какое новое число записалось в стек. Выводы запишите в отчет.
3.7. Продолжая пошаговый режим, выполните команду RET процедуры С10. Определите, как изменилось содержимое указателя вершины стека SP, какое число записалось в регистр команд IP, какое число исчезло из стека. Проверьте по листингу, какая команда находится по адресу, указанному в регистре команд IP. Выводы запишите в отчет.
3.8. Продолжая пошаговый режим, выполните команду RET процедуры B10. Определите, как изменилось содержимое указателя вершины стека SP, какое число записалось в регистр команд IP, какое число исчезло из стека. Проверьте по листингу, какая команда находится по адресу, указанному в регистре команд IP. Выводы запишите в отчет.
3.9. Для выхода из отладчика введите команду Q.
4. Программа: расширение операции пересылки.
4.1. В данном разделе изучим пересылку данных, которые имеют длину более двух байт.
В текстовом редакторе NORTON запишите следующую программу в ЕХЕ-формате:
.286
TITLE EXMOVE (EXE) Расширенная пересылка
;-------------------------------------------------------
STACKSG SEGMENT PARA STACK 'Stack'
DW 32 DUP(?)
STACKSG ENDS
;-------------------------------------------------------
DATASG SEGMENT PARA 'Data'
NAME1 DB 'ABCDEFGHI'
NAME2 DB 'JKLMNOPQR'
NAME3 DB 'STUVWXYZ*'
DATASG ENDS
;--------------------------------------------------------
CODESG SEGMENT PARA 'Code'
BEGIN PROC FAR
ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG
PUSH DS;Записать DS в стек
SUB AX,AX;Записать в стек
PUSH AX;нулевой адрес
MOV AX,DATASG;Поместить адрес DATASG
MOV DS,AX;в регистр DS
MOV ES,AX
CALL B1OMOVE;Вызвать п/п
CALL C1OMOVE;Вызвать п/п
RET;Вернуться в DOS
BEGIN ENDP
; Расширенная пересылка,
; использующая переход по условию:
;------------------------------------------------------------
B1OMOVE PROC
LEA SI,NAME1;Инициализация адресов
LEA DI,NAME2;NAME1 и NAME2
MOV CX,09;Переслать 9 символов
B20: MOV AL,[SI];Переслать из NAME1
MOV [DI],AL;Переслать в NAME2
INC SI;Следующ.симв.в NAME1
INC DI;Следующ.поз. в NAME2
DEC CX;Уменьшить сч. цикла
JNZ B20;Счетчик > 0? Да-цикл
RET;Если счетчик = 0, то вернуться
B1OMOVE ENDP
; Расширенная пересылка,
; использующая команду LOOP
;----------------------------------------------------------
C1OMOVE PROC
LEA SI,NAME2;Инициализация адресов
LEA DI,NAME3;NAME2 и NAME3
MOV CX,09;Переслать 9 символов
C20: MOV AL,[SI];Переслать из NAME2
MOV [DI],AL;Переслать в NAME3
INC SI;Следующ.симв.в NAME2
INC DI;Следующ.поз. в NAME3
LOOP C20;Уменьшить счетчик,
;если не 0, то цикл
RET;Если счетчик = 0, то вернуться
C1OMOVE ENDP
CODESG ENDS
END BEGIN
Сегмент данных содержит три девятибайтовых поля: NAME1, NAME2, NAME3. Цель программы - переслать данные из поля NAME1 в поле NAME2 и переслать данные из поля NAME2 в поле NAME3. Так как эти поля имеют длину девять байт каждое, то для пересылки данных кроме простой команды MOV требуются еще другие команды.
Процедура BEGIN инициализирует сегментные регистры и затем вызывает процедуры B1OMOVE и C1OMOVE. Процедура B1OMOVE пересылает содержимое поля NAME1 в поле NAME2. Так как каждый раз пересылается только один байт, то процедура начинает с самого левого байта в поле NAME1 и в цикле пересылает затем второй байт, третий и т.д.
Для продвижения в полях NAME1 и NAME2 в регистр СХ заносится значение 9, а регистры SI и DI используются в качестве индексных. Две команды LEA загружают относительные адреса полей NAME1 и NAME2 в регистры SI и DI.
Для пересылки содержимого первого байта из поля NAME1 в первый байт поля NAME2 используются адреса в регистрах SI и DI. Квадратные скобки в командах MOV означают, что для доступа к памяти используется адрес в регистре, указанном в квадратных скобках. Таким образом, команда MOV AL,[SI] означает: использовать адрес в регистре SI (т.е.NAME1) для пересылки соответствующего
байта в регистр АL. И команда MOV [DI],AL означает: переслать содержимое регистра AL по адресу, лежащему в регистре DI (т.е.NAME2).
Следующие команды увеличивают значения регистров SI и DI и уменьшают значение в регистре СХ. Если в регистре СХ не нулевое значение, управление передается на следующий цикл (на метку В20). Так как содержимое регистров SI и DI было увеличено на 1, то следующие команды MOV будут иметь дело с адресами NAME1+1 и NAME2+1. Цикл продолжается таким образом, пока не будет передано содержимое NAME1+8 и NAME2+8.
Команда JNZ выполняет переход на метку В20, если в результате выполнения команды DEC CX получится результат, отличный от нуля. Команда DEC CX уменьшает содержимое регистра СХ на 1.
Процедура С1OMOVE аналогична процедуре B1OMOVE с двумя исключениями: она пересылает данные из поля NAME2 в поле NAME3 и использует команду LOOP вместо DEC и JNZ.
4.2. Выполните ассемблирование и компоновку программы. Листинг программы запишите в отчет.
4.3. Вызовите отладчик DEBUG на выполнение программы exmove.exe.
4.4. Проведите пошаговое выполнение команд до первой команды CALL. При этом, в регистр DS загрузится начальный адрес сегмента данных. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.5. Продолжите пошаговое выполнение команд до метки В20. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.6. Продолжите пошаговое выполнение команд до первой команды INC. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.7. Продолжите пошаговое выполнение команд до команды JNZ. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.8. Выполните команду JNZ. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.9. Выполните полный цикл до команды JNZ, продолжая пошаговое выполнение команд. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.10. Продолжите пошаговое выполнение команд, выполните все оставшиеся циклы, до выполнения команды RET. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.11. Выполните команду RET. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.12. Выполните команду CALL. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.13. Выполните полный цикл до команды LOOP, продолжая пошаговое выполнение команд. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.14. Выполните команду LOOP. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.15. Выполните программу до конца. Последнюю команду RET не выполнять. Определите, какие изменения произошли в регистрах микропроцессора, просмотрите, что записано в сегменте данных вводом команды D DS:00, просмотрите, что записано в сегменте стека вводом команды D SS:00. Выводы запишите в отчет.
4.16. Выйдите из отладчика, введя команду Q.
5. Программа: замена строчных букв на заглавные.
5.1. Заглавные буквы от А до Z имеют коды от 41Н до 5АН, а строчные буквы от а до z имеют коды от 61Н до 7АН. Единственная разница в том, что пятый бит равен 0 для заглавных букв и 1 для строчных:
Биты: 7 6 5 4 3 2 1 0 Биты: 7 6 5 4 3 2 1 0
Буква А: 0 1 0 0 0 0 0 1 Буква а: 0 1 1 0 0 0 0 1
Буква Z: 0 1 0 1 1 0 1 0 Буква z: 0 1 1 1 1 0 1 0
Запишите в текстовом редакторе NORTON следующую программу в COM-формате:
.286
TITLE CASE (COM) Перекодировка в заглавные буквы
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG
ORG 100H
BEGIN: JMP MAIN
;----------------------------------------------------------
TITLEX DB 'Change to uppercase letters'
;----------------------------------------------------------
MAIN PROC NEAR
LEA BX,TITLEX+1;Адрес первого символа
MOV CX,31;Число символов
B20: MOV AH,[BX];Символ из TITLEX
CMP AH,61H;Это
JB B30;прописная
CMP AH,7AH;буква
JA B30;?
AND AH,11011111B;Да - преобразовать
MOV [BX],AH;Записать в TITLEX
B30: INC BX;Следующий символ
LOOP B20;Повторить цикл 31 раз
RET
MAIN ENDP
CODESG ENDS
END BEGIN
Эта программа преобразует данные в поле TITLEX из строчных букв в прописные начиная с адреса TITLEX+1. Программа инициализирует регистр ВХ адресом TITLEX+1 и использует его для пересылки символов в регистр АН начиная с TITLEX+1.
Команда CMP сравнивает код символа в регистре АН с числом 61Н.
Команда JB обеспечивает переход на метку В30, если в результате сравнения АН < 61Н.
Команда JA обеспечивает переход на метку В30, если в результате сравнения АН > 7АН.
Если 61Н < AH < 7AH, то будет выполняться команда AND. Команда AND умножает соответствующие биты числа в АН и числа 11011111 (логическое умножение). В результате умножения все биты числа в АН, кроме пятого, останутся без изменений. Пятый бит установится в 0, что соответствует коду заглавной буквы. Измененные символы засылаются обратно в область TITLEX, значение в регистре ВХ увеличивается для очередного символа и осуществляется переход на следующий цикл.
Используемый таким образом регистр ВХ действует как индексный регистр для адресации в памяти.
5.2. Выполните ассемблирование и компоновку программы case.asm. Запишите листинг программы в отчет. Вызовите отладчик DEBUG для пошагового выполнения программы.
5.3. Выполните первую команду JMP. Просмотрите сегмент кодов, введя команду D CS:100. Определите в каких параграфах находятся коды символов символьной константы TITLEX. Выводы запишите в отчет.
5.4. Выполните в пошаговом режиме 10 - 15 циклов работы программы. Количество циклов контролируйте по регистру СХ. Просмотрите сегмент кодов. Выводы запишите в отчет.
5.5. Выполните трассировку программы до конца, до команды RET. Просмотрите сегмент данных. Выводы запишите в отчет.
5.6. Введите команду Q для выхода из отладчика.