Перейти к содержимому
ProgramCrafter

Архитектура MOV для OpenComputers

Рекомендуемые сообщения

Что это?

Пока разрабатывается OpenComputers II, у меня уже появилась идея для OpenComputers III.

Основывается она на далеко не новом принципе: сделать компьютер, в котором все вычисления происходят в памяти/регистрах, а единственная возможная команда - MOV (скопировать значение из одного регистра в другой). Но я не встречал никаких виртуальных машин для такой архитектуры, поэтому решил написать свою.

 

Для чего?

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

 

Где потыкать?

Текущие реализации (2 штуки, не во всех случаях работают одинаково):

https://github.com/ProgramCrafter/python-mov-vm - на Python

https://github.com/ProgramCrafter/rust-mov-vm - на Rust

У меня была и реализация на Lua, но её я куда-то потерял. :(

Сейчас думаю написать на Scala, как дополнительную архитектуру к OpenComputers.

 

Что умеет?

Пока что - печатать текст в консоль и считывать там же нажатия клавиш.

Вообще, насколько я посчитал, любая инструкция x86 представляется в виде не более чем 8 MOV-инструкций, так что эта архитектура не должна быть существенно медленнее. Кроме того, каждая инструкция здесь 32-битная, поэтому предсказатель ветвлений и конвейер инструкций (в физическом варианте процессора) будут быстрее работать.

 

Как выглядит какая-нибудь программа?

Выводит

╔══════════════════════════════════════════════════════════╗
║  TigerOS v0.0.1 | not licensed!!!                        ║
╚══════════════════════════════════════════════════════════╝

Выход по нажатию пробела в консоли.

 

Байткод: \x80<\x00\x1c\x80\n\x00\x1b\x80\x01\x00\x04\x00\x03\x00\x14\x00\x1d\x00\x15\x80\x07\x00\x16\x00\x17\x00\x1b\x00\x1e\x00\x10\x00\x05\x00\x03\x80\x03\x00\x1b\x00\x10\x00\x03\x80 \x00\x04\x00\x05\x00\x14\x80N\x00\x15\x80\x10\x00\x16\x00\x17\x00\x1b\xa5T\x00\x10\x00\x1c\x00\x03\x80\x02\x00\x04\x00\x05\x00\x03\xa5P\x00\x1e\x80\x17\x00\x1d\x80\x02\x00\x1b\xa5W\x00\x10\x80\n\x00\x10\xa5Q\x00\x10\x80 \x00\x10\x80 \x00\x10\x80T\x00\x10\x80i\x00\x10\x80g\x00\x10\x80e\x00\x10\x80r\x00\x10\x80O\x00\x10\x80S\x00\x10\x80 \x00\x10\x80v\x00\x10\x800\x00\x10\x80.\x00\x10\x800\x00\x10\x80.\x00\x10\x801\x00\x10\x80 \x00\x10\x80|\x00\x10\x80 \x00\x10\x80n\x00\x10\x80o\x00\x10\x80t\x00\x10\x80 \x00\x10\x80l\x00\x10\x80i\x00\x10\x80c\x00\x10\x80e\x00\x10\x80n\x00\x10\x80s\x00\x10\x80e\x00\x10\x80d\x00\x10\x80!\x00\x10\x80!\x00\x10\x80!\x00\x10\x00\x1c\x00\x03\x80$\x00\x04\x00\x05\x00\x03\x80 \x00\x1e\x80B\x00\x1d\x80\x02\x00\x1b\xa5Q\x00\x10\x80\n\x00\x10\xa5Z\x00\x10\x00\x1c\x00\x03\x80\x02\x00\x04\x00\x05\x00\x03\xa5P\x00\x1e\x80K\x00\x1d\x80\x02\x00\x1b\xa5]\x00\x10\x81\x00\x00\x10\x80\n\x00\x1b\x81\x01\x00\x10

 

Ассемблер (программа для перевода в байткод лежит вместе со всем на Python):

Скрытый текст


L0      mov     60      [w]

