11,9K подписчиков

Архитектура ЭВМ. Адресные пространства и переключение программа/ОС

148 прочитали

Цикл статей об архитектуре ЭВМ задумывался как достаточно высокоуровневый, но вопросы читателей потребовали более глубокого погружения, вплоть до логического уровня. Так и появилась статья

Почему я о ней напоминаю? Потому что сегодня мы будем на нее в значительной степени опираться. А еще точнее, будем разбираться, что и как (и почему) нужно изменить, чтобы наш процессор мог действительно смог работать не только с данными во внутренних регистрах. Потребуется нам и то, что мы рассматривали в предыдущей статье, но на верхних уровнях, без детального погружения в устройство процессора

Но сначала нам нужно разобраться с еще одним высокоуровневым понятием - адресными пространствами. Я уже касался этого вопроса в статье

Но сегодня нам нужно более детальное рассмотрение.

Адресные пространства

Ранее мы рассматривали память вне процессора как нечто абстрактное и аморфное - просто набор ячеек, каждая из которых может хранить данные и имеет собственный уникальный адрес. Но память бывает очень и очень разная. Не только по устройству или организации, но и по функциональному назначению прежде всего.

Мы рассматривали стековую, аккумуляторную, регистровую архитектуру процессора. И я уже говорил, что набор внутренних регистров процессора это блок регистровой памяти. Пусть объем этой памяти и мал, но мы выбирали регистры по их адресу, который чаще называют просто номером регистра. Названия регистров, их имена, важны человеку, но не машине. Таким же блоком памяти является внутренний аппаратный стек, который не является адресуемым, с точки зрения программиста, но процессор использует адреса на логическом и схемотехническом уровне.

Гораздо более известно ОЗУ - Оперативное Запоминающее Устройство, которое в англоязычной нотации называется RAM - Random Access Memory (память с произвольным доступом). ОЗУ есть в подавляющем большинстве современных ЭВМ, включая встраиваемые машины и микроконтроллеры. Но в большинстве машин есть и ПЗУ - Постоянное Запоминающее Устройство, оно же ROM - Read Only Memory (только читаемая память). ОЗУ и ПЗУ, в отличии от регистровой памяти, действительно внешняя память, по отношению к процессору. Даже в том случае, если физически размещаются на одном кристалле с процессором, например, в микроконтроллере.

С функциональной точки зрения ОЗУ и ПЗУ могут быть как совершенно разными, так и идентичными. Что бы с этим разобраться, нужно вспомнить две самые известные архитектуры ЭВМ - фон Неймана и Гарвардскую (о них разговор еще впереди). В архитектуре фон Неймана вся память является универсальной, предназначенной для хранения как программ (машинных кодов), так и данных. Поэтому ОЗУ и ПЗУ являются просто различными областями этой универсальной памяти, их функция идентична.

Да, ПЗУ и ОЗУ могут иметь разное назначение на более высоких уровнях. Например, в ПЗУ может располагаться начальный загрузчик (и код, и данные), а ОЗУ использоваться для программ пользователя (тоже код и данные). Но с точки зрения процессора, а мы сегодня именно с этой точки зрения все рассматриваем, между ОЗУ и ПЗУ нет функциональной разницы.

В Гарвардской же архитектуре память разделена на две непересекающиеся области - память программ и память данных. При этом память программ может быть реализована как в виде ПЗУ, так и в виде ОЗУ. Точно так же, память данных может быть выполнена не только в виде ОЗУ, но и в виде ПЗУ (например, для констант).

Под функциональным назначением будем понимать тип хранимой в памяти информации (машинные команды, данные). Но ОЗУ и ПЗУ, по самой своей природе, поддерживают разный набор операций. Для ОЗУ можно выполнять как чтение, так и запись. Для ПЗУ возможно только чтение. При этом в ПЗУ могут храниться и данные, например, таблицы констант.

Поэтому для нас сегодня важным являются не особенности построения различных типов памяти, а их функциональное назначение, с точки зрения процессора - универсальная память, память программ, память данных.

Но это еще не все. Кроме процессора и памяти любая ЭВМ содержит и периферийные устройства, которые чаще всего называют устройствами ввода-вывода. Любое периферийное устройство, опять с точки зрения процессора, представлено набором регистров. То есть, тоже небольшим блоком памяти, только уже не в процессоре. Более того, периферийное устройство может содержать и полноценный блок памяти, например, буфер данных.

