Джоэл МакКормак является разработчиком NCR Corporation версии p- кодовая машина, которая является своего рода стековой машиной, популярной в 1970-х годах как предпочтительный способ реализации новых вычислительных архитектур и языков, таких как Pascal и BCPL <58.>. Дизайн NCR не имеет общей архитектуры с Pascal MicroEngine, разработанным Western Digital, но оба предназначены для выполнения UCSD p-System. [1,2]
Урс Амманн, ученик Никлауса Вирта, первоначально представил p-код в его докторской диссертации (см. Урс Амманн, О генерации кода в компиляторе Паскаля, Программное обеспечение - Практика и опыт, Том 7, № 3, 1977, стр. 391–423). Основная идея заключается в том, что сложная программная система кодируется для несуществующего, вымышленного, минимального компьютера или виртуальной машины, и этот компьютер реализован на конкретном реальном оборудовании с интерпретирующей компьютерной программой, которая обычно является небольшой и простой., и быстро развивался. Язык программирования Паскаль приходилось переписывать для каждого нового приобретаемого компьютера, поэтому Амманн предложил один раз написать систему для виртуальной архитектуры. Успешной академической реализацией Pascal стала p-System UCSD, разработанная Кеннетом Боулзом, профессором UCSD, который начал проект разработки универсальной Среда программирования Pascal, использующая архитектуру P-machine для множества различных вычислительных платформ, используемых в то время. Маккормак был частью команды студентов, работавших над проектом. [3] Он взял это знание и опыт с собой в NCR.
В 1979 году МакКормак был принят на работу в NCR сразу после окончания колледжа, и они разработали Bit spling реализация машины p-кода с использованием набора микросхем Am2900. У этого CPU было множество проблем с синхронизацией и производительностью, поэтому МакКормак предложил полностью модернизировать процессор, используя программируемое логическое устройство на основе Microsequencer. Маккормак покинул NCR, чтобы основать компанию Volition Systems, но продолжил работу над ЦП в качестве подрядчика. В новом процессоре использовался микроворд шириной 80 бит, поэтому параллелизм в микрокоде был радикально улучшен. В микрокоде было несколько циклов, состоящих из одной инструкции, и многие из более простых операций p-кода занимали 1 или 2 инструкции микрокода. Благодаря широкому микрослову и тщательному расположению шин, а также увеличению регистров адресов памяти, ЦП мог выполнять операции внутри ALU, передавая слово памяти непосредственно во встроенный стек, или подавать один источник в ALU при отправке ранее вычисленный регистр на шину назначения за один микроцикл.
ЦП работал на трех разных тактовых частотах (с использованием линий задержки для выбираемых часов); два бита в микростроке выбирают время цикла для этой инструкции. Часы около 130, 150 и 175 наносекунд. Новые компоненты от AMD могли бы позволить более быстрый цикл 98 нс для самых быстрых инструкций, но они не вышли с соответственно более быстрым блоком управления переходами.
Был отдельный блок упреждающей выборки / форматирования инструкций (опять же, с использованием останавливаемых часов линии задержки для синхронизации... асинхронная логика допускает перекос таймингов). Он имел 32-битный буфер и мог доставлять следующие данные в виде байта со знаком, байта без знака, 16-битного слова или «большого» операнда (одно- или двухбайтовый формат, где 0..127 были закодированы как один байт, а 128..32767 было закодировано как два байта).
На плате был стек из 1024 16-битных слов, так что в нем можно было работать как со скалярами, так и с наборами. Верхняя часть стека фактически хранилась в одном из регистров AMD 2901, так что простые операции, такие как сложение целых чисел, занимали один цикл. раньше мы украли метод хранения верхнего слова стека в одном из регистров AMD 2901. Часто это приводило к уменьшению на одну микрокоманду. (Стек работает не совсем так... он уменьшается до того, как в него записываются данные, и увеличивается после чтения.)
Поскольку управление следующим адресом и следующее расположение микрокода находились в каждом широком микроворде, не было штрафа за выполнение микрокода в любом порядке. Таким образом, у нас была таблица из 256 меток, и компилятор микрокода переместил первую инструкцию на каждой из этих меток в первые 256 ячеек памяти микрокода. Единственное ограничение, наложенное на микрокод, заключалось в том, что если для p-кода требуется более одной микрокоманды, то для первой микрокоманды не может быть задано какое-либо управление потоком (так как она будет заполнена с помощью "goto
ЦП использовал технику хранения верхнего слова стека в одном из регистров AMD 2901. Это часто приводило к на одну микрокоманду меньше. Например, вот несколько p-кодов, как они заканчиваются up.tos - это регистр, а q - регистр. "|" означает параллельные действия в одном цикле. (Стек не совсем так работает... он уменьшается до того, как данные будут записаны в него, и увеличивается после данных считывается.)
Так как управление следующим адресом и следующее расположение микрокода находились в каждом широком микрорде, не было штрафа за выполнение микрокода в любом порядке. Таблица из 256 меток, и компилятор микрокода переместил первая инструкция на каждой из этих меток к первым 256 ячейкам памяти микрокода. Ограничение, наложенное на микрокод, заключалось в том, что если p-код требовал более одной микрокоманды, то для первой микрокоманды не могло быть задано какое-либо управление потоком (поскольку оно было бы заполнено с помощью «goto
получить% Fetch и сохранить в регистре AMD код операции следующего байта из% блока предварительной выборки и перейти к этому месту в микрокоде. q: = ubyte | goto ubyte SLDCI% Короткая константа загрузки, целое число (проталкивание байта кода операции)% Перемещение регистра AMD вершины стека в реальный стек, загрузка% регистра вершины стека с выбранным кодом операции, который привел нас сюда dec (sp) | стек: = tos | tos: = q | goto fetch LDCI% Загрузить целое число константы (слово кода операции push)% Во многом похоже на SLDCI, за исключением выборки 2-байтового слова и «push» в стек dec (sp) | стек: = tos | tos: = слово | goto fetch SLDL1% Локальная переменная короткой загрузки со смещением 1% mpd0 - это указатель на локальные данные со смещением 0. Записать соответствующий адрес% данных в адресный регистр памяти с байтовым адресом mar: = mpd0 + 2% Push tos, load new tos из памяти SLDX dec (sp) | стек: = tos | tos: = memword | goto fetch LDL% Загрузить локальную переменную со смещением, указанным операндом "big" r0: = big mar: = mpd0 + r0 | goto sldx INCR% Увеличивает верхнюю часть стека на большой операнд tos: = tos + big | goto fetch ADI% Добавить два слова поверх стека tos: = tos + stack | inc (sp) | goto fetch EQUI% Два первых слова в стеке равны? тестовые пакеты - стек | inc (sp) tos: = 0 | if ~ zero goto fetch tos: = 1 | goto fetch
Эту архитектуру следует сравнить с исходной спецификацией машины P-кода, предложенной Никлаусом Виртом.
Конечным результатом был 9 "x11" для процессора, который работал UCSD p-System быстрее, чем что-либо еще, с большим отрывом. В 35-50 раз быстрее, чем интерпретатор LSI-11, и в 7-9 раз быстрее, чем у Western Digital Pascal MicroEngine при замене микрокода LSI-11 на p- код микрокода. Он также работал быстрее, чем машина Niklaus Wirth Lilith, но не обладал возможностями растровой графики и примерно такой же скоростью, как и VAX-11/750. собственный код. (Но VAX помешал плохой код, исходящий из компилятора Berkeley Pascal, а также был 32-битной машиной.)