L1      mov     $L5     addr
-- function L1 (char -> [char], n -> sub0, ret -> [L1RET])
L2.0    mov     1       sub1
L2.1    mov     sub0    atz0
        mov     [L1RET] atz1
        mov     $L3     atz2
        mov     atz     addr
L3      mov     [char]  cio
L4      mov     sub     sub0
L4D     mov     $L2.1   addr
L4DD    

L5      

-- main loop
L6      mov     cio     sub0
        mov     32      sub1 -- exit on Space
        mov     sub     atz0
        mov     $L19    atz1
        mov     $L7     atz2
        mov     atz     addr
L7      mov     9556    cio
L8      mov     [w]     sub0
        mov     2       sub1
        mov     sub     sub0
        mov     9552    [char]
        mov     $L9     [L1RET]
        mov     $L2.0   addr
L9      mov     9559    cio
L10     mov     10      cio
L11     mov     9553    cio
L11.5   mov     32      cio
        mov     32      cio
        mov     84      cio
        mov     105     cio
        mov     103     cio
        mov     101     cio
        mov     114     cio
        mov     79      cio
        mov     83      cio
        mov     32      cio
        mov     118     cio
        mov     48      cio
        mov     46      cio
        mov     48      cio
        mov     46      cio
        mov     49      cio
        mov     32      cio
        mov     124     cio
        mov     32      cio
        mov     110     cio
        mov     111     cio
        mov     116     cio
        mov     32      cio
        mov     108     cio
        mov     105     cio
        mov     99      cio
        mov     101     cio
        mov     110     cio
        mov     115     cio
        mov     101     cio
        mov     100     cio
        mov     33      cio
        mov     33      cio
        mov     33      cio
L12     mov     [w]     sub0
        mov     36      sub1
        mov     sub     sub0
        mov     32      [char]
        mov     $L13    [L1RET]
        mov     $L2.0   addr
L13     mov     9553    cio
L14     mov     10      cio
L15     mov     9562    cio
L16     mov     [w]     sub0
        mov     2       sub1
        mov     sub     sub0
        mov     9552    [char]
        mov     $L17    [L1RET]
        mov     $L2.0   addr
L17     mov     9565    cio
L18     mov     256     cio
L18D    mov     $L6     addr

-- exit
L19     mov     257     cio

 

 

Структура команд

Каждая команда является 32-битной: первые 16 бит описывают источник, следующие 16 - номер регистра назначения, куда надо записать значение источника.

 

Если первый (старший) бит из 16, задающих источник, равен единице, то оставшиеся 15 бит - это число, которое будет записано в регистр назначения.

Иначе эти 15 бит задают номер регистра-источника, из которого будет считано значение.

 

Набор регистров

Каждый регистр хранит 64-битное целое число. Всего регистров может быть не более 32768 из-за адресации.

Номера регистров:

Скрытый текст

{'add0': 0, 'add1': 1, 'add': 2,
 'sub0': 3, 'sub1': 4, 'sub': 5,
 'mul0': 6, 'mul1': 7, 'mul': 8,
 'div0': 9, 'div1': 10, 'div': 11, 'mod': 12,
 'tlt0': 13, 'tlt1': 14, 'tlt': 15,
 'cio': 16,
 'io0': 17, 'io1': 18, 'io': 19,
 'atz0': 20, 'atz1': 21, 'atz2': 22, 'atz': 23,
 'memory': 24, '': 25, 'maddr': 26,
 'addr': 27,
 'reg0': 28, 'reg1': 29, 'reg2': 30, 'reg3': 31, 'reg4': 32, 'reg5': 33, 'reg6': 34, 'reg7': 35}

 

Значение доступных на данный момент регистров:

Скрытый текст

add = add0 + add1
sub = sub0 - sub1
mul = mul0 * mul1
div = div0 / div1 (если div1 = 0, то div = div0)
mod = div0 % div1 (если div1 = 0, то mod = 0)
tlt = если tlt0 < tlt1, то 1; иначе 0
atz = если atz0 == 0, то atz1; иначе atz2 (очень удобно для условных прыжков)
addr = текущая инструкция (аналог IP - Instruction Pointer в x86/x64)
reg0-7 = регистры общего назначения (ничего не считают)