Таким образом, мы можем выделить такие функциональные типы памяти:

  • регистровая память
  • универсальная память
  • память программ
  • память данных
  • память периферийных устройств

Не обязательно ЭВМ имеет все эти типы памяти, например, в ЭВМ архитектуры фон Неймана будет универсальная память, но не будет отдельных памяти программ и памяти данных. Но в любом случае возникает вопрос, а как процессор будет различать эти типы памяти? Ведь недостаточно указать просто адрес ячейки памяти, надо указать и к какому типу памяти он относится.

Это и подводит нас к понятию адресного пространства. Мы уже выделили несколько функциональных типов памяти. Возьмем все ячейки с одинаковым функциональным назначением и дадим им адреса в пределах этой совокупности, но без учета всех других функциональных групп. Мы получим несколько отдельных совокупностей, причем в каждой из них ячейки будут иметь адреса от 0 до N. Это и есть те самые адресные пространства.

  • Адресное пространство это логическая и семантическая совокупность адресов ячеек с одинаковым функциональным назначением, внутри которой которой адреса присваиваются независимо от остальных совокупностей.

Это может показаться сложным, но на самом деле понятие адресного пространства довольно простое. Возьмем ЭВМ архитектуры фон Неймана. У нас есть универсальная память, ячейки которой и образуют совокупность. У нас есть периферийные устройства, регистры и внутренняя память (при наличии) которых образуют другую совокупность. И у нас есть процессор, например, регистровой архитектуры, адреса внутренних регистров которого образуют еще одну совокупность.

Адреса ячеек в каждой совокупности абсолютно независимы от других совокупностей. Диапазон адресов всех ячеек универсальной памяти образуют адресное пространство памяти машины. Диапазон адресов все регистров периферийных устройств образуют адресное пространство ввода-вывода. Адреса регистров образуют адресное пространство регистровой памяти.

В каждом адресном пространстве может быть ячейка, например, с адресом 10. Но в адресном пространстве памяти машины это будет ячейка в ПЗУ или ОЗУ. В адресном пространстве ввода-вывода это будет регистр, например, команд накопителя на жестких дисках. В адресном пространстве регистров это будет, например, регистр адреса команды IP (Instruction Pointer).

Влияние адресных пространств на адресацию

Зачем нужны адресные пространства? Дело в том, что адресное пространство это не только совокупность адресов однотипных, с функциональной точки зрения, ячеек, но и, возможно, определенный протокол доступа к этим ячейкам. Универсальная память может быть подключена к одной шине процессора, а периферийные устройства к другой. Память команд и память данных в ЭВМ Гарвардской архитектуры тоже используют разные шины процессора. А ведь существуют и более специфические типы памяти.

Например, в микроконтроллерах MCS-51 адресуемыми являются не только отдельные ячейки, но и отдельные биты некоторых ячеек памяти внутри процессора. Да, каждый бит некоторых ячеек имеет полноценный адрес, а не номер бита внутри ячейки. Как же со всем этим справляться? Есть несколько способов, мы кратко рассмотрим лишь пару самых распространенных.

Использование различных команд

Рассмотрим машину архитектуры фон Неймана. Думаю, многие читатели знают, что в процессорах есть команды пересылки данных (например, STA, LDA, PUSH, POP, MOV), но могут быть и команды ввода-вывода (IN, OUT). Команды пересылки данных работают только с ячейками памяти машины, а команды ввода-вывода только с регистрами периферийных устройств. Выбор адресного пространства осуществляется дешифратором команд процессора. С каждой командой жестко связано определенное адресное пространство

Выбор адресного пространства жестко связан с типом машинной команды. Иллюстрация моя
Выбор адресного пространства жестко связан с типом машинной команды. Иллюстрация моя

Изменить связь команды с адресным пространством невозможно. Например, в данном случае мы не можем командой PUSH получить доступ к регистру ввода-вывода, а командой IN к ячейке универсальной памяти. Это может показаться существенным ограничением, но это ошибочное мнение.

Для Гарвардской архитектуры адресное пространство памяти машины будет разделено на два независимых пространства для кода программ и для данных. И команда PUSH с последней иллюстрации будет обращаться к адресному пространству данных. И изменить это тоже нельзя. К адресному пространству программ будут обращаться команды JMP, CALL, RETURN, INT (прерывание). Операнд в этих командах будет относиться к адресному пространству команд.

Использование деления общего адресного пространства

