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

Комментарии 64

Посмотрите https://www.nand2tetris.org

Есть ещё очень занимательная игрушка Turing Complete, где аналогично шаг за шагом строишь на логических элементах компьютер с нуля. Очень классные головоломки. Есть над чем поскрипеть мозгами.

Эта игра во многом и вдохновила на написание этой статьи, определенно лучшая игра на эту тему. Также могу посоветовать MHRD, там также создание процессора, но с помощью упрощённой версии Verilog, помогает разобраться как спроектировать что-нибудь без визула, только текстом.

Удалось собрать все ачивки и пройти до конца?

Прошёл все кроме некоторых assembly challenges, немного наскучило писать программы на асме, увидел что в игре есть экспорт в Верилог и попробовал синтезировать в Quartus, но оказалось что игра не лучший софт для проектирования микросхем, поэтому решил перейти в более специализированные программы.

Ну, вообще-то, даже полевых транзисторов отнюдь не два типа, а ведь есть ещё и биполярные, на которых строились все машины средней и высокой производительности вплоть до конца 1980-х. Понятно, что описывать их все в подобной статье смысла нет, но хотя б упомянуть, что мир этим не исчерпывается, стоило бы.

Реализация АЛУ тоже... скажем так, типична для ПЛИС, но не шибко эффективна: много лишней логики получается. Можно сравнить, например, с устройством классического АЛУ SN74181, а заодно разобраться в ограничениях по скорости из-за переносов и как они могут быть смягчены в реальных схемах.

Отразил в статье что есть разные типы транзисторов, было слишком упрощенно, спасибо

Принцип сложения двоичных чисел идентичен сложению десятичных - сложить разряд и перенести, если есть переполнение. 

Можно сказать иначе: Сложение чисел реализуется через сложение цифр и знака переноса.

Как следствие, простейшее АЛУ - это одноразрядные сумматор,сдвигатель,инвертор .

Строго говоря все современные процессоры с кэш-памятью можно отнести к
гарвардской архитектуре, так как у них разделяется кэш команд и кэш
данных

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

Вы правы, спасибо, удалил этот абзац.

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

Вообще, очень много проблем возникает из-за неряшливого обращения с терминами, и "архитектура" здесь одна из наиболее пострадавших. Вон, кажись, вчера мелькала статейка про то ли интеловские, то ли АМДшные процы, где архитектуру использовали вместо микроархитектуры. Так и с гарвардской/фон-неймановской получилось: смотрят на некий простой формальный признак, а не на суть этих понятий.

А в чём отличие архитектуры от микроархитектуры?
Микроархитектура это конкретная реализация архитектуры? То есть, примеру, x86 это архитектура, а intel 286 это микроархитектура имплементирующая x86?

В первом приближении -- да. Впервые разделение на архитектуру (представление машины с точки зрения программиста) и реализацию ввела IBM в Системе 360, но микроархитектуру тогда ещё не придумали, т.е. не отделили её от физической реализации. Микроархитектура -- это, скорей, нечто промежуточное между архитектурой и физическим воплощением: логическое внутреннее устройство процессора, но без жёсткой привязки к "железу". Скажем, можно взять какой-нибудь интеловский проц (официально они называют современную архитектуру Intel 64 -- не брать же название AMD64 :) , а её 32-разрядного предка -- IA-32, хотя в "разговорной речи" обычно все говорят об x86) какой-нибудь определённой микроархитектуры, скажем, Sandy Bridge, но реализовать его по иным технологическим нормам (не 22 нм или сколько там было в нём, а, скажем, 7 нм). Понятно, что физически реализация уже будет другой, но если в "схемы" (реально -- в исходные тексты на Верилоге или ещё каком языке описания аппаратуры) никаких изменений не вносили, то микроархитектура останется прежней (а архитектура -- и подавно).

Спасибо за разъяснения. Кстати, не подскажите, в реальном проектировании микроархитектур используется Verilog или VHDL, или там уже что-то другое, а эти языки больше для FPGA?

