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

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

Если не касаться деталей, то наблюдать события в параллельной вселенной всегда интересно. Даже есть шансы появления новой Интел, основанной на других стартовых условиях в виде более совершенной аппаратной базы.

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

И всё зависит от цели построения. Если проектируется традиционная малоядерная система — подход традиционен, и выигрыш может быть получен от количества заложенных идей (чем сложнее, тем лучше). А если многоядерная, то, на мой взгляд, выиграет максимально простая, но быстрая архитектура.
Максимально простая, но быстрая — это MIPS. И что-то она не выигрывает(
Транспьютер — проще, но тоже неТОП! ))) и (i8080)
Самый большой антагонизм, который встретился при работе с ПЛИС, возник при попытке поместить всю работу в один такт. Вначале (от незнания и отстутствия опыта) это даже как-то удалось, но в результате работало очень нестабильно. Т.е. была попытка после выборки команды сразу произвести её разбор, выбрать аргументы из регистрового файла, выполнить инструкцию и поместить результат назад. Вопреки всему такой подход даже как-то работал, но при любом чихе всё рассыпалось. Даже понижение тактовой частоты не очень помогало. Прилось на время отказаться от одного такта и разложить операции на более простые. Как результат — теперь непонятно от чего разработчики конкурирующих устройств снижают тактовую частоту — если разложить на стадии, то можно не задумываться о переходных процессах и работать на максимальной частоте, заявленной производителем ПЛИС.

Т.е. проект в текущем его состоянии весьма прост. А помещвть всё в один такт придётся с помощью конвейера, которого сейчас нет в устройстве. Конвейер не поддерживается не только из за сложности или лени, а потому что ограниченный объем логических элементов хочется использовать для других целей. Но со временем, если архитектура заинтересует разработчиков, можно будет подумать и о конвейере.
интересна идея AMDешников в разделении ALU команд и управленческих: GPU исполняет команды ветвления, встречая опкод вызова цепочки ALUушных команд дружно их исполняет до опкода возврата, после которого продолжает исполнение обычного потока ветвлений. Это позволяет увеличить количесво опкодов, и появляется смысл в конвеере.

Во вторых, джампы intel x86 — самое тупое инженерное решение, в те времена не помышляли о параллельном исполнении команд, по этому сильно упростили автомат, который сохраняет изменения только в IP, плюс 8 битное наследие — логические джампы в +127… -128 байт (байт не инструкций — еще один маразм).
Логические условия не всегда приводят к ветвлениям: A &= (0 < B); F = (0 < B)? sin: cos; return F(A? 0: x);
Симулировать сие джампами? Нет, условия должны возвращать в регистре размноженный бит от требуемой комбинации на флагах, и могут выполнятся на ALU, а джамп может выполнить ретурн.
Можно Вас спросить, а есть ли антагонизм? На сколько помню, Дэйкстра говорил об разноуровневых абстрактных машинах. Если нижележащий уровень оптимизирован для НЕвыполнения большого спектра программ на более высоком уровне абстрактных машин (как в х86), то это не проблема антагонизма, а отсталость инженерного/технологического уровня.

Я совершенно с вами согласен, в том, что «А если многоядерная, то, на мой взгляд, выиграет максимально простая, но быстрая архитектура.», только уточню: с минимальным(минимальнейшим) тепловыделением. Уже давно плотность кода не является первоочередным показателем, в то же время изоляция приложений друг от друга все актуальнее и актуальнее.
Абсолютных адресов нет вообще, или только для переходов? А как работать с динамическими структурами данных, например, со списком?
Только для переходов.
Может я не понял чего, поясните:
LOCK; Захват буфера сообщения
SET_MR MR0, R2; установка идентификатора сообщения
SET_MR MR1, R3; установка аргумента сообщения
SEND; передача сообщения
RECV; ожидание ответа на сообщение
GET_MR R0, MR0; чтение кода возврата
FREE; освобождение буфера сообщения

