Выбор архитектуры процессора для 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) будет работать.