Продолжаем разбираться с разрядностью ЭВМ, в целом, и процессоров, в частности. Причем все большее внимание будем уделять более низкоуровневым моментам. Но начнем с довольно простого - байта. Да, опять и снова! Но рассматривать будем уже совершенно реальные ЭВМ.
Это можно считать как курьезом, мол чего там в древности только не напридумывали, так и нюансом, который вполне реален и сегодня, пусть и в специализированных машинах. И даже во вполне современных универсальных процессорах, что бы будем рассматривать отдельно (и точно не сегодня)
Сегодня всем привычны машины с разрядностью процессоров 32 и 64. Речь идет об универсальных массовых ЭВМ и "внешней" разрядности процессора. То есть, разрядности с точки зрения обычного пользователя и программиста. В предыдущей статье
я уже говорил, что внутренняя архитектура процессора может отличаться от той, которую видят пользователи и программисты, даже системные.
Один из читателей в комментариях как то заметил, что "абсолютно все ЭВМ могут работать с байтом, который всегда состоит из 8 бит". Разрядность байта мы уже обсуждали и повторяться нет смысла. Но вот то, что все машины могут работать с данными разрядностью 1 байт... Это ведь не всегда так! Требуете доказательств?
Наверное все знают о двух наиболее распространенных сериях, или линейках, ЭВМ:
- ЕС ЭВМ, Единая Система ЭВМ - копии, пусть и не совсем и не всегда точные, машин IBM
- СМ ЭВМ, Система Малых ЭВМ - копии, пусть и не совсем и не всегда точные, машин DEC
ЕС ЭВМ мы сегодня трогать не будем, а вот к СМ ЭВМ присмотримся повнимательнее. Дело в том, что копии машин DEC PDP-11 это не вся линейка СМ, а лишь машины начиная с СМ-3. Наиболее распространенной была СМ-4. Всю линейку сегодня рассматривать не будем. Но ведь были и совсем другие машины - СМ-1 и СМ-2. И эти машины были копиями не машин DEC, а машин Hewlett Packard HP-2000.
Серия СМ (она же АСВТ-СМ), в виде СМ-1 и СМ-2, в 1975 году пришла на замену серии АСВТ-М (Агрегатная система Средств Вычислительной Техники). Средний уровень АСВТ-М включал в себя машины М-6000 и М-7000, которые и были копиями HP-2116A. Вот эти машины и стали СМ-1 и СМ-2.
Нам во всем этом интересно лишь то, что эти машины были 16-разрядными. Причем только 16-разрядными, так как машинных команд работающих с 8-битными данными они не имели. Вот с этим и будем разбираться немного подробнее.
Коротко об архитектуре М-6000 (HP-2116)
Увы, подробной информации о М-6000 и М-7000 сохранилось мало, равно как и о HP-2000. Но о HP-2000 все таки удалось найти несколько документов, которыми я и воспользуюсь для подтверждения своих слов:
Машины HP-2116A и HP-2116C 16-разрядные и немного различаются, но для нас сегодня эти различия не принципиальны. Есть и "Карманное руководство по компьютерам 2100", в котором описываются не только сами машины, но и программирование, включая языки высокого уровня, для них.
HP-2116 построены по аккумуляторной архитектуре, но имеют два аккумулятора: A и B
Аккумуляторы 16-разрядные. Память (MEMORY на иллюстрации) тоже хранит информацию в виде 16-разрядных слов, с точки зрения процессора и программиста. Но физически информация хранится в виде 17-разрядных слов. О существовании байт ни процессор, ни память, не знают.
Таким образом, память (ОЗУ) 16-разрядная, с точки зрения программиста, но 17-разрядная, с точки зрения электронщика (и схемотехника, и обслуживающий персонал). Но об этом будет отдельный разговор, причем не сегодня.
Память разбита на страницы, но подробности адресации нас сегодня не интересуют.
Давайте кратко посмотрим на остальные регистры процессора:
- M - регистр адреса памяти. Хранит адрес слова в памяти к которому обращается процессор для чтения или записи.
- T - регистр данных памяти. Хранит данные слова, которое прочитано из памяти или будет записано в память.
- P -регистр счетчик команд (регистр адреса команды). Хранит адрес следующей машинной команды, которая будет выбираться из памяти и выполняться.
Не стоит путать регистры P и M. Содержимое регистра M будет изменяться в ходе выполнения "многофазной" команды, то есть, команды адресующей слово в памяти, тогда как содержимое регистра P будет оставаться неизменным.
Если вспомнить мои статьи об архитектуре процессора, то можно сказать, что регистр P входит в состав блока выборки и дешифрации команд, а регистр M в состав блока работы с памятью.
A и B это регистры аккумуляторы, как уже было сказано. А вот дальше немного интереснее... В процессоре этой машины нет регистра состояния процессора или регистра флагов, к которым мы сегодня так привыкли. Зато есть два отдельных однобитных регистра:
- Extend (E) - регистр расширения. Используется в качестве расширения регистров A и B для индикации переполнения и в операциях сдвигов.
- Overflow - регистр переполнения. Используется для индикации выхода результата арифметической операции с регистрами A и B за допустимые границы. То есть, это перенос в знаковый бит слова.
Обратите внимание, что каждый из этих регистров связан с обоими аккумуляторами. Фактически, это просто триггер связанный с АЛУ, а не с регистрами, хоть а документации это и не говорится. Кроме того, признак переполнения описан неточно, но мы сегодня не будем на этом сосредотачиваться.
Остался регистр I, который используется для хранения и декодирования кода инструкции (часть кода машинной команды). Этот регистр нам сегодня не интересен.
Базовый, и единственный реализованный аппаратно, тип данных - целое число со знаком
Причем отрицательные числа хранятся в виде "дополнения до двух". Числа без знака (unsigned, в нотации языка C) в этом машине отсутствуют. Равно как и байты!
Все прочие типы данных, как четко говорится на иллюстрации, определены не аппаратно, а лишь "в стандартных программных пакетах". То есть, реализованы не аппаратно, а программно. На уровне компиляторов и системных библиотек, как мы уже ранее рассматривали. Давайте заглянем в "Карманное руководство" (ссылка приведена выше), где можно увидеть эти "программно реализованные" типы данных
И в "Карманном руководстве" тоже четко говорится о программной реализации, например, упаковки двух байт в слово
Немного о машинных командах М-6000 (HP-2116)
У некоторых читателей могут возникнуть подозрения, что я чего-то недоговариваю... Мол АЛУ то там 16-разрядное, но это же не мешает на уровне машинных команд работать и с байтами. Ведь Intel x86 вполне себе это умеет.
Увы, я вынужден разочаровать таких читателей. На уровне машинных команд все строго 16-разрядное! Более того, нет даже намека на "беззнаковость". Полное описание системы машинных команд можно найти в документации, ссылки на которую даны ранее. Но давайте все таки, пусть и обзорно, посмотрим на эти машины с точки зрения программиста.
Все машинные команды делятся на три группы:
- Команды использующие обращения к памяти
- Команды работающие только с регистрами
- Команды ввода/вывода
Группировка основана на общности форматов кодирования команд
Команды использующие обращения к памяти
Как и ожидалось, обращающиеся к памяти команды имеют поле адреса. Причем поле адреса занимает всего 10 бит, что определяет размер страницы 1024 слова. То есть, не смотря на 16-разрядный процессор, мы не можем напрямую адресовать ячейки памяти 16-разрядным адресом. Адресация страничная, но тонкости адресации памяти в М-6000/М-7000 (HP2116) мы рассматривать не будем. Нам важно лишь вот такое общее правило, для всех машин, в общем и целом:
- Адресация памяти не связана напрямую с разрядностью машины! Разрядность адреса памяти машины может быть как больше, так и меньше, разрядности процессора.
Хочу особо это выделить для тех читателей, которые однозначно связывают разрядность процессора и адресуемый размер памяти. Разрядность шины адреса памяти может быть как меньше разрядности процессора, так и больше.
Бит 10 (Z/C) в коде команды позволяет указать, относится ли адрес слова в памяти к текущей странице, с которой и выбрана текущая команда, или он относится к "базовой" странице, которой считается страница 0.
Если вы еще недостаточно запутались, то я вам помогу :) Бит 15 (D/I) в коде команды определяет режим адресации прямой/косвенный. При косвенной адресации слово, адрес которого задан в коде команды, используется как полный 16-разрядный адрес данных в памяти.
То есть, при прямой адресации мы работаем с памятью в страничном режиме. Причем адресовать можем лишь слово в странице 0 или в текущей, в которой расположена выполняющаяся команда. Ни какая другая страница нам не доступна. А при косвенной нам доступен весь установленный к машине объем памяти. Но вот полный адрес может быть получен из слова, которое опять таки расположено лишь на текущей или нулевой страницах.
Как и положено в машинах аккумуляторной архитектуры, здесь есть команды загрузки (LD) и сохранения (ST). Но поскольку аккумулятора два, то команд не пара, а две пары: LDA/STA и LDB/STB. Кроме того, есть команда сложения, которая тоже может работать с обоими аккумуляторами: ADA и ADB. Разумеется, результат помещается в соответствующий аккумулятор. Команды вычитания нет!
А вот дальше уже немного интереснее. В эту же группу включены две команды перехода. Нелогично? С точки зрения HP вполне логично. Ведь они же используют адрес в памяти. Первая команда, JMP, выполняет безусловный переход. Вторая команда, JSB, выполняет вызов подпрограммы.
А теперь мы, возможно, с некоторым удивлением, обнаруживаем связь между HP-2116 и микроконтроллерами Microchip PIC! Мне кажется, что архитекторы Microchip вдохновлялись машинами HP-2000... Речь идет о командах, которые пропускают выполнение следующей команды по некоторому условию.
Команды CPA и CPB выполняют сравнение содержимого соответствующего аккумулятора и слова в памяти. Если они различаются, то выполнение следующей команды пропускается. Команда ISZ выполняет инкремент указанного слова в памяти, если результат равен 0, то выполнение следующей команды пропускается. В Microchip PIC аналогичное поведение, пропуск следующей команды, используется командами INCFSZ/DECFSZ/BTFSC/BTFSS.
Оставшиеся три команды, AND/IOR/XOR, выполняют соответствующие логические операции между словом в памяти и аккумулятором A. Команд для выполнения этих операций с аккумулятором B нет. Так что аккумуляторы не обладают равной функциональностью.
Еще раз подчеркну, что вариантов команд, которые работают с данными разрядностью отличной от 16 (с байтами) нет в принципе!
Команды работающие только с регистрами
Команд работающих только с регистрами гораздо больше 39 штук. Мы не будем их подробно рассматривать, все таки статья о разрядности машин. Команды, работающие только с регистрами, делятся на две группы. Причем в каждой группе мы можем комбинировать сразу несколько команд в одном командном слове. Именно это обозначено на предыдущей иллюстрации как "Microinstructions". Команды из разных групп мы не можем скомбинировать в одном командном слове.
- Первая группа - команды сдвигов-вращений (SRG). Однако, в эту группу включены не только инструкции сдвигов. Сюда затесались и "чуждые" инструкции - NOP, CLE (сброс EXTEND), SLA/SLB (пропуск следующей команды, если бит 0 соответствующего аккумулятора равен 0). Кстати, SLA/SLB фактически являются проверкой на четность содержимого соответствующего аккумулятора.
- Вторая группа - команды изменения-пропуска. Впрочем, в эту группу тоже затесались "чуждые" инструкции. Например, CLA/CLB (очистка соответствующего аккумулятора).
Инструкции (не команды!) первой группы можно скомбинировать, по определенным правилам, до четырех в одной команде. Инструкции второй группы можно скомбинировать до 8 в одной команде, тоже по определенным правилам. Подробности я опущу, но если кому то будет интересно, то можно обсудить это отдельно.
Все команды, работающие только с регистрами, оперируют словами разрядностью 16 бит. Исключением является регистры E (EXTEND) и OVERFLOW, которые являются однобитными. Нет команд работающих с байтами!
Команды ввода вывода
Поскольку архитектура ввода-вывода в М-6000 (HP2116) заметно отличается от существующих сегодня вариантов, набор команд команд ввода-вывода может показаться непривычным:
- Команды сброса/установки/проверки флагов в устройствах. Сюда же отнесем команды установки/сброса бита управления.
- Команды сброса/установки регистра (флага, по сути) OVERFLOW.
- Команды собственно ввода-вывода. Их мы рассмотрим немного подробнее.
- Команда останова процессора.
Флаги, любые, нас сегодня не интересуют. А вот связанные непосредственно с передачей данных при вводе-выводе команды мы кратко рассмотрим.
Но сначала надо разобраться с буферами ввода-вывода. Точнее, с их разрядностью. Ведь внешние (периферийные) устройства могут иметь разрядность отличающуюся от разрядности процессора. Неразумно ограничивать ввод-вывод лишь данными из 16 разрядов, например, для принтера вполне достаточно 8 бит (и даже меньше). Равно как и для перфоленты, которая может использоваться для обмена текстовой информацией с другими машинами (причем самых разных типов).
Буферы ввода и вывода показаны в нижней части иллюстрации с архитектурой HP-2116. Это первая иллюстрация в статье. Но разрядность буферов на иллюстрации не указана. Дело в том, что разрядность буферов зависит от внешнего устройства. В самом процессоре буферы 16-разрядные, но в устройстве может быть и меньше. Как же это тогда работает?
В статьях про архитектуру ЭВМ и процессоров я говорил об "адресных пространствах". В М-6000 (HP-2116) тоже есть два адресных пространства:
- адресное пространство памяти
- адресное пространство ввода-вывода
Поле команды группы ввода-вывода "SELECT CODE", которое занимает 6 бит, позволяет адресовать одно из 64 возможных устройств (или функций). Это поле и содержит адрес устройства. А дальше в дело вступают команды загрузки/сохранения LIA/LIB/OTA/OTB, которые аналогичны LDA/LDB/STA/STB по смыслу, но работают не с памятью, а в буферами ввода и вывода соответствующих устройств.
В "Карманном руководстве" поле "SELECT CODE" называется так же "Channel No" (номер канала).
Если буфер устройства имеет разрядность меньшую 16, то в обмене данными участвуют лишь младшие разряды аккумуляторов. С командами OTA и OTB вопросов не возникает, так как в буфер меньшей разрядности просто попадут младшие разряды аккумуляторов, а старшие будут проигнорированы. Но с командами LIA и LIB вопросы могут возникнуть. Да, в аккумулятор, начиная с младших разрядов, попадет содержимое буфера. А вот состояние отсутствующих в буфере разрядов в документации не указывается. Но, насколько я помню, они обнулялись.
Однако, давайте вспомним, что "программным способом" мы можем упаковать два байта в одно слово. Иллюстрацию я приводил. Для облегчения такой упаковки были предусмотрены две специальные команды MIA и MIB. Это сокращение от "Merge input into A/B". На самом деле, это обычная команда "логическое ИЛИ" между содержимым соответствующего аккумулятора и содержимым буфера соответствующего устройства.
Зачем понадобились эти дополнительные команды, разве LIA/LIB недостаточно? Недостаточно. LIA/LIB изменяют содержимое аккумуляторов полностью. И для упаковки двух байт в одно слово нам потребуется или второй аккумулятор, или ячейка памяти, с которыми мы будем выполнять серию сдвигов и логических операций. А команды MIA/MIB позволяют обойтись только сдвигами. Загружаем первый байт с помощью, например, LIA. Сдвигаем A на 8 разрядов влево. Загружаем второй байт с помощью MIA. Старшие разряды A при этом сохранят свое значение (первый упакованный байт).
Обратите внимание, что не смотря на наличие команд MIA/MIB нельзя сказать, что М-6000 (HP-2116) умеет работать с байтами на аппаратном уровне! Команды MIA/MIB точно такие же 16-разрядные, как и все прочие. Просто размер буфера устройства может быть меньше 16 разрядов. Но ведь меньше это и например, 11 или 5 разрядов, не обязательно 8.
Заключение
Сегодня мы рассмотрели довольно оригинальные машины, которые существовали в реальности. Да, они в прошлом. Но мы еще увидим, что и сегодня достаточно тонкостей, пусть и не таких экзотических, пусть не видимых глазом обычных прикладных программистов, но реально существующих.
Почему я уделил машинам M-6000/M-7000 (HP-2116) столько внимания? Прежде всего, именно с обсуждения в комментариях разрядности M-7000 и начался весь сыр-бор, который стал причиной появления этого цикла. Кроме того, эти машины позволяют наглядно показать и разницу между разрядностью адреса памяти и разрядностью процессора. А еще, и это более важно, на примере этих машин отлично видно, что компиляторы (для этих машин Basic и Fortran) позволяют скрыть от прикладного программиста даже весьма существенные тонкости собственно машины.
При этом "за кадром" зачастую остаются "накладные" расходы такого сокрытия. В данном случае, использование в программе 8-разрядных данных приведет к увеличению ее размера, вопреки ожиданиям программиста, за счет дополнительных команд обеспечивающих такую неестественную для машины разрядность. И к снижению быстродействия, по той же причине.