1. Поменяли адрес функции на «идентификатор сообщения»? Хрен стал слаще редьки?
2. Буфер один (или нет?), системным функциям не полагается друг друга вызывать? А прикладным?
и еще
3. Как общаться с внешним миром без абсолютных адресов?
1. Пример не показывает с кем ведётся обмен сообщениями. В регистре R0 идентификатор процесса получателя сообщения, в регистре R1 таймаут. Может так получиться, что помимо задачи, которая реализует функцию puts, сущесттвует задача с более высоким приоритетом, которая бы запустилась по истечении кванта времени текущей задачи. В этом случае обмен сообщенем задержится пока более приоритетная задача не заблокируется или не выработает свой квант времени. Другой случай — приёмник сообщения чем-то занят и не готов принять сообщение. Как результат, время простоя будет отдано планировщиком другим задачам. Т.е. с помощью инструкций SEND и RECV вводится точка переключения контекста. У меня как раз возник спор по этому поводу на одном из форумов — предполагается что переключение контекста по таймеру, когда задача исчерпала свой квант времени, это более редкая операция чем переключение контекста в момент обмена сообщениями. Иными словами — большую часть времени все задачи будут блокированы при исполнении инструкции RECV, ожидая внешних событий. Это нормальное состояние устройства. Напротив, блокирование задачи при исполнении инструкции SEND говорит о том, что приёмник в данный момент времени чем-то занят и не готов принять новое сообщение. Таких блокировок надо по возможности избегать и минимизировать их возникновение.

Иначе говоря, любая система строится как множество взаимодействующих субъектов (задач, слушающих сообщения, обрабатывающих сообщения каким-то образом и затем отвечающих на эти сообщения).

2. Буфер не один, иначе он полностью теряет смысл. В идеальном случае количество буферов равно количеству задач. Но для большинства применений оптимальное количество буферов может быть половиной от количества задач. Почему была выбрана именно такая схема работы с буфером сообщений? Дело в том, что при таком подходе можно спрятать от программиста детали аппаратной реализации. С помощью буфера сообщений можно передавать данные между задачами, исполняющимися на одном ядре, можно передавать сообщения между разными процессорными ядрами в одном корпусе. Если постараться, то можно реализовать нечто вроде DMA, передавая содержимое буфера между процессорами на общей шине. В общем случае программист может даже не знать где находится адресат сообщения — соседняя thread на этом же ядре, другое вычислительное ядро (core), соседний процессор на многопроцессорной плате или удалённый узел кластера, общающийся с задачей через proxy-функцию. Т.е. вот такой интерфейс, а детали его реализации скрыты.
Отличия между системными и прикладными задачами на уровне железа не вводятся.

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

3. Наверное мне неоюходимо исправить статью, чтобы исключить эту двойственность толкования — абсолютные адреса не используются в командах условных и безусловных переходов и вызовах функций. Обращение к памяти по абсолютному адресу, разумеется, необходимо и оно осуществляется с помиощью регистров общего назначения (значение регистра это абсолютный адрес).

Контекст (регистры, PC, буфер сообщений, флаги) нельзя выгрузить?
Сейчас нельзя. В текущей версии ограничение на 31 задачу. Для микроконтроллера вполне достаточно. В будущем, если ничего не помешает, то будет реализована выгрузка задач в ОЗУ.

Интересная работа, но честно говоря меня больше интересует Ваш план по продвижению своего микропроцессора на рынок. У Вас ведь есть какой-то план? Без такого плана такая работа теряет смысл.
Как Вы планируете завоевывать рынок?
Выпустить свой чип довольно дорогое дело, но наверное еще дороже убедить разработчиков в преимуществах своей системы.
Каков Ваш план «монетизации проекта» — вот первый вопрос, который спросит у Вас каждый инвестор.
Мне интересен Ваш ответ, так как я и сам уже долгое время разрабатываю свой «процессор», а плана монетизации у меня как такового и нет.
Уже два раза представлял проект перед инвесторами на выездных сессиях «Сколково» и оба раза получил отказ. Но не думаю что это плохо — кроме инвесторов на презентации присутствовали и технические специалисты, они подходили после презентации и интересовались проектом.

Монетизация по типу fabless компаний — продажа IP блоков и, возможно, лицензий. А вот как прийти к монетизации это сложный вопрос. Доработка и развитие устройства, убеждение разработчиков в преимуществах архитектуры, формирование сильной команды и формиравние комьюнити — вот это всё, помноженное на время, и есть путь к монетизации. Кстати, сейчас хороший момент для публикации в прессе — многие издания готовы опубликовать технические материалы — хороший вариант убеждения разработчиков.

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

Кстати, с интересом наблюдаю за Вашими проектами — Марсоход2 удивительное устройство, о котором раньше можно было только мечтать.
Уже два раза представлял проект перед инвесторами на выездных сессиях «Сколково» и оба раза получил отказ. Но не думаю что это плохо — кроме инвесторов на презентации присутствовали и технические специалисты, они подходили после презентации и интересовались проектом.

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