Проектировать микроархитектуру можно на чём угодно, хоть на chisel. Verilog, VHDL, Chisel и т.д. - это всего лишь языки описания аппаратуры, разной степени абстракции. На практике, почти вся индустриальная разработка сидит на Verilog/SystemVerilog. В академии больше любят VHDL.

Ну, скажем, Cortex-M1 и Cortex-M3 написаны на Верилоге (исходники есть). Вряд ли другие ядра они писали на чём-то другом.

Архитектура - то, что доступно с уровня машинных команд. Микроархитектура - соответственно, с уровня микрокоманд (если он есть), или с уровня реализации выполнения машинных команд средствами комбинационной логики.

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

Спасибо за статью, включу в свою библиотеку. Мне, как программисту, в своё время сильно прояснила дело книжка Чарлза Гилмора "Введение в микропроцессорную технику" (Мир, 1984). На понятных структурных схемах по шагам показано, как всё движется в типичных случаях.

зачетно, интересно, пасиб. Жду продолжения в третьем номере FPGA журнала ;)

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

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

Исправил, спасибо.

Интересная тема. Жду продолжения.

Существует два основных вида транзисторов: биполярные и полевые. Основное отличие заключается в том что биполярные транзисторы управляются током, в то время как полевые управляются напряжением, создающим электрическое поле.

Существует два логических типа полевых транзисторов: n-тип, который пропускает ток при подаче тока на затвор

Нет ли во второй цитате описки относительно "подачи тока на затвор" вместо "подачи напряжения на затвор"?

Схема логического инвертора в двух состояниях

На картинке выше вроде как в правой части на выходе должна быть "1"

P.S.: Давно мечтаю освоить радиоэлектронику, чтение схем, но в каждую попытку освоения натыкаюсь на такие вот необъяснимые коллизии в описании и освоение откладывается до каких-нибудь иных времен.

Исправил, спасибо
А в схеме в правой части действительно 1, '0' там обозначает что резистор подтягивает выход к нулю, а цвет провода обозначает значение. Упустил момент с объяснением обозначения и предназначения резисторов и выходов с неопределенным значением.

Кстати, с биполярными транзисторами всё хитрее. Вроде бы, на уровне физики они тоже управляются напряжением, но для практических расчётов удобнее считать, что током, почему так и считают. Впрочем, в этом вопросе не поклянусь, сам разбирался, как оно работает, ещё школьником, а это было 100500 лет назад :)

Вентиль NOT (НЕ) это тот же NAND с объединенными входами.

Простыми словами принцип работы можно объяснить таким образом: стандартное состояние триггер принимает при получении на вход 1 и 1, в этом состоянии он возвращает свой сохраненный бит,

  1. Для RS-триггера две единицы на входах (S и R) является запрещенной комбинацией. Режим хранения это два нуля.

  2. Схема RS-триггера в статье не верная - сигнал сброса (R) должен находиться вверху напротив неинвертирующего выхода.

Про RS-триггер на русском.

rs-триггер это первый компонент с последовательной, а не комбинаторной логикой,

RS-триггер это всё еще комбинационная асинхронная схема, где Вы в ней увидели сигнал тактирования ? Чтобы его сделать синхронным (получить D-триггер) требуется на входе еще три элемента.

Регистр содержит два последовательных D-триггера и обозначется (ТТ в русскоязычной литературе). Делается это для того, чтобы избавиться от случайных изменений выхода в процессе записи (в течении одного такта), т.е. запись происходит по переднему фронту в первый триггер, а по спаду - даннное перекладывается из первого триггера во второй.

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

При разработке цифровых схем последовательностная логика всегда синхронная, RS-триггеры почти не используются, поэтому когда говорят "последовательностная логика" всегда где-то рядом есть сигнал тактирования.

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

Ссылка

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

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

В ПЛИС использовать можно и то, и другое, но, во-первых, флип-флопы у тебя "бесплатны" (нет смысла экономить: они всё равно реализованы), а во-вторых, ПО не умеет правильно считать задержки и прочая при использовании защёлок, поэтому обеспечение правильной синхронизации становится задачей разработчика (с флип-флопами считать намного проще из-за того, что они меняют своё состояние лишь в момент фронта/спада тактового импульса).

