3.3. РАБОТА МИКРОПРОЦЕССОРА С ПАМЯТЬЮ. МЕТОДЫ АДРЕСАЦИИ
К оглавлению1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1617 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
Адресное пространство МП состоит из множества ячеек памяти ОЗУ, из которых он может брать информацию или засылать ее. Как говорилось выше, начиная с 4-го поколения доминирует байтовая организация памяти, и минимально адресуемой единицей является байт. Например, для ОЗУ емкостью 1024 кбайта адреса байтов таковы:
00000 00001 ... FFFFF
(как принято, записываем их в шестнадцатеричнои системе; адрес последнего байта есть 1024*1024 -1=1 048 576 - 1 = FFFFF). Длина же ячейки («машинного слова») может быть как один, так и несколько байтов в зависимости от типа процессора и команды, обрабатывающей соответствующую информацию.
При обмене информацией с памятью процессор обращается к ячейкам ОЗУ по их номерам (адресам). Способы задания требуемых адресов в командах ЭВМ принято называть методами адресации. От видов и разнообразия методов адресации существенно зависит эффективность работы программы с данными, особенно если последние организованы в определенную структуру.
Для того, чтобы процессор мог извлечь данные из ячейки ОЗУ или поместить их туда, необходимо где-то задать требуемый адрес. Если адрес находится в самой команде, то мы имеем дело с прямой адресацией. Поскольку при подобном способе слишком сильно возрастает длина команды, то, чтобы избежать этого неприятного эффекта, при обращении к ОЗУ процессор использует метод косвенной адресации. Идея состоит в том, что адрес памяти предварительно заносится в один из регистров МП, а в команде содержится лишь ссылка на этот регистр. Если учесть, что при хранении адреса в регистре его еще очень удобно модифицировать (скажем, циклически увеличивая на заданную величину), становится понятным, почему косвенная адресация нашла такое широкое применение.
Приведем описание наиболее распространенных вариантов ссылок на исходную информацию (учитывая, что терминология для разных МП может различаться, названия методов адресации не приводятся):
1) данные находятся в одном из регистров МП;
2) данные входят непосредственно в состав команды, т.е. размещаются после кода операции (операции с константой);
3) данные находятся в ячейке ОЗУ, адрес которой содержится в одном из регистров МП;
4) данные находятся в ячейке ОЗУ, адрес которой вычисляется по формуле
адрес = базовый адрес + смещение.
Базовый адрес хранится в одном из регистров МП и является начальной точкой массива данных. Смещение может быть как некоторой константой, так и содержимым другого регистра. Часто такой способ доступа к ОЗУ называют индексным, так как это похоже на нахождение элемента в одномерном массиве по его индексу.
Следует подчеркнуть, что здесь описаны лишь наиболее общие методы адресации. У конкретных моделей МП существуют некоторые особенности адресации ОЗУ. Кроме того, имеющиеся методы адресации могут быть комбинированными. Так, например, в процессорах семейства PDP возможна двойная косвенная адресация: данные хранятся в ячейке ОЗУ, адрес которой хранится в ячейке, адрес которой находится в указанном регистре (как тут не вспомнить детский стишок о синице, которая ворует пшеницу, которая в темном чулане хранится, в доме, который построил Джек?).
Методы адресации могут быть и более экзотическими. Рассмотрим, например, широко распространенный сегментный способ, принятый в процессорах фирмы «Intel». Известный американский программист Питер Нортон метко назвал эют способ словом «клудж» (от английского «kludge» - приспособление для временного устранения проблемы). Сегментный метод адресации был предложен для первого 16-разрядного МП 8086 для того. чтобы, используя 16-разрядные регистры, можно было получить 20-разрядный адрес и тем самым расширить максимально возможный объем ОЗУ с 64 кбайт до 1 Мбайта. Суть метода состоит в том, что адрес ОЗУ вычисляется как сумма двух чисел (сегмента и смещения), причем одно из них сдвинуто влево на 4 двоичных разряда, т.е. умножено на 16. Пусть, например, сегмент в шестнадцатеричном виде равен АООО, а смещение - 1000. Общепринятая запись такого адреса имеет вид АООО: 1000. Итоговый адрес равен
А000()
+ 1000
А1000
«Такой способ адресации более 64 кбайт памяти кажется довольно странным, однако он работает», - не без некоторой иронии замечает по этому поводу Питер Нортон.
Добавим, что, помимо всего прочего, при сегментной адресации один и тот же адрес ОЗУ может быть представлен несколькими комбинациями чисел (в самом деле, одну и ту же сумму можно получить разными способами)
Поскольку современные интелловские процессоры, начиная с 80386, стали 32-разрядными, их регистров хватает, чтобы адресовать до 4 Гбайт памяти Сегментный способ при этом становится излишним, хотя и сохраняется как вариант ради обеспечения программной совместимости с предыдущими моделями.
Нам осталось рассмотреть еще один очень специфический, но интересный и часто используемый на практике способ адресации данных в ОЗУ. Речь пойдет о работе со стеком. Сам термин происходит от английского слова «stack», имеющего множество значений, причем ни одно из них не подходит достаточно точно. Чаще всего в литературе упоминается магазин револьвера, который по очереди обеспечивает доступ к каждому патрону. Даже если не учитывать ненужную «милитаризацию» терминологии, такой перевод явно не подходит к современной реализации стека. Во-первых, стек не является круговым, а во-вторых, информация в стеке микрокомпьютера не смещается (для точности аналогии пришлось бы признать, что магазин покоится, а вращается револьвер!). Поэтому возьмем термин «стек» как есть, без перевода, и перейдем к определению.
Стек - это неявный способ адресации, при котором информация записывается и считывается только последовательным образом с использованием, так называемого, указателя стека.
Обратимся к примеру. Пусть требуется на время сохранить значения трех целочисленных переменных N1, N2 и N3, а затем их все сразу восстановить. Попробуем воспользоваться для этого стековой памятью. Прежде всего запомним, что стек всегда имеет единственный вход и выход информации - для .хранения его адреса и нужен указатель стека. Пусть для определенности он сейчас содержит адрес 2006 (рис. 4.13, а). Тогда по команде «записать в стек N1» (обратите внимание, что в команде не фигурирует явно ни адрес ОЗУ, ни регистр МП!) процессор проделает следующее:
1) уменьшит указатель стека на 2 (целое число занимает в памяти 2 байта);
2) запишет N1 по полученному адресу 2004 (рис. 4.13, б).
Аналогично при выполнении команд «записать в стек N2» и «записать в стек N3» значения этих переменных попадут в ячейки 2002 и 2000, причем указатель стека станет равным 2000 (рис. 4.13, в).
Рис. 4.13. Пример для изучения принципа работы стека
Теперь займемся извлечением информации. Как видно из рис. 4.13, в, указатель сейчас «направлен» на значение переменной N3, а значит считывать придется, начиная с него. Выполним команду «прочитать из стека N3». При этом процессор
1) считает в N3 значение из стека;
2) увеличит указатель на 2 (рис. 4.13, г).
Аналогично прочитаем N2 и N1, после чего стек опустеет и вернется к начальному состоянию, изображенному на рис. 4.13, а.
Примечание. Обратим внимание на то, что значение в стеке после считывания, конечно же, не исчезает, как это условно показано на рис. 4.13, г, но есть причины полагать, что мы его там можем больше не увидеть. Дело в том, что процессор имеет право иногда временно использовать стек для своих «внутренних» нужд. При этом некоторые ячейки, адреса которых меньше текущего указателя стека, естественно, изменятся. Следовательно, во избежание неприятностей лучше всегда считать, что после считывания информации в стековой памяти она пропадает.
Подводя итоги рассмотрения примера, обратим внимание на следующее. Та информация, которая заносится в стек первой, извлекается последней и наоборот. Обычно об организации стека говорят: «первым пришел - последним ушел». Удобно представить себе аналогию с детской пирамидкой, нижнее кольцо которой невозможно снять до тех пор, пока не будут сняты все остальные.
Еще раз подчеркнем, что в командах работы со стеком адрес ОЗУ не фигурирует в явном виде. Но при этом молчаливо предполагается, что указатель стека уже задан. Как правило, инициализацию указателя стека компьютер делает сам, но не мешает поинтересоваться, так ли это в вашем конкретном случае и достаточно ли памяти под стек имеется при этом. Если указатель стека определен неправильно, то запись в стек может разрушить полезную информацию в ОЗУ и вызвать непредсказуемые последствия.
Интересно, что со стековым способом организации мы имеем дело в жизни гораздо чаще, чем это может показаться на первый взгляд. Во-первых, дисциплине «первым пришел - последним ушел» подчиняются скобки в арифметических выражениях: первой всегда закрывается «самая внутренняя», т.е. как раз последняя скобка. Если вы знакомы с программированием на любом алгоритмическом языке, то без труда найдете и еще два примера: вложенные циклы и подпрограммы.
Итак, мы подробно рассмотрели общие принципы записи информации в стек. Остается сказать, что стековый способ организации ОЗУ используется в вычислительной технике очень широко. На аппаратном уровне процессор «обучен» сохранять в стеке текущий адрес программы при выполнении команды перехода с возвратом, т.е. при вызове подпрограммы. Часто программа предварительно заносит в тот же самый стек необходимые для подпрограммы параметры: так реализуется, например, вызов процедур и функций с параметрами в языке «Паскаль». Кроме того. стек часто используется для временного сохранения значений тех или иных внутренних регистров процессора. Наконец, процессор активно использует стек при реализации прерываний от внешних устройств (об этом будет рассказано в следующем параграфе).
Адресное пространство МП состоит из множества ячеек памяти ОЗУ, из которых он может брать информацию или засылать ее. Как говорилось выше, начиная с 4-го поколения доминирует байтовая организация памяти, и минимально адресуемой единицей является байт. Например, для ОЗУ емкостью 1024 кбайта адреса байтов таковы:
00000 00001 ... FFFFF
(как принято, записываем их в шестнадцатеричнои системе; адрес последнего байта есть 1024*1024 -1=1 048 576 - 1 = FFFFF). Длина же ячейки («машинного слова») может быть как один, так и несколько байтов в зависимости от типа процессора и команды, обрабатывающей соответствующую информацию.
При обмене информацией с памятью процессор обращается к ячейкам ОЗУ по их номерам (адресам). Способы задания требуемых адресов в командах ЭВМ принято называть методами адресации. От видов и разнообразия методов адресации существенно зависит эффективность работы программы с данными, особенно если последние организованы в определенную структуру.
Для того, чтобы процессор мог извлечь данные из ячейки ОЗУ или поместить их туда, необходимо где-то задать требуемый адрес. Если адрес находится в самой команде, то мы имеем дело с прямой адресацией. Поскольку при подобном способе слишком сильно возрастает длина команды, то, чтобы избежать этого неприятного эффекта, при обращении к ОЗУ процессор использует метод косвенной адресации. Идея состоит в том, что адрес памяти предварительно заносится в один из регистров МП, а в команде содержится лишь ссылка на этот регистр. Если учесть, что при хранении адреса в регистре его еще очень удобно модифицировать (скажем, циклически увеличивая на заданную величину), становится понятным, почему косвенная адресация нашла такое широкое применение.
Приведем описание наиболее распространенных вариантов ссылок на исходную информацию (учитывая, что терминология для разных МП может различаться, названия методов адресации не приводятся):
1) данные находятся в одном из регистров МП;
2) данные входят непосредственно в состав команды, т.е. размещаются после кода операции (операции с константой);
3) данные находятся в ячейке ОЗУ, адрес которой содержится в одном из регистров МП;
4) данные находятся в ячейке ОЗУ, адрес которой вычисляется по формуле
адрес = базовый адрес + смещение.
Базовый адрес хранится в одном из регистров МП и является начальной точкой массива данных. Смещение может быть как некоторой константой, так и содержимым другого регистра. Часто такой способ доступа к ОЗУ называют индексным, так как это похоже на нахождение элемента в одномерном массиве по его индексу.
Следует подчеркнуть, что здесь описаны лишь наиболее общие методы адресации. У конкретных моделей МП существуют некоторые особенности адресации ОЗУ. Кроме того, имеющиеся методы адресации могут быть комбинированными. Так, например, в процессорах семейства PDP возможна двойная косвенная адресация: данные хранятся в ячейке ОЗУ, адрес которой хранится в ячейке, адрес которой находится в указанном регистре (как тут не вспомнить детский стишок о синице, которая ворует пшеницу, которая в темном чулане хранится, в доме, который построил Джек?).
Методы адресации могут быть и более экзотическими. Рассмотрим, например, широко распространенный сегментный способ, принятый в процессорах фирмы «Intel». Известный американский программист Питер Нортон метко назвал эют способ словом «клудж» (от английского «kludge» - приспособление для временного устранения проблемы). Сегментный метод адресации был предложен для первого 16-разрядного МП 8086 для того. чтобы, используя 16-разрядные регистры, можно было получить 20-разрядный адрес и тем самым расширить максимально возможный объем ОЗУ с 64 кбайт до 1 Мбайта. Суть метода состоит в том, что адрес ОЗУ вычисляется как сумма двух чисел (сегмента и смещения), причем одно из них сдвинуто влево на 4 двоичных разряда, т.е. умножено на 16. Пусть, например, сегмент в шестнадцатеричном виде равен АООО, а смещение - 1000. Общепринятая запись такого адреса имеет вид АООО: 1000. Итоговый адрес равен
А000()
+ 1000
А1000
«Такой способ адресации более 64 кбайт памяти кажется довольно странным, однако он работает», - не без некоторой иронии замечает по этому поводу Питер Нортон.
Добавим, что, помимо всего прочего, при сегментной адресации один и тот же адрес ОЗУ может быть представлен несколькими комбинациями чисел (в самом деле, одну и ту же сумму можно получить разными способами)
Поскольку современные интелловские процессоры, начиная с 80386, стали 32-разрядными, их регистров хватает, чтобы адресовать до 4 Гбайт памяти Сегментный способ при этом становится излишним, хотя и сохраняется как вариант ради обеспечения программной совместимости с предыдущими моделями.
Нам осталось рассмотреть еще один очень специфический, но интересный и часто используемый на практике способ адресации данных в ОЗУ. Речь пойдет о работе со стеком. Сам термин происходит от английского слова «stack», имеющего множество значений, причем ни одно из них не подходит достаточно точно. Чаще всего в литературе упоминается магазин револьвера, который по очереди обеспечивает доступ к каждому патрону. Даже если не учитывать ненужную «милитаризацию» терминологии, такой перевод явно не подходит к современной реализации стека. Во-первых, стек не является круговым, а во-вторых, информация в стеке микрокомпьютера не смещается (для точности аналогии пришлось бы признать, что магазин покоится, а вращается револьвер!). Поэтому возьмем термин «стек» как есть, без перевода, и перейдем к определению.
Стек - это неявный способ адресации, при котором информация записывается и считывается только последовательным образом с использованием, так называемого, указателя стека.
Обратимся к примеру. Пусть требуется на время сохранить значения трех целочисленных переменных N1, N2 и N3, а затем их все сразу восстановить. Попробуем воспользоваться для этого стековой памятью. Прежде всего запомним, что стек всегда имеет единственный вход и выход информации - для .хранения его адреса и нужен указатель стека. Пусть для определенности он сейчас содержит адрес 2006 (рис. 4.13, а). Тогда по команде «записать в стек N1» (обратите внимание, что в команде не фигурирует явно ни адрес ОЗУ, ни регистр МП!) процессор проделает следующее:
1) уменьшит указатель стека на 2 (целое число занимает в памяти 2 байта);
2) запишет N1 по полученному адресу 2004 (рис. 4.13, б).
Аналогично при выполнении команд «записать в стек N2» и «записать в стек N3» значения этих переменных попадут в ячейки 2002 и 2000, причем указатель стека станет равным 2000 (рис. 4.13, в).
Рис. 4.13. Пример для изучения принципа работы стека
Теперь займемся извлечением информации. Как видно из рис. 4.13, в, указатель сейчас «направлен» на значение переменной N3, а значит считывать придется, начиная с него. Выполним команду «прочитать из стека N3». При этом процессор
1) считает в N3 значение из стека;
2) увеличит указатель на 2 (рис. 4.13, г).
Аналогично прочитаем N2 и N1, после чего стек опустеет и вернется к начальному состоянию, изображенному на рис. 4.13, а.
Примечание. Обратим внимание на то, что значение в стеке после считывания, конечно же, не исчезает, как это условно показано на рис. 4.13, г, но есть причины полагать, что мы его там можем больше не увидеть. Дело в том, что процессор имеет право иногда временно использовать стек для своих «внутренних» нужд. При этом некоторые ячейки, адреса которых меньше текущего указателя стека, естественно, изменятся. Следовательно, во избежание неприятностей лучше всегда считать, что после считывания информации в стековой памяти она пропадает.
Подводя итоги рассмотрения примера, обратим внимание на следующее. Та информация, которая заносится в стек первой, извлекается последней и наоборот. Обычно об организации стека говорят: «первым пришел - последним ушел». Удобно представить себе аналогию с детской пирамидкой, нижнее кольцо которой невозможно снять до тех пор, пока не будут сняты все остальные.
Еще раз подчеркнем, что в командах работы со стеком адрес ОЗУ не фигурирует в явном виде. Но при этом молчаливо предполагается, что указатель стека уже задан. Как правило, инициализацию указателя стека компьютер делает сам, но не мешает поинтересоваться, так ли это в вашем конкретном случае и достаточно ли памяти под стек имеется при этом. Если указатель стека определен неправильно, то запись в стек может разрушить полезную информацию в ОЗУ и вызвать непредсказуемые последствия.
Интересно, что со стековым способом организации мы имеем дело в жизни гораздо чаще, чем это может показаться на первый взгляд. Во-первых, дисциплине «первым пришел - последним ушел» подчиняются скобки в арифметических выражениях: первой всегда закрывается «самая внутренняя», т.е. как раз последняя скобка. Если вы знакомы с программированием на любом алгоритмическом языке, то без труда найдете и еще два примера: вложенные циклы и подпрограммы.
Итак, мы подробно рассмотрели общие принципы записи информации в стек. Остается сказать, что стековый способ организации ОЗУ используется в вычислительной технике очень широко. На аппаратном уровне процессор «обучен» сохранять в стеке текущий адрес программы при выполнении команды перехода с возвратом, т.е. при вызове подпрограммы. Часто программа предварительно заносит в тот же самый стек необходимые для подпрограммы параметры: так реализуется, например, вызов процедур и функций с параметрами в языке «Паскаль». Кроме того. стек часто используется для временного сохранения значений тех или иных внутренних регистров процессора. Наконец, процессор активно использует стек при реализации прерываний от внешних устройств (об этом будет рассказано в следующем параграфе).