LINUX.ORG.RU

Энтузиасты дизассемблировали микрокод i386 и создали открытый CPU z386

 , , , z386,

Энтузиасты дизассемблировали микрокод i386 и создали открытый CPU z386

6

6

Энтузиасты смогли успешно извлечь и дизассемблировать микрокод процессора Intel 80386, который из-за отсутствия документации считался «чёрным ящиком». Бинарный образ микрокода был воссоздан с привлечением AI по фотографиям кристалла в высоком разрешении, а логика работы разобрана через трассировку соединений на кристалле. Постепенно были определены структура микрокоманд (μ-ops), поля, порядок исполнения и маркеры конца инструкций. Наработки проекта опубликованы на GitHub как общественное достояние.

Выявлено, что в CPU 80386 каждая инструкция полностью исполняется через микрокод, в то время как в 8086 и современных процессорах часть инструкций обрабатывается напрямую. Кроме того, в отличие от процессоров 8086, в 80386 микрокод не реализует алгоритмы напрямую, а в основном настраивает аппаратные ускорители (умножитель, делитель, быстрый сдвиг, PTU (Protection Test Unit)).

В ходе исследования также была обнаружена возможная проблема с безопасностью при обработке битовой карты прав доступа к вводу/выводу (IO permission bitmap): при 4-байтовом обращении к портам проверялись биты прав доступа только для первых 3 байтов, а доступ к 4-му байту не проверялся, что теоретически допускало обращение к аппаратным регистрам, доступ к которым должен был быть запрещён.

На основе опубликованного микрокода разработан открытый CPU z386, реализованный на языке SystemVerilog и работающий с использованием FPGA. Вместо реализации каждой инструкции в форме отдельного RTL (wikipedia.org) (Register-transfer level) в z386 реализованы аппаратные структуры, которыми управляет оригинальный микрокод. Производительность подготовленной реализации соответствует быстрому 386 ПК (~70MHz). Под управлением z386 удалось успешно запустить DOS 6/7, DOS/4GW, DOS/32A и игры, такие как Doom и Cannon Fodder.

>>> Подробности на opennet



Проверено: dataman ()
Последнее исправление: dataman (всего исправлений: 1)
Ответ на: комментарий от drfaust

Минский интеграл выпускал линейку от 286го до 486го проца. Причём компы на ентих процах серии ЕС спокойно продавались в магазах РБ, ну как спокойно - «квартиру продай и покупай»...

И ты конечно же приведёшь модели? Бред. Полупроводниковая промышленность СССР не могла выпустить ничего сложнее i8086, тем более, за $1000, которые тогда стоила квартира в Белоруссии. И то, полной совместимости с PC в конечных моделях, по ряду причин, не было. Единственный полноценный не мифический клон 286-го процессора, u80601, производился в ГДР. Единственная ЭВМ на его базе называлась Robotron EC 1835, производилась там же. Ни о каких 386-х, 486-х речи быть не могло.

lenin386 ★★★★★
()
Последнее исправление: lenin386 (всего исправлений: 4)
Ответ на: комментарий от monk

У Эльбруса (e2k) лучше. Там каждый массив контролируется, включая те, что на стеке.

Безусловно лучше! Надеюсь, что такой контроль никак не сказывается на производительности. Особенно при такой то длине слова. Хи-хи, отличная идея!

VIT ★★
()
Ответ на: комментарий от GAMer

даже 4 ядра не прокачают два канала.

Дело не в канале, а в пропускной способности шины подключения ядра к NOC. Она примерно 8-10GB/s. Это и есть реальное ограничение доступа ядра к памяти независимо от типа памяти и количества каналов.

VIT ★★
()
Ответ на: комментарий от Radjah

Лет 30 назад за такое могли бы по судам затаскать скорее всего.

Та нууу, что там взять, так повякали бы и спустили.

VIT ★★
()
Ответ на: комментарий от kirill_rrr

С другой стороны, кто нибудь оценивал как на практике могла бы выглядеть 16-ядерная версия i386 на 12нм при частоте 3-4Ггц?

А нафеухуа, пардон зa мой «китайский»??.. ;))

Somebody ★★★★
()
Ответ на: комментарий от splinter

