Организация основной памяти и средства аппаратной поддержки управления памятью
Рассмотрим организация памяти в микропроцессорах i8086, i386 и више.
Организация основной памяти в микропроцессоре i8086. В микропроцессоре i8086 для адресации основной памяти предусматриваются 20-битовые адреса, что позволяет работать с основной памятью до 1 Мбайта [35].
Минимальной адресуемой единицей основной памяти ПЭВМ является байт, состоящий из 8 бит. Доступ к байтам основной памяти осуществляется по номерам (номер байта является его физическим адресом в устройстве памяти).
Физический адрес в микропроцессоре i8086 формируется из 16-битового смещения и содержимого 16-битового сегментного регистра, сдвинутого влево на 4 бита (рис. 3.2).
Для размещения программ и данных в основной памяти выделяются специальные области - сегменты. Адреса этих областей хранятся в специальных сегментных регистрах [35].
Каждый из четырех сегментных регистров используется для хранения адреса определенного сегмента (рис. 3.3):
сегмента кодов, т. е. области программ;
сегмента данных, т. е. области размещения данных;
дополнительного сегмента данных, используемого некоторыми командами;
сегмента стека, т.е. области размещения стека.
Стек – эта специальным образом организованная область оперативной памяти [34, 37], допускающую последовательную запись элементов данных длиной 2 байта (слово) и чтение их в порядке, обратном порядку записи, т.е по принципу «последним вошел - первым вышел» (LIFO). Байты программы в оперативной памяти располагаются последовательно по нарастающим адресам. Стек заполняется по последовательно убывающим адресам. Во избежание перекрытия этих двух областей памяти стек обычно располагается в старших адресах.
Начальный адрес стека, называемый дном (bottom) записывается в регистр SP командой MOV SP,0fffeh. Вместо 0fffeh - адрес предпоследнего байта сегмента, может быть другое значение, но выравненное по двухбайтовым, т. е. четным адресам. Текущее значение содержимого SP называется, также адресом вершины стека (top). Если адрес вершины совпадает с адресом дна - стек считается пустым. Рассмотрим механизм помещения в стек и извлечения из него данных на примере команд PUSH AX и POP BX. Пусть начальное значение аккумулятора AX равно 8а4c.
Команда PUSH выполняется в четыре этапа:
Адрес в SP уменьшается на 1: (SP) =(SP) - 1.
По этому адресу помещается старший байт 8а: ((SP)) = (AH).
Содержимое SP снова уменьшается на 1: (SP)=(SP) - 1.
По полученному адресу загружается младший байт 4c: ((SP)) = (AL).
Действие команды POP аналогично описанному процессу, но в происходит в обратном порядке:
(BL) = ((SP)),
(SP) = (SP) + 1,
(BH) = ((SP)),
(SP) =(SP) + 1.
Байты в стек помещаются по правилу "старший байт по старшему адресу". Преимущество стека в том, что программисту не нужно заботиться об абсолютных значениях адресов переменных, но в этом таится и опасность, если текущее содержимое указателя стека будет потеряно, при неаккуратных действиях программиста, то работа компьютера станет непредсказуемой и он, как говорят в таких случаях, «зависнет».
В программах стек используется для:
1) сохранения и извлечения адреса возврата из подпрограмм командами ассемблера CALL и RET (IRET),
2) хранения локальных переменных,
3) передачи фактических параметров подпрограммам (трансляторами с языков высокого уровня),
4) временного хранения содержимого регистров фоновой программы при ее прерывании.
Формат команд микропроцессора 8086
Формат команд микропроцессора 8086 позволяет указывать в команде только один операнд, размещенный в основной памяти, т. е. одной командой нельзя, например, сложить содержимое двух ячеек памяти. С форматами команд микропроцессоров i386, i486 и Pentium можно ознакомиться по работам [33, 34] или при изучении раздела 2.2 данной работы
Принципиально допускается 8 способов задания смещения (исполнительного адреса) операндов, размещенных в основной памяти [35]:
SI + <индексное смещение>
DI + <индексное смещение>
BP + <индексное смещение>
BХ+ <индексное смещение>
BP + SI + < индексное смещение>
BP + DI +< индексное смещение>
BX + SI + <индексное смещение>
BX + DI + <индексное смещение>
Во всех случаях исполнительный адрес операнда определяется как сумма содержимого указанных регистров и индексного смещения, представляющего собой некоторое число (одно- или двухбайтовое).
Выполнение программы
Содержимое регистров СS и IP, в которых хранится базовый адрес сегмента кодов и смещение очередной команды относительно начала сегмента, определяет физический адрес команды, которая должна быть выполнена на следующем шаге [35].
По указанному адресу из основной памяти считывается команда и пересылается в микропроцессор. Команда длиной от 1 до 8 байт помещается в очередь команд, откуда поступает в устройство управления, где дешифрируется.
Если при выполнении команды требуются данные, расположенные в основной памяти, то специальное поле кода команды определяет способ адресации и вычисляется исполнительный, и затем и физический адрес данных.
Данные, считанные из основной памяти по указанному адресу, пересылаются в регистр данных или в арифметико-логическое устройство и обрабатываются в соответствии с кодом команды. Результат помещается либо в регистры, либо (в соответствии с командой) в какую-либо область основной памяти.
Если выполненная команда не являлась командой передачи управления, то содержимое регистра IP увеличивается на длину выполненной команды, в противном случае в регистр IP заносится исполнительный адрес команды, которая должна выполняться следующей.
Затем процесс повторяется.
Организация основной памяти в микропроцессоре i386. Еще более сложный метод адресации памяти с сегментированием использован в процессоре Intel 80386 и в более поздних моделях процессоров фирмы Intel [34,35, 36]. Этот метод иллюстрируется рис. 3.4.
Адрес памяти (физический адрес) вычисляется в три этапа. Сначала вычисляется так называемый эффективный адрес (32-разрядный) путем суммирования трех компонентов: базы, индекса и смещения (Base, Index, Displacement), причем возможно умножение индекса на масштаб (Scale). Эти компоненты имеют следующий смысл:
смещение - это 8-, 16- или 32-разрядное число, включенное в команду.
база - это содержимое базового регистра процессора. Обычно оно используется для указания на начало некоторого массива.
индекс - это содержимое индексного регистра процессора. Обычно оно используется для выбора одного из элементов массива.
масштаб - это множитель (он может быть равен 1, 2, 4 или 8), указанный в коде команды, на который перед суммированием с другими компонентами умножается индекс. Он используется для указания размера элемента массива.
Затем специальный блок сегментации вычисляет 32-разрядный линейный адрес, который представляет собой сумму базового адреса сегмента из сегментного регистра с эффективным адресом. Наконец, физический 32-битный адрес памяти образуется путем преобразования линейного адреса блоком страничной переадресации, который осуществляет перевод линейного адреса в физический страницами по 4 Кбайта.
В любом случае сегментирование позволяет выделить в памяти один или несколько сегментов для данных и один или несколько сегментов для программ. Переход от одного сегмента к другому сводится всего лишь к изменению содержимого сегментного регистра. Иногда это бывает очень удобно. Но для программиста работать с сегментированной памятью обычно сложнее, чем с непрерывной, несегментированной памятью, так как приходится следить за границами сегментов, за их описанием, переключением и т.д.