Вопрос скорее в терминологии. По той же ссылки написано:

Секвенциальная логика — это логика памяти цифровых устройств. Название «секвенциальная» восходит к англ. sequential. Соответствующая логика может именоваться также как последовательностная, хотя последний термин по преимуществу употребляется в связи с логическими автоматами.

То есть "последовательностная" логика употребляется при работе с автоматами и предполагает синхронизацию. В случае RS-триггера правильный термин это "секвенциальная".

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

Активный режим триггера для схемы на И-НЕ является 0, так что при подаче 0 0 будет неопределенное состояние, также порядок входов приведенном вами изображении для триггера на ИЛИ-НЕ, вот картинка из статьи по ссылке для И-НЕ. Постараюсь более явно выразить в статье на основе какого вентиля построен триггер и в чем их отличие.

Для элементов И-НЕ всё верно. Извините, глаз замылился к трем часам ночи. :)

Но Вы не упомянули про запрещенное состояние.

Приведенная схема полного сумматора является самой неэффективной - увеличение разрядности сумматора в двое влечет удвоение времени задержки, что уменьшает тактовую частоту процессора в двое. Существуют более сложные схемы с распространением переноса наперед (carry-lookahead adder, carry-skip adde и т.д.)

Ну, на ПЛИС примерно такое обычно и синтезируется: несколько отдельных блоков для сложения, И, ИЛИ и т.п., а на выходе -- мультиплексор для выбора результата. Реализовать ручками ускоренный перенос можно, но он будет, скорей всего, работать медленнее последовательного, т.к. для последовательного переноса у ПЛИСины имеется специально для этого выделенная связь и всё такое прочее, максимально оптимизированные по скорости, а ускоренный придётся делать обычной логикой и разводить обычной медленной коммутацией через 100500 невидимых мультиплексоров. Вот в заказной микросхеме или на рассыпухе -- другое дело.

Если говорить про ПЛИСы, то все зависит от разрядности сумматора и обычно такие схемы синтезируются в готовые блоки АЛУ. Я же пишу про теоретический аспект. :)

А что если в качестве сигнала Conditional использовать флаг Carry от АЛУ и выкинуть блок сравнения вместе с его инструкцией ?

Да, так и правда значительно эффективнее с точки зрения транзисторного бюджета, и эстетичнее с точки зрения технического дизайна, но я хотел выделить этот тип операций в отдельный блок, для лучшего восприятия что именно происходит в момент сравнения. Если использовать флаг переполнения, можно было бы задействовать последний слот в двух-битовом значении как операцию с загрузкой константы в определенный регистр, что определенно упростило бы программирование. Хотелось иметь инструкцию типа "JMP (адрес)", чтобы было проще её понять, ведь она фундамент любого ветвления.

С моей точки зрения гораздо интереснее является дизайн вычислителя в котором все операции выполнятся через АЛУ, в том числе пересылка регистр-регистр. Посмотрите на TD4 CPU, если вдруг не сталкивались еще.

Это, кстати, не всегда эффективно. Скажем, одной из причин, хотя и далеко не основной, очень значительного (в 4-6 раз) повышения производительности процессора ЕС-1022 по сравнению с ЕС-1020 является то, что в нём есть два параллельно работающих пути данных: через АЛУ и прямая передача мимо АЛУ, что позволяет в одной микрокоманде совмещать часто используемые пересылки с вычислениями, а не разносить их по разным тактам. Хотя, понятно, по количеству логики такое устройство затратнее.

Разумеется. А еще АЛУ может быть несколько штук, они могут быть разных видов, и т.д. Но мы же говоим про обучающий минималистичный вариант вычислителя.

Кстати не нашел у автора про реализацию сдвигателя. Как же без SLL и SRL ? :)

Ну, сдвиг влево можно реализовать сложением числа с самим собой :) Например, именно так поступают в секционных АЛУ К589ИК02, в девичестве i3002. Но вот сдвиг вправо таки нужен в явном виде.

