Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Организация ЭВМ и систем. Учебное пособие
.pdf
граммах, так как стек часто используется для временного хранения данных и управ-
ления вызовами функций.
8.3.6 Индексная адресация, также известная как адресация с индексированием,
представляет собой режим адресации, в котором эффективный адрес операнда вы-
числяется как сумма значения смещения, указанного в команде, и содержимого ре-
гистров SI или DI (см. рисунок 8.6). В этом режиме адресации индексными реги-
страми обычно служат регистры SI и DI, и смещение указывается в команде. Этот
режим позволяет создавать адреса, которые могут изменяться во время выполнения
программы, и часто используется для доступа к элементам массивов или структур
данных, где каждый элемент имеет постоянное смещение относительно базового
адреса.
Рисунок 8.6 – Индексная адресация
Индексная адресация обычно применяется для доступа к элементам одномер-
ных массивов. В этом режиме смещение указывает на фиксированный начальный
адрес массива, определенный во время ассемблирования, и значение в индексном
регистре (обычно SI или DI) определяет, к какому элементу массива нужно обра-
титься. Поскольку все элементы массива имеют одинаковый размер, простые опера-
ции над содержимым индексного регистра позволяют обращаться к любому элемен-
ту массива.
Режимы базовой и индексной адресации в процессоре К1810 схожи, так как
базовые адреса и индексные значения имеют одинаковую длину 16 бит. В языке ас-
семблера индексную адресацию можно обозначить как ADDR16 [IREG], где
141

ADDR16 представляет 16-битное смещение, а IREG обозначает один из индексных
регистров SI или DI. Ниже приведены примеры команд с индексной адресацией на
языке ассемблера.
MOV ARRAY[SI], AX ; передать АХ в элемент массива.
ADD CX, ROV[DI] ; прибавить к СХ элемент массива.
XOR DL, MATRIX[SI] ; операция с элементом массива.
8.3.7 Адресация с использованием базы и индексирования представляет собой
режим адресации, в котором эффективный адрес вычисляется как сумма содержи-
мого базового регистра, индексного регистра и смещения, указанного в команде (см.
рисунок 8.7). Этот режим адресации является наиболее гибким, поскольку позволяет
варьировать и изменять два компонента адреса в процессе выполнения программы.
Регистры ВР и ВХ могут использоваться в качестве базовых, а регистры SI и DI как индексные, что дает четыре возможные комбинации регистров для адресации.
Этот режим позволяет эффективно обращаться к данным, расположенным в
памяти с использованием базового адреса, индексного значения и смещения. Такой
подход полезен, например, при работе с многомерными массивами, структурами
данных и другими сложными структурами, где необходимо манипулировать адре-
сами в процессе выполнения программы.
Рисунок 8.7 – Базовая индексная адресация
Поскольку в этом режиме адресации выполняется два отдельных смещения,
он оказывается удобным для обращения к двумерным массивам. В данном случае,
142

базовый регистр содержит начальный адрес массива, а значения сдвига и индексно-
го регистра представляют собой смещения по строке и столбцу.
Предположим, что ваш компьютер отслеживает состояние шести предохрани-
тельных клапанов на химическом заводе. Компьютер считывает их состояния каж-
дые 30 минут и сохраняет их в ячейках памяти. За неделю считывания образуют
массив, состоящий из 336 блоков (48 считываний в течение 7 дней), каждый блок
содержит шесть элементов, всего - 2016 значений.
Если начальный адрес массива хранится в регистре ВХ, смещение блока (рас-
считанное как номер считывания, умноженный на 12) - в регистре DI, а номер кла-
пана задан в переменной VALVE, то команда MOV AX, VALVE [BX][DI] загрузит
необходимое состояние клапана в регистр АХ. На рисунке 8.8 изображен процесс
извлечения результата третьего считывания (с номером 2) для клапана 4 из массива,
у которого смещение в сегменте данных равно 100Н.
Приведем несколько допустимых форматов операндов, адресуемых по базе с
индексированием.
MOVE AX, [BX+2+DI] ; операнды можно заключать в скобки в
MOVE AX, [DI+BX+2] ; любом порядке, а сдвиг можно соче-
MOVE AX, [BX+2][DI] ; тать с любым из регистров.
MOVE AX, [BX][DI+2]
Рисунок 8.8 – Извлечение значения элемента двухмерного массива
143