cio - ввод-вывод текста через терминал; на Rust использует библиотеку termion, на Python - curses, на Lua(OpenComputers) - Term API.

Чтение значения из cio возвращает -1, если не нажата ни одна кнопка, а иначе код нажатой клавиши (может быть, код символа, я не помню).

Запись 256 в cio очищает экран, 257 - отключает curses и возвращается в обычную консоль, запись любого другого числа выводит на экран символ с данным кодом.

 

memory - находится в разработке (возникает проблема с тем, что регистры 64-битные, а память квантуется по 32 бита, так как команды короткие).

io - старый способ вывода данных на экран (не позволяет очистить экран, например)

Пока виртуальные машины несовместимы друг с другом только при переполнении чисел в регистрах. Rust упадёт с ошибкой, Python начнёт спокойно использовать длинную арифметику, а Lua начнёт спокойно терять точность, используя double.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@ProgramCrafter А как ты планируешь реализовать доступ к периферии? Или это очередной язык программирования, оторванный от игровой реальности?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
8 часов назад, eu_tomat сказал:

А как ты планируешь реализовать доступ к периферии?

Пока единственная идея, которая у меня появлялась - использовать регистры io. io0 - индекс устройства, io - регистр для обмена данными.

Протокол обмена данными с разными компонентами надо, конечно, продумывать. Например, с дискетой или жёстким диском такой обмен данными будет очень медленным, по 8 байт за операцию. Но, например, роботу хватит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
20 часов назад, ProgramCrafter сказал:

Rust упадёт с ошибкой

Чтобы в Rust при переполнении чисел не падал, надо явно указать поведение при арифметических операциях. Например, saturating_add - при прибавлении число просто clamp в лимит типа.

 

https://doc.rust-lang.org/std/primitive.i32.html#method.saturating_add

fn main() {
    println!("{}", i32::MAX.saturating_add(100)); // выведет 2147483647
}

То же самое есть и для других операций - pow, sub, mul, div и т.д.

 

Вообще насколько я помню при переполнении чисел программа падает только в debug режиме, в release должен быть просто wrapping

Изменено пользователем Laine_prikol

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
14 часа назад, ProgramCrafter сказал:

по 8 байт за операцию.

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

 

Если хотят создать процессор на ячейках памяти, то подачу команд и данных организовывают таким образом, что подача команды и обрабатываемых данных в качестве адреса вызывает готовый ответ без необходимости вычислений. А наличие возможности менять возвращаемое для поданной связки команда+данные содержимое реестра памяти открывает двери в по-своему увлекательный мир микропрограммирования, и с этого момента не помешает существование нишевого ИИ, помогающего инженеру решить самопоставленную задачу. По сути таким образом можно получить небинарную вычислительную среду на бинарных компонентах. В своё время разработчики вычислительной техники хотели использовать небинарную вычислительную среду, но столкнулись со сложностью как разработки самой таковой вычислительной техники, так и со сложностью создания по для оного. Кто знает, возможно, в наши дни эта тема снова может стать повесткой дня.

 

А какие, кстати, задачи планируется решать на разрабатываемой архитектуре?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Либо я не понял идею, либо она мне кажется странной.

Я так понимаю автор решил создать несколько регистров "предварительно" содержащих результат любой возможной операции?

А их содержимое просто копировать?

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

Изменено пользователем ZO125

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@ZO125 

https://esolangs.org/wiki/Mov

 

@Taoshi 

Про небинарные системы, есть источники, где ты это все подчерпнул?

Про ИИ тоже хотелось бы поподробнее.

 

@ProgramCrafter 

>реализация на питоне, расте, луа, а теперь и скале

Ты из под скакалки хочешь запилить архитектуру https://ocdoc.cil.li/tutorial:modding_architecture для ос? Почему не на джаве?

По поводу питонокода, нотация ISomething вроде сишарповская, в питоне вроде так непринято, просто к сведению.

И ещё на хомяке в гитхабе у тебя "middle programmer", если имелось в виду "средний программист", то лучше поменять на decent programmer.

 

