УМ-М: Регистры и косвенная адресация
Один из способов повысить эффективность работы программы — предусмотреть небольшое количество выделенных быстродействующих ячеек памяти — регистров общего назначения
- Проблема абсолютной адресации стоит не так остро: если операндами являются регистры, то их номера занимают небольшое число битов, и их можно гарантированно разместить в команде — в отличие от полных адресов ячеек памяти. Напомним, что размер адреса обычно сопоставим с размером машинного слова, нередко — равен ему.
- Скорость доступа к содержимому регистра обычно намного (на несколько порядков!) быстрее чтения из памяти.
Регистр может содержать адрес, а процессор — иметь доступ к памяти по адресу, хранящемуся в регистре (это называется косвенной адресацией). Косвенная адресация позволяет работать с массивами денных без модификации кода.
Регистровая учебная машина УМ-Р
- Адресуемая ячейка памяти — 16 разрядов
- Целое число — 32 разряда
- 16 32-разрядных регистров (идентификатор регистра — четыре разряда в коде инструкции)
- Арифметические операции имеют вид (КК — код операции, П — регистр-приёмник, И — регистр-источник, АААА — адрес ячейки-операнда, 0 — поле, не используемое в УМ-Р)
«Регистр-Регистр» (одна ячейка) : КК П И
«Регистр-Память» (две ячейки): КК П 0 АААА
в modelmachine реализована как подмонжество УМ-М
16 регистров позволяют проводить довольно сложные вычисления без дополнительного обмена с ОП. В начале программы данные загружаются из памяти, в конце — результаты выгружаются в память.
Пример: максимум из трёх чисел (воспользуемся совместимой с УМ-Р поддерживаемой эмулятором архитектурой УМ-М)
mmm [config] input = 0x20,0x22,0x24 output = 0x26 [code] 00 1 0 0020 ; 00 ; загрузка A в R1 00 2 0 0022 ; 02 ; загрузка B в R2 00 3 0 0024 ; 04 ; загрузка C в R3 20 4 1 ; 06 ; R4:=R1 25 4 2 ; 07 ; Сравнить R4 и R2 84 0 0 000B ; 08 ; Если ≥, обойти следующую инструкцию 20 4 2 ; 0A ; R4:=R2 25 4 3 ; 0B ; Сравнить R4 и R3 84 0 0 000F ; 0C ; Если ≥, обойти следующую инструкцию 20 4 3 ; 0E ; R4:=R3 10 4 0 0026 ; 0F ; выгрузить R4 в D 99 0 0 ; 11 ; [input] 32 24 22
В регистрах можно эффективно хранить границы и изменения циклов.
Пример: ввести M и N, посчитать сумму квадратов от M2+(M+1)2+…+(N-1)2+N2
mmm [config] input = 0x1000, 0x1002 output = 0x1004 [code] 00 1 0 1000 ; 00; R1:=M 00 2 0 1002 ; 02; R2:=N 22 3 3 ; 04; R3-=R3 (обнуление) 00 A 0 0013 ; 05; RA:=1 25 1 2 ; 07; сравнить R1 и R2 86 0 0 0010 ; 08; Переход если > 20 4 1 ; 0A; R4:=R1 23 4 1 ; 0B; R4*=R4 21 3 4 ; 0C; R3+=R4 21 1 A ; 0D; R1+=RA (+=1) 80 0 0 0007 ; 0E; продолжение цикла 10 3 0 1004 ; 10; выгрузить R4 в S 99 0 0 ; 12; стоп 00 0 0 0001 ; 13; 1 [input] 5 10
Косвенная адресация. Модификация адреса
Как было ранее показано, работа с массивами данных при помощи самомодификации кода имеет серьёзные недостатки, в частности, трудность отладки неработающей программы. Переменный размер команды эти трудности только усугубляет.
Нужен механизм, позволяющий хранить адреса вне инструкций (в памяти или в регистрах) и использовать эти адреса для доступа к соответствующим ячейкам оперативной памяти. Тогда проход по массиву данных циклом будет состоять в циклическом изменении не ячейки с командой, а ячейки, хранящей адрес.
Косвенная адресация — механизм доступа к оперативной памяти, при котором в инструкции указывается не сам адрес, а место хранения этого адреса (например, регистр).
В некоторых архитектурах разрешена косвенная адресация по памяти (из ячейки памяти считывается адрес другой ячейки памяти, по которому берётся значение) и даже двойная косвенная адресация (адрес адреса!).
Очевидный недостаток косвенной адресации — усложнение такта работы машины: извлечение адреса плюс чтение значения вместо одного чтения. Косвенная адресация по «медленной» памяти вдобавок сильно замедляет такт.
Машина с модификацией адреса УМ-М
Поскольку работа с массивами данных происходит в оперативной памяти, в УМ-М косвенная адресация используется в командах вида «Регистр-Память». Второй операнд — регистр команд вида «регистр-память» — называется смещением.
Исполнительный адрес (актуальный адрес, с которым работает инструкция), — сумма поля адреса и содержимого регистра смещения.
Такт работы операции вида «КК П С АААА», где КК — код операции, П — номер регистра-приёмника, С — номер регистра-смещения, AAAA — базовый адрес в УМ-Р
- Считать ячейку «КК П С»
- Проанализировать размер инструкции
- Считать ещё одну ячейку «АААА»
Вычислить адрес операнда, равный AAAA + содержимое регистра № С
- Загрузить операнд
- Вычислить операцию КК
- Результат поместить в регистр П
- Вычислить адрес следующей команды
Исключение: значение 0 в поле смещения означает прямую адресацию (без смещения). Регистр R0, таким образом, невозможно использовать для смещения.
Пример: Прибавить константу 0x123 к четырём (количество произвольное) ячейкам памяти, начиная с адреса 0x1000.
mmm [config] input = 0x1000, 0x1002, 0x1004, 0x1006 output = 0x1000, 0x1002, 0x1004, 0x1006 [code] 22 4 4 ; 00 ; обнуление регистра (вычтем R4 из R4) 00 2 4 1000 ; 01 ; загрузим R4-й элемент массива (поначалу нулевой) в R2 01 2 0 000e ; 03 ; добавим 123 к R2 10 2 4 1000 ; 05 ; запишем обратно 01 4 0 0010 ; 07 ; добавим 2 к R4 05 4 0 0012 ; 09 ; сравним с последним индексом массива 95 0 0 0001 ; 0B ; переход обратно, если не больше 99 0 0 ; 0D ; 00000123 ; 0E ; 0x123 00000002 ; 10 ; 2 00000006 ; 12 ; 6 [input] 123 234 345 456
Здесь R4 играет роль индекса массива: инструкции 00 и 10 содержат 0x1000 в качестве базового адреса, к которому при чтении и, соответственно, записи, прибавляется содержимое R4. Размер целого в УМ-М — 4 байта, т. е. две ячейки, поэтому к R4 в цикле прибавляется константа 2.
- При вычислении адреса в УМ-М от суммы базового адреса и смещения берётся остаток по модулю 0x10000 (объём адресного пространства).
Дополнительная инструкция 11 П С АААА вычисляет исполнительный адрес (содержимое регистра С + число АААА, адрес) и записывает его в регистр П.
Замечание: нет никакой принципиальной разницы между выполнением:
команды 00 1 2 1000 при R2==8
команды 00 1 2 0008 при R2==0x1000
Однако команда 00 1 0 1008 выполняется слегка по-другому, т. к. содержимое R0 не используется, и сложения не производится.
Смещение присутствует и в командах перехода УМ-М. Это позволяет вычислять и изменять адрес перехода, не модифицируя код программы.
А зачем это может быть нужно?
В других архитектурах механизмы адресации могут быть и другие:
Во многих случаях удобно использовать непосредственную адресацию. Мы встречались с ней в стековой машине: это ситуация, когда один из операндов команды содержит не номер ячейки, а само число. Непосредственно в поле операнда можно хранить, например:
- приращение счётчика, которое надо прибавить или отнять; оно обычно невелико — это 1, или размер ячейки (в УММ — 2), или размер одного набора данных
относительный адрес перехода, при организации ветвлений и циклов, переход вперёд — положительное число, назад — отрицательное; опять-таки, это редко бывает далеко
в современных архитектурах полный адрес занимает довольно много места, поэтому в операндах типа «регистр+число» поле «число» (относительно небольшое) трактуется не как адрес, а как всё то же короткое целое, то есть как смещение. Собственно адрес лежит в регистре; правда при этом получается неразбериха: модифицируем мы регистр, то есть адрес, а непосредственно заданное смещение остаётся нетронутым
- Регистр, в котором лежит смещение, может быть неявным: при выполнении адресных операций его содержимое прибавляется ко всем адресам. Такие регистры смещения обычно не смешиваются с регистрами общего назначения
Данные и программа могут иметь разные регистры смещений
- …
TODO Ещё пример на косвенную адресацию?
Программирование в машинных кодах и язык ассемблера
Цель: небессмысленно выполнить произвольную программу на ЭВМ
Задача: ввести готовую программу и данные в ОЗУ, запустить программу, получить данные
- Ввод программы
- Вручную (пульт)
- Из ПЗУ
- С устройства хранения (требуется операционная система)
- Ввод данных
Вводится вся оперативная память, включая данные и программу (возможно, не до конца, как в УМ)
- Повторно, тем же способом, что и ввод программы (надо отдельно указать адрес начала данных)
- Программа сама вводит данные после запуска (требуется операционная система)
- Вывод результатов
- Вручную (доступ пользователя к ОЗУ, как в УМ)
- Программа сама выводит на внешнее устройство (требуется операционная система)
- Адрес старта
- Зафиксировать единственный для всех программ
- Вводить с помощью специального инструмента (пульта)
Включить адрес старта в формат исполняемого файла (требуется операционная система)
Недостатки программирования в кодах
- Неудобное представление (нужен специальный редактор или транслятор из текстового представления чисел, как в УМ)
- Приходится работать со всей ОП (нет возможности заполнить только нужные ячейки в разных местах, например, код + данные)
- Трудно запомнить систему команд в виде чисел
- Адреса переменных и переходов — числа, трудно соотнести со смыслом алгоритма
Главное: адреса переменных и особенно переходов меняются при изменении кода программы