В этом случае у нас нет отдельных команд, но есть общее адресное пространство (логическое), которое объединяет все отдельные адресные пространства. Но каждое отдельное адресное пространство имеет собственный базовый (начальный) адрес. И программист в командах указывает адрес ячейки с учетом базового адреса нужного адресного пространства

Выбор адресного пространства с помощью базового адреса. Иллюстрация моя
Выбор адресного пространства с помощью базового адреса. Иллюстрация моя

Обратите внимание, что я показал на иллюстрации и адресное пространство регистров процессора! Да, такое тоже возможно! Нельзя сказать, что это является распространенным решением, но встречается (PDP-11, MCS-51). Это позволяет, в частности, получать доступ к неактивному банку регистровой памяти в процессорах с переключаемыми банками (блоками, наборами) регистров. Мы кратко рассмотрим это изучая прерывания.

Поскольку у нас теперь одна и та же команда (не только мнемоника, но и код) может работать с разными адресными пространствами дешифратор команд не в состоянии определить, к какому именно пространству требуется доступ. И выбор адресного пространства выполняет блок выборки операндов осуществляя анализ вычисленного адреса операнда и/или режима адресации.

Кстати, для машин с единым логическим пространством не обязательно всегда указываются адреса, например, регистров ввода-вывода как "базовый адрес адресного пространства + адрес регистра". Зачастую просто указывается суммарный адрес, который относится к общему логическому пространству.

Гибридный способ

Реальные процессоры могут использовать оба рассмотренных метода выбора адресного пространства для операнда, причем одновременно. Это приводит к возможности получения доступа к одной и той же ячейке памяти (регистру) несколькими способами

Доступ к одной и той же ячейке с помощью разных способов выбора адресного пространства. Иллюстрация моя
Доступ к одной и той же ячейке с помощью разных способов выбора адресного пространства. Иллюстрация моя

Если адресное пространство выбирается командой, то это ограничивает выбор адреса. То есть, мы не можем написать

IN Base_IO + 1234

так как это подразумевает использование адресации в общем (логическом) адресном пространстве, а команда IN уже переключила адресное пространство на ввод-вывод. Обеспечение ограничения может осуществляться ограничением размера поля адреса в команде IN. Если разработчик процессора этого не предусмотрел, то должен формироваться сигнал ошибки.

То есть, если используемая команда уже подразумевает ограничение на выбор адресного пространства, то выбранное дешифратором команд адресное пространство имеет приоритет над блоком выборки операндов.

Комплексный пример организации адресации

Давайте, в качестве примера, рассмотрим гипотетическую ЭВМ архитектуры фон Неймана, в которой несколько разных типов памяти:

  1. ПЗУ программ и данных, хранящее начальный загрузчик (Boot). Недоступно для программ, но доступно в сервисных режимах работы, например, при тестах или для обновления ПО.
  2. ОЗУ программ и данных, расположенное в одном корпусе с процессором (Int_RAM).
  3. Внешнее ОЗУ, которое может быть подключено к ЭВМ пользователем через специальный интерфейс (Ext_RAM).
  4. Внешнее ПЗУ, которое может быть подключено к ЭВМ пользователем через специальный интерфейс (Ext_ROM). В эту область невозможно выполнить запись.
  5. Регистры периферийных устройств (IO_Reg).
  6. Буферная память периферийных устройств (IO_Buf). Возможность размещения буферов периферийных устройств в ОЗУ пока не будем рассматривать.
  7. Переключаемые блоки регистров процессора (CPU_Reg). Используются при переключении режимов работы процессора и позволяют ОС иметь доступ к содержимому регистров пользовательского режима работы процессора при работе процессора в режиме ядра. Не является в явном виде адресуемым для программ.

При этом наша гипотетическая ЭВМ будет иметь единое логическое адресное пространство, но будет иметь и команды, которые жестко связаны определенным адресным пространством.

Вот так, примерно, это все выглядит

Структура распределения адресов нашей гипотетической ЭВМ. Иллюстрация моя
Структура распределения адресов нашей гипотетической ЭВМ. Иллюстрация моя

Именно такой схемой распределения адресов памяти мы будем пользоваться в дальнейшем, включая последующие статьи. Сейчас это выглядит немного избыточным, но потом позволит нам поговорить и о режимах работы процессора, и о защите памяти.