Мне кажется, будут полезны инструкции для загрузки Big- и Little-ending. Для упрощения обмена данными со сторонними системами.
Прежде всего спасибо за заботу о системных программистах, но пожалуйста, сделайте что нибудь другое)Потому что планировщика в операционной системе может и не быть в принципе, это, и тактика навязывания рамок как аппаратный обмен сообщениями успеха в будущем точно не принесет.
Немного размышлений:

1.Например потому что уже существует в архитектуре spark, правда там происходит не обмен сообщениями между задачами, а обмен окнами между юнитами (Integer Unit), которые также можно крутить между задачами инструкциями save\restore, подробностей не знаю, но идея обменивать данные регистров при переключении похожа на вашу.Тоесть уже существует, но там уже «планировщику» нужно прокрутить регистровое окно, чтобы оно из одного треда перекочевало в другое.
2.Интересное получается кино… одна задача исполнила инструкцию передачи сообщения, по вашем следует то что она либо остановится на таймаут, либо сделает исключительное программное переключение через планировщик, а иначе как понять какая из 10 заблокированных ожидающих задач приоритетнее? допустим планировщик тут же передаст управление смежной из этой сладкой парочки задаче, та дойдет до инструкции приема через полчаса работы, и допустим у операции не кончилось время.Простейшая передача блока данных сообщений превратилось в ожидание задачи в полчаса времени! или вообще накрылась медным тазом т.к. таймат истек и обе задачи в недоумении, куда это годится, да, вы можете не останавливать первую задачу а продолжить ее исполнение, но увы, у вас нет механизма транзакционной памяти, как например у интел, процессор которой в случае блокировки по ресурсу (у них память а не буфер, что не меняет сути) смотрит на инструкцию которая для него промаркирована, у вас это получается отдельная инструкция и запоминает адрес для возврата.
3.Может стоить придумать обмен не «сообщениями» а данными произвольного размера через общую память и задачи не блокировать?
4.Хорошо придумано то что передаваемые данные скрыты от других задач и появятся точно у адресата.
5.Инструкция Idle, вход в планировщик, а если у меня 18 диспетчеров и в любой нужно зайти при каких то обстоятельствах c прикладного кольца, чтобы не делать лишние прыжки? тогда для idle нужен аргумент, в таком случае чем она отличается от syscall\sysexit?
6.Мое личное мнение что нужно больше уделять вниманию не инструкциям а архитектуре, ведь полно чего еще не придумали в моделях памяти, распределении данных и задач.

2) Да, L4 — «НЕсистема» реального времени, это одна из причин, по которой ее не используют, но есть надежда, что увеличение количества ядер и тактовой частоты позволит реагировать на события более-менее приемлемо.
3) тут покруче проблема, весь контекст должен сохраниться/востановиться, а это: 16 регистров, 64 в буфере, флаги и адресс следующей инструкции за RECV… по этому никто их сохранять не будет, и количесво сервисов — ограничено!
5) сервис в L4 обслуживающий ID — один, пришел процесс — сервис «просыпается», если он хочет «разбудить» 18 сервисов, то последовательно их будит.
Без планировщика рухнет вся идея передачи сообщений. Увы, выкинуть его не получится. Подразумевается древовидная структура приоритетов планирования. В корне дерева сам планировщик, который распределяет время между узлами, исходящими из корня. Если задача в узле блокирована, то её время отдаётся подзадачам. Т.е. задачи, находящиеся в подветвях получают управление только в том случае, если их узловая задача блокирована. Чем дальше задача от корня дерева, тем ниже её приоритет.

Что касается архитектуры Sparc, то, похоже, она гораздо привлекательнее для реализации микроядра L4, чем архитектура x86. Проблема в том, что сейчас архитектура Sparc превратилась в экзотическую и вести разработку под неё не имеет смысла.

Вы очень точно описали проблему блокировок при использовании синхронных сообщений. Но в этой слабости и сила решения. Если обработчику сообщения понадобится полчаса на то, чтобы дойти до инструкции ожидания сообщения, то этот обработчик неправильно спроектирован. Любой обработчик обязан максимально быстро обработать входящее сообщение и снова войти в состояние ожидания. Нормальное состояние системы когда все обработчики забокированы в ожидании входящих сообщений. Любое входящее сообщение провоцирует «цепную реакцию» обмена сообщениями, которая в конечном счёте приводит к последующей блокировке в ожидании следующего события. Во время ожидания процессор находится в режиме низкого энергопотребеления. А чтобы прогаммистам не было грустно и тоскливо пользоваться этим, то им будет предложено API, решающее проблемы блокировок.

