Немного про ЭВМ 50-х и 60-х годов
Сегодня хотелось бы поговорить немного об эпохе 50–х и 60–х, когда персональных компьютеров с микропроцессорами не было, а компьютеры были вещью крайне дорогой и занимали подчас целый этаж здания.
(Компьютер IBM–701)
Как шутят некоторые статьи «когда то вычислительную мощность измеряли в килодевушках». Необходимость проведения массивных вычислений возникла довольно давно и решалась исторически довольно просто — ручными вычислениями.
(Зал с девушками–компьютерами времен Второй Мировой)
Конечно девушки активно пользовались подручными средствами — счётами и первыми механическими калькуляторами, но скорость счёта всё-равно была ограничена скоростью человеческих рук. Профессия ручного счетовода так и называлась «computer», поэтому когда появились механические и автоматические «вычислители» для массовых расчётов они просто унаследовали это название от профессии «кожаных мешков» ™.
Прогресс шёл очень быстро, механика сменилась электрикой, каждую десятилетку изобретались новые способы хранения информации как в быстрой так и в долговременной памяти.
Что же представлял из себя типовой компьютер 50/60–х с точки зрения программиста?
Прежде всего создатели компьютеров сталкивались с вопросом: «какую ширину слова выбрать для новой ЭВМ?». Дело в том, что общепринятой концепции байтов тогда еще не было — эту концепцию внедрили мейнфреймы IBM System/360.
На них я остановлюсь чуть подробнее в силу их легендарности — 1964 году IBM анонсировала долгоиграющую древнюю линейку мейнфреймов System/360. До этого всех документациях к компьютерам почти всегда писали «компьютерные» числа в 8–ричной системе исчисления в силу того, что как раз ширина слов (количество бит в ячейке памяти) выбиралась обычно кратная трём битовым разрядам — например 12, 18 или 36 бит в ячейке памяти. Восьмеричная система прекрасно под это подходила, была и достаточно экономной и легко считываемой. В System/360 же документация содержала только 16–ричные коды в силу 8–битного байта, где удобнее было делить байт на 4–битные «цифры» и к моменту появления микропроцессоров и микрокомпьютеров они практически выжили 8–ричную систему из употребления.
Один из потрясающих фактов является то, что IBM пришлось вложить в разработку System/360… $5 млрд в ценах тех лет, что по сегодняшнему курсу с учётом инфляции составляет больше $30 млрд и это делает этот проект вторым по стоимости НТР–проектом 60–ых годов после полёта на Луну!
Более того, архитектура System/360 прошла последовательное развитие с сохранением обратной совместимости и жива до сих пор и ныне в линейке серверов IBM zSeries. Пятьдесят четыре года обратной совместимости!
Архитектура, впрочем, довольно зрелая, так что неудивительно — шестнадцать 32–битных высокоортогональных регистров общего назначения и 24–битная шина адреса в System/360 поступили в продажу еще в 1964 году.
Но вернемся к более привычным архитектурам в те годы. Итак — первый вопрос встающий перед разработчиком ЭВМ тогда был «сколько бит делать в ячейке памяти»? Вообще такая ячейка памяти называлась регистром (даже если речь шла про ячейку ОЗУ/ПЗУ), поэтому можно переформулировать как «разрядность регистра». Популярными были числа 12, 18 и 36. Разрядность регистра определяла как разрядность чисел так и насколько удобно будет делать систему команд машины, какова будет разрядность её адресного пространства и насколько плотно в неё будет укладываться полезная информация. Разные вещи вступали друг с другом в конфликт, поэтому выбор был тяжкий.
Рассмотрим на примере первой ламповой машины IBM выпущенной в 1952 году — IBM–701 (она изображена на первой картинке).
IBM–701
В IBM–701 разрядность слова была 36–бит, однако максимальный объём ОЗУ в 2048 ячейки делал невыгодным хранение одной инструкции в целых 36 битах и там применялась схема деления каждой ячейки памяти на два полуслова в 18 бит. Можно даже сказать, что это были 18–битные байты этой архитектуры, хотя такая терминология тогда еще не использовалась — просто полуслова.
Прежде всего в полуслова аккуратно и экономно влазили коды инструкций. Классическая для того времени однооперандная архитектура хранила в 18 битах инструкции 5 бит на код инструкции и 13 бит на адрес второго операнда в памяти. Первым вменялся или аккумулятор AC или вспомогательный регистр MQ и кроме счётчика инструкций программных регистров здесь в общем то больше и не было. Забавно, что этот адрес зашитый в инструкцию был со знаком, потому что по наличию знака определялось к чему идёт обращение — к слову или к полуслову в памяти.
Если, например, нужно было загрузить из памяти в аккумулятор слово (или сложить его со словом), то в качестве адреса в инструкции требовалось указать отрицательное чётное число (самый младший бит адреса при этом равнялся всегда нулю).
Если же нужно было считать из памяти полуслово (или инструкцию), то в качестве адреса указывалось положительное число от 0 до 4095 — при таких адресах считывалось соответствующее полуслово (как будто бы память состоит из 4096 18–битных ячеек) при этом в аккумулятор они грузились не в младшие, а в старшие биты — то есть полуслова грузились/сохранялись как слова с занулёнными нижними, менее значащими битами.
Рассмотрим команды сложения/вычитания — они реализованы в опциональном сочетании с занулением аккумулятора, что даёт нам следующие варианты инструкций (X — ячейка памяти с которой складываем/вычитаем аккумулятор):
Получалось, что «Reset and ADD» (обнулить аккумулятор и добавить к нему содержимое ячейки с адресом X) работала как просто загрузка в аккумулятор значения из ячейки памяти — поэтому аналогичная команда LOAD просто отсутствовала. Видимо такое странное обозначение соответствовало тому что происходило «под капотом» машины.
Этот же подход унаследует в дальнейшем машина IBM–704. И так же там будет уделено внимание арифметике с отбрасыванием знака аргумента, видимо без дополнения до двух это было актуально.
Индексных регистров или сложных режимов адресации у 701 не было и потому единственным способом косвенной адресации являлась самомодификация программы. Весьма популярный в те времена приём.
Под это существовала инструкция:
Эта инструкция всегда работает с полусловом по адресу X и переписывает ему нижние 12 бит нижними битами аккумулятора — адресную часть, сохраняя остальные биты (код инструкции, включая знак адресной части).
Таким образом по сути в таких компьютерах был единственный режим адресации — прошитый в слово инструкции адрес ячейки памяти в которую или из которой бралось/ложилось данное, так что косвенные адресации/индексации приходилось проводить через самомодификацию кода.
IBM–704
(План установки IBM–704 из книги «Coding for the MIT–IBM 704 computer»)
IBM–704 — компьютер–легенда. С ним связано сразу несколько прорывов в области IT.
Во первых — это был первый компьютер с аппаратной поддержкой плавающей точки в широкой продаже.
Под «широкой продажей» тут понимается «больше 100 штук», т.к. мы всё–таки говорим о «больших ЭВМ», физически занимавших этаж здания и представленных на рынке в 1954 году.
Основным радиотехническим элементом машины была электронная лампа, а память была основана на магнитных сердечниках — поэтому мы так же говорим о дотранзисторной эпохе.
Во вторых — на этой машине был разработан язык программирования Fortran — чему способствовала её «научная архитектура».
Ну и в третьих — на этой машине был разработан язык программирования Lisp и архитектура IBM–704 даже оставила в нём навечно один характерный отпечаток, о чём я повторю википедию много ниже.
Машинное слово IBM–704 было 36–битным и в отличие от 701 они не делились на 18–битные полуслова. 8–битными байтами здесь так же еще не пахло.
В базовой комплектации в машине было 8192 ячеек 36–битной памяти, но максимально под шину адреса было отведено 15 бит, то есть максимально можно было адресовать 32768 ячеек 36–битной памяти, что эквивалентно 147456 байтам. Адресное пространство было так же единым для кода и данных и сама архитектура всё так же настаивала на самомодифицирующемся коде, под что были специальные инструкции и специальные форматы данных (что и оставило отпечаток на лиспе).
Регистры:
AC — аккумулятор (36 бит)
MQ — вспомогательный регистр множитель/делитель (multiplier–quotinent) (36 бит)
ILC — счётчик инструкций (instruction location counter) (15 бит)
IR1, IR2, IR4 — индексные регистры (15 бит), названия их как видно сформированы как значения числа из трёх соответствующих бит, и это так и есть, это упрощало их комбинацию в инструкциях
Выделялись так же флаги PF и QF, а нулевой бит аккумулятора AC[0] обозначается часто как флаг знака SF.
Тут можно вспомнить как шкафы компьютеров того времени перемигивались загадочно сотнями лампочек — это были просто выведены битовые представления самых важных регистров и проходящих данных по узлам компьютера для мониторинга и отладки.
Битовое представление отрицательных целых чисел тут было то ли в прямом то ли в обратном коде, но не в дополнении до двух, то есть бит знака и число позволяли описывать как +0 так и –0, что иногда требовалось учитывать в коде, т.к. +0 считался числом большим, чем –0 при сравнениях. Вещественные числа тоже как понятно были 36–битные и проходили через те же регистры, что и целочисленные — формат данного подразумевался из инструкций.
Почти все инструкции (как понятно всегда 36–битные) содержали 15 бит «адресного поля» (ADDR), что позволяло в каждой из них сослаться на одну из ячеек памяти. Поэтому архитектура инструкций была всё той же однооперандной аккумулятор–память. Для косвенных адресаций применялся следующий принцип — 3 бита в каждой инструкции отводились под «маску индексов» — если один индексных битов в инструкции был зажжён, то из поля ADDR вычиталось содержимое соответствующего индексного регистра для формирования адреса ячейки. Более того, если были указаны сразу несколько индексных бит, то вычитаемое формировалось как логический OR соответствующих индексных регистров, что позволяло адресовать многомерные массивы размеры измерений которых были кратны степеням двойки.
Ряд инструкций (ровно 6 штук) содержал так же 15 бит «поля декремента» (DECR), что это и зачем это — я расскажу ниже, но главное — что был ряд инструкций позволяющий независимо сохранять и загружать поля ADDR и DECR в/из памяти.
Инструкций довольно много, машину никак нельзя назвать аскетичной — отыгрались инженеры вовсю.
Те кто хочет поразглядывать их подробнее может пройти по ссылке gamedev.ru/flame/forum/?id=226622&page=23#m334
Такие инструкции как STD M или STA M как раз позволяют, например, сохранить в биты ADDR или DECR ячейки памяти такие же биты из аккумулятора — эти и другие инструкции позволяют относится к 36–битным ячейкам памяти как к запакованным структурам из двух полей ADDR и DECR, чьи размеры позволяют адресовать любую ячейку памяти.
Именно это и делал язык Lisp появившийся на этой платформе и поэтому его реализация списков функции соответствующие head/tail называются CAR/CDR.
На самом деле это аббревиатуры от «Contents of the Address part of Register и „Contents of the Decrement part of Register“, то есть как раз поля ADDR/DECR. Напоминаю, что под „register“ в этой архаичной уже терминологии имелись ввиду ячейки памяти вообще.
Забавно, что это поле DECR делалось ради шести инструкций особого способа управления циклами, ныне вполне закономерно вымершего (здесь I это номер индексного регистра, M — поле ADDR, а D — поле DECR машинного слова):
И это при том, что в этой ЭВМ были и более классические условные переходы.
Ну и напоследок давайте еще заглянем в то как обстояли дела у одного из злейших конкурентов — компании Digital Equipment Corporation или просто DEC. Мимоходом замечу, что меня очень позабавило, что в инструкции по эксплуатации к их миникомпьютеру PDP–7 (а это тоже легенда на которой появилась впервые операционная система Unix) в первых строках написано, что компьютер такой компактный и удобный, что не требует нестандартных источников питания, усиленной вентиляции или укреплённой несущей поверхности пола.
(Компьютер PDP–7)
PDP–1
PDP–1 — первый компьютер DEC, созданный в 1960 году — через несколько лет после IBM–701 и IBM–704 и мне показалось забавным как он исправлял, так сказать, недостатки конкурентов.
PDP–1, судя по вики, стал первым (мини)компьютером на котором была создана одна из первых видеоигр — Spacewar! и первым компьютером на котором эта первая видеоигра была запущена на нескольких экземплярах машины (то есть была размножена).
Такое вот витиеватое достижение.
Машинное слово в PDP–1 было 18–битным. В 18–битной команде находилось 5 бит опкода, 1 бит индирекции и 12 бит адреса ячейки памяти для второго аргумента. То есть такая же классическая архитектура „аккумулятор–память“ как серия IBM 700.
Первое явное улучшение уже озвучено — в командах присутствовал бит индирекции, если он был зажжён, то второй аргумент для инструкции извлекался не из адреса указанного в инструкции, а из адреса по адресу указанному в инструкции. То есть любая команда работающая с памятью могла быть переключена в режим косвенной адресации. Однако несмотря на это команда перезаписывания адресной части инструкции в памяти всё таки была — DAP X (Deposit Address Part), более того была и парная команда перезаписывания кода инструкции в ячейке памяти — DIP X (Deposit Instruction Part), то есть самомодификация кода всё–таки приветствовалась и имела поддержку в системе команд.
Есть экзотическая для современности инструкция XCT X (eXeCuTe) — которая исполняет одну инструкцию по адресу X, но продолжает выполнение со следующей инструкции в текущем потоке команд! Не очень понятно зачем оно вообще надо было.
И вот второе усовершенствование — в IBM 701/704 не было стека и не было вообще никакой поддержки вызова процедур — только условные и безусловные переходы.
Видимо к началу 60–х процедуры уже замаячили со всей отчётливостью, но поддержка их была реализована пока еще довольно спорно.
На самом деле существует несколько вариантов вызова процедуры в PDP–1 разной степени калечности, но я опишу только самый передовой:
Инструкция Jump and Deposit Accumulator: JDA X
Эта инструкция сохраняла значение аккумулятора в ячейку X, далее содержимое счётчика инструкций (адрес возврата) сохраняется в аккумулятор и совершается переход на ячейку X+1.
Фактически вызванная процедура должна была сохранить в заранее оговоренную ячейку памяти AC и потом вернуться по этому адресу.
Забегая вперёд — в компьютере PDP–4 эту систему еще более усовершенствовали — аналогичная команда не трогала аккумулятор, а сразу сохраняла адрес возврата в X и переходила на X+1. Таким образом процедуры в таких компьютерах предполагалось делать так, что возвращались они в вызывающий код путём перехода по адресу из ячейки в голове процедуры. Это соглашение о вызове, как я понял, было довольно популярно в подобных допотопных ЭВМ шестидесятых — ячейки перед телом процедуры должны были при её вызове быть заполнены параметрами и адресом возврата.
И как понятно такие процедуры были абсолютно нереентерабельными. Это находит своё отражение в языке Fortran в котором только в более поздних версиях появилось ключевое слово RECURSIVE для описания реентерабельных/рекурсивных процедур и функций.
Вообще, если я правильно понял беглым взглядом, то получается что DEC имела как бы три линейки „классических“ компьютеров:
12–битные PDP–5/8/12/14, характеризовались тем, что поле адреса в инструкции было совсем маленьким и память дробилась на страницы полностью адресовать которые можно было только методом косвенной адресации через нулевую страницу.
18–битные PDP–1/4/7/9/15 — описаны выше.
36–битные PDP–6/10 — вот тут был сделан забавный коленкор, ширина инструкции позволяла зашить в неё не только адрес второго операнда, но и 16 первых ячеек памяти адресовались как первый операнд, то есть похожая на набор регистров общего назначения система, правда они тут все по традиции назывались аккумуляторами.
Возможно именно 36–битные аккумуляторы подсказали и в 1970–м году DEC выпускает новую 16–битную архитектуру PDP–11, которая резко уходит в другие концепции — семь регистров общего назначения повышенной ортогональности и 64Кб побайтовой памяти довольно быстро становятся самой популярной миниЭВМ на рынке. С пьедестала её спустят уже только микропроцессорные микрокомпьютеры. На PDP–11 появится наша любимая сишечка с implementation–defined знаком char–а ну архитектура сия явно повлияет на будущие поколения процессоров, вдохновляться ей будут еще долго.
Вероятно можно сказать, что поколение 8–битных микропроцессоров Motorola/MOS вдохновлялись системами класса IBM–700 или PDP–4, а вот Intel/Zilog были больше похожи на PDP–11.
(Компьютер IBM–701)
Как шутят некоторые статьи «когда то вычислительную мощность измеряли в килодевушках». Необходимость проведения массивных вычислений возникла довольно давно и решалась исторически довольно просто — ручными вычислениями.
(Зал с девушками–компьютерами времен Второй Мировой)
Конечно девушки активно пользовались подручными средствами — счётами и первыми механическими калькуляторами, но скорость счёта всё-равно была ограничена скоростью человеческих рук. Профессия ручного счетовода так и называлась «computer», поэтому когда появились механические и автоматические «вычислители» для массовых расчётов они просто унаследовали это название от профессии «кожаных мешков» ™.
Прогресс шёл очень быстро, механика сменилась электрикой, каждую десятилетку изобретались новые способы хранения информации как в быстрой так и в долговременной памяти.
Что же представлял из себя типовой компьютер 50/60–х с точки зрения программиста?
Прежде всего создатели компьютеров сталкивались с вопросом: «какую ширину слова выбрать для новой ЭВМ?». Дело в том, что общепринятой концепции байтов тогда еще не было — эту концепцию внедрили мейнфреймы IBM System/360.
На них я остановлюсь чуть подробнее в силу их легендарности — 1964 году IBM анонсировала долгоиграющую древнюю линейку мейнфреймов System/360. До этого всех документациях к компьютерам почти всегда писали «компьютерные» числа в 8–ричной системе исчисления в силу того, что как раз ширина слов (количество бит в ячейке памяти) выбиралась обычно кратная трём битовым разрядам — например 12, 18 или 36 бит в ячейке памяти. Восьмеричная система прекрасно под это подходила, была и достаточно экономной и легко считываемой. В System/360 же документация содержала только 16–ричные коды в силу 8–битного байта, где удобнее было делить байт на 4–битные «цифры» и к моменту появления микропроцессоров и микрокомпьютеров они практически выжили 8–ричную систему из употребления.
Один из потрясающих фактов является то, что IBM пришлось вложить в разработку System/360… $5 млрд в ценах тех лет, что по сегодняшнему курсу с учётом инфляции составляет больше $30 млрд и это делает этот проект вторым по стоимости НТР–проектом 60–ых годов после полёта на Луну!
Более того, архитектура System/360 прошла последовательное развитие с сохранением обратной совместимости и жива до сих пор и ныне в линейке серверов IBM zSeries. Пятьдесят четыре года обратной совместимости!
Архитектура, впрочем, довольно зрелая, так что неудивительно — шестнадцать 32–битных высокоортогональных регистров общего назначения и 24–битная шина адреса в System/360 поступили в продажу еще в 1964 году.
Но вернемся к более привычным архитектурам в те годы. Итак — первый вопрос встающий перед разработчиком ЭВМ тогда был «сколько бит делать в ячейке памяти»? Вообще такая ячейка памяти называлась регистром (даже если речь шла про ячейку ОЗУ/ПЗУ), поэтому можно переформулировать как «разрядность регистра». Популярными были числа 12, 18 и 36. Разрядность регистра определяла как разрядность чисел так и насколько удобно будет делать систему команд машины, какова будет разрядность её адресного пространства и насколько плотно в неё будет укладываться полезная информация. Разные вещи вступали друг с другом в конфликт, поэтому выбор был тяжкий.
Рассмотрим на примере первой ламповой машины IBM выпущенной в 1952 году — IBM–701 (она изображена на первой картинке).
IBM–701
В IBM–701 разрядность слова была 36–бит, однако максимальный объём ОЗУ в 2048 ячейки делал невыгодным хранение одной инструкции в целых 36 битах и там применялась схема деления каждой ячейки памяти на два полуслова в 18 бит. Можно даже сказать, что это были 18–битные байты этой архитектуры, хотя такая терминология тогда еще не использовалась — просто полуслова.
Прежде всего в полуслова аккуратно и экономно влазили коды инструкций. Классическая для того времени однооперандная архитектура хранила в 18 битах инструкции 5 бит на код инструкции и 13 бит на адрес второго операнда в памяти. Первым вменялся или аккумулятор AC или вспомогательный регистр MQ и кроме счётчика инструкций программных регистров здесь в общем то больше и не было. Забавно, что этот адрес зашитый в инструкцию был со знаком, потому что по наличию знака определялось к чему идёт обращение — к слову или к полуслову в памяти.
Если, например, нужно было загрузить из памяти в аккумулятор слово (или сложить его со словом), то в качестве адреса в инструкции требовалось указать отрицательное чётное число (самый младший бит адреса при этом равнялся всегда нулю).
Если же нужно было считать из памяти полуслово (или инструкцию), то в качестве адреса указывалось положительное число от 0 до 4095 — при таких адресах считывалось соответствующее полуслово (как будто бы память состоит из 4096 18–битных ячеек) при этом в аккумулятор они грузились не в младшие, а в старшие биты — то есть полуслова грузились/сохранялись как слова с занулёнными нижними, менее значащими битами.
Рассмотрим команды сложения/вычитания — они реализованы в опциональном сочетании с занулением аккумулятора, что даёт нам следующие варианты инструкций (X — ячейка памяти с которой складываем/вычитаем аккумулятор):
R ADD X ; AC=X (Reset and ADD)
ADD X ; AC=AC+X (ADD)
ADD AB X ; AC=AC+|X| (ADD ABsolute)
R SUB X ; AC=–X (Reset and SUB)
SUB X ; AC=AC–X (SUB)
SUB AB X ; AC=AC–|X| (SUB ABsolute)
Получалось, что «Reset and ADD» (обнулить аккумулятор и добавить к нему содержимое ячейки с адресом X) работала как просто загрузка в аккумулятор значения из ячейки памяти — поэтому аналогичная команда LOAD просто отсутствовала. Видимо такое странное обозначение соответствовало тому что происходило «под капотом» машины.
Этот же подход унаследует в дальнейшем машина IBM–704. И так же там будет уделено внимание арифметике с отбрасыванием знака аргумента, видимо без дополнения до двух это было актуально.
Индексных регистров или сложных режимов адресации у 701 не было и потому единственным способом косвенной адресации являлась самомодификация программы. Весьма популярный в те времена приём.
Под это существовала инструкция:
STORE A X ; X.ADDR = AC.ADDR (STORE Address)
Эта инструкция всегда работает с полусловом по адресу X и переписывает ему нижние 12 бит нижними битами аккумулятора — адресную часть, сохраняя остальные биты (код инструкции, включая знак адресной части).
Таким образом по сути в таких компьютерах был единственный режим адресации — прошитый в слово инструкции адрес ячейки памяти в которую или из которой бралось/ложилось данное, так что косвенные адресации/индексации приходилось проводить через самомодификацию кода.
IBM–704
(План установки IBM–704 из книги «Coding for the MIT–IBM 704 computer»)
IBM–704 — компьютер–легенда. С ним связано сразу несколько прорывов в области IT.
Во первых — это был первый компьютер с аппаратной поддержкой плавающей точки в широкой продаже.
Под «широкой продажей» тут понимается «больше 100 штук», т.к. мы всё–таки говорим о «больших ЭВМ», физически занимавших этаж здания и представленных на рынке в 1954 году.
Основным радиотехническим элементом машины была электронная лампа, а память была основана на магнитных сердечниках — поэтому мы так же говорим о дотранзисторной эпохе.
Во вторых — на этой машине был разработан язык программирования Fortran — чему способствовала её «научная архитектура».
Ну и в третьих — на этой машине был разработан язык программирования Lisp и архитектура IBM–704 даже оставила в нём навечно один характерный отпечаток, о чём я повторю википедию много ниже.
Машинное слово IBM–704 было 36–битным и в отличие от 701 они не делились на 18–битные полуслова. 8–битными байтами здесь так же еще не пахло.
В базовой комплектации в машине было 8192 ячеек 36–битной памяти, но максимально под шину адреса было отведено 15 бит, то есть максимально можно было адресовать 32768 ячеек 36–битной памяти, что эквивалентно 147456 байтам. Адресное пространство было так же единым для кода и данных и сама архитектура всё так же настаивала на самомодифицирующемся коде, под что были специальные инструкции и специальные форматы данных (что и оставило отпечаток на лиспе).
Регистры:
AC — аккумулятор (36 бит)
MQ — вспомогательный регистр множитель/делитель (multiplier–quotinent) (36 бит)
ILC — счётчик инструкций (instruction location counter) (15 бит)
IR1, IR2, IR4 — индексные регистры (15 бит), названия их как видно сформированы как значения числа из трёх соответствующих бит, и это так и есть, это упрощало их комбинацию в инструкциях
Выделялись так же флаги PF и QF, а нулевой бит аккумулятора AC[0] обозначается часто как флаг знака SF.
Тут можно вспомнить как шкафы компьютеров того времени перемигивались загадочно сотнями лампочек — это были просто выведены битовые представления самых важных регистров и проходящих данных по узлам компьютера для мониторинга и отладки.
Битовое представление отрицательных целых чисел тут было то ли в прямом то ли в обратном коде, но не в дополнении до двух, то есть бит знака и число позволяли описывать как +0 так и –0, что иногда требовалось учитывать в коде, т.к. +0 считался числом большим, чем –0 при сравнениях. Вещественные числа тоже как понятно были 36–битные и проходили через те же регистры, что и целочисленные — формат данного подразумевался из инструкций.
Почти все инструкции (как понятно всегда 36–битные) содержали 15 бит «адресного поля» (ADDR), что позволяло в каждой из них сослаться на одну из ячеек памяти. Поэтому архитектура инструкций была всё той же однооперандной аккумулятор–память. Для косвенных адресаций применялся следующий принцип — 3 бита в каждой инструкции отводились под «маску индексов» — если один индексных битов в инструкции был зажжён, то из поля ADDR вычиталось содержимое соответствующего индексного регистра для формирования адреса ячейки. Более того, если были указаны сразу несколько индексных бит, то вычитаемое формировалось как логический OR соответствующих индексных регистров, что позволяло адресовать многомерные массивы размеры измерений которых были кратны степеням двойки.
Ряд инструкций (ровно 6 штук) содержал так же 15 бит «поля декремента» (DECR), что это и зачем это — я расскажу ниже, но главное — что был ряд инструкций позволяющий независимо сохранять и загружать поля ADDR и DECR в/из памяти.
Инструкций довольно много, машину никак нельзя назвать аскетичной — отыгрались инженеры вовсю.
Те кто хочет поразглядывать их подробнее может пройти по ссылке gamedev.ru/flame/forum/?id=226622&page=23#m334
Такие инструкции как STD M или STA M как раз позволяют, например, сохранить в биты ADDR или DECR ячейки памяти такие же биты из аккумулятора — эти и другие инструкции позволяют относится к 36–битным ячейкам памяти как к запакованным структурам из двух полей ADDR и DECR, чьи размеры позволяют адресовать любую ячейку памяти.
Именно это и делал язык Lisp появившийся на этой платформе и поэтому его реализация списков функции соответствующие head/tail называются CAR/CDR.
На самом деле это аббревиатуры от «Contents of the Address part of Register и „Contents of the Decrement part of Register“, то есть как раз поля ADDR/DECR. Напоминаю, что под „register“ в этой архаичной уже терминологии имелись ввиду ячейки памяти вообще.
Забавно, что это поле DECR делалось ради шести инструкций особого способа управления циклами, ныне вполне закономерно вымершего (здесь I это номер индексного регистра, M — поле ADDR, а D — поле DECR машинного слова):
TIX M, I, D ; Если I > D, то уменьшаем I на D и переходим на M, иначе переходим
; на следующую инструкцию (Transfer on IndeX)
TNX M, I, D ; Если I > D, то уменьшаем I на D и переходим на следующую
; инструкцию, иначе переходим на M (Transfer on No indeX)
TXH M, I, D ; Если I > D, то переходим на M (Transfer on indeX High)
TXL M, I, D ; Если I <= D, то переходим на M (Transfer on indeX Low or equal)
TXI M, I, D ; Увеличиваем I на D и переходим на M (Transfer with indeX Increased)
И это при том, что в этой ЭВМ были и более классические условные переходы.
Ну и напоследок давайте еще заглянем в то как обстояли дела у одного из злейших конкурентов — компании Digital Equipment Corporation или просто DEC. Мимоходом замечу, что меня очень позабавило, что в инструкции по эксплуатации к их миникомпьютеру PDP–7 (а это тоже легенда на которой появилась впервые операционная система Unix) в первых строках написано, что компьютер такой компактный и удобный, что не требует нестандартных источников питания, усиленной вентиляции или укреплённой несущей поверхности пола.
(Компьютер PDP–7)
PDP–1
PDP–1 — первый компьютер DEC, созданный в 1960 году — через несколько лет после IBM–701 и IBM–704 и мне показалось забавным как он исправлял, так сказать, недостатки конкурентов.
PDP–1, судя по вики, стал первым (мини)компьютером на котором была создана одна из первых видеоигр — Spacewar! и первым компьютером на котором эта первая видеоигра была запущена на нескольких экземплярах машины (то есть была размножена).
Такое вот витиеватое достижение.
Машинное слово в PDP–1 было 18–битным. В 18–битной команде находилось 5 бит опкода, 1 бит индирекции и 12 бит адреса ячейки памяти для второго аргумента. То есть такая же классическая архитектура „аккумулятор–память“ как серия IBM 700.
Первое явное улучшение уже озвучено — в командах присутствовал бит индирекции, если он был зажжён, то второй аргумент для инструкции извлекался не из адреса указанного в инструкции, а из адреса по адресу указанному в инструкции. То есть любая команда работающая с памятью могла быть переключена в режим косвенной адресации. Однако несмотря на это команда перезаписывания адресной части инструкции в памяти всё таки была — DAP X (Deposit Address Part), более того была и парная команда перезаписывания кода инструкции в ячейке памяти — DIP X (Deposit Instruction Part), то есть самомодификация кода всё–таки приветствовалась и имела поддержку в системе команд.
Есть экзотическая для современности инструкция XCT X (eXeCuTe) — которая исполняет одну инструкцию по адресу X, но продолжает выполнение со следующей инструкции в текущем потоке команд! Не очень понятно зачем оно вообще надо было.
И вот второе усовершенствование — в IBM 701/704 не было стека и не было вообще никакой поддержки вызова процедур — только условные и безусловные переходы.
Видимо к началу 60–х процедуры уже замаячили со всей отчётливостью, но поддержка их была реализована пока еще довольно спорно.
На самом деле существует несколько вариантов вызова процедуры в PDP–1 разной степени калечности, но я опишу только самый передовой:
Инструкция Jump and Deposit Accumulator: JDA X
Эта инструкция сохраняла значение аккумулятора в ячейку X, далее содержимое счётчика инструкций (адрес возврата) сохраняется в аккумулятор и совершается переход на ячейку X+1.
Фактически вызванная процедура должна была сохранить в заранее оговоренную ячейку памяти AC и потом вернуться по этому адресу.
Забегая вперёд — в компьютере PDP–4 эту систему еще более усовершенствовали — аналогичная команда не трогала аккумулятор, а сразу сохраняла адрес возврата в X и переходила на X+1. Таким образом процедуры в таких компьютерах предполагалось делать так, что возвращались они в вызывающий код путём перехода по адресу из ячейки в голове процедуры. Это соглашение о вызове, как я понял, было довольно популярно в подобных допотопных ЭВМ шестидесятых — ячейки перед телом процедуры должны были при её вызове быть заполнены параметрами и адресом возврата.
И как понятно такие процедуры были абсолютно нереентерабельными. Это находит своё отражение в языке Fortran в котором только в более поздних версиях появилось ключевое слово RECURSIVE для описания реентерабельных/рекурсивных процедур и функций.
Вообще, если я правильно понял беглым взглядом, то получается что DEC имела как бы три линейки „классических“ компьютеров:
12–битные PDP–5/8/12/14, характеризовались тем, что поле адреса в инструкции было совсем маленьким и память дробилась на страницы полностью адресовать которые можно было только методом косвенной адресации через нулевую страницу.
18–битные PDP–1/4/7/9/15 — описаны выше.
36–битные PDP–6/10 — вот тут был сделан забавный коленкор, ширина инструкции позволяла зашить в неё не только адрес второго операнда, но и 16 первых ячеек памяти адресовались как первый операнд, то есть похожая на набор регистров общего назначения система, правда они тут все по традиции назывались аккумуляторами.
Возможно именно 36–битные аккумуляторы подсказали и в 1970–м году DEC выпускает новую 16–битную архитектуру PDP–11, которая резко уходит в другие концепции — семь регистров общего назначения повышенной ортогональности и 64Кб побайтовой памяти довольно быстро становятся самой популярной миниЭВМ на рынке. С пьедестала её спустят уже только микропроцессорные микрокомпьютеры. На PDP–11 появится наша любимая сишечка с implementation–defined знаком char–а ну архитектура сия явно повлияет на будущие поколения процессоров, вдохновляться ей будут еще долго.
Вероятно можно сказать, что поколение 8–битных микропроцессоров Motorola/MOS вдохновлялись системами класса IBM–700 или PDP–4, а вот Intel/Zilog были больше похожи на PDP–11.
0 комментариев