Завидую, сколько же у людей свободного времени, поссоны ваще ребята!

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

VIT ★★
()
Ответ на: комментарий от watchcat382

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

cobold ★★★★★
()
Ответ на: комментарий от praseodim

как это 286 не успели? А ПК «Поиск» это недостаточно серийно? Я бы лично напротив 286 ставил жирную зелёную галочку. С 386 - да, где-то не повезло, не фортануло, и, я считаю, что не из-за технических сложностей.

shprotua
()
Ответ на: комментарий от GAMer

Их, АФАИК, всё-таки несколько даже от МЦСТ. Режим защищенного исполнения с тегами и общий режим.

Защищённый режим работает на любой ОС на уровне приложения. Для специальных целей вся ОС компилируется в защищенном режиме.

monk ★★★★★
()
Ответ на: комментарий от VIT

Безусловно лучше! Надеюсь, что такой контроль никак не сказывается на производительности. Особенно при такой то длине слова. Хи-хи, отличная идея!

Меньше сказывается, чем если каждый массив в отдельном сегменте.

monk ★★★★★
()
Ответ на: комментарий от monk

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

VIT ★★
()
Ответ на: комментарий от shprotua

Поиск - 8088. Мифические Поиск-2.286 - чей-то наркоманский бред. Никто эти компьютеры никогда не видел. Нет ни фоток, ни рекламы, ни документации, ничего. Если что и было, то скорее всего, это какой-то пионэр наклеил на рэндомный писюк импортозамещающий шильдик, и продал государству.

lenin386 ★★★★★
()
Последнее исправление: lenin386 (всего исправлений: 4)
Ответ на: комментарий от VIT

Особенно при такой то длине слова.

А ты для скорости до сих пор 32-битные указатели используешь?

monk ★★★★★
()
Ответ на: комментарий от monk

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

VIT ★★
()
Последнее исправление: VIT (всего исправлений: 1)
Ответ на: комментарий от watchcat382

К примеру давно уже никому не нужны предметы одежды, которые можно передать по наследству детям,а то и внукам

И поэтому мы получаем по 100 млрд * 0.93 тонн мусора в год. Этим не гордится надо, а прекращать как можно скорее.

Andrew-R ★★★★★
()
Ответ на: комментарий от Andrew-R

В чём собственно проблема мусора? За его вывоз боссы мафии дерутся. И основная его часть, 90% - упаковка. Просто, ходите с сумками, а не с пакетами, заворачивайте в бумагу, как это делалось в СССР - и 90% мусора нет.

lenin386 ★★★★★
()
Последнее исправление: lenin386 (всего исправлений: 2)
Ответ на: комментарий от Displacer

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

EvAn
()
Ответ на: комментарий от lenin386

Вы были в Индии? Вопрос риторический.

VIT ★★
()
Ответ на: комментарий от VIT

Ну вот пример

#include <stdlib.h>
#define N 1000

int *gp;
int main()
{
  gp = (int*)malloc(N*sizeof(int));
  gp[N/2] = N/2;
  gp[-1] = 14; // ошибка
  return 0;
}

В обычном режиме 6 тактов (помимо вызова malloc).

        {
          setwd wsz = 0x8, nfx = 0x1, dbl = 0x0
          setbn rsz = 0x3, rbs = 0x4, rcur = 0x0
          disp  %ctpr1, malloc
          getsp,0       _f32s,_lts2 0xfffffff0, %r2
          adds,1        0xe, 0x0, %r3
          adds,2        0x0, _f16s,_lts1lo 0x1f4, %r4
        }
        {
          nop 3
          addd,0        0x0, _f16s,_lts0lo 0xfa0, %b[0]
        }
        {
          call  %ctpr1, wbs = 0x4
        }
        {
          return        %ctpr3
          std,2 0x0, [ _f64,_lts1 gp ], %b[0]
          addd,3        0x0, 0x0, %r0
          stw,5 %b[0], _f16s,_lts0lo 0x7d0, %r4
        }
        {
          nop 4
          stw,5 %b[0], _f16s,_lts0lo 0xfffc, %r3
        }
        {
          ct    %ctpr3
        }

