Как стать автором
Обновить
2
0

Пользователь

Отправить сообщение
Ну вот легко же вы лауреатов премии Тьюринга в глупых ошибках обвиняете :)

Вопрос со слотами задержки на самом деле интереснее: даже в высокопроизводительных ядрах это местами полезно.
Например, это дает возможность сделать более качественный branch target buffer с меньшим количеством логики, потому что есть дополнительный цикл перед переходом.
Также оно уменьшает количество пустых циклов после неправильного предсказания. Но в целом, реализацию современного фетчера инструкции оно, скорее, усложняет (исключения в слоте задержки, переход в другую страницу или вообще IO регион памяти и всякое такое) Да и заполнить эти слоты компилятор может далеко не всегда.
В MIPS r6 их никуда не убрали, там только новые инструкции добавили без слота задержкки. Но старые инструкции все еще поддерживаются, поэтому логика фетчера инструкций только усложнилась. А поддержка r6 есть далеко не везде (фиг знает, добавили ее в мейнстримный бинутилс, хотя бы?)

Но тем не менее: история этот вопрос рассудила в пользу отсутствия слотов задержки, и это, кмк, жирный плюс. Впрочем, nobody cares.

Странно отсутствие явной глупости записывать в преимущества.

Эта явная глупость есть в SPARC, MIPS и PA-RISC, например. Это почти каждый второй риск.

И обработчик page fault, да?

(картинка с добрым котом)

И обработчик page fault, да :)

В архитектуре Alpha нет ничего хорошего.

Есть:

  • изначально 64 битная архитектура. Никаких слоев совместимости*, никаких битов состояния

  • отсутствие delay slots

  • все платфотмо-зависимое вынесено в пал-код. Совсем все. В отличие от RISC-V, который тащит за собой Cp0 из Мипса.

*За слой совместимости можно условно принять совместимый с VAX формат чисел с плавающей запятой. А можно и не принять, если OpenVMS нас не беспокоит, благо IEEE-версия тоже в наличии.

А сборщик мусора как часто вызывается? И каким образом? Сам по себе после интерпретации, принудительно или по прерыванию какому?

А как это работает?
Ну, всякое ECC с коррекцией можно поставить на статическую память. Можно самотестирование сделать. Два ядра дают какое-то (ограниченное) redundancy. Но что делать с SEU в триггере где-нибудь посреди процессорного пайплайна? От этого только библиотека с ячейками потолще и семь-бед-один-ресет?

Аналоговое — тысячу раз да. Вот тут было одно или два видео с аналоговым дизайном на >70ГГц:
https://www.youtube.com/user/TheSignalPathBlog

Причем, автор оговорился о том, что рассаказать может не всё.

Ну а с процессорами — да, интересно, конечно, что там у конкурентов. Но если у вас на руках готовый чип — вы уже опоздали минимум на три года.
Да и такое часто в Microprocessor Report открытым текстом пишут, за существенно меньшие деньги. А еще бывает, что у конкурентов все примитивнее и даже тупо хуже, но с лучшей техподдержкой, например :)

Спасибо за отличную статью!


Восстановление перемычек, чтение памяти и меткие правки оной — дело, безусловно, понятное и полезное. Но вот реверс чисто цифровых схем и, в частности процессоров, как мне кажется, уже не работает и работать не может в силу безумной сложности дизайна. Восстановление схемы не приблизит к пониманию того, как оно работает и уж точно не даст возможности что-то там нетривиально исправить. Пример выше с Байкалом — а это не самый производительный процессор на сегодня — но уже с ним невозможно ничего сделать. Там даже при наличии документации и полного доступа к исходникам сложно понять, как, почему и зачем он работает. Потому что это процессор с внеочередным исполнением, с точными (ну, почти:) исключениями, внятным предсказанием ветвлений, не самым глупым модулем выборки-хранения и ещё кучей свистелок и перделок, которые никому, кроме разработчиков, не интересны. Точное знание о предсказателе ветвлений реверсерам принесёт только вред — там немало сил потрачено на правильную работу с неспекулятивными и некешированными режимами, и оно специфично для мипс (delay slots!) Сами же алгоритмы многократно описаны в книгах и статьях, и это вопрос разумного применения уже известного, а не сверхсекретных нанотехнологий и инноваций.


Ну и вот, к чему это я: ценность реверса, кмк, сильно преувеличена, а нетривиальные закладки и вовсе близки к ненаучной фантастике.

