Стив Возняк. Где мои 16 лет. Велосипеды.

Я так понимаю, каждый уважающий себя айтишник должен придумать свой собственный процессор. Ну вы только посмотрите что творится вокруг DCPU-16. Ну Нотч, ну игра, ну процессор. А что такого особенного в этом DCPU16? По-моему самый обычный вымышленный 16-разрядный процессор. Нет, это конечно хорошо что народ начал писать эмуляторы, компиляторы, на verilog там что-то делают, да, толчок дали хороший. Но это все — маркетинг, и лучше бы для других процессоров делали то же самое. А то — для AVR эмулятора под linux нет толкового, так чтобы расширять можно было легко и просто. Для PIC кажется тоже. Для STM8 очень классных и модных — вообще ничего нет, даже ассемблера! Но все пишут и пишут для практически непригодного DCPU-16. На этом фоне эмулятор Cortex на AVR выглядит намного круче, хотя шума о нем меньше.

Ну ладно, разворчался я что-то.

А причем тут Возняк?

Когда создавался компьютер Apple II Стив Возняк писал для него интерпретатор BASIC. При чем процессор был 8-битным, а BASIC хотели сделать 16-битным. Чтобы упростить себе задачу Возняк сначала разработал байт-код для виртуального 16-битного процессора, и уже для этого байт-кода написал BASIC. Назывался этот байт-код SWEET16.

Примечательно, что весил интерпретатор этого языка всего 300 байт. Итак, что же он умел?

Было 16 регистров R0..R15 (регистры 16-разрядные). Часть регистров были особыми (указатель на вершину стека, счетчик инструкций, флаги сравнений). Регистр R0 — это аккумулятор. Инструкций было 16 регистровых (у которых аргументы — регистры), и почти 16 нерегистровых (разнообразное ветвление, nop, ret). Подробнее про SWEET16 — здесь.

Вот это на мой взгляд пример хорошего вымышленного байт-кода — экономит кучу времени на разработку ПО, просто реализован, очень лаконичный и легко обрабатывается интерпретатором.

Велосипеды

А я вот хотел написать что-то такое сам. Мне хотелось тоже сделать байт-код, тоже для дохлых железок.

Вот чему меня научил Стив Возняк своим SWEET16:
* 16 бит — хороший компромисс для байт-кода. 32 бита — сложно запустить на 8-битном процессоре, 8 бит — неудобно писать программы.
* 16 регистров — этого более чем достаточно.
* инструкции одинаковой длины — не совсем удобно. Много байт будут расходоваться впустую.
* чем больше инструкции похожи друг на друга (их коды), тем проще интерпретатор байт-кода.
* умножение и деление — это непростительная роскошь.
* аккумулятор очень упрощает инструкции.
* очень удобно отделить регистровые инструкции от нерегистровых. Упрощает систему команд.
* все виды адресации должны быть максимально удобными.

И вот что у меня получилось. Не судите строго.

Мой SW16

Регистры. Я решил, что у меня их будет всего 8 штук, но зато 16-разрядных:

  • r0 — аккумулятор
  • r1..r5 — общего назначения (должно хватит, а?)
  • r6 — указатель на вершину стека
  • r7 — счетчик инструкций

Формат инструкций решил сделать везде одинаковым. Вначале идет один байт:


IIIIFRRR

* IIII - инструкция
* F - особый флажок, о нем ниже
* RRR - регистр

Исходя из этого формата мы можем сделать 15 инструкций, работающих с регистрами. Для нерегистровых инструкций I и F равны нулю, т.е. нерегистровых инструкций может быть 7.
Т.е. нерегистровые инструкции выглядят как 00000III. Итак, что же за инструкции есть?

00000000 SYS Выполняет системный вызов. Просто особая инструкция, VM может реализовывать ее как угодно, это позволит расширить систему команд domain-specific инструкциями.
00000001 SHL сдвигает r0 на 1 бит влево
00000010 SHR сдвигает r0 на 1 бит вправо
00000011 [ADDR] JZ Перейти на указанный 16-битный адрес A (адрес следует за инструкцией) если r0 == 0
00000100 [ADDR] CALL Войти в подпрограмму по адресу A. Сохраняет адрес возврата на стеке и переходит на указанный адрес
00000101 RET Выйти из подпрограммы
00000110 COM Устанавливает r0 := ~r0
00000111 NEG Устанавливает r0 := -r0
Регистровые инструкции
00010RRR
00011RRR [N]
LD r0, rX
LD r0, N
Eсли флаг F=0, то r0 := rX. Если же флаг F=1, то за инструкцией идет число, его нужно положить в аккумулятор: r0 := N
00100RRR LD rX, r0 Сохраняет значение аккумулятора в регистре: rX := r0
00110RRR
00031RRR
LDI r0, [rX] Косвенная адресация — r0 := mem[rX]. Если флаг F=1, то считывается не байт, а слово по адресу rX (порядок байт little-engian)
01000RRR
00031RRR [N]
STI r0, [rX] mem[rX] := r0 (аналогично LDI можно считать как байт, так и слово)
01010RRR POP rX Извлекает со стека значение rX
01100RRR PUSH rX Кладет на стек значение rX
01110RRR reserved Пока не задействовано
10000RRR SUB rX
SUB rX, [N]
r0 := r0 — rX
rX := rX — N
10010RRR ADD rX
ADD rX, [N]
r0 := r0 + rX
rX := rX + N
10100RRR AND rX r0 := r0 & rX
10100RRR OR rX r0 := r0 | rX
10100RRR XOR rX r0 := r0 ^ rX
10100RRR EQ rX r0 := (rX == r0)
10100RRR LESS rX r0 := (rX < r0)
10100RRR ULESS rX r0 := (rX < r0), где rX и r0 — беззнаковые целые

Получается, все инструкции кроме JZ, CALL и некоторых типов SUB/ADD/LD — однобайтные. Те инструкции, которые могут принимать еще 16-битное число в качестве аргумента — трехбайтные. Возможно, используя varint, можно было сделать также двухбайтные инструкции для маленьких чисел до 128.

Интерпретатор такого байт-кода для AVR получился размером меньше килобайта, и из оперативной памяти требуется только место под регистры и около 8 байт стека для локальных переменных.

Вывод

Каждый может сочинить свой байт-код. Хороший он будет или плохой — решать вам самим. Я хотел получить что-то маленькое и быстрое. Пусть он не для всех конструкций языка, скажем, C подходит идеально, но писать на нем можно, и выполнять его можно. Если не забуду, то скоро расскажу про компиляторы для моего скромного байт-кода.

Реклама

One comment on “Стив Возняк. Где мои 16 лет. Велосипеды.

  1. Илюха:

    > Если не забуду, то скоро расскажу про компиляторы для моего
    > скромного байт-кода.
    Я Вам напоминаю 🙂

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s