8.3.8 В режиме относительной адресации эффективный адрес вычисляется как
сумма фиксированного смещения, находящегося в команде, и текущего значения
программного счетчика (РС). Программный счетчик (РС) указывает на адрес следу-
ющего байта после текущей команды, предполагая, что команда с относительной
адресацией уже считана из памяти. Этот режим применяется в МП К1810 только в
командах условных и безусловных переходов, вызовов программ и управления ите-
рациями (или циклами).
Команда содержит короткое 8-битное смещение, которое затем расширяется
до 16 бит с учётом знака, и затем это значение прибавляется к содержимому РС. Та-
ким образом, этот режим позволяет осуществлять переходы в пределах диапазона –
128 до +127 байт от текущей команды. Короткие (SHORT) переходы часто исполь-
зуются в циклических программах и составляют до 80% всех команд передачи
управления.
Рисунок 8.9 – Относительная адресация
Важно отметить, что в ассемблерных программах программист указывает не
абсолютный адрес перехода, а метку команды, к которой необходимо осуществить
переход. Значение смещения, которое определяет фактическое расстояние до ука-
занной метки, автоматически вычисляется программой-ассемблером.
Значение смещения остается постоянным независимо от местоположения про-
граммы в адресном пространстве памяти. Это означает, что относительная адреса-
ция обеспечивает позиционную независимость программы, поскольку переходы вы-
полняются на основе относительных смещений, и программа будет работать кор-
ректно вне зависимости от места её размещения в памяти.
144

8.3.9 В адресации цепочек команд не используются обычные режимы адреса-
ции памяти. Вместо этого неявно применяются индексные регистры, как показано
на рисунке 8.10, для доступа к операндам цепочечных команд.
Рисунок 8.10 – Адресация цепочек
При выполнении цепочной команды предполагается, что регистр SI указывает
на первый байт (или слово) цепочки-источника, а регистр DI - на первый байт (или
слово) цепочки-получателя. В случае повторяющихся цепочечных операций МП ав-
томатически корректирует содержимое регистров SI и DI по мере перехода к следу-
ющим элементам цепочек.
8.4 Ассемблерный уровень архитектуры ЭВМ
Ассемблер – это машинно-ориентированный язык низкого уровня. Програм-
ма-ассемблер заменяет мнемонические обозначения команд и операндов соответственно на коды команд и адреса операндов. Этот процесс называют ассемблированием кода.
Ассемблерная программа состоит из операторов и директив. Операторы – это
инструкции, исполняемые процессором (например, MOV, ADD и т. д.). Директивы,
как правило, служат для указания режимов работы ассемблера (например, директива
.MODEL, см. ниже), для разбиения потока операторов на сегменты и процедуры,
определения данных (также см. ниже), указания размера операнда (BYTE PTR,
WORD PTR) и выполнения некоторых других операций.
Некоторые команды (операторы) могут быть снабжены меткой, по которой
будет сгенерирован адрес команды. Метка должна начинаться с латинской буквы
145

либо символов $, _, @, и может содержать в себе латинские буквы и символы $, _,
@, и цифры. В качестве метки нельзя использовать зарезервированные слова,
названия команд и директив [17-18].
Общий вид оператора на языке ассемблера приведен ниже.
[Метка:] Код_операции [Операнды] [; Комментарий].
В квадратных скобках указаны поля, которые могут отсутствовать, то есть
необязательные поля.
Приведем несколько примеров операторов:
Metka_1: MOV BX, [SI] ; Загрузить в регистр BX содержимое ячейки
; памяти со смещением в регистре SI.
ADD BX, [SI] ; Сложить содержимое регистра BX с содержи-
; мым ячейки памяти
PUSH BX ; Запись содержимое регистра BX в стек.
Программа состоит из трех сегментов: кода, данных и стека. Сегменты опре-
деляются с помощью двух директив: начало (открытие) сегмента с помощью дирек-
тивы SEGMENT, а конец (закрытие) сегмента - ENDS.
Рассмотрим пример определения сегмента.
Имя SEGMENT Тип
Операторы
…
Имя ENDS,
где Имя – произвольное имя сегмента;
Тип – ‘code’ – сегмент кода; ‘data’ – сегмент данных; ‘stack’ – сегмент стека.
Заканчивается программа директивой END. Она имеет вид:
END метка,
где метка – название метки, определяющей адрес оператора программы, который
должен быть выполнен первым при старте программы.
Рассмотрим создание сегмента данных.
146

Сегмент данных предназначен для определения и хранения данных и резуль-
татов программы. Для определения и резервирования данных существуют специ-
альные директивы:
1) DB – размер константы один байт;
2) DW – размер константы два байта (слово);
3) DD – размер константы четыре байта (двойное слово).
Эти директивы имеют 3 формы:
1) D* константа – выделение памяти под переменную и занесение в нее ука-
занной константы;
2) D* константа, константа, …, константа – выделение памяти под массив с
одновременным занесением в него данных. Используется для небольших массивов;
3) D* число элементов DUP (константа) – используется для больших мас-
сивов и служит для выделения памяти под массив с нужным числом элементов и
занесение в каждый элемент массива определенной константы.
Вместо конкретной константы в этих директивах можно указать символ ?,
обозначающий, что под переменную или массив просто выделяется место с неопре-
деленным значением.
Пример сегмента данных.
Date_5 SEGMENT ‘data’
DAN_1 DB 50 ; Переменная с начальным значением 50
DAN_2 DW ? ; Переменная с неопределенным значением
Masiv_5 DB 25 DUP(1) ; Массив из 25 элементов с единичным значением
Masiv_2 DW 1,17,4,-25,0,3 ; Массив из 6 элементов с заданными значениями
Date_5 ENDS
Рассмотрим определение сегмента стека.
Сегмент стека обычно состоит из директивы DB 100 DUP (?), предписывающей
ассемблеру выделить 100 байт под стек:
Stseg5 SEGMENT ‘stack’
DB 100 DUP (?)
Stseg5 ENDS.
147

Сегмент кода содержит все операторы (команды) программы. Описание этого
сегмента всегда содержит директиву ASSUME, которая делает привязку сегментов
к сегментным регистрам и имеет следующий вид:
ASSUME CS: имя сегмента кода, DS: имя сегмента данных, SS: имя сегмента стека.
8.4.1 Форматы ассемблерных программ для последующего создания EXE и
СОМ файлов.
Существует два типа выполняемых программ: ЕХЕ-программы и СОМ-
программы.
Рассмотрим создание ЕХЕ-программ. В ЕХЕ-программе обычно используется
несколько сегментов памяти (сегменты кода, и при необходимости, данных, стека и
дополнительного сегмента кода) и каждый из этих сегментов должен быть в программе описан.
При запуске ЕХЕ-программы и загрузке ее в оперативную память DOS авто-
матически настраивает сегментные регистры DS и ES на начало PSP, который ре-
зервируется операционной системой DOS непосредственно перед EXE-программой
в памяти, а регистр CS – на начало сегмента кода.
Примерный формат ЕХЕ-программы.
stacks_1 segment para stack 'stack' ; Описание сегмента стека
db 100 dup (?) ; Под стек выделяется 100 байт
stacks_5 ends
dats_5 segment para public 'data' ; Описание сегмента данных
… ; Данные
dats_5 ends
cods_5 segment para public 'code' ; Объявление сегмента кода
assume cs: cods_5, ds: dats_5, ss: staks_5 ; Оператор привязывает сегмент-
; тные регистры к объявленным
; сегментам для правильной
; трансляции
begin: mov ax,dats_5 ; В сегментный регистр
mov ds,ax ; ds загружается базовый адрес
148

; сегмента данных
… ; программа
mov ah,4ch ; выход в операционную систему
int 21h
cods_5 ends ; закрытие сегмента кода
end begin ; конец программы
Ассемблерная программа пишется практически в любом редакторе, например
в блокноте, но имейте в виду, что ввод для Ассемблера должен осуществляться од-
нобайтовыми символами и должен включать служебные символы. Поэтому ввод
текста в MS WORD недопустим. Ассемблерная программа должна иметь расшире-
ние .asm.
После написания программа (имя.asm) должна быть оттранслирована с помо-
щью транслятора tasm.exe (в командной строке набирается: tasm.exe имя .asm, или
просто tasm имя файла). В результате получается файл имя.obj.
Далее необходимо установить связи с помощью редактора связей tlink.exe (в
командной строке набирается: tlink.exe имя.obj или просто tlink имя файла).
В результате получится требуемый файл имя.exe, который может быть запу-
щен на выполнение.
Для отладки программы или просмотра результата или хода работы можно
использовать отладчик Turbo Debuger ( в командной строке набирается: td.exe имя
.exe, или просто td имя файла).
Приведем пример программы, которая находит сумму трех чисел: X1=24,
Х2=-36, Х3=-42 и сохраняет все результаты в ячейках памяти с именами RES_1 и
RES_2 (переменные RES_1 и RES_2).
; Объявляем все сегменты: стека, данных, кода
; Сегмент стека
Stseg1 SEGMENT STACK ‘stack’
DB 100 DUP (?)
Stseg1 ENDS
; Сегмент данных
149

Datseg1 SEGMENT ‘data’
X1 DB 24
X2 DB -36
X3 DB -42
RES_1 DB ?
RES_2 DB ?
Datseg1 ENDS
; Сегмент кода
Codseg1 SEGMENT ‘code’
ASSUME CS: Codseg1, DS: Datseg1, SS:Stseg1
; Программа
; Настроим DS на наш сегмент данных
Start:
MOV AX, Datseg1
MOV DS, AX
; Делаем вычисления
MOV AL, X1 ; Заносим переменную X1 в регистр AL
ADD AL, X2 ; Складываем X1 и X2, результат в AL
MOV REZ_1, AL ; Сохраняем результат в памяти
ADD AL, X3 ; Добавляем к сумме переменную X3, результат в AL
MOV RES_2, AL ; Переписываем полученную сумму в память
Codseg1 ends
End start
8.4.2 Просмотр результатов работы программы.
Для просмотра результатов необходимо запустить отладчик программ. Иссле-
дуя работу программы в отладчике, мы можем поближе познакомиться с архитектурой ЭВМ:
увидеть, как кодируются числа со знаком;
как данные располагаются в памяти;
как осуществляется адресация команд и данных в памяти;
150
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