О! Радует, что необычная архитектура получила развитие! Спасибо за статью, ждем результаты с кремния!

В новой ревизии немало архитектурных изменений.
Вот, в частности, возможность адресовать аргументы в памяти для любых команд — а как в этом случае выполняются зависимости по памяти?
Например, чтение после записи в пределах одного параграфа. А если в разных параграфах? Есть ли какая-то модель памяти, которой придерживается процессор? Является ли завершение параграфа барьером по записи?

Еще вот интересно: в первых версиях, насколько я понял, распределение инструкций по клеткам было реализовано «по модулю»: каждая n-ая команда попадает в n-ую клетку. Добавили ли хитрый планировщик, который мог бы учитывать фактическую готовность клетки?
Вопрос про formal — не в бровь, а в глаз.
Я тут недавно с удивлением обнаружил, что в RISC-V оно *уже* есть, причем, на открытых инструментах и с довольно общими проверками (ну, например, проверяется не порядок retirement/graduation, а ненарушение зависимостей через регистровый файл) Да, там много ограничений и да, это врядли прокатит для больших и страшных процессоров, но для любителей это огромный шаг вперед и манна небесная. Ну и вообще, будущее.

Вот тут презентация: http://riscv.org/wp-content/uploads/2018/12/13.30-Humbenberger-Wolf-Formal-Verification-of-RISC-V-processor-implementations.pdf

А вот тут — впечатления от использования: https://tomverbeure.github.io/risc-v/2018/11/19/A-Bug-Free-RISC-V-Core-without-Simulation.html
Ну, так конечно будет работать, но тогда теряется интерес. Рукописного ввода прямо карандашом на листочке не будет, да и сама сеть не нужна: 15 бит можно полностью покрыть table lookup-ом :)

А в LeNet'е ценность в том, что он хоть и маленький, но полностью настоящий. Учебно-боевой. Но там, если мне память не изменяет, 400k коэффициентов.
Ну правильно, комменты о фамилии, внешнем виде и БолгенОС.

Меж тем, предложенный проект весьма непрост, хотя, казалось бы, циферки — это даже не котят распознавать.

Если брать, например, Ленет, то несжатые коеффициенты не влезут в набортную память недорогих ПЛИС. О более крупных сетях я даже не говорю.
А значит, нужно как-то планировать вычисления: загрузить часть коэффициентов, применить, загрузить следующую.
Вот какую именно и в каком именно порядке — нетривиальное решение для сверточных сетей, особенно когда надо целиком уместиться в 128 кбайт и при этом не быть безнадежно тормознутым. Ну, вот, в частности, если хочется выгружать хотя бы по 16 коэффициентов из однопортовой памяти за раз, нужно чтобы они были расположены рядом. Если брать стандартный row-major alignment из всяких кафе и тензорфлоу, то хорошо будут работать первые слои, а если col-major из Julia с матлабом, то последние. И видимо, нужно или городить многопортовую память, или хитро готовить данные в зависимости от слоя. Кажется, именно последнее делает nvidiа и movidius, но как именно, они, конечно, не спешат рассказывать. Еще туда же: некоторые университетские реализации эту проблему вообще не решают и говорят, что у нас будут только сверточные слои.
Другая проблема — переполнение/нормализация. В выгодном на ПЛИС целочисленном режиме за этим нужно внимательно следить. Настолько внимательно, что, кажется, проще использовать аппаратное FP. В принципе, если выкинуть denormals, то оно не такое страшное и вполне компактное для фп16. Другой (куда более модный) подход — угореть по одно- двух- или четырехбитным коеффициентам. Это реально работает (тм), куча статей с историями успеха, но этот путь явно сложнее.

Так что да, проект крутой, несмотря на весь хайп и определенно менее затасканный, чем свой процессор.
В качестве идеи, можно использовать сенсор от оптической мышки и радостно демонстрировать realtime распознавание. Даром, что для этого не нужна такая уж прямо скорость :)
Вот лучше «на ты», в самом-то деле. Интернет же!

По clock gating'у:
В ПЛИС есть несколько выделенных линий тактовых сигналов (6, чтоли, в недорогих циклонах?) и управлять можно только всей линией целиком.
Возможно, в новых дорогих ПЛИСах с этим проще, но в любом случае на синтезатор полагаться не стоит — нужно напрямую указывать библиотечный компонент.
Ну, или делать enable во всех интересующих последовательностных блоках (а еще, можно вообще забить: ну не потребует собственный процессор принудительного охлаждения:)