Обмен данными произвольного размера это важная часть спецификации L4, которое предлагает две вещи — «строки» (блоки памяти) и операции маппинга. В случае «строк» происходит их физическое копирование между задачами и их оптимально использовать для передачи небольших порций данных между адресными пространствами. Для передачи больших объемов памяти спецификация предлагает мапинг универсальных страниц виртуальной памяти — регион памяти, который описывается с помощью нескольких универсальных виртуальных страниц, можно передать в сообщении с помощью операции «маппинга» или «гранта» (прошу прощения за транслитерацию — пока не могу подобрать эквивалентных русскоязычных терминов) в обеих случаяъ область памяти, описываемая универсальными страницами виртуальной памяти, отображается в адресное пространство процесса получателя сообщения, но в случае гранта эти страницы убираются из адресного пространства источника сообщения. Это интересная возможность, но её удастся реализовать не раньше чем заработает передача «простых» сообщений. В нынешнем виде устройство не оперирует понятием адресных пространств и не имеет вирутальной памяти.

Инструкция idle действительно не очень нужна. Сейчас она используется для отладки устройства.

по поводу spark, есть опенсорсный spark, чтобы все снова не проектировать моно его верилоговскир блоки брать, так думал.
1) Поясните опкоды 1101хххх (что с чем)?
2) 0110хххх — почему нет шинного SWAP?
3) Для чего циклические сдвиги, как много языков их используют?
4) нет SIMD, хотя бы спаренных
5) LOAD16 & LOAD32 -> MOV8 rM,(arN+data8*4) или LOAD8 rN, data8; MOV rM, (arN+rN*4)
6) &(potan) — прав, и CALL сбрасываться должен в ar15, а не в r15; arN & pc — должны указывать относительно региона с проверкой превышения диапазона, привязка региона (не-сегмента) к arN можно осуществить аппаратной реализацией (за место сегментной организации) L4
7) что делает DEBUG?
8) не проще ли за место пустых опкодов использовать буферные регистры? какое повышение, и чего даст реализация дополнительных комманд при усложнении логики интерпретатора опкодов, все равно же будут включаться другие вентили? Если ну-очень-хочется, то мона использовать сопроцессорный аналог Вашего LOCK...FREE. Давным-давно, в далекой галактике у интела была связка микросхем i8086-i8087, да только у нее был векторный конкурент en.wikipedia.org/wiki/Weitek с CPU оно общалось через общую память, проц подготавливал вектор заданий, а сопроцессор обрабатывал их асинхнонно. У Вас же есть буфер, в память ничего класть не нужно… самое ОНО! Подготовил вектор, и арбайтн!
1101xxxx это операции c аргументами следующего вида:
(Rn + disp), Rm
Rn, (Rm + disp)
эти операции служать для работы с указателями со смещениями в коде операции. Могут применяться при адресации полей структур. Имеют возможности для расширения адресации.

Шинный SWAP? Если не затруднит, скажите подробней что имеете в виду. Может быть упустил из виду и если так, что в следующей версии можно будет добавить.

Циклический сдвиг ввёл «потому что они есть в x86». Использовать можно для неразрушающего вытеснения бита в перенос.

Почему нет SIMD? Есть идея тегового сопроцессора, который должен восполнить отсутствие SIMD и прочих удобств. Идея заключается в использовании дополнительных устройств, берущих на себя часть задач процессора. Например, на этапе инициализации программы в сопроцессор загружаются математические выражения, а в процессе работы с помощью сообщений в сопроцессор посылаются коэффициенты выражения, сопроцессор независимо от процессора вычисляет выражение, а по готовности вычисления посылает результат(ы) в ответном сообщении.

Пункты 5) и 6) немного не понял. Можно ли немного подробностей?

Инструкиция DEBUG, в текущей реализации, переводит процессор в пошаговый режим и мультиплексирует UART, выводя состояние шин процессора в последовательный порт. каждый байт, принятый из UART, выполняет одну инструкцию с выводом состояния шин.

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

### Шинный SWAP? Если не затруднит, скажите подробней что имеете в виду. Может быть упустил из виду и если так, что в следующей версии можно будет добавить.
###
Используется в неблокирующих многозадачных структурах: меняет местами содержимое регистра и области памяти
SWAP rN,(arM) -> (блокирует ячейку кеша с адресом (arM)); MOV Temp, rN; MOV rN, (arM); MOV (arM), T; (разблокирует ячейку кеша со адресом (rN));