На этой иллюстрации указано несколько адресных пространств:

  • Аппаратное адресное пространство. Это адресное пространство и формируется, и адресуется, на аппаратном, даже схемотехническом, уровне. Причем оно не будет единым и непрерывным физически, оно единое и непрерывное лишь логически. И то частично. Позже мы поговорим об этом.
  • Единое логическое адресное пространство. Именно для этого адресного пространства указываются базовые адреса различных диапазонов (не обязательно адресных пространств) памяти. Адреса ячеек от 0 до Max_Addr можно, теоретически, использовать как адреса операндов в машинных командах.
  • Адресное пространство ввода-вывода. Мы уже рассматривали его ранее. Регистры периферийных устройств могут быть доступны в командах IN и OUT, через это адресное пространство, или через любые другие машинные команды (кроме IN и OUT!) в едином логическом адресном пространстве.
  • Адресное пространство регистров процессора. Оно не обозначено явно, как адресное пространство, но именно им и является. Регистры процессора не имеют адресов в едином логическом пространстве. Как с ними работать мы увидим чуть позже.

У нас нет других адресных пространств, нет других функциональных совокупностей ячеек, которые имеют собственные адреса внутри совокупности. Например, Ext_RAM является физической и логической совокупностью ячеек (располагаются во внешней памяти), но адресовать ее ячейки мы можем только внутри единого логического пространства.

Области памяти, которые не являются адресными пространствами

Немного отвлечемся от адресных пространств и посмотрим на области памяти. Область памяти это логическая и семантическая совокупность ячеек. Причем область может быть как частью адресного пространства, так и охватывать несколько адресных пространств, даже не смежных.

Так область памяти "Память ОС и программ" является частью единого логического адресного пространства. При этом она включает и ОЗУ (внутреннее и внешнее), и ПЗУ (внешнее), но не включает внутреннее ПЗУ (Boot). Эта область памяти предназначена для размещения кода программ, как прикладных, так и ОС, и данных, как прикладных, так и ОС. С точки зрения процессора, структура этой области не важна, за исключением деления на ОЗУ и ПЗУ. Но ОС, скорее всего, разделит эту область памяти на несколько разделов, что бы изолировать различные прикладные программы от взаимного влияния. Кроме того, для самой ОС будет выделен отдельный раздел, что бы прикладные программы не могли повлиять на ее работу.

Деление памяти с точки зрения ОС мы рассматривать не будем. Но в последующих статьях посмотрим, как может быть организована изоляция программ и ОС, как может быть обеспечена защита памяти.

Область памяти "Доступно для ОС" тоже является частью единого адресного пространства, но включает в себя и адресное пространство ввода-вывода, чего не было в ранее рассмотренной области. Предполагается, что прикладные программы не могут напрямую работать с регистрами периферийных устройств и их буферами памяти. Работа возможна только через ОС. Это ограничение тоже обеспечивается на аппаратном уровне.

Аппаратное адресное пространство регистров процессора

Я обещал, что мы отдельно рассмотрим, как работают и для чего применяются переключаемые блоки регистров процессора. Наша гипотетическая ЭВМ имеет процессор, который может работать в двух режимах (диагностический пока рассматривать не будем):

  • Пользовательский режим. В этом режиме выполняются прикладные программы. Привилегированные машинные команды и доступ к областям ввода-вывода (регистры и буферы) невозможен.
  • Режим ядра. В этом режиме работает ядро ОС. Возможно использовать любые команды иметь полный доступ к всем областям памяти.

Прикладная программа может вызвать ОС в любой момент времени для выполнения каких-либо действий или ввода-вывода. Разумеется, ОС потом передает управление обратно прикладной программе. Кроме того, ОС может получать управление при возникновении прерываний. Переключение между прикладной задачей и ОС не должно нарушать их работы и должно занимать минимальное время. Мы можем сохранять состояние процессора при переключении ОС/программа так же, как это делается при вызове подпрограмма - в стеке. Но это не позволяет изолировать области памяти программы и ОС.

Мы можем разделить области памяти программы и ОС с помощью таблиц трансляции адресов. Нам достаточно (для нашей машины) пары таблиц. Одна будет отображать физические адреса на логические для программы, вторая для ОС. Это позволит радикально сократить время переключения программа/ОС.

Но мы можем ввести и два различных набора регистров процессора, включая служебные. Переключаясь между программой и ОС мы меняем режим работы процессора, что автоматически будет переключать таблицу трансляции адресов и набор регистров. Скоро мы рассмотрим, как это может быть реализовано.

Трансляция адресов и переключение программа/ОС

Будет полезно вспомнить, какой может быть организация памяти машины. Прочитайте еще раз старую статью