В ASIC такой gating не работает потому что enable всегда задержан относительно тактового сигнала в зависимости от температуры и напряжения. Поэтому чтобы не было просечек, что-либо переключать лучше тогда, когда clk == 0. Сделать это можно, например, комбинацией гейта и защелки.

А в симуляторе причина та же, по которой не стоит использовать неблокирующие присваивания в комбинаторной логике.
Неблокируемость означает, что конкретно в этом цикле симуляции обновлять зависимые блоки не нужно, а новое значение еще не действует.
Ну то есть, последовательностная логика, работающая от тактового сигнала увидит изменения на следующем этого тактового сигнала. С комбинационной сложнее, и тут возможны варианты, в зависимости от того, что написано в других блоках. Если их нет, то все даже будет работать. А вот если есть, могут появиться спецэффекты: в waveform'ах вы увидите правильное поведение логики, но триггеры будут защелкивать неконсистентное состояние. С синтезом — как повезет. Скорее всего, проканает :) С gating'ом тактового сигнала та же история. Если все работает от gated clock — ну так и будет работать. А вот если в тестбенч clock обычный, а в дизайне — gated, то будут точно такие же спецэффекты, что и выше.
О! Написание процессоров — дело почетное и адски полезное!

Рискну дать непрошенный совет автору:

— clock gating в стиле «assign g_clk = cond & clk»
— неблокирующие присваивания в комбинаторной логике

Обе конструкции нормально не работают нигде: ни в симуляции, ни в FPGA, ни в ASIC.
Зато они создают опасную иллюзию корректно работающей схемы и дарят часы отладки дельта-циклов. В качестве конструктива, в плане clock gating'a в ПЛИС проще (а для незамороченных проектов — лучше) использовать вход «En» в самом триггере. В таком духе: «if(condition) q <= d»
Вот жеж. И это — в восьмидесятых! А публиковалось же наверняка что-то на эту тему? Я на этот предмет только книгу Игоря Маркова знаю, да курс VLSI на курсере.
В смысле DC?

В смысле — да, Design Compiler конечно.

Это не так, в 1980-х Synopsys продавал Design Compiler именно как способ оптимизации. Причем в компаниях типа Texas Instruments были люди, которые говорили, что их кучу assign-ов лучше не сделать, а синопсоиды показывали что таки можно сделать.

Ну то есть — оптимизировалось конкретное комбинаторное выражение в каждом отедельно взятом assign'e? И светочи из TI при этом все равно были биты?

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

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

Жестоко. Как раз из серии «синтезатор не нужен».
А это было в каком синтезаторе, если не секрет? Особенно вот год интересен. Помнится, свежий Vivado оставлял приятное впечатление (может, обманчивое?) — там и path groups были с весами, и location задавать можно более гибко. Не помогло?
Самый банальный пример — дешифратор:

logic [63:0] onehot_out;

always_comb begin : p_blah
   onehot_out = '0;
   onehot_out[idx] = 1'b1;
end : p_blah


Нормальный синтезатор (VCS, например) на такое хорошо реагирует.
Другой пример получше: комбинационная логика декодера инструкций, когда перечислять все сто выходов на каждую вариацию — один из способов самоубийства.

if-else if-else — семантически это сразу priority encoder. Понятно, что это медленнее, но тут получается ровно то, что было заказано. Независимые условия типа 'if(foo) blah; if(bar) blahblah; отличаются от assign только упоротым режимом xprop.
С case'ом все неочевидно, зачастую из-за самого верилога (привет, casez/casex), но и там можно пинками обьяснить синтезатору, что требуется получить в итоге (parallel case, case(1'b1) и всякое такое)
Совсем плохо это работает только для сложной логики с вызовом функций и мутным имеративным кодом (опять же, VCS)
Не, я понимаю, что если написать все в лоб на одних assign'aх, а регистры инстанциировать, то вариантов плохого синтеза не будет вообще.
В основном потому, что сам синтезатор в этом случае нафиг не уперся :)

Вообще, мне кажется, аргумент сводится к программированию на ассемблере против C++ конца 90х. Ну да, перф иногда бывает хуже, но понятно когда и известно, как исправить.

Минусовал не я, но я не согласен с тем, что @* это всегда плохо. Оно очень полезно, когда нужно, например, присвоить значение по-умолчанию на всю структуру/вектор целиком, а потом поменять какие-то поля по условиям. Ну и да, always_comb устраняет большинство старых претензий и потенциальных косяков.

1

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность