Comments 21
С тем же успехом всю vm можно бы было уместить в 1, 10 или 42 строки. Всего лишь нужно ещё большее число действий запихивать в нечитаемые однострочники
Чтобы джампнуть по адресу n нужно выполнить jmp n-1. Это бай дизайн?
Почему не реализоыана rti, она же элементарна
Странная система комманд с add dst,src,0 вместо mov dst,src
Для vliw-подобных инструкций с фиксированной длиной проще работать 3-операндными операциями с данными. Кстати, регистр флага состояний становится не нужен, т.к. условные переходы тоже могут прямо в себе содержать вычисления на alu. В "Turing complete" это упрощение используется в LEG-архитектуре
Вообще я бы многие уровни Turing Complete ввел в обязательную подготовку программистов. И суть не в понимании низкоуровневщены, а то что игра учит очень сильно развивать мышление нужное для решения проблем и задач. Открыл ее для себя 2 недели назад и прошел на одном дыхании. Уже 7 джунов(и даже одного биолога) усадил за нее и прямо вижу пробелы в мышлении и как это дело фиксится по мере прохождении игры
насчет п.1 я ошибся
Странная система комманд с add dst,src,0 вместо mov dst,src
Что тут странного? Так делают в RISC процессорах.
Например в IBM Power
"mr rA,rS" equivalent to "or rA,rS,rS"
"li rD,value" equivalent to "addi rD,0,value"
Ведь зачем нужен лишний опкод, если он не нужен?
Я конкретно про сложение с нулём писал (там складывается с нулевым регистром).
CMP — для SUBS
Это в ARMv8+. В предыдущих — нет (из-за отсутствия ZR).
"эх, молодость...."
Очень похожую VM мы на курсаче на первом курсе делали примерно 25 лет назад. Только не на С, а на Паскале.
Система команд была немного побогаче в плане арифметических и логических операций, плюс надо было визуальный отладчик сделать и транслятор с ассемблера в "машинный код".
Такое интересно было делать в своё время. Остальные курсачи в основном более унылые были, насколько помню...
Люблю такие издевательства. Прямо воспоминания из лучших времен.
uint16_t mem[UINT16_MAX] = {0};
тут потенциальное UB, потому что из кода VM можно адресоваться к ячейке за пределами массива.
op_ex[OP(instr)](instr); // эта инструкция выполнит операцию, связанную с OP(instr)
static inline void add(uint16_t i) { /* код */ }
static inline void and(uint16_t i) { /* код */ }
Для функций, вызываемых по адресу из таблицы, модификатор inline указывать бессмысленно. Мелочь, ни на что не влияет, но показывает уровень, насколько автор понимает происходящее.
UINT16_MAX=65535
. Поэтому, если говорить о перспективе, то наша система довольно ограничена и не сможет выполнять/загружать программы с более, чем 65535 инструкциями.
С оценкой уровня автора согласен. Где-то с четвертого-пятого абзаца всего перевода начало создаваться впечатление, что проект является студенческой курсовой работой.
Тем не менее, как введение для новичков походит, если не брать все утверждения в статье за непогрешимую истину.
Про это, кажется, не думает ни один из крупных нынче языков с VM( python, js .. ). Везде одни и те же грабли глобального состояния. Причины и проявления разные, но результат один и тот же - однопоточность к VM прибита гвоздями. Кто-то даже проявляет ПТСР и доказывает, что так и надо и что так даже правильно - ведь можно просто запустить 10 копий VM.
Кажется в коде для инструкции br ошибка. Проверка выполнения условия записана как "reg[RCND] & FCND(i)". Может хотя бы так: "(reg[RCND] & FCND(i)) == FCND(i)"?
А так, для новичков вроде неплохо. За исключением названий переменных, дефайнов и прочего (кроме названий инструкций, конечно - тут классика).
trap
, не содержащая проверку на соответствие границам массива, позволяет получить много интересного Undefined Behaviour. Вместо fprintf(stdout, "%c", ...)
проще использовать putc
. Вывод строки циклом fprintf
--- тоже отдельная песня.
"Программу для генерации программы" можно было бы превратить в аналог ассемблера, добавив #define
на каждый опкод и используя их внутри массива. Да еще в вызове fwrite ошибка длины.
Касательно самой архитектуры тоже есть вопросы. Хотелось бы аппаратные push
/pull
. И регистр флагов обновлять можно не всегда, а только по требованию (как в Aarch64).
А вообще было бы интересно увидеть, например, порт RatC ("A Book on C", R.E. Berry and B.A. Meekings, 1984), генерирующий код для этой VM.
Умещаем простую 16-битную VM в 125 строк Си