В защищённом 9 тактов.

        {
          nop 1
          setwd wsz = 0x12, nfx = 0x1, dbl = 0x0
          setbn rsz = 0x7, rbs = 0xa, rcur = 0x0
          setbp psz = 0x0
          getsap,0      _f32s,_lts1 0xffffffe0, %r18
        }
        {
          nop 1
          stapb,2       %r18, 0x0, %r18
        }
        {
          disp  %ctpr1, malloc
          movtq,0,sm    %r18, %b[0]
          addd,2        0x0, _f16s,_lts0lo 0xfa0, %b[2]
          adds,3        0xe, 0x0, %r1
          adds,4        0x0, _f16s,_lts0hi 0x1f4, %r2
        }
        {
          nop 3
          aptoapb,0     %r18, _f16s,_lts0lo 0x20, %b[0]
        }
        {
          call  %ctpr1, wbs = 0xa
        }
        {
          return        %ctpr3
          adds,3        0x0, 0x0, %r0
          stapw,5       %b[0], _f16s,_lts0lo 0x7d0, %r2
        }
        {
          stgdq,2,sm    0x0, [ _f32s,_lts0 gp ], %b[0]
        }
        {
          nop 3
          stapw,5       %b[0], _f16s,_lts0lo 0xfffc, %r1
        }
        {
          ct    %ctpr3
        }

Так как чтение-запись по указателю не в каждой команде встречается, то в среднем 80% от полной скорости.

monk ★★★★★
()
Ответ на: комментарий от EvAn

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

firkax ★★★★★
()
Ответ на: комментарий от watchcat382

Думаю что не обязательно вот прямо каждый-каждый массив пихать в отдельный сегмент в тех программах где массивов много. Можно же объявить сегмент, содержащий сразу несколько/много массивов. Для каких-нибудь буферов в самый раз будет - в крайнем случае будет попорчен только соседний буфер, но не получится испортить что-то еще(код, стек) или передать управление в записанные в массив данные, выполнив их как код.

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

В 64-битном режиме возможна рандомизация кучи и можно каждый важный буфер (а не только стек) так разместить, что до и после него будут сотни мегабайт несмонтированных страниц и любой выход за границы вызовет исключение (ты, конечно, можешь сказать «а вот если знать точный адрес, то можно же обратиться...», но так то и зная селектор сегмента можно обратиться к нему). Так уже делают, когда хочется защищённости.

А сегментацию из 64-битного режима таки выпилили, оставив только права доступа сегментов без возможности задавать нормально базу и размер. Полноценные сегменты остались только в режиме совместимости с 32-битным кодом.

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

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 4)
Ответ на: комментарий от VIT

Я обязательно посмотрю повнимательнее, но сходу вопрос - такты как считали?

По фигурным скобкам, которые группируют параллельные команды.

Да. Невнимательно почитал. Не учёл такты ожидания (отмечены nop).

Обычный 13 тактов
Защищённый 16 тактов

То есть, даже меньше отклонение.

monk ★★★★★
()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от shprotua

как это 286 не успели? А ПК «Поиск» это недостаточно серийно?

Где ты видел 286-е Поиски? Я даже на википедию залез, там это какие-то слухи про Поиск 2.286. Я помню несколько лет назад на сайте ретрокомпьютерщиков пытались отыскать советский 286-й процессор и даже фоток его не смогли найти, нашли только фотки микросхем чипсета.

П.С. Вождь пролетариата тебе примерно о том же написал.

praseodim ★★★★★
()
Ответ на: комментарий от praseodim

всегда думал что в Поиске 286, по причине того что он 16 разрядный. Поиск 2 врядли существовал в виде изделий. Моя ошибка.

shprotua
()
Ответ на: комментарий от shprotua

Поиск 2 как раз был и даже Поиск-3 был, но туда ставили аналог 8086-2. Тоже вообще-то причем нечасто встречающийся процессор, но он все-таки серийно выпускался.

praseodim ★★★★★
()
Ответ на: комментарий от drfaust

Погуглил сейчас, нет, не было никогда у ПО «Интеграл» своих 286-486-х. По крайней мере в 90-х, теоретически сейчас, наверное могли бы выпустить, если бы очень захотели, но смысла в этом уже никакого. В ЕС ставились импортные чипы, по некоторым слухам, возможно в своей корпусировке какие-то клоны (не от Intel и AMD), но это неточно.

praseodim ★★★★★
()
Ответ на: комментарий от firkax

С точки зрения исходного текста, z386 не является копией, ибо написан с нуля на SystemVerilog. И это даже не продукт реверс-инжениринга,так как в железе не реализован. Но вот эта реализация системы команд микрокода i386 может иметь последствия, так как получена не официально и благодаря реверс-инженирингу. Что в целом не мешает указать лицензию на исходники z386, ведь сами по себе это независимая разработка. Я так вижу…

EvAn
()
Ответ на: комментарий от EvAn

А по-моему там вовсе не «написан с нуля» а отреверсенную микросхему закодили на verilog. Микрокод был бы бесполезен, если бы там не скопировали и железо, его исполняющее.

Можно было бы отмазаться «сделали аналог по спецификациям», но спецификаций внутренней работы 386 не было, их тоже считай спиратили.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от VIT

Это был намёк на то, что инструкция за такт слишком большое допущение.

Это суть Эльбрусовского ассемблера. Там нет суперскалярности. Каждая инструкция отражает такт и в ней много команд, которые можно в этот такт начать и которые могут выполняться параллельно. Если к следующему такту ничего выполнить нельзя, то чтобы не писать пустые инструкции пишется nop и количество тактов задержки.

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

И, разумеется, call выполняется не один такт, а столько, сколько вызванная подпрограмма.

monk ★★★★★
()
Ответ на: комментарий от monk

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

Это я понимаю. Это говорит о том, что вы можете эти команды «issue» в тот же такт. Причём я не знаю правил выборки, поэтому вам верю на слово, хороший ассемблер должен сигнализировать, если есть конфликт. Но это не значит что

  1. Команды из одного bundle будут dispatch в один такт, и тем более в один и тот же цикл и

  2. Эта команды имеют одинаковую latency в один такт. Уверен, что любая арифметика - это минимум 3 цикла, вы банально нормализацию должны сделать и перенос учесть, то есть три цикла минимум.

Поэтому я и говорю, вполне возможно «issue» циклы вы действительно не сильно увеличили, а вот dispatch и latencies считать во-первых дело не простое, во-вторых таблицы надо иметь (допускаю, что у вас они есть), а в-третьих случаев разбора слишком много, ошибиться легко. Поэтому если у вас действительно есть доступ к таблицам, то по-любому должен быть cycle-accurate симулятор, проще на нём прогнать и посмотреть. Но тогда возникнут, как вы сами заметили, вопросы к кэш (ну хорошо, допустим данные в кэш, а с интрукциями что), я не знаю, как происходит обработка адресов, кто преобразует виртуальные адреса в физические и на каком этапе (если на уровне LLC, то это слишком поздно, спекулятивное вычисление при ошибке адреса может уйти очень далеко). Да и L1 cache touch тоже по-любому не 1 такт, вам надо адрес взять, преобразовать, сравнить, прочитать флаг, и выдать в регистр, пять тактов минимум, может больше.

Короче, вопрос не тривиальный, если делать по уму. Я вполне допускаю, что вы можете провести такое исследование. Я сомневаюсь, что защищёный режим даёт всего 20% накладных расходов. По-честному, у меня нет информации, чтобы предметно говорить за Эльбрус, но есть опыт работы с Power, SPARC, и x86, и он говорит мне что эта цифра нереальная.

Прошу прощения за английскую терминологию. Когда идёт речь о профессиональных вопросах, я русскоязычные термины просто не знаю.

VIT ★★
()
Ответ на: комментарий от VIT

Команды из одного bundle будут dispatch в один такт, и тем более в один и тот же цикл и

Значит. Компилятор заведомо складывает операции, для которых есть свободный блок выполнения в этот такт.

Из-за этого, кстати, вызов подпрограммы в Эльбрусе двухстадийный: сначала disp %ctpr1 подготавливает переход, а потом через 4 такта call. И возврат из подпрограммы также.

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

Да. В этот такт команда запущена. Следующую на этот исполнитель можно подать через заданное количество тактов. Но их компилятор явно отмечает через nop. Поэтому посчитать можно.

