MIX — это гипотетический компьютер, использованный в монографии Дональда Кнута, «Искусство программирования»[1]. Номер модели компьютера MIX — 1009, происходит от комбинации номеров и названий коммерческих моделей машин, современных времени написания книги и показавшихся автору значимыми. Кроме того, «MIX» равняется 1009 в Римской системе счисления.
MIX 1960-х был заменён новой (также гипотетической) компьютерной архитектурой, MMIX, которая будет включена в ожидаемой редакции книги. Программные реализации MIX- и MMIX-архитектур были разработаны различными авторами и свободно доступны (например, разработанные самим Кнутом MIXware и MMIXware).
Архитектура
правитьMIX представляет собой гибридный двоично-десятичный компьютер. Когда компьютер программируется в бинарном режиме, каждый байт имеет 6 бит (значения от 0 до 63). В десятичном режиме каждый байт имеет 2 десятичных знака (значения от 0 до 99). Байты сгруппированы в слова по пять байт со знаком. Большинство программ, написанных для MIX, будут работать как в бинарном, так и в десятичном режимах, пока они не попытаются сохранить значение больше 63 в одном байте.
Слово изменяется в пределах от −1.073.741.823 до 1.073.741.823 (включительно) в бинарном режиме и от −9.999.999.999 до 9.999.999.999 (включительно) в десятичном режиме. В компьютере MIX различаются числа −0 и +0, чего нет на современных компьютерах, в которых есть только одно представление нуля, но количество отрицательных чисел, которые могут быть представлены определённым числом бит, на единицу больше количества положительных чисел.
Регистры
правитьВ компьютере MIX 9 регистров:
- rA: Аккумуляторный регистр (accumulator)(полное слово (full word), пять байт со знаком);
- rX: Расширение (extension) (полное слово, пять байт со знаком);
- rI1, rI2, rI3, rI4, rI5, rI6: Индексные регистры (Два байта и знак);
- rJ: Адрес перехода (два байта, всегда положительный).
Полагается, что байт имеет, как минимум, 6 бит. Большинство инструкций могут указывать, какие из полей (байт) регистра требуется изменить, используя суффикс в форме (первый: последний). Нулевое поле — однобитовый знак.
MIX также записывает, вызвала ли предыдущая операция переполнение и один из трёх индикаторов (меньше, равно или больше). На диаграмме ниже каждый регистр показан разделённым на свои поля.
|
|
|
|
|
|
|
|
|
|
|
Память и ввод-вывод
правитьКомпьютер MIX имеет 4000 слов хранения (каждый по 5 байт со знаком), адресуемых с 0 до 3999. Кроме того, есть множество устройств ввода и вывода:
- Магнитофонные устройства (устройства 0 … 7);
- Диск или барабанные устройства (устройства 8 … 15);
- Устройство чтения карт (устройство 16);
- Карточный перфоратор (устройство 17);
- Построчный принтер (устройство 18);
- Пишущая машинка (устройство 19);
- Перфолента (устройство 20).
Инструкции
правитьКаждая машинная инструкция в памяти занимает одно слово и состоит из 4 частей: адрес (2 байта со знаком) в памяти для чтения или записи, указание индексного регистра (1 байт, определяющий, какой индексный регистр rI использовать) для добавления к адресу, модификация (1 байт), определяющая, какие части регистра или ячейки памяти будут прочитаны или изменены, и код операции (1 байт). Все коды операции имеют словесные обозначения.
Программы MIX часто используют самомодифицирующийся код, в частности, чтобы вернуться из подпрограммы, так как в MIX отсутствует автоматический стек подпрограмм.
Программы для компьютера MIX обычно пишутся на языке MIXAL.
Команды загрузки
Содержимое поля по адресу [ ADDR + rIi(содержимое регистра I с индексом i) ] загружается в регистр.
LDA ADDR, i(0 : 5) | rA := memory[ ADDR + rIi ]; | загрузить в A |
---|---|---|
LDX ADDR, i(0 : 5) | rX := memory[ ADDR + rIi ]; | загрузить в X |
LDi ADDR, i(0 : 5) | rIi := memory[ ADDR + rIi ]; | загрузить в I с индексом i |
LDAN ADDR, i(0 : 5) | rA := -memory[ ADDR + rIi ]; | загрузить в A с обратным знаком |
LDXN ADDR, i(0 : 5) | rX := -memory[ ADDR + rIi ]; | загрузить в X с обратным знаком |
LDiN ADDR, i(0 : 5) | rIi := -memory[ ADDR + rIi ]; | загрузить в Ii с обратным знаком |
Команды записи в память
Записывает содержимое регистра в ячейку памяти с адресом [ ADDR + rIi ]
STA ADDR, i(0 : 5) | memory[ ADDR + rIi ] := rA; | записать A |
---|---|---|
STX ADDR, i(0 : 5) | memory[ ADDR + rIi ] := rX; | записать X |
STi ADDR, i(0 : 5) | memory[ ADDR + rIi ] := rIi; | записать Ii |
STJ ADDR, i(0 : 5) | memory[ ADDR + rIi ] := rJ; | записать J |
STZ ADDR, i(0 : 5) | memory[ ADDR + rIi ] := 0; | обнулить содержимое ячейки |
Арифметические команды
ADD ADDR, i(0 : 5) | rA := rA + memory[ ADDR + rIi ]; | сложение |
---|---|---|
SUB ADDR, i(0 : 5) | rA := rA - memory[ ADDR + rIi ]; | вычитание |
MUL ADDR, i(0 : 5) | (rA, rX) := rA * memory[ ADDR + rIi ]; | умножение |
DIV ADDR, i(0 : 5) | rA := int((rA, rX) / memory[ ADDR + rIi ]); rX := (rA, rX) % memory[ ADDR + rIi ]; |
деление |
Команды операций с адресами
ENTA ADDR, i | rA := ADDR + rIi; |
---|---|
ENTX ADDR, i | rX := ADDR + rIi; |
ENT? ADDR, i | rI? := ADDR + rIi; |
ENNA ADDR, i | rA := - ADDR - rIi; |
ENNX ADDR, i | rX := - ADDR - rIi; |
ENN? ADDR, i | rI? := - ADDR - rIi; |
INCA ADDR, i | rA := rA + ADDR + rIi; |
INCX ADDR, i | rX := rX + ADDR + rIi; |
INC? ADDR, i | rI? := ADDR + rIi; |
DECA ADDR, i | rA := rA - ADDR - rIi; |
DECX ADDR, i | rX := rX - ADDR - rIi; |
DEC? ADDR, i | rI? := rI? - ADDR - rIi; |
Команды сравнения
CMPA ADDR, i(0 : 5) | compare rA with memory[ ADDR + rIi ]; |
---|---|
CMPX ADDR, i(0 : 5) | compare rX with memory[ ADDR + rIi ]; |
CMP? ADDR, i(0 : 5) | compare rI? with memory[ ADDR + rIi ]; |
Команды перехода
JMP ADDR, i | goto ADDR + rIi; |
---|---|
JSJ ADDR, i | goto ADDR + rIi; rJ не меняется! |
JOV ADDR, i | if (overflow) then overflow := false; goto ADDR + rIi; |
JNOV ADDR, i | if (no overflow) then goto ADDR + rIi; else overflow := false; |
JL, JE, JG ADDR, i JGE, JNE, JLE ADDR, i |
if (less, equal, greater) then goto ADDR + rIi; if (no less, unequal, no greater) then goto ADDR + rIi; |
JAN/JAZ/JAP ADDR, i JANN/JANZ/JANP ADDR, i |
if (rA < 0 or rA == 0 or rA > 0) then goto ADDR + rIi; if (rA >= 0 or rA != 0 or rA <= 0) then goto ADDR + rIi; |
JXN/JXZ/JXP ADDR, i JXNN/JXNZ/JXNP ADDR, i |
if (rX < 0 or rX == 0 or rX > 0) then goto ADDR + rIi; if (rX >= 0 or rX != 0 or rX <= 0) then goto ADDR + rIi; |
J?N/J?Z/J?P ADDR, i J?NN/J?NZ/J?NP ADDR, i |
if (rI? < 0 or rI? == 0 or rI? > 0) then goto ADDR + rIi; if (rI? >= 0 or rI? != 0 or rI? <= 0) then goto ADDR + rIi; |
Другие команды
MOVE ADDR, i(F) | for(n = 0; n < F; n++, rI1++) memory[ ADDR + rIi + n ] := memory[ rI1 ]; |
---|---|
SLA/SRA ADDR, i SLAX/SRAX ADDR, i SLC/SRC ADDR, i |
shift rA to the left/right by ADDR+rIi bytes shift (rA, rX) to the left/right by ADDR+rIi bytes rotate (rA, rX) to the left/right by ADDR+rIi bytes |
NOP | do nothing; |
HLT | halt execution; |
Команды ввода-вывода
IN ADDR, i( F ) | read in one block from input unit F into memory[ ADDR + rIi ] onwards; |
---|---|
OUT ADDR, i( F ) | output one block to unit F from memory[ ADDR + rIi ] onwards; |
IOC ADDR, i( F ) | send control instruction to i/o unit F; |
JRED ADDR, i( F ) | if (i/o unit F is ready) then goto ADDR + rIi; |
JBUS ADDR, i( F ) | if (i/o unit F is busy) then goto ADDR + rIi; |
Команды преобразования
NUM | rA := numerical value of characters in ( rA,rX ); |
---|---|
CHAR | ( rA, rX ) := character codes representing value of rA; |
Примечания
править- ↑ Вся информация в этой статье взята из указанной книги
Ссылки
править- MMIX 2009: A RISC Computer for the Third Millennium Knuth’s official MIX page
- MMIX News Knuth’s official MIX news
- MMIXware: A RISC Computer for the Third Millennium Knuth’s official MIX book
- Open Directory: Computers: Programming: Languages: Assembly: MIX-MMIX many MIX-MMIX/MIXAL-MMIXAL links