Выбор архитектуры процессора для LLVM/CLANG

Я проектирую серийный компьютер TTL, и я борюсь за выбор архитектуры, более подходящей для бэкэнда компилятора LLVM (я хочу иметь возможность запускать любое программное обеспечение С++ там). Не будет MMU, нет умножения/деления, нет аппаратного стека, нет прерываний.

У меня есть 2 основных варианта:

1) 8-разрядная память, 8-битная ALU, 8-разрядные регистры (~ 12-16). Ширина адреса 24 бит. Поэтому мне нужно будет использовать 3 регистра как IP и 3 регистра для любой ячейки памяти.

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

2) 24-битная память, 24-битная ALU, 24-битные регистры (~ 6-8). Плоская память, приятно. Недостатки состоят в том, что из-за серийного характера конструкции каждая операция будет занимать 3 раза больше часов, даже если мы будем работать с некоторыми булевыми. Ширина данных в 24-битной памяти дорогая. И сложнее реализовать в аппаратных средствах вообще.


Вопрос: Как вы думаете, возможно ли реализовать все возможности С++ на этом 8-битном, основанном на стеках аппаратном обеспечении, или мне нужно иметь более сложное оборудование для генерации кода с разумным качеством и скоростью?

Ответы

Ответ 1

Во-вторых, предложение использовать LCC. Я использовал его в этом 16-битном проекте RISC с доморощенным: http://fpgacpu.org/xsoc/cc.html.

Я не думаю, что это должно иметь большое значение, строите ли вы 8-битный вариант и используете 3 add-with-carry для увеличения IP-адреса или 24-битного варианта и делаете все на аппаратном уровне. Вы можете скрыть разницу в своем ассемблере.

Если вы посмотрите на мою статью выше или еще более простой процессор здесь: http://fpgacpu.org/papers/soc-gr0040-paper.pdf, вы увидите, что вам действительно не нужно, чтобы многие операторы/инструкции охватывают целочисленную C-повторную запись. На самом деле есть утилита lcc (ops) для печати минимального набора операторов для данной машины.

Для получения дополнительной информации см. мою статью о переносе lcc на новую машину здесь: http://www.fpgacpu.org/usenet/lcc.html

Как только я портировал lcc, я написал ассемблер, и он синтезировал большую репетицию инструкций от базовых. Например, моя машина имела байты с байтом без знака, но не с байтовыми байтами, поэтому я выбрал эту последовательность:

lbs rd,imm(rs) ->
  lbu rd,imm(rs)
  lea r1,0x80
  xor rd,r1
  sub rd,r1

Итак, я думаю, что вы можете пройти с этим минимальным покрытием операций:

  registers
  load register with constant
  load rd = *rs
  store *rs1 = rs2
  + - (w/ w/o carry)    // actually can to + with - and ^
  >> 1                  // << 1 is just +
  & ^                   // (synthesize ~ from ^, | from & and ^)
  jump-and-link rd,rs   // rd = pc, pc = rs
  skip-z/nz/n/nn rs     // skip next insn on rs==0, !=0, <0, >=0

Еще проще не иметь регистров (или, что то же самое, размывает регистры с памятью - все регистры имеют адрес памяти).

Отложите регистр для SP и напишите обработчик функции prolog/epilog в компиляторе, и вам не придется беспокоиться о инструкциях стека. Там только код для хранения каждого из регистров сохранения вызываемого абонента, настройки SP по размеру кадра и т.д.

Прерывания (и возврат от прерываний) просты. Все, что вам нужно сделать, это заставить команду перехода и перехода в регистр команд. Если вы выбрали битовый шаблон для того, чтобы быть чем-то вроде 0, и поместили правильные адреса в регистр источника rs (особенно, если он равен r0), это можно сделать с помощью триггера reset или дополнительной силы - to-0 и ворота. Я использую подобный трюк во второй статье выше.

Интересный проект. Я вижу, что конкурс TTL/7400 идет полным ходом, и я думал о том, насколько простым может быть машина, и может ли это быть обманом, чтобы добавить асинхронный SRAM на 32 КБ или 128 КБ на компьютер для хранения кода и данных.

В любом случае, счастливый взлом!

p.s.

1) Вам нужно будет решить, насколько величен каждый тип интеграла. Вы можете сделать char, short, int, long, long long и т.д. Того же размера, одно слово 24b, если хотите, хотя оно не будет соответствовать диапазонам минимального представления.

2) И хотя я сосредоточился на этом, вы спрашивали о С++. Я рекомендую сначала перенести С. После того, как вы все выяснили для C, включая *,/,% операторов в программном обеспечении и т.д., Должно быть более целесообразным перейти на полномасштабный С++, будь то в LLVM или GCC. Разница между C и С++ - это "только" дополнительные таблицы vtables и RTTI и последовательности кода (полностью созданная примитивным оператором оператора C), необходимая для обработки вызовов виртуальных функций, указателя на разыменование участников, динамические приведения, статические конструкторы, исключение обработки и т.д.

Ответ 2

IMHO, возможно для компилятора c. Однако я не уверен в С++.

LLVM/CLang может быть трудным выбором для 8-битного компьютера,

Вместо этого сначала попробуйте lcc, затем второй llvm/etc, HTH.

Bill Buzbee преуспевает в том, чтобы перенацелить lcc-компилятор для своего Magic-1 (известного как homebrewcpu).