### Циклический сдвиг ввел «потому что они есть в x86». Использовать можно для неразрушающего вытеснения бита в перенос.
###
Их используют только асемблерщики

### 5) LOAD16 & LOAD32 -> MOV8 rM,(arN+data8*4) или LOAD8 rN, data8; MOV rM, (arN+rN*4)
###
Смысл так делать только, если выравнивать команды на границу 2х или 4х байт, т.е. все JMP добавляют к адресу справа нолик или два;
Можно выделить отдельный адресный регистр под сегмент констант, и все константы занимающие больше баита хранить там.
LOAD8 rN, data8; MOV rM, (arN+rN*4); // загрузить смещение в регN, и выполнить загрузку константы со смещения в сегменте констант.

### 6) А адресные и общего назначения регистры, как я понял, не разделены? По моему лучше разделить. За счет небольшого увеличения количества команд при той же разрядности в двое увеличивается количество регистров.

Мне кажется, будут полезны инструкции для загрузки Big- и Little-ending. Для упрощения обмена данными со сторонними системами.
###
К Вашим r0-r15 добавить ar0-ar15, \MOV rN, arM; \MOV arM, rN;, все "\OPCODE ...(rN)...;" заменить на "\OPCODE ...(arM)...;", они могут адресовать или хранить значение, но…
внутри региона: есть 16 регионов доступные через контролер Memory-Maper, который и хранит реальный адрес страницы и размер региона. Если адрес внутри страницы, то все обрабатывается как у Вас, а если страница не отображена — то прерывается (как RECV). Регион состоит из страниц, в CPU хранится количество страниц, номер страницы в регионе, и адрес в памяти этой страницы. Т.е. в каждый момент таска имеет доступ к 16/17 страницам…
Упс, забыл про парсеры байт, инструкции, которые дербанят регистры побайтно, как в MMX.
Ответ на Ваш habrahabr.ru/post/113654/#comment_5746133:
### Спасибо. Я не привязывался к системе команд, поэтому вроде бы противоречий нет, можно и без флагов.

Мне тоже нравится большое число РОН, но возникает вопрос при вытеснении блока регистров задачи в оперативную память. Сейчас об этом речи нет, но если такую возможность не реализовать, то за пределы области применения микроконтроллеров — не выйти.
###
И все же, флаги оставили — печаль ( как вариант: отдельный регистр с переменной логикой 1) «опкод-ветвления» + LT/LE/EQ — переводит регистр «Т» в состояние интерпретатор (LT, LE или EQ) 2) «опкод-арг-левый» + rN — посылает содержимое в левый тригер 2) «опкод-арг-правый» + rN — посылает содержимое в правый тригер 4) «опкод-rТ в регистр» + rN — считывает условие в регистр исходя из режима (LT/LE/EQ); Можно упростить прос — сделать отдельно rT_LT, rT_LE и rT_EQ; или еще проще — вычислить в регистре rN, и в нем же оценить rN (LT rN / LE rN / EQ rN)

Со второй частью — еще проще: «регистровый файл — строка кеша», при загрузке задачи указывается адресс, недоступный для запускаемого процесса, TCB (task control block), если его нет в кеше — он загружается, возможно вытесняя устаревший и становится текущим регистровым файлом, то есть не свопируется до тех пор пока количество тасков меньше объема кеша.

habrahabr.ru/post/113654/#comment_5746121 ))) ага человек про EXO-ядра не слышал
И далее:
###
Если говорить о микроядре L4 в целом, то профит легко находится в универсальных виртуальных страницах. Для описания региона памяти их требуется меньше, чем обычных виртуальных страниц фиксированного размера.

Причину по которой во всех современных ОС используется модель страниц фиксированного размера Вы найдете в любом документе по проектированию ОС, тут вообще без комментариев.
###
Регионы могут улазывать на страницы: регион состоящий из (М) страниц не обязательно должен быть загружен полностью, вероятно будет указывать только на одну из страниц, выход за пределы которой генерирует различные прерывания: 1) ниже верхней грани региона — обращение к планеровщику памяти, 2) если выше — ACCESS DENIED.

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

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

Благодарю Вас за внимание к проекту и рекомендации. Возможно я не все предложенные идеи способен понять и оценить, но даже те моменты, которые понял, они весьма полезны. Спасибо!

Регионы и страницы — это абстракции разного уровня, то что CPU видит страницы, не значит, что таски не обмениваются регионами.

Про, то что это прототип — понятно, я к тому, что концепт нужно строить с оглядкой на область применения и развитие. Не все фичи, но не переписывать же все с нуля, после их добавления.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории