This article needs additional citations for verification. (December 2009) |
Набор инструкций Burroughs B6x00-7x00 включает набор допустимых операций для Burroughs B6500, [1] B7500 и более поздних больших систем Burroughs , включая текущие (по состоянию на 2006 год) системы Unisys Clearpath/MCP; он не включает инструкции для других больших систем Burroughs, включая B5000, B5500, B5700 и B8500. Эти уникальные машины имеют отличительную конструкцию и набор инструкций. Каждое слово данных связано с типом, и эффект операции над этим словом может зависеть от типа. Кроме того, машины основаны на стеке [a] до такой степени, что у них нет регистров с пользовательской адресацией.
Как и следовало ожидать от уникальной архитектуры, используемой в этих системах, они также имеют интересный набор инструкций . Программы состоят из 8-битных слогов , которые могут быть Name Call, быть Value Call или образовывать оператор, который может быть длиной от одного до двенадцати слогов. Существует менее 200 операторов , все из которых умещаются в 8-битные слоги. Если проигнорировать мощные операторы сканирования строк, передачи и редактирования, то базовый набор составляет всего около 120 операторов. Если удалить операторы, зарезервированные для операционной системы, такие как MVST и HALT, то набор операторов, обычно используемых программами пользовательского уровня, составляет менее 100. Слоги Name Call и Value Call содержат пары адресов; слоги Operator либо не используют адреса, либо используют управляющие слова и дескрипторы в стеке.
Поскольку нет программно адресуемых регистров, большинство операций по манипулированию регистрами, требуемых в других архитектурах, не нужны, как и варианты для выполнения операций между парами регистров , поскольку все операции применяются к вершине стека . Это также делает файлы кода очень компактными, поскольку операторы имеют нулевой адрес и не должны включать адрес регистров или ячеек памяти в поток кода. Часть плотности кода была обусловлена перемещением важной информации операндов в другое место, в «теги» на каждом слове данных или в таблицы указателей. Многие из операторов являются общими или полиморфными в зависимости от типа данных, с которыми действуют, как указано в теге. Общие коды операций требовали меньше битов кода операции, но делали оборудование более похожим на интерпретатор, с меньшей возможностью конвейеризации общих случаев.
Например, набор инструкций имеет только один оператор ADD. Он должен был извлечь операнд, чтобы определить, было ли это целочисленное сложение или сложение с плавающей точкой. Типичные архитектуры требуют несколько операторов для каждого типа данных, например add.i, add.f, add.d, add.l для целых, float, double и long типов данных. Архитектура различает только числа одинарной и двойной точности — целые числа — это просто действительные числа с нулевой экспонентой . Когда один или оба операнда имеют тег 2, выполняется сложение двойной точности, в противном случае тег 0 указывает на одинарную точность. Таким образом, сам тег является эквивалентом расширения оператора .i, .f, .d и .l. Это также означает, что код и данные никогда не могут быть несоответствующими.
Два оператора важны при обработке данных в стеке – Value Call (VALC) и Name Call (NAMC). Это двухбитные операторы, 00 – это VALC, а 01 – это NAMC. Следующие шесть бит слога, объединенные со следующим слогом, обеспечивают адресную пару. Таким образом, VALC охватывает значения слогов от 0000 до 3FFF, а NAMC от 4000 до 7FFF.
VALC — еще один полиморфный оператор. Если он попадает в слово данных, это слово загружается в верхнюю часть стека . Если он попадает в IRW, то он следует, возможно, в цепочке IRW, пока не будет найдено слово данных. Если найден PCW, то вводится функция для вычисления значения, и VALC не завершается, пока функция не вернет управление.
NAMC просто загружает пару адресов наверх стека как IRW (при этом тег автоматически устанавливается на 1).
Статические переходы (BRUN, BRFL и BRTR) использовали два дополнительных слога смещения. Таким образом, арифметические операции занимали один слог, операции адресации (NAMC и VALC) занимали два, переходы — три, а длинные литералы (LT48) — пять. В результате код был намного плотнее (имел лучшую энтропию), чем традиционная архитектура RISC, в которой каждая операция занимает четыре байта. Лучшая плотность кода означала меньше промахов кэша инструкций и, следовательно, лучшую производительность при запуске крупномасштабного кода.
В следующих пояснениях операторов помните, что A и B — это два верхних регистра стека. Расширения двойной точности обеспечиваются регистрами X и Y; таким образом, два верхних операнда двойной точности задаются AX и BY. (В основном AX и BY подразумеваются просто A и B.)
Текущий LL | Лексический уровень битов | Индексные биты |
---|---|---|
0-1 | 13 | 12-0 |
2-3 | 13-12 | 11-0 |
4-7 | 13-11 | 10-0 |
8-15 | 13-10 | 9-0 |
16-31 | 13-9 | 8-0 |
В B6500 слово имеет 48 бит данных и три бита тега. расширено до трех бит за пределами 48-битного слова в тег. Биты данных - это биты 0-47, а тег - это биты 48-50. Бит 48 - это бит только для чтения, таким образом, нечетные теги обозначают управляющие слова, которые не могут быть записаны программой уровня пользователя. Кодовым словам присваивается тег 3. Вот список тегов и их функции:
Ярлык | Слово доброе | Описание |
---|---|---|
0 | Данные | Все виды пользовательских и системных данных (текстовые данные и числа одинарной точности) |
2 | Двойной | Данные двойной точности |
4 | СИВ | Шаг Индексное слово (используется в циклах) |
6 | Неинициализированные данные | |
СКВ | Программное управляющее слово (используется для сокращения стека) | |
1 | ИРВ | Косвенное референтное слово |
SIRW | Косвенно-указательное слово | |
3 | Код | Кодовое слово программы |
МСКВ | Отметить контрольное слово стека | |
РКВ | Возврат контрольного слова | |
ТОСКВ | Управляющее слово вершины стека | |
СД | Описатель сегмента | |
5 | Дескриптор | Дескрипторы блоков данных |
7 | ПКВ | Программное контрольное слово |
Текущее воплощение этих машин, Unisys ClearPath, расширило теги еще больше до четырехбитного тега. Уровень микрокода, который определял четырехбитные теги, назывался уровнем Gamma.
Слова с четными тегами — это пользовательские данные, которые могут быть изменены пользовательской программой как пользовательское состояние. Слова с нечетными тегами создаются и используются непосредственно оборудованием и представляют состояние выполнения программы. Поскольку эти слова создаются и используются определенными инструкциями или оборудованием, точный формат этих слов может меняться между аппаратной реализацией, и пользовательским программам не нужно перекомпилировать, поскольку тот же поток кода будет выдавать те же результаты, даже если системный формат слова мог измениться.
Слова тега 1 представляют адреса данных в стеке. Обычный IRW просто хранит пару адресов для данных в текущем стеке. SIRW ссылается на данные в любом стеке, включая номер стека в адрес.
Слова тега 5 являются дескрипторами, которые более подробно описаны в следующем разделе. Слова тега 5 представляют адреса данных вне стека.
Тег 7 — это управляющее слово программы, которое описывает точку входа в процедуру. Когда операторы попадают в PCW, процедура вводится. Оператор ENTR явно вводит процедуру (невозвращающую значение процедуру). Функции (возвращающие значение процедуры) неявно вводятся операторами, такими как вызов значения (VALC). Глобальные процедуры хранятся в среде D[2] как SIRW, которые указывают на PCW, хранящийся в словаре сегмента кода в среде D[1]. Среда D[1] не хранится в текущем стеке, поскольку на нее могут ссылаться все процессы, совместно использующие этот код. Таким образом, код является реентерабельным и общим.
Тег 3 представляет сами кодовые слова, которые не будут встречаться в стеке. Тег 3 также используется для управляющих слов стека MSCW, RCW, TOSCW.
Оптимизация оборудования стека заключается в предоставлении регистров D (или «дисплея»). Это регистры, которые указывают на начало каждого вызываемого кадра стека. Эти регистры обновляются автоматически при входе и выходе из процедур и не доступны никакому программному обеспечению. Имеется 32 регистра D, что ограничивает 32 уровня лексической вложенности.
Рассмотрим, как мы могли бы получить доступ к глобальной переменной лексического уровня 2 (D[2]) из лексического уровня 5 (D[5]). Предположим, что переменная находится на расстоянии 6 слов от базы лексического уровня 2. Таким образом, она представлена парой адресов (2, 6). Если у нас нет регистров D, мы должны посмотреть на управляющее слово в базе кадра D[5], которое указывает на кадр, содержащий среду D[4]. Затем мы смотрим на управляющее слово в базе этой среды, чтобы найти среду D[3], и продолжаем таким образом, пока не пройдем по всем ссылкам обратно к требуемому лексическому уровню. Это не тот же путь, что и обратный путь через процедуры, которые были вызваны для того, чтобы добраться до этой точки. (Архитектура сохраняет как стек данных, так и стек вызовов в одной и той же структуре, но использует управляющие слова, чтобы различать их.)
Как вы можете видеть, это довольно неэффективно для простого доступа к переменной. С регистрами D регистр D[2] указывает на базу лексического уровня 2 среды, и все, что нам нужно сделать для генерации адреса переменной, это добавить ее смещение от базы кадра стека к базовому адресу кадра в регистре D. (Существует эффективный оператор поиска по связанному списку LLLU, который может выполнять поиск в стеке указанным выше способом, но подход с регистром D все равно будет быстрее.) С регистрами D доступ к сущностям во внешних и глобальных средах так же эффективен, как и доступ к локальной переменной.
Данные тега D — пара адресов, комментариизарегистрироваться
| 0 | n | (4, 1) Целое число n (объявляется при входе в блок, а не в процедуру)|-----------------------|| D[4]==>3 | MSCW | (4, 0) Управляющее слово стека меток, содержащее ссылку на D[3].|========================|| 0 | r2 | (3, 5) Реальный r2|-----------------------|| 0 | r1 | (3, 4) Реальный r1|-----------------------|| 1 | p2 | (3, 3) Ссылка SIRW на g в (2,6)|-----------------------|| 0 | p1 | (3, 2) Параметр p1 из значения f |-----------------------|| 3 | RCW | (3, 1) Возврат контрольного слова|-----------------------|| D[3]==>3 | MSCW | (3, 0) Управляющее слово стека меток, содержащее ссылку на D[2].|========================|| 1 | a | (2, 7) Массив a ======>[блок памяти из десяти слов]|-----------------------|| 0 | g | (2, 6) Реальное g |-----------------------|| 0 | f | (2, 5) Реальное f |-----------------------|| 0 | k | (2, 4) Целое число k |-----------------------|| 0 | j | (2, 3) Целое число j |-----------------------|| 0 | i | (2, 2) Целое число i|-----------------------|| 3 | RCW | (2, 1) Возврат контрольного слова|-----------------------|| D[2]==>3 | MSCW | (2, 0) Управляющее слово стека меток, содержащее ссылку на предыдущий кадр стека.|========================| — Стек снизу
Если бы мы вызвали процедуру p как сопрограмму или инструкцию процесса, среда D[3] стала бы отдельным стеком на основе D[3]. Это означает, что асинхронные процессы по-прежнему имеют доступ к среде D[2], как подразумевается в программном коде ALGOL. Сделав еще один шаг вперед, совершенно другая программа могла бы вызвать код другой программы, создав стековый фрейм D[3], указывающий на среду D[2] другого процесса поверх своего собственного стека процесса. В одно мгновение все адресное пространство из среды выполнения кода изменяется, делая среду D[2] в собственном стеке процесса не адресуемой напрямую, а вместо этого делая среду D[2] в стеке другого процесса адресуемой напрямую. Вот как реализуются библиотечные вызовы. При таком перекрестном вызове стека вызывающий код и вызываемый код могут даже происходить из программ, написанных на разных исходных языках, и компилироваться разными компиляторами.
Окружения D[1] и D[0] не встречаются в стеке текущего процесса. Окружение D[1] — это словарь сегментов кода, который используется всеми процессами, выполняющими один и тот же код. Окружение D[0] представляет сущности, экспортируемые операционной системой.
Кадры стека на самом деле даже не обязательно должны существовать в стеке процесса. Эта функция использовалась на раннем этапе для оптимизации ввода-вывода файлов, FIB (блок информации о файле) был связан с регистрами отображения в D[1] во время операций ввода-вывода. В начале девяностых эта возможность была реализована как языковая функция как STRUCTURE BLOCKs и – в сочетании с библиотечной технологией – как CONNECTION BLOCKs. Возможность связывать структуру данных с областью адреса регистра отображения реализовала объектную ориентацию. Таким образом, B6500 фактически использовал форму объектной ориентации задолго до того, как этот термин был когда-либо использован.
В других системах компилятор мог бы построить свою таблицу символов аналогичным образом, но в конечном итоге требования к хранению были бы сопоставлены, и машинный код был бы написан для использования плоских адресов памяти 16-бит или 32-бит или даже 64-бит. Эти адреса могли бы содержать что угодно, так что запись по неправильному адресу могла бы повредить что угодно. Вместо этого двухкомпонентная схема адресации была реализована аппаратно. На каждом лексическом уровне переменные размещались со смещениями вверх от основания стека уровня, обычно занимая одно слово — переменные двойной точности или комплексные переменные занимали бы два. Массивы не хранились в этой области, хранился только однословный дескриптор для массива. Таким образом, на каждом лексическом уровне общие требования к хранению были невелики: десятки, сотни или несколько тысяч в крайних случаях, определенно не количество, требующее 32 бит или больше. И действительно, это было отражено в форме инструкции VALC (вызов значения), которая загружала операнд в стек. Этот код операции был длиной в два бита, а остальная часть битов байта была объединена со следующим байтом, чтобы получить четырнадцатибитное поле адресации. Выполняемый код будет на некотором лексическом уровне, скажем, шесть: это означало, что только лексические уровни с нуля по шесть были допустимы, и поэтому для указания желаемого лексического уровня требовалось всего три бита. Таким образом, адресная часть операции VALC зарезервировала для этой цели всего три бита, а оставшиеся были доступны для ссылки на сущности на этом и более низких уровнях. Глубоко вложенная процедура (то есть на высоком лексическом уровне) имела бы меньше битов, доступных для идентификации сущностей: для уровня шестнадцать и выше потребовалось бы пять битов для указания выбора уровней 0–31, таким образом, оставляя девять бит для идентификации не более первых 512 сущностей любого лексического уровня. Это намного компактнее, чем адресация сущностей по их буквальному адресу памяти в 32-битном адресном пространстве. Кроме того, данные загружал только код операции VALC: коды операций ADD, MULT и т. д. не выполняли адресацию, работая исключительно с верхними элементами стека.
Гораздо важнее то, что этот метод означал, что многие ошибки, доступные системам, использующим плоскую адресацию, не могли произойти, потому что они были просто невыразимы даже на уровне машинного кода. Задача не имела возможности повредить память, используемую другой задачей, потому что она не имела возможности разработать свой адрес. Смещения от указанного D-регистра проверялись оборудованием по границе стекового кадра: неверные значения были бы перехвачены. Аналогично, внутри задачи дескриптор массива содержал информацию о границах массива, и поэтому любая операция индексации проверялась оборудованием: другими словами, каждый массив формировал свое собственное адресное пространство. В любом случае, маркировка всех слов памяти обеспечивала второй уровень защиты: неправильно направленное назначение значения могло перейти только в место хранения данных, а не в то, которое содержало указатель или дескриптор массива и т. д., и уж тем более не в место хранения машинного кода.
— затем NAMC для загрузки PCW, затем передача параметров по мере необходимости, затем ENTR)
— сохранить значение в регистре B в памяти, адресуемой регистром A. — Удалить значение из стека.
Инструкция Load может сработать при косвенном обращении или, что еще хуже, при замаскированном вызове процедуры преобразования по имени .
— При необходимости проследите цепочку адресов.
Они использовались для передачи строк обычно до тех пор, пока в исходной строке не был обнаружен определенный символ. Все эти операторы защищены от переполнения буфера, будучи ограниченными границами в дескрипторах.
Они использовались для сканирования строк, полезных при написании компиляторов . Все эти операторы защищены от переполнения буфера , будучи ограниченными границами в дескрипторах.
Это были специальные операторы для сложных операций со строками, особенно в бизнес-приложениях.