Нам понадобятся логические адреса и страничная организация памяти. Давайте разобьем единое логическое адресное пространства на страницы одинакового размера. Одинаковый размер позволит значительно упростить управление трансляцией адресов, по сравнению со страницами произвольной длины. И мы можем избежать жесткой привязки используемых в программе адресов к физическим адресам. Я повторю иллюстрацию из этой статьи

Моя иллюстрация из статьи об организации памяти ЭВМ, я просто повторил ее здесь
Моя иллюстрация из статьи об организации памяти ЭВМ, я просто повторил ее здесь

Остается расширить "адрес памяти" до "адрес в едином логическом адресном пространстве". Да, такая схема трансляции адресов позволяет переопределить даже регистры периферийных устройств, что позволяет ОС создавать "виртуальные" устройства эмулируя работу физически отсутствующих. Но сегодня об этом не будем.

Таблица, которая показана на иллюстрации как набор адресов начал страниц, и называется таблицей трансляции адресов. С ее помощью мы можем собрать в единое пространство логических адресов разрозненные участки физической памяти.

Как трансляция адресов поможет нам в ускорении переключения между программой и ОС? Мы уже знаем, что можно использовать две таблицы трансляции, которые будут переключаться в зависимости от режима работы процессора. Вот так

Использование двух таблиц трансляции адресов единого адресного пространства при переключении программа/ОС. Иллюстрация моя
Использование двух таблиц трансляции адресов единого адресного пространства при переключении программа/ОС. Иллюстрация моя

На просто нужен дополнительный признак, сигнал, который определяет режим работы процессора. Тот же самый сигнал может использоваться для переключения набора (банка) регистров процессора. Но тут возникает проблема. Ведь у нас регистры процессора не имеют адресов в едином логическом адресном пространстве. Все верно, но у нас в поле адреса операнда команды может указывать номер регистра, а не только полноценный адрес ячейки. Вот этот номер регистра и является аппаратным адресом регистра. И нам не нужна трансляция адресов регистров.

Остается добавить, что режим работы процессора может быть представлен битом MODE в слове состояния процессора (PSW) и мы получим полную логическую схему

Переключение логических адресных пространств программ при переключении режима работы процессора. Иллюстрация моя
Переключение логических адресных пространств программ при переключении режима работы процессора. Иллюстрация моя

Здесь есть один элемент, о котором я ранее упоминал лишь вскользь. Это бит sw в коде команды и элемент исключающее-ИЛИ. Пришло время разобраться с этим.

У нас есть два набора регистров процессора, но в каждом режиме работы процессора будет доступен лишь один. Это правильно для прикладной программы, но сильно ограничивает ОС в управлении программами. Нам нужна возможность как то получать доступ а регистрам процесса другого режима.

Подходящим решением будет введение привилегированных команд, которые доступны только в режиме ядра, обеспечивающих доступ к неактивному банку регистров. Не суть важно, будут ли это отдельные команды, или отдельные режимы адресации в единых командах. Важно, что мы сможем обеспечить инверсию сигнала MODE (бита в PSW) на время выполнения команды. Вот эту возможность и обеспечивает бит sw ы команде вместе с элементом исключающее-ИЛИ.

На самом деле, мы можем не ограничиваться кратковременным переключение доступа к другому банку регистров. Мы можем точно так же реализовать возможность кратковременного переключения таблиц трансляции адресов.

Какое отношение все описанное имеет к адресным пространствам? Самое непосредственное! Ведь это, по сути своей, переключение логических адресных пространств программ. Причем ОС это ведь тоже программа. У нас получилось разделить логическое адресное пространство программы и логическое адресное пространство машины (которое мы даже назвали физическим, хоть оно именно логическое).

Нам сейчас не важно, где именно располагаются таблицы трансляции адресов. Это может быть как отдельный блок ОЗУ, так и основное ОЗУ. Для простоты будем считать, что используется отдельный модуль памяти, это поможет упростить логические схемы в последующих статьях.

Заключение

Адресные пространства, на первый взгляд, кажутся очень простыми, но эта концепция может использоваться для реализации далеко не самых простых функций. Адресные пространства лишь частично связаны с режимами адресации.

Сегодня мы кратко рассмотрели лишь функциональную сторону. Логическая реализация будет рассматриваться в следующей статье. И это тоже лишь один из модулей полноценного процессора. А наша гипотетическая машина задумана как не самый простой простой процессор. Это гораздо интереснее, но я не уверен, что получится рассказать достаточно просто и понятно. Впрочем, увидим...

До новых встреч!