===

>очередной язык программирования, оторванный от игровой реальности

Это что, ОБЕСЦЕНИВАНИЕ?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, prop сказал:

Про небинарные системы, есть источники, где ты это все подчерпнул?

Про ИИ тоже хотелось бы поподробнее

1.Строго говоря сейчас я не припомню где впервые читал о них. Было это около чуть более 20 лет тому. Но сейчас о троичном компьютере можно почитать например тут: 

https://cyberleninka.ru/article/n/istoriya-sozdaniya-troichnogo-kompyutera/viewer либо сдедать запрос в поисковой системе. 

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

2.О ИИ, как я написал, "не помешает существование нишевого", имея ввиду что такового нет: На данном этапе развития отрасли проектирования ИИ все они довольно узкопрофильные и создаются под поставленные узкопрофильные  задачи не охватывающие всего разнообразия когнитивной деятельности, потому только ваять лично либо искать кого-то кто заинтересуется и напишет соответствующую сетку. Если, конечно, мои сведения не устарели - эта сфера развивается ощутимо быстро.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 08.04.2022 в 06:40, ProgramCrafter сказал:

Протокол обмена данными с разными компонентами надо, конечно, продумывать. Например, с дискетой или жёстким диском такой обмен данными будет очень медленным, по 8 байт за операцию. Но, например, роботу хватит.

А ты планируешь использовать только новую периферию, изначально написанную под этот мод, или создать протокол для работы с периферией CC и OC?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 08.04.2022 в 08:40, ProgramCrafter сказал:

Пока единственная идея, которая у меня появлялась - использовать регистры io. io0 - индекс устройства, io - регистр для обмена данными.

Протокол обмена данными с разными компонентами надо, конечно, продумывать. Например, с дискетой или жёстким диском такой обмен данными будет очень медленным, по 8 байт за операцию. Но, например, роботу хватит.

До периферии нужно ещё как-то заставить компьютер работать, вопрос в том как программа будет попадать в movmachine?

Нащелкиванием через front panel или через реликтовые прото(перфокарты/дискеты) с boot'ером, неизвестно как оказавшиеся в данжах?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
16 часов назад, Taoshi сказал:

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

Имеешь в виду программируемые логические матрицы? Кстати, да, хорошая альтернатива разработке специализированного процессора. Особенно, на этапе тестирования идеи.

 

16 часов назад, Taoshi сказал:

В своё время разработчики вычислительной техники хотели использовать небинарную вычислительную среду, но столкнулись со сложностью как разработки самой таковой вычислительной техники, так и со сложностью создания по для оного. Кто знает, возможно, в наши дни эта тема снова может стать повесткой дня.

Небинарные вычислительные среды существуют и совершенствуются. Есть довольно свежее видео:

Скрытый текст

 

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
22 часа назад, Laine_prikol сказал:

Чтобы в Rust при переполнении чисел не падал, надо явно указать поведение при арифметических операциях. Например, saturating_add - при прибавлении число просто clamp в лимит типа

Да, я знаю, надо только записать в документацию поведение при переполнении.

 

15 часов назад, ZO125 сказал:

Придется дожидаться установки последнего из возможных регистров перед выполнением следующей инструкции

Необязательно, можно же так расположить команды, что в большинстве мест можно будет выполнять по два или больше mov одновременно.

Например, условные переходы у меня сейчас используют особый регистр atz: он возвращает atz1, если atz0 == 0, иначе atz2.

Значит, если я хочу при v == 0 прыгнуть в одно место, а при v != 0 в другое, то я могу одновременно записывать v, положение первого и второго места в atz0, atz1 и atz2.

 

Я говорю вот что: во-первых, mov исполняется никак не медленнее любой инструкции x86 (может быть, медленнее nop, но это не точно); во-вторых, вроде бы, любую из старых инструкций x86 (до появления дополнений с векторизацией и тому подобным) можно превратить не более чем в 8 моих инструкций. Работать будет, конечно, медленно, но будет.

 

5 часов назад, prop сказал:

Ты из под скакалки хочешь запилить архитектуру https://ocdoc.cil.li/tutorial:modding_architecture для ос? Почему не на джаве?

Например, чтобы и скалу подучить. Для джавы у меня другой проект, OCTechnics :)

 

5 часов назад, prop сказал:

По поводу питонокода, нотация ISomething вроде сишарповская, в питоне вроде так непринято, просто к сведению

Да какая разница, я могу код и без этого писать...

 

5 часов назад, prop сказал:

И ещё на хомяке в гитхабе у тебя "middle programmer", если имелось в виду "средний программист", то лучше поменять на decent programmer

То есть, грейды junior-middle-senior только у нас так называют?

 

24 минуты назад, eu_tomat сказал:

А ты планируешь использовать только новую периферию, изначально написанную под этот мод, или создать протокол для работы с периферией CC и OC?

Скорее всего, только новую.

 

Только что, prop сказал:

Нащелкиванием через front panel или через реликтовые прото(перфокарты/дискеты) с boot'ером, неизвестно как оказавшиеся в данжах?

Через протоеепромы, конечно. Например, просто перекрутить обычный EEPROM гаечным ключом сколько-то раз.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
16 часов назад, Taoshi сказал:

А наличие возможности менять возвращаемое для поданной связки команда+данные содержимое реестра памяти открывает двери в по-своему увлекательный мир микропрограммирования

Да, насколько я знаю, теории конечных автоматов с изменяющимися правилами ещё никто не создавал.

(Кстати, может, именно поэтому не могут вывести "формулу всего" в физике?)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
16 часов назад, Taoshi сказал:

А какие, кстати, задачи планируется решать на разрабатываемой архитектуре?

Например, ОС написать. Или портировать что-нибудь из линуксов, я вообще хочу попробовать написать транслятор x86 в movasm.

И будет наконец без помощи VirtualBox в майнкрафте серьёзная ОС.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
3 часа назад, ProgramCrafter сказал:

теории конечных автоматов с изменяющимися правилами ещё никто не создавал

Опс, я понял: если взять в качестве состояния не только текущую вершину, но и набор существующих на данный момент рёбер, то получится не менее конечный автомат, размер которого будет n * 2^(n^2/2). Теперь единственная проблема, что этот граф слишком большой, чтобы с ним по-нормальному работать, но как минимум, он не бесконечный. А значит, с ним можно работать, как с обычным...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
5 часов назад, ProgramCrafter сказал:

То есть, грейды junior-middle-senior только у нас так называют?

Middle на каком стеке?
Обычно так обозначается опыт, например, Middle Python программист, 5 лет опыта, далее перечисление проектов с датами и местом работы.
Без опыта работы и конкретного указания проектов Middle Programmer выглядит странно.

 

5 часов назад, ProgramCrafter сказал:

хочу попробовать написать транслятор x86 в movasm

Так ведь есть уже
GitHub - xoreaxeaxeax/movfuscator: The single instruction C compiler

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, prop сказал:

Без опыта работы и конкретного указания проектов Middle Programmer выглядит странно

Так это и не резюме (как минимум, пока что).

 

1 час назад, prop сказал:

Так ведь есть уже

Посмотрел, увидел, что компилирует только C/C++/что-то в LLVM, закрыл :). Хотя, мб, можно линукс перегнать в такой формат. Но надо ещё разбираться, как используемые регистры у x86 соответствуют моим.

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

 

Например, аллокатор, который я сейчас пишу (да, здесь могут быть баги и тому подобное):

_static_alloc = 1024

def _static_allocate(size):
  _static_alloc += size
  return _static_alloc - size

def _static_deallocate(p): pass

_alloc_cl_first = _static_allocate(4)
_alloc_cl_first->first = 1048575

def _list_ins_between(L: *list_node,
    R: *list_node, u: pair<size_t, size_t>):
  v = _static_allocate(4)
  v->first = u.first
  v->second = u.second
  v->third = R
  v->fourth = L
  if L: L->third = v
  if R: R->fourth = v
  return v

...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в тему...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...