Хотя дизайн оборудования и конструкция Magic-1 обычно привлекают наибольшее внимание, большая часть проекта (безусловно) разрабатывает/переносит программное обеспечение. С этой целью мне пришлось писать ассемблер и компоновщик с нуля, переназначить компилятор C, написать и перенести стандартные библиотеки C, написать упрощенную операционную систему, а затем перенести более сложную. Это было непросто, но весело. Я полагаю, что я немного искажен, но мне, похоже, нравится отлаживать сложные проблемы. И когда ошибка, которую вы пытаетесь отследить, может включать в себя один или несколько из: дефект аппаратного дизайна, свободный или сломанный провод, потерянный или плохой TTL-чип, ошибка ассемблера, ошибка компоновщика, ошибка компилятора, ошибка библиотеки времени выполнения C или, наконец, ошибка в программе, о которой идет речь, есть много возможностей для развлечения. О, и у меня также нет роскоши обвинять ошибки в ком-то еще.

Я постоянно удивляюсь, что проклятая вещь работает вообще, а тем более бегает так же хорошо, как и она.

Ответ 3

На мой взгляд, безплатное оборудование уже плохо подходит для кода C и С++. Если у вас есть вложенные вызовы функций, вам все равно нужно эмулировать стек в программном обеспечении, что, конечно, намного медленнее.

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

  • Непосредственный адрес (24 бит) как часть кода операции
  • Непосредственный адрес (24 бит) плюс индексный регистр (8 бит)
  • Косвенный доступ: немедленный 24-битный адрес в память, содержащий фактический адрес
  • Косвенный доступ: 24-битный адрес в память, 8-разрядный индексный регистр добавлен к значению из памяти.

Режимы адресов, описанные выше, позволят эффективный доступ к массивам, структурам и объектам, размещенным на постоянном адресе (статическое распределение). Они будут менее эффективными (но все же пригодными для использования) для динамически и объектов, размещенных в стеке.

Вы также получите некоторую выгоду от своего серийного дизайна: обычно добавление 24 бит + 8 бит не занимает 24 цикла, но вместо этого вы можете закоротить добавление, когда перенос равен 0.

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

Я думаю, что если вы тщательно сконструируете процессор, вы можете использовать многие возможности С++ довольно эффективно. Однако не ожидайте, что любой случайный код на С++ будет работать быстро на таком ограниченном процессоре.

Ответ 4

Реализация, безусловно, возможна, но я сомневаюсь, что она будет полезной (а не для кода на С++). Как уже отмечалось, первой проблемой является отсутствие стека. Далее, куча С++ в значительной степени связана с распределением динамической памяти, также С++ "внутренние" структуры довольно большие.

Итак, как мне кажется, будет лучше, если вы:

  • Избавиться от требования С++ (или, по крайней мере, ограничить себя некоторым подмножеством)
  • Используйте 24 бита, а не 8 бит для всего (для регистров тоже)
  • Добавить аппаратный стек

Ответ 5

Вы не сможете запускать "любой" код на С++. Например fork(), system() и т.д. Все, что явно полагается на прерывания, например. Конечно, вы можете пройти долгий путь. Теперь вы имеете в виду любые программы, которые могут/были написаны на С++ или вы ограничиваете себя только языком, а не библиотеками, которые обычно связаны с C/С++? Сам язык - гораздо более легкое правило, с которым можно жить.

Я думаю, что проще ответить на вопрос, почему бы просто не попробовать? что ты уже испробовал? Можно утверждать, что x86 - это 8-разрядная машина, не учитывающая выравнивание и много 8-битных инструкций. msp430 был перенесен на llvm, чтобы показать, как легко и быстро это можно сделать, я хотел бы видеть, что платформа с лучшей поддержкой (а не там, где мои сильные стороны лежат иначе, я бы это сделал) - 16-битную платформу. no mmu. имеет стеки и прерывания, конечно, не нужно их использовать, и если вы удаляете правила библиотеки, то что осталось, что требует прерывания?

Я бы посмотрел на llvm, но заметьте, что созданная документация, показывающая, насколько легко переносится, устарела и ошибочна, и вам в основном нужно разобраться с ней из источников компилятора. У llc есть книга, известная тем, что не оптимизирована. Источники не очень хорошо компилируются на современных компьютерах, всегда должны идти назад вовремя, чтобы использовать его, каждый раз, когда я приближаюсь к нему после вечера, просто пытающегося его построить, так как я сдаюсь. vbcc, простой, чистый, документированный, недружелюбный к меньшим процессорам. Это С++, не помню. Из всех них проще всего получить компилятор и запустить. Из всех из них LLVM является наиболее привлекательным и полезным, когда все сказано и сделано. не ходите близко к gcc или даже не думайте об этом, клейкую ленту и проводящую проволоку внутри, удерживая ее вместе.

Вы уже изобрели свой набор инструкций? у вас еще есть симулятор и ассемблер? Посмотрите lsasim в github, чтобы найти мой набор инструкций. Вы можете написать llvm backend для моей, как для вашей практики... grin... (мой бэкенд vbcc ужасен, мне нужно начать все сначала)...

У вас должно быть некоторое представление о том, как будет реализован высокий уровень, но вам действительно нужно начать с набора команд и симулятора набора инструкций и какого-либо ассемблера. Затем начните ручную конвертацию кода C/С++ в сборку для вашего набора команд, который должен довольно быстро получить вас через "могу ли я сделать это без стека" и т.д. В этом процессе определите свое соглашение о вызове, реализуйте больше кода C/С++ вручную используя ваше соглашение о вызове. Затем копайте в компилятор и сделайте задний конец. Я думаю, что вы должны рассматривать vbcc как ступеньку, затем отправляйтесь в LLVM, если это будет похоже (isa) будет работать.