ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Пятница
19 апреля
946495
fk0, легенда (16.09.2019 14:24, просмотров: 2887) MBedder
Пока читал про SIM-карты наткнулся на "Mobile Application Development with SMS and the SIM Toolkit Scott B. Guthery Mary J. Cronin." (см. ссылку), там описание виртуальных машин на 215 странице. Вспомнилось, что один коллега спрашивал как бы свою http://caxapa.ru/946408.html
VM реализовать (для загружаемого кода). Попытки реализации регистровой машины, типа RISC-V на любом языке программирования натыкаются на относительно высокую сложность декодирования инструкций (в инструкции масса опций, плюс ещё пара регистров закодирована). Чтоб раскодировать инструкцию нужно через маски и сдвиги вытащить все опции и регистры, а потом по таблице вызвать функцию реализующую инструкцию например. Речь о JIT ни в коем случае не идёт. Крайне неудобно, не эффективно, медленно. О чём Чарльз Мур (изобретатель Forth) ещё писал, предлагая быстрые маленькие forth-процессоры, без регистров, как альтернативу медленным регистровым машинам. В последнее время всё же регистровые машины победили, по другой причине: у стековой машины есть сложности с параллельным исполнением инструкций, так как практически все инструкции зависят от содержимого стека, или же используют стек для сохранения результата. Допустим, если есть сложное арифметическое выражение, состоящее из большого числа подвыражений. Часть из них может быть посчитана параллельно и регистровая машина (имеющая более одного АЛУ) легко это осуществляет. Стековая машина же вынуждена работать строго последовательно из-за зависимости от стека. Она даже имея два АЛУ не сможет одновременно перемножить два числа. С другой стороны у регистровой машины есть масса проблем, опять же вспоминая Мура, во-первых сложность декодирования инструкций, во-вторых зависимости по данным между регистрами, переименованием регистров (для избавления от зависимостей) -- должен заниматься процессор, что весьма нетривиально. Потому как набор команд последовательный, а исполнение -- частично параллельное. А компилятор к тому же должен заниматься сложной аллокацией регистров и постоянно жонглировать данными между регистрами и стеком. Если реализовывать виртуальную машину на обычном компьютере программно, то сложный набор команд с регистрами тоже не эффективен. Для программной реализации кажется более эффективной стековая машина, тот же Forth или Java. Противопоставляя обе модели вычислений, стековую и регистровую приходят разные идеи, вроде множественных стеков, но картина в целом не складывается. Хочется и регистровую модель избавить от сложного набора инструкций, и стековую от зависимости по данным. Был на "Демодуляции" организованной яндексом в субботу (14 сентября), там кто-то притаскивал самодельный компьютер на базе герконовых реле. Идея так себе, brainfuck (причём в буквальном смысле). Автор экспоната даёт просто огромное количество мыслей для размышления, но об этом позже. Просто простота реализация натолкнула на мысли. Некоторое время назад читал про процессоры реализующие минимально возможный набор команд (MISC), и среди них, в частности, выделяются так называемые one instruction set CPU. И в частности, есть архитектура состоящая из одной инструкции MOVE. Идея простая: есть шина данных на которой доступны АЛУ (может быть несколько), регистры памяти, периферия... и единственная инструкция позволяющая копировать из одного адреса по другому, или записывать константу по какому-либо адресу. По такой архитектуре сделан процессор MAXQ фирмы Dallas Semiconductor (теперь Maxim): https://pdfserv.ma …d.com/en/an/AN4811.pdf Стала крутиться в голове мысль, не может ли быть move-only архитектура каким-то связующим звеном между регистровыми и стековыми машинами. С одной стороны она сохраняет преимущества простоты декодирования команд присущие стековой машине, с другой стороны обладает малой связностью по данным и позволяет эффективно реализовать параллельные вычисления (допустим, машина имеет несколько АЛУ и может выполнять команды загрузки быстрей, чем АЛУ получают результат). При этом сложность связанная с распараллеливанием переходит от процессора к компилятору. Не нужно ни отслеживание зависимостей, ни переименование регистров -- компилятор должен при компиляции задумываться о зависимостях и времени срабатывания АЛУ. И программная реализация виртуальной машины кардинально упрощается и ускоряется (но в самой инструкции по прежднему кодируется либо адрес ячейки памяти, либо константа). Но у MOV-архитектура в чистом виде видимо не так хороша, что не получила распространения. Очевидно, что кроме АЛУ там сразу должны появиться и регистры косвенной адресации, и в основном память будет адресоваться через них, а не непосредственно, и что операции над набором регистров быстро начинают напоминать обычный регистровый CPU, при этом на любую операцию нужно несколько команд вместо одной в обычном CPU. Подумалось, а что если архитектура оставалось бы стековой, но с бесконечно растущим в одну сторону стеком. А на самом деле с кольцевым буфером из регистров. Тогда в большинстве случаев операция выполняется над вершиной стека (и адресация как таковая не нужна), а поскольку стек только растёт, то переименование регистров становится не очень нужным, по крайней мере недавно используемые регистры не встречаются в последующих инструкциях если нет явной зависимости по данным. Результат операций, если он есть, подразумевается что записывается в ячейку куда указывал указатель стека в момент начала инструкции (указатель стека сдвигается). Разумеется через некоторое время данные в регистрах бы перезаписывались новой информацией и если необходимо сохранить старые значения их нужно постоянно перекидывать на вершину стека или сохранять в оперативной памяти. Этим мог бы заняться компилятор. На самом деле в большинстве случаев это не нужно, пока размера стека/буфера хватает на все вычисления. Такой подход позволит стековой машине эффективно распараллеливать инструкции. Правда это уже будет не совсем стековая машина. На самом деле, может так в современных процессорах внутри и сделано... Идея в том, что к вершине стека всегда подключены одно или несколько АЛУ (тоже с ротацией), устройств косвенной адресации (способных записать число с вершины стека, по адресу записанному после числа, или наоборот, прочитать по адресу и сохранить на стеке). И команды или активируют соответствующее устройство, или вносят константу на стек, или копируют значение с заданным смещением от вершины стека на вершину стека (чтение результатов инструкций или ранее сохранённых данных). Идея в том, что чаще нужны данные на вершине стека и они адресуются непосредственно (может быть стоит добавить инструкции вроде dup, rot, swap, over из forth), данные зарытые в глубине стека адресуются через их дупликацию на вершине. Компилятор следит за порядком инструкций и временем работы устройств обращения к памяти или АЛУ и переупорядочивает инструкции так, чтобы читать результат когда вычисления фактически произведены (подразумевается, что поток инструкций быстрей времени обращения к памяти или времени срабатывания АЛУ). Не знаю, понятно ли описал. Я не знаю, существуют ли такие архитектуры. Интересно было бы знать. По сравнению с классической регистровой, даже с RISC, набор команд ещё меньше и проще. Поэтому команды могут быть быстрые, маленькие, и несколько команд могут быть упакованы в одно машинное слово (как в форт-процессорах Мура). Нет проблемы с параллельными вычислениями (но глубина ограничена стеком-буфером, который может быть достаточно большиой). Нужен несколько более сложный компилятор, должен следить и за параллельными исполнением, и за глубиной стека, вовремя перекидывать нужные данные на вершину, чтоб не были переписаны. Ряд значений на стеке-буфере явно окажутся классическим указателем стека, организованным в оперативной памяти, и это кажется не эффективным. Не знаю как это можно было бы улучшить. Может кто выскажет своё мнение.
[ZX]