Преобразование виртуальных в физические через IOMMU.

Загрузка из памяти в регистр 1-2 такта (1 такт если сразу в арифметическую операцию).

В защищённом режиме медленнее только за счёт преобразования указателей (1 такт на преобразование). Ну и глобально скорость памяти фиксирована, а объём указателей больше.

monk ★★★★★
()
Ответ на: комментарий от monk

Мне нужно время, чтобы переварить всё сказанное, но одно замечание - я пишу на ассемблере не потому, что я хакер и не потому, что мне по-приколу, а потому, что компилятор не способен решить «простую» np-полную проблему распределения ресурсов. Вы, мне кажется, ожидаете от компилятора много больше, чем он способен сделать на самом деле. Возможно, у Эльбрус какой-то магический компилятор, но в это я тоже не верю.

Вообще, как вы уже заметили, я вообще в мало, что верю, когда речь идёт об оценках производительности. Даже прогон на симуляторе имеет много допусков и не является действительной проверкой. А уж в таких аналитических оценках сделать ошибку в 3-5 раз проще пареной репы, а мы рассуждаем о 20% эффекте.

VIT ★★
()
Ответ на: комментарий от monk

Загрузка из памяти в регистр 1-2 такта (1 такт если сразу в арифметическую операцию).

Не верю. Я вверху объяснил, почему. Знаю архитектуры, где 3. Знаю где 5 и это описал вверху, это Power. x86 может сделать за 5, но есть условия.

VIT ★★
()
Ответ на: комментарий от VIT

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

Там магический ассемблер. Компилятор может дать команду предподкачки блока памяти (включая кэш команд). Может дать команду подготовить возможные переходы (три регистра). Почти любую команду можно сделать условной (как в x86 CMOV) от одного из 32 логических регистров. И регистров общего назначения 256.

Вот детализация тактов: https://mcst.ru/doc/elbrus_prog/html/chapter12.html

А вот магия компилятора: http://elbrus.ivk.ru/pub/docs/elbrus_prog/html/chapter6.html

Даже прогон на симуляторе имеет много допусков и не является действительной проверкой.

Для суперскаляра да. Для VLIW всё детерминировано. Только неожиданный промах кэша может затормозить выполнение.

monk ★★★★★
()
Ответ на: комментарий от monk

от одного из 32 логических регистров. И регистров общего назначения 256.

он не потеет сохранять это всё при переключении задач, обработке прерываний?

madcore ★★★★★
()
Ответ на: комментарий от VIT

Не верю. Я вверху объяснил, почему. Знаю архитектуры, где 3.

Да. Чтение из L1 3 такта.

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

monk ★★★★★
()
Ответ на: комментарий от madcore

Я уверен, что он сохраняет только 16 или около того. Остальные если надо ручками.

VIT ★★
()
Ответ на: комментарий от monk

Там магический ассемблер. Компилятор может дать команду предподкачки блока памяти (включая кэш команд). Может дать команду подготовить возможные переходы (три регистра). Почти любую команду можно сделать условной (как в x86 CMOV) от одного из 32 логических регистров. И регистров общего назначения 256.

Корректнее сказать магическая система команд, правда пока я ничего магического не вижу. Блоковая операция load, подготовка таблицы переходов, маскирование операции. У SPARC было 1024 регистра, только одновременно контексту доступно 32. Пока ничего магического, всё по уму.

VIT ★★
()
Ответ на: комментарий от monk

Если переключение контекста имеет фиксированное время, то вызов использует только регистры, и там должно быть регистровое окно. Регистры не сохраняются, а переименовываются. Короче, это называется context window. Действительно, так надо сохранить на стеке всего три регистра: BL, SP, и A (branch and link, stack pointer, and accumulator). Это может делать один опкод или несколько руками, тогда последняя операция будет jl - jump and link - или что то подобное.

Сколько копий было поломано в прошлом на этом форуме доказывая, что это хороший способ или плохой способ смены контекста! Хорошо, что хоть кто-то вообще понимает, о чём здесь речь идёт. Это вам не PyTorch, тут знать нужно!

VIT ★★
()
Ответ на: комментарий от VIT

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

monk ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.