Аж олдскулы свело бывшего студента вычислетеля, спасибо за статью. Годное объяснение

А что умеет чайник с таким процессором ?

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

Понятный текст, отличные иллюстрации - покажу детям, спасибо

Существует два логических типа полевых транзисторов: n-тип, который пропускает ток при подаче напряжения на затвор, и p-тип, который, наоборот, перестаёт пропускать ток при подаче напряжения на затвор.

Нет! P-тип - не реле с нормально-замкнутыми контактами. Он тоже пропускает ток про подаче напряжения на затвор, но не просто «напряжения», а относительно истока, и это напряжение отрицательное. Чтобы его использовать в положительной логике, его исток цепляют к плюсу, и управляют им подтягиванием затвора к нулю.

NAND и XOR [...] — это универсальные вентили, из каждого из которых можно получить все остальные, соответственно, всего лишь из NAND-вентилей можно построить логическую схему любой сложности

XOR является функцией, сохраняющей 0, и заодно линейной функцией. То есть система из одной этой функции критерию Поста не удовлетворяет. А вот система из одной функции NAND — удовлетворяет.

Возможно построить NAND из 4 XOR вентилей, так что должно быть возможно построить из XOR всё что возможно построить из NAND.

Можно построить один XOR из четырёх NAND, а вот наоборот...

Да, вы правы, думал о NOR, а не XOR, поправил этот момент в статье, из NOR и NAND можно получить друг друга инверсией входов или выходов.

Функция XOR позволяет реализовать любую схему при добавлении к ней константы 1. Тогда получается полный базис.

Подробнее - см. Полином Жегалкина

Цитирую Вику:

Этому требованию отвечает, в частности, система функций ⟨∧,⊕,1⟩  (конъюнкция, сложение по модулю два, константа 1). На её основе и строятся полиномы Жегалкина.

Как видим, эти полиномы содержат функции AND и XOR, а не одну только XOR. Речь же о возможности создания любой логики на одном типе логических элементов.

Делать на фпга проц - зачем? Если можно сразу всю логику изделия зашить.

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

А ещё можно сделать ради собственного удовольствия :) Ну или как прототип будущей заказной микросхемы. Или как железный эмулятор древнего компа -- но с последним не всегда получится в лоб. Скажем, проц от СМ-1420 для симуляции в какой-нить там Квесте перевести на Верилог можно, а вот для синтеза в ПЛИС без существенных переделок -- фигвам: там и двунаправленные шины с открытым коллектором или с тремя состояниями, и куча одновибраторов, длительность импульсов которых задаётся RC-цепочками... И несколько ошибок, и реальный проц работает только потому, что в схемотехнике ТТЛ они оказались некритичными :)

Есть книжка Харрис и Харрис, там это все тоже очень хорошо и доступно излагается. Очень рекомендую!

Спасибо, плюсую! На базовом уровне даже дополнить нечего.

Здесь уже делали замечание по этому утверждению:

Существует два логических типа полевых транзисторов: n-тип, который пропускает ток при подаче напряжения на затвор, и p-тип, который, наоборот, перестаёт пропускать ток при подаче напряжения на затвор.

Немного уточню.

Вообще-то есть, как минимум, ЧЕТЫРЕ типа полевых транзисторов (на самом деле больше). Главная ошибка в том, что и P и N -канальные транзисторы при подаче напряжения на затвор начинают пропускать ток! Рзница только в полярности подаваемого на затвор относительно истока напряжения.

А вот полевые транзисторы со встроенным каналом (depletion mode MOSFET) - проводят ток при нулевом напряжении на затворе. Причём как P, так N. Вот такие транзисторы:

перестаёт пропускать ток при подаче напряжения на затвор

Но они весьма специфичны и не используются в цифровых системах.

Поэтому правильнее будет написать примерно так:

N-тип, который начинает пропускать ток при подаче положительного напряжения относительно истока и P-тип, который пропускает ток при подаче отрицательного напряжения относительно истока.

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

Добавил Вашу версию текста в скобках как более корректную.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории