GNU MIX Development Kit (mdk): Учебник по MIX и MIXAL

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2. Учебник по MIX и MIXAL

В серии книг Искусство программирования Д. Кнута для иллюстрации алгоритмов и умений, необходимых каждому серьёзному программисту, автор использует виртуальный компьютер MIX (вместе с соответствующим набором двоичных инструкций). Как для любого реального компьютера, существует символический язык ассемблера, на котором можно программировать MIX -- язык ассемблера MIX, MIX assembly language, сокращённо MIXAL. В следующих подразделах вы найдёте учебник, который даст вам основы архитектуры MIX и научит программировать MIX на языке MIXAL.

2.1 Компьютер MIX  Архитектура и набор инструкций
                                компьютера MIX.
2.2 MIXAL  Язык ассемблера MIX.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1 Компьютер MIX

В этом разделе вы найдёте описание компьютера MIX, его компонентов и набора инструкций.

2.1.1 Архитектура MIX  
2.1.2 Набор инструкций MIX  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.1 Архитектура MIX

Основной единицей информации в компьютере MIX является байт, в котором хранится положительное значение в диапазоне от 0 до 63. Имейте в виду, что байт MIX может быть представлен шестью битами, а не восемью, как регулярный байт. Если иное не оговорено специально, слово байт будет обозначать 6-битный байт MIX.

Слово MIX определяется как набор из пяти байтов и знака. Байты слова нумеруются от 1 до 5, первым является старший байт. Знак обозначается индексом 0. Графически,

 
 -----------------------------------------------
|   0   |   1   |   2   |   3   |   4   |   5   |
 -----------------------------------------------
|  +/-  | байт  | байт  | байт  | байт  | байт  |     
 -----------------------------------------------
Примеры слов MIX: `- 12 00 11 01 63', `+ 12 11 34 43 00'.

Вы можете ссылаться на часть слова, используя спецификацию поля (fspec) в виде: "(L:R)", где L обозначает первый байт, а R -- последний байт поля. Когда L равно нулю, поле включает знак слова. Спецификация может также быть представлена одним числом F, вычисляемым как F = 8*L + R (так, спецификация `(1:3)', обозначающая первые три байта слова, представляется числом 11).

Компьютер MIX сохраняет информацию в регистрах, хранящих либо слово, либо два байта и знак (см. ниже), и в ячейках памяти, каждая из которых содержит слово. Если быть точным, компьютер MIX имеет 4000 ячеек памяти с адресами от 0 до 3999 (т.е., для адресации ячейки памяти достаточно двух байтов) и следующие регистры:

rA
Регистр A. Регистр общего назначения, хранящий слово. Обычно его содержимое служит операндом арифметических операций и инструкций сохранения в памяти.
rX
Регистр X. Регистр общего назначения, хранящий слово. Часто выступает как расширение или замена `rA'.
rJ
Регистр J (jump, переход). Этот регистр содержит положительное двухбайтовое значение, обычно представляющее адрес перехода.
rI1, rI2, rI3, rI4, rI5, rI6
Индексные регистры. Эти шесть регистров могут сохранять двухбайтовое значение со знаком. Их содержимое используется как индексирующее значение при вычислении эффективных адресов памяти.

Кроме того, компьютер MIX содержит:

  • Триггер переполнения (один бит со значениями включен и выключен). В настоящем руководстве этот триггер обозначается OV.
  • Индикатор сравнения (имеющий три значения: РАВНО, БОЛЬШЕ и МЕНЬШЕ). В настоящем руководстве этот индикатор обозначается CM, а его возможные значения сокращаются E (equal), G (greater) и L (less).
  • Блочные устройства ввода/вывода. Каждое устройство обозначено un, где n пробегает значения от 0 до 20. В определении Кнута, устройства от u0 до u7 -- носители на магнитной ленте, от u8 до u15 -- диски и барабаны, u16 -- устройство чтения перфокарт, u17 -- устройство записи перфокарт, u18 -- строчный принтер, u19 -- текстовый терминал, и u20 -- перфоленточное устройство. Наша реализация отображает эти устройства в дисковые файлы, кроме u19, представляющего собой стандартный вывод.

Как замечено выше, компьютер MIX взаимодействует с внешним миров с помощью набора устройств ввода/вывода, которые могут быть к нему "подключены". Компьютер обменивается информацией, используя блоки слов, длина которых зависит от устройства (see section 6.3 Блочные устройства MIX). Эти слова интерпретируются устройством либо как двоичная информация (для устройств 0-16), либо как представление печатаемых литер (устройства 17-20). В последнем случае каждый байт MIX отображается в литеру в соответствии со следующей таблицей:

00 01 A 02 B 03 C
04 D 05 E 06 F 07 G
08 H 09 I 10 d 11 J
12 K 13 L 14 M 15 N
16 O 17 P 18 Q 19 R
20 s 21 p 22 S 23 T
24 U 25 V 26 W 27 X
28 Y 29 Z 30 0 31 1
32 2 33 3 34 4 35 5
36 6 37 7 38 8 39 9
40 . 41 , 42 ( 43 )
44 + 45 - 46 * 47 /
48 = 49 $ 50 < 51 >
52 @ 53 ; 54 : 55 '
Значение 0 представляет пробел. Буквы нижнего регистра (d, s, p) в этой таблице обозначают литеры, не представимые как литеры ASCII (соответственно, прописные дельта, сигма и гамма), байтам в диапазоне 56-63 литеры не сопоставлены.

Наконец, компьютер MIX имеет виртуальный центральный процессор, управляющий вышеперечисленными компонентами, который может выполнять богатый набор инструкций (составляющих его машинный язык, похожий на используемые в реальных центральных процессорах), включая арифметические и логические операции, инструкции помещения значения в память, сравнения и перехода. Являясь типичным компьютером фон Неймана, ЦП MIX последовательно (если только не встречается инструкция перехода) извлекает из памяти двоичные инструкции и сохраняет адрес следующей выполняемой инструкции во внутреннем регистре, называемом счётчиком положения (в других архитектурах также известен как программный счётчик).

Следующий раздел, See section 2.1.2 Набор инструкций MIX, даёт полное описание доступных двоичных инструкций MIX.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2 Набор инструкций MIX

В следующих подразделах полностью описан набор инструкций компьютера MIX. Мы начнём с описания структуры двоичной инструкции и используемой для ссылки на её поля нотации. Остальные подразделы посвящены описанию собственно инструкций, которые может использовать программист MIX.

2.1.2.1 Структура инструкции  
2.1.2.2 Команды загрузки  
2.1.2.3 Команды запоминания  
2.1.2.4 Арифметические команды  
2.1.2.5 Команды пересылки адреса  
2.1.2.6 Команды сравнения  
2.1.2.7 Команды перехода  
2.1.2.8 Команды ввода/вывода  
2.1.2.9 Команды преобразования  
2.1.2.10 Команды сдвига  
2.1.2.11 Прочие команды  
2.1.2.12 Временные характеристики  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.1 Структура инструкции

Инструкции MIX кодируются словами со следующей структурой полей:

Поле fspec Описание
ADDRESS (0:2) Первые два байта и знак являются полем адреса. Вместе с полем INDEX они обозначают используемый инструкцией адрес памяти.
INDEX (3:3) Третий байт -- индекс, обычно используемый для модификации адреса(4).
MOD (4:4) Четвёртый байт используется либо как модификатор кода операции, либо как спецификация поля.
OPCODE (5:5) Последний (младший) байт слова определяет код операции.

или, графически,

 
 ------------------------------------------------
|   0   |   1   |   2   |   3   |   4   |   5    |
 ------------------------------------------------
|        ADDRESS        | INDEX |  MOD  | OPCODE |     
 ------------------------------------------------

Для каждой инструкции `M' обозначает адрес памяти, получаемый после модификации поля ADDRESS байтом INDEX, а `V' -- содержимое описываемого байтом MOD поля ячейки памяти с адресом `M'. Например, предположим, что содержимое регистров и ячеек памяти MIX таково:

 
[rI2] = + 00 63
[31] = - 10 11 00 11 22
где `[n]' обозначает содержимое n-й ячейки памяти, а `[rI2]' -- содержимое регистра `rI2'(5). Рассмотрим двоичную инструкцию `I = - 00 32 02 11 10'. Для этой инструкции:

 
ADDRESS = - 00 32 = -32
INDEX = 02 = 2
MOD = 11 = (1:3)
OPCODE = 10

M = ADDRESS + [rI2] = -32 + 63 = 31
V = [M](MOD) = (- 10 11 00 11 22)(1:3) = + 00 00 10 11 00

Обратите внимание, при вычислении `V', используя слово и спецификацию поля, мы применяем к выбранным `MOD' байтам левое заполнение, чтобы получить в качестве результата целое слово.

В следующих подразделах мы присвои каждой инструкции MIX мнемонику или символическое имя. Например, мнемоникой инструкции с `OPCODE' 10 будет `LD2'. Таким образом, вышеприведённую инструкцию можно переписать:

 
LD2  -32,2(1:3)
а в общем случае:

 
MNEMONIC  ADDRESS,INDEX(MOD)
Некоторые инструкции идентифицируются и полем OPCODE, и полем MOD. В этих случаях в символическом представлении MOD будет отсутствовать. Если ADDRESS или INDEX равны нулю, они также могут быть опущены. Наконец, значение MOD по умолчанию составляет (0:5) (означающее всё слово).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.2 Команды загрузки

Для загрузки содержимого памяти в регистр могут использоваться следующие инструкции:

LDA
Поместить в rA содержимое ячейки памяти M. OPCODE = 8, MOD = fspec. rA <- V.
LDX
Поместить в rX содержимое ячейки памяти M. OPCODE = 15, MOD = fspec. rX <- V.
LDi
Поместить в rIi содержимое ячейки памяти M. OPCODE = 8 + i, MOD = fspec. rIi <- V.
LDAN
Поместить в rA содержимое ячейки памяти M с противоположным знаком. OPCODE = 16, MOD = fspec. rA <- -V.
LDXN
Поместить в rX содержимое ячейки памяти M с противоположным знаком. OPCODE = 23, MOD = fspec. rX <- -V.
LDiN
Поместить в rIi содержимое ячейки памяти M с противоположным знаком. OPCODE = 16 + i, MOD = fspec. rIi <- -V.

Во всех вышеперечисленных инструкиях поле `MOD' выбирает байты из ячейки памяти с адресом `M', загружаемые в нужный регистр (указанный `OPCODE'). Например, слово `+ 00 13 01 27 11' представляет собой инструкцию:

 
LD3    13,1(3:3)
 ^      ^ ^  ^
 |      | |  |
 |      | |   --- MOD = 27 = 3*8 + 3
 |      |  --- INDEX = 1
 |       --- ADDRESS = 00 13
  --- OPCODE = 11
Предположим, что перед выполнением этой инструкции компьютер MIX находился в следующем состоянии:

 
[rI1] = - 00 01
[rI3] = + 24 12
[12] = - 01 02 03 04 05
Поскольку, в этом случае `M = 13 + [rI1] = 12',

 
V = [M](3:3) = (- 01 02 03 04 05)(3:3)
  = + 00 00 00 00 03
(имейте в виду, что указанное поле заполняется слева нулевыми байтами до полного слова). Отсюда, состояние MIX после выполнения инструкции будет:

 
[rI1] = - 00 01
[rI3] = + 00 03
[12] = - 01 02 03 04 05

Чтобы ещё проиллюстрировать команды загрузки, приведём таблицу, показывающую содержимое `rX' после различных инструкций `LDX':

`LDX 12(0:0) [rX] = - 00 00 00 00 00'
`LDX 12(0:1) [rX] = - 00 00 00 00 01'
`LDX 12(3:5) [rX] = + 00 00 03 04 05'
`LDX 12(3:4) [rX] = + 00 00 00 03 04'
`LDX 12(0:5) [rX] = - 01 02 03 04 05'


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.3 Команды запоминания

Следующие инструкции обратны операциям загрузки -- они используются для запоминания поля регистра в памяти. Здесь MOD обозначает поле ячейки памяти, которое должно быть перезаписано байтами из регистра. Берутся самые правые байты регистра.

STA
Запомнить rA. OPCODE = 24, MOD = fspec. V <- rA.
STX
Запомнить rX. OPCODE = 31, MOD = fspec. V <- rX.
STi
Запомнить rIi. OPCODE = 24 + i, MOD = fspec. V <- rIi.
STJ
Запомнить rJ. OPCODE = 32, MOD = fspec. V <- rJ.
STZ
Запомнить ноль. OPCODE = 33, MOD = fspec. V <- 0.

Для примера, рассмотрим инструкцию `STA 1200(2:3)'. Она заставит MIX взять байты 4 и 5 регистра A и скопировать и в байты 2 и 3 ячейки памяти 1200 (помните, что в этих инструкциях MOD задаёт поле адреса памяти). Остальные байты ячейки памяти сохраняют своё значение. Так, если до выполнения инструкции:

 
[1200] = - 20 21 22 23 24
[rA] = + 01 02 03 04 05
то в конце концов будет:

 
[1200] = - 20 04 05 23 24
[rA] = + 01 02 03 04 05

Ещё один пример: `ST2 1000(0)' установит знак `[1000]' равным знаку `[rI2]'.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.4 Арифметические команды

Следующие инструкции осуществляют арифметические операции над регистрами rA и rX и содержимым памяти.

ADD
Прибавить и установить OV при переполнении. OPCODE = 1, MOD = fspec. rA <- rA +V.
SUB
Вычесть и установить OV при переполнении. OPCODE = 2, MOD = fspec. rA <- rA - V.
MUL
Умножить V на rA и поместить 10-байтовое произведение в rAX. OPCODE = 3, MOD = fspec. rAX <- rA x V.
DIV
rAX рассматривается как 10-байтовое число и делится на V. OPCODE = 4, MOD = fspec. rA <- rAX / V, rX <- остаток.

Во всех вышеперечисленных инструкциях одним из операндов бинарной арифметической операции является `[rA]', другим -- `V' (заданное поле ячейки памяти с адресом `M'), заполненное нулевыми байтами слева до полного слова. В операциях умножения и деления регистр `X' играет роль правого расширения регистра `A', так что мы можем работать с 10-байтовыми числами, старшие байты которых располагаются в `rA' (знаком 10-байтового числа является знак `rA', знак `rX' игнорируется).

Сложение и вычитание слов MIX может приводить к переполнению, поскольку результат сохраняется в регистре, содержащем только 5 байтов (и знак). Если это происходит, в `rA' помещается результат операции по модулю 1 073 741 823 (максимальное значение, хранимое в слове MIX) и устанавливается триггер переполнения.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.5 Команды пересылки адреса

В этих инструкциях `M' (адрес после модификации) используется как число, а не как адрес ячейки памяти. Соответственно, `M' может иметь любое допустимое для слова значение (т.е. не ограничено диапазонов адресов памяти 0-3999).

ENTA
Загрузить `M' в [rA]. OPCODE = 48, MOD = 2. rA <- M.
ENTX
Загрузить `M' в [rX]. OPCODE = 55, MOD = 2. rX <- M.
ENTi
Загрузить `M' в [rIi]. OPCODE = 48 + i, MOD = 2. rIi <- M.
ENNA
Загрузить `-M' в [rA]. OPCODE = 48, MOD = 3. rA <- -M.
ENNX
Загрузить `-M' в [rX]. OPCODE = 55, MOD = 3. rX <- -M.
ENNi
Загрузить `-M' в [rIi]. OPCODE = 48 + i, MOD = 3. rIi <- -M.
INCA
Увеличить [rA] на `M'. OPCODE = 48, MOD = 0. rA <- rA + M.
INCX
Увеличить [rX] на `M'. OPCODE = 55, MOD = 0. rX <- rX + M.
INCi
Увеличить [rIi] на `M'. OPCODE = 48 + i, MOD = 0. rIi <- rIi + M.
DECA
Уменьшить [rA] на `M'. OPCODE = 48, MOD = 1. rA <- rA - M.
DECX
Уменьшить [rX] на `M'. OPCODE = 55, MOD = 0. rX <- rX - M.
DECi
Уменьшить [rIi] на `M'. OPCODE = 48 + i, MaOD = 0. rIi <- rIi - M.

В вышеперечисленных инструкциях поле `ADDRESS' (модифицированное) играет роль непосредственного операнда, и позволяет напрямую устанавливать содержимое регистров MIX без перенаправления к ячейкам памяти (в реальных процессорах это означает, что они выполняются быстрее, чем обсуждавшиеся ранее инструкции, операнды которых берутся из памяти). Так, если вы хотите поместить в `rA' значение -2000 (- 00 00 00 31 16), вы можете использовать двоичную инструкцию + 31 16 00 03 48, или, символически,

 
ENNA 2000
В сочетании с командами запоминания (`STA', `STX' и т.д.) эти инструкции позволяют устанавливать конкретные значения содержимого ячеек памяти.

Имейте в виду, что в командах пересылки адреса поле `MOD' -- не спецификатор поля, а служит для определения (вместе с `OPCODE') конкретной выполняемой операции.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.6 Команды сравнения

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

Следующие инструкции сравнивают значение регистра с `V' и соответствующим образом устанавливают индикатор CM (т.е., `E', `G' или `L', "равно", "больше" или "меньше" соответственно).

CMPA
Сравнить [rA] с V. OPCODE = 56, MOD = fspec.
CMPX
Сравнить [rX] с V. OPCODE = 63, MOD = fspec.
CMPi
Сравнить [rIi] с V. OPCODE = 56 + i, MOD = fspec.

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


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.7 Команды перехода

Компьютер MIX содержит внутренний регистр, называемый счётчиком положения, сохраняющий адрес следующей инструкции, которая должна быть получена из памяти и обработан виртуальным процессором. Вы не можете напрямую изменять содержимое этого внутреннего регистра инструкцией загрузки: после получения текущей инструкции он автоматически увеличивается на 1 самим MIX. Тем не менее, существует набор инструкций (называемых инструкциями перехода), которые могут изменять содержимое счётчика положения при выполнении некоторого условия. При этом значение адреса инструкции, которая выполнялась бы следующей, если бы не было перехода, помещается в `rJ' (кроме JSJ), а значение счётчика положения устанавливается равным `M' (таким образом, следующая инструкция берётся по этому новому адресу). Позднее вы можете вернуться к отправной точке перехода, читая адрес, сохранённый в `rJ'.

Компьютер MIX имеет следующие инструкции перехода:

Эти инструкции выполняют обязательный переход по указанному адресу. Используйте `JSJ', если адрес возврата вам не нужен.

JMP
Безусловный переход. OPCODE = 39, MOD = 0.
JSJ
Безусловный переход без изменения rJ. OPCODE = 39, MOD = 1.

Эти инструкции для принятия решения о переходе проверяют триггер переполнения.

JOV
Выполнить переход при установленном OV (OV сбрасывается). OPCODE = 39, MOD = 2.
JNOV
Выполнить переход при сброшенном OV (OV остаётся сброшенным). OPCODE = 39, MOD = 3.

В следующих инструкциях переход обусловлен содержимым флага сравнения:

JL
Выполнить переход, если [CM] = L. OPCODE = 39, MOD = 4.
JE
Выполнить переход, если [CM] = E. OPCODE = 39, MOD = 5.
JG
Выполнить переход, если [CM] = G. OPCODE = 39, MOD = 6.
JGE
Выполнить переход, если [CM] не равно L. OPCODE = 39, MOD = 7.
JNE
Выполнить переход, если [CM] не равно E. OPCODE = 39, MOD = 8.
JLE
Выполнить переход, если [CM] не равно G. OPCODE = 39, MOD = 9.

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

JAN
JAZ
JAP
JANN
JANZ
JANP
Выполнить переход, если содержимое rA, соответственно, отрицательно, равно нулю, положитнльно, неотрицательно, не равно нулю или неположительно. OPCODE = 40, MOD = 0, 1, 2, 3, 4, 5.
JXN
JXZ
JXP
JXNN
JXNZ
JXNP
Выполнить переход, если содержимое rX, соответственно, отрицательно, равно нулю, положительно, неотрицательно, не равно нулю или неположительно. OPCODE = 47, MOD = 0, 1, 2, 3, 4, 5.
JiN
JiZ
JiP
JiNN
JiNZ
JiNP
Выполнить переход, если содержимое rIi, соответственно, отрицательно, равно нулю, положительно, неотрицательно, не равно нулю или неположительно. OPCODE = 40 + i, MOD = 0, 1, 2, 3, 4, 5.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.8 Команды ввода/вывода

Как объясняется в предыдущих разделах (see section 2.1.1 Архитектура MIX), компьютер MIX может взаимодействовать с большим количеством блочных устройств. Для этого в вашем распоряжении имеются следующие инструкции:

IN
Пересылает блок слов с указанного устройства в память, начиная с адреса M. OPCODE = 36, MOD = номер устройства.
OUT
Пересылает блок слов из памяти (начиная с адреса M) на указанное устройство. OPCODE = 37, MOD = номер устройства.
IOC
Выполняет управляющую команду (заданную M) к указанному устройству. OPCODE = 35, MOD = номер устройства.
JRED
Выполнить переход по адресу M, если указанное устройство готово к работе. OPCODE = 38, MOD = номер устройства.
JBUS
Выполнить переход по адресу M, если заданное устройство занято. OPCODE = 34, MOD = номер устройства.
Во всех вышеперечисленных инструкциях значение `MOD' должно быть в диапазоне 0-20, поскольку оно обозначает целевое устройство операции. Инструкция `IOC' имеет смысл только для ленточных устройств (`MOD' = 0-7 или 20): она сдвигает маркер чтения/записи на число слов, заданное `M' (если оно равно нулю, лента перематывается на начало)(6).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.9 Команды преобразования

Следующие инструкции осуществляют преобразования между числовыми значениями и их литерными представлениями.

NUM
Преобразует rAX, содержимое которого рассматривается как литерное представляение числа, в его числовое значение и помещает его в rA. OPCODE = 5, MOD = 0.
CHAR
Преобразует число, помещённое в rA, в литерное представление и помещает его в rAX. OPCODE = 5, MOD = 1.
Цифры в MIX представляются диапазоном значений 30-39 (цифры 0-9). Так, если содержимое `rA' и `rX' равно, например,

 
[rA] = + 30 30 31 32 33
[rX] = + 31 35 39 30 34
это представляет число 0012315904, и `NUM' поместит это значение в `rA' (т.е., `[rA]' будет равно + 0 46 62 52 0 = 12315904). `CHAR' осуществляет обратную операцию.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.10 Команды сдвига

Следующие инструкции осуществляют побайтовый сдвиг содержимого `rA' и `rX'.

SLA
SRA
SLAX
SRAX
SLC
SRC
Сдвинуть rA или rAX налево или направо или сдвинуть rAX циклически (см. пример ниже) налево или направо. M задаёт число байтов, на которое проивзодится сдвиг. OPCODE = 6, MOD = 0, 1, 2, 3, 4, 5.
Если, скажем, вначале `[rA]' = - 01 02 03 04 05, при выполнении инструкций сдвига содержимое `rA' будет меняться следующим образом:

SLA 2 [rA] = - 03 04 05 00 00
SRA 1 [rA] = - 00 01 02 03 04
SLC 3 [rA] = - 04 05 01 02 03
SRC 24 [rA] = - 05 01 02 03 04
Имейте в виду, что операции сдвига не влияют на знаки. С другой стороны, `SLAX' и `SRAX' рассматривают `rA' и `rX' как один 10-байтовый регистр (опять-так, игнорируя знаки), поэтому, если вначале `[rA]' = + 01 02 03 04 05 и `[rX]' = - 06 07 08 09 10, выполнение `SLAX 3' даст:

 
[rA] = + 04 05 06 07 08  [rX] = - 09 10 00 00 00


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.11 Прочие команды

Наконец, приведём список трёх остальных инструкций MIX, не описанных в предыдущих подразделах:

MOVE
Переместить MOD слов с адреса M по адресу, хранящемуся в rI1. OPCODE = 7, MOD = число слов.
NOP
Нет операции. OPCODE = 0, MOD = 0.
HLT
Останов. Прекратить разбор инструкций. OPCODE = 5, MOD = 2.
Эффект выполнения `NOP' ограничивается увеличением счётчика положения. `HLT' обычно обозначает завершение выполнения программы.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1.2.12 Временные характеристики

При написании программ на MIXAL (или любых других программ) нас часто интересует время их выполнения. Приблизительно, нас интересует ответ на вопрос: как долго будет выполняться программа? Конечно, это время выполнения является функцией от объёма входных данных, и ответ на наш вопрос обычно даётся в виде асимптотического поведения функции от объёма входных данных. В любом случае, для вычисления асимпотического приближения нам нужна мера времени выполнения одной инструкции на нашем (виртуальном) процессоре. Поэтому с каждой инструкцией MIX связано время выполнения, заданное в относительных единицах (в реальных компьютерах значение этой единицы зависит от аппаратной конфигурации). Когда наша виртуальная машина MIX выполняет программы, она может (по желанию) выводить значение времени выполнения на основе времени выполнения каждой отдельной инструкции.

В следующей таблице приведены значения времени выполнения (в вышеупомянутых относительных единицах) инструкций MIX.

NOP 1 ADD 2 SUB 2 MUL 10
DIV 12 NUM 10 CHAR 10 HLT 10
SLx 2 SRx 2 LDx 2 STx 2
JBUS 1 IOC 1 IN 1 OUT 1
JRED 1 Jx 1 INCx 1 DECx 1
ENTx 1 ENNx 1 CMPx 1 MOVE 1+2F

В таблице 'F' обозначает число перемещаемых блоков (заданное полем FSPEC инструкции), SLx и SRx -- сокращения для операций побайтового сдвига, LDx обозначает все операции загрузки, STx -- все операции запоминания, Jx обозначает все операции перехода, и т.д. для остальный сокращений.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2 MIXAL

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

В этом разделе мы опишем MIXAL, язык ассемблера MIX. Реализации ассемблера MIX и эмулятора компьютера MIX, входящие в состав MDK, описаны позднее (see section 3. Начало работы).

2.2.1 Базовая структура программы  Написание базовых программ на MIXAL.
2.2.2 Директивы MIXAL  Директивы ассемблера.
2.2.3 Выражения  
2.2.4 W-выражения  Вычисление w-выражений.
2.2.5 Локальные символы  
2.2.6 Литеральные константы  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.1 Базовая структура программы

Ассемблер MIX читает файлы MIXAL построчно, создавая, при необходимости, двоичную инструкцию, связанную с определённым адресом в памяти. Чтобы следить за текущим адресом, ассемблер поддерживает внутренний счётчик положения, увеличиваемый при каждой компиляции инструкции. Кроме инструкция MIX в файл MIXAL можно включать директивы ассемблера (или псевдоинструкции), предназначенные для самого ассемблера (например, указывающие, где начинается и заканчивается программа, или переопределяющие счётчик положения, см. ниже).

Инструкции MIX и директивы ассемблера(7) записываются на MIXAL (одна на строку исходного файла) в соответствии со следующим шаблоном:

 
[LABEL]   MNEMONIC  [OPERAND]   [COMMENT]

где `ОПЕРАНД' имеет вид:

 
[ADDRESS][,INDEX][(MOD)]

Элементы, заключённые в круглые скобки могут отсутствовать.

LABEL
-- алфавитно-цифровой идентификатор (символ), получающий текущее значений счётчика положения, и может быть использован в последующих выражениях,
MNEMONIC
-- литерал, обозначающий код операции инструкции (например, LDA, STA, see section 2.1.2 Набор инструкций MIX) или псевдоинструкцию ассемблера (например, ORIG, EQU),
ADDRESS
-- выражение, описывающее поле адреса инструкции,
INDEX
-- выражение, описывающее поле индекса инструкции, по умолчанию 0 (т.е. индекс не используется). Может использоваться только если присутствует ADDRESS,
MOD
-- выражение, описывающее поле модификатора инструкции. Значение по умолчанию, если выражение опущено, зависит от OPCODE,
COMMENT
любое количество пробелов после операнда обозначает начало комментария, т.е. любой текст, отделённый пробелами от операнда ассемблером игнорируется (имейте в виду, что пробелы внутри поля `OPERAND' недопустимы).

Обратите внимание, что между полями ADDRESS, INDEX и MOD, если они присутствуют, пробелы недопустимы. Для разделения метки, кода операции и операнда в инструкции используются пробелы(8).

Мы уже перечислили мнемоники, сопоставленные каждой инструкции MIX. Приведём пример инструкций MIXAL, представляющих инструкции MIX:

 
HERE     LDA  2000         HERE представляет текущий счётчик положения
         LDX  HERE,2(1:3)  это комментарий
         JMP  1234


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.2 Директивы MIXAL

Инструкция MIXAL может быть либо одной из машинных инструкций MIX (see section 2.1.2 Набор инструкций MIX), либо одной из следующих псевдоинструкций ассемблера:

ORIG
Устанавливает значение адреса памяти, по которому будет расположена после компиляции следующая инструкция.
EQU
Используется для определения значения символа, например, SYM EQU 2*200/3.
CON
Значение заданного выражения непосредственно копируется в память по текущему адресу.
ALF
Принимает в качестве операнда пять литер, составляющих пять байтов слова, которое непосредственно копирует в память по текущему адресу.
END
Обозначает конец программы. Операнд этой инструкции содержит адрес, с которого начинается выполнение программы.

Операндом ORIG, EQU, CON и END может быть любое выражение, задающее слово MIX-константу, т.е. либо простое выражение MIXAL (состоящее из чисел, символов и бинарных операций, see section 2.2.3 Выражения), либо w-выражение (see section 2.2.4 W-выражения).

Любая программа на MIXAL должна содержать директиву END с двоякой целью: во-первых, она обозначает точку прекращения работы ассемблера, и во-вторых, её (обязательный) операнд указывает начальный адрес скомпилированной программы (адрес, по которому виртуальная машина MIX должна начать разбор инструкций после загрузки программы). Также является обычной практикой (хотя и не обязательно) включать в программу по крайней мере одну директиву ORIG, чтобы обозначить начальное значение счётчика положения ассемблера (помните, что он содержит адрес, связанные с каждой скомпилированной инструкцией MIX). Таким образом, минимальной программой на MIXAL будет:

 
          ORIG  2000    установить начальный адрес компиляции
          NOP           эта инструкция будет загружена по адресу 2000
          HLT           а эта по адресу 2001
          END   2000    конец программы, начало по адресу 2000
эта строка не анализируется ассемблером
Ассемблер создаст две двоичные инструкции (NOP (+ 00 00 00 00 00) и HLT (+ 00 00 02 05)), которые будут загружены по адресам 2000 и 2001. Выполнение программы начнётся с адреса 2000. Каждая программа на MIXAL должна также содержать инструкцию HLT, которая означает конец выполнения программы (но не компиляции программы).

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

 
START     EQU   2000
          ORIG  START
          NOP
          HLT
          END   START
что даст тот же самый скомпилированный код. Символические константы (или, коротко, символы) могут определяться неявно, если их поместить в поле LABEL инструкции MIXAL. В этом случае перед компиляцией строки ассемблер присвоит символу значение счётчика положения. Поэтому третий способ записи нашей тривиальной программы:

 
          ORIG  2000
START     NOP
          HLT
          END   START

Директива CON позволяет непосредственно задавать содержимое, находящееся в памяти по адресу, указанному счётчиком положения. Например, если ассемблер встретит следующий участок кода:

 
          ORIG  1150
          CON   -1823473
он поместит в ячейку памяти 1150 значение - 00 06 61 11 49 (соответствующее десятичному значению -1823473).

Наконец, директива ALF позволяет задавать содержимое памяти как набор пяти литер (в кавычках), которые транслируются ассемблером в соответствующие значения байтов, создавая, таким образом, двоичное слово, размещаемое в соответствующей ячейке памяти. Эта директива полезна, если вам нужно поместить по адресу памяти сообщения для печати, как в следующем примере:

 
          OUT  MSG       MSG здесь ещё не определено (ссылка вперёд)
MSG       ALF  "THIS "   MSG определяется здесь
          ALF  "IS A "
          ALF  "MESSA"
          ALF  "GE.  "
Этот участок кода также показывает использование ссылок вперёд, что означает использование символа (в этом примере MSG) до его реального определения. Ассемблер MIXAL может обрабатывать ссылки вперёд с некоторыми ограничениями, описанными в следующем разделе (see section 2.2.3 Выражения).

Любая строка, начинающаяся со звёздочки, считается комментарием и игнорируется ассемблером.

 
* Это комментарий: эта строка игнорируется.
    * Это ошибка: * должна быть в первой колонке.

Как показано в предыдущем разделе, комментарии могут также быть расположены после поля OPERAND инструкции, отделённые от него пробелами:

 
LABEL     LDA   100  Это также комментарий


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.3 Выражения

Поля ADDRESS, INDEX и MOD инструкции MIXAL могут быть выражениями, состоящими из чисел, идентификаторов и знаков бинарных операций (+ - * / // :). + и - могут также использоваться как знаки унарных операций. Операторы выполняются слева направо, других правил приоритета операторов нет, и использовать скобки для группировки нельзя. Отдельная звёздочка обозначает текущее положение в памяти. Так, например:

 
     4+2**

обозначает 6 (4+2), умноженное на текущее положение в памяти. Пробелы внути выражений не допускаются.

Специальная бинарная операция : имеет то же значения, что и в спецификациях полей, т.е.

 
A:B = 8*A + B
в то время как A//B обозначает деление 10-байтового числа A 00 00 00 00 00 (A, дополненное справа пятью нулевыми байтами, или, что то же самое, умноженное на 64 в пятой степени), разделённое на B. Примеры выражений:

 
18-8*3 = 30
14/3 = 4
1+3:11 = 4:11 = 43
1//64 = (01 00 00 00 00 00)/(00 00 00 01 00) = (01 00 00 00 00)
Имейте в виду, что любое выражение MIXAL вычисляет слово MIX (по определению).

Все символы, встречающиеся в выражениях, должны бы предварительно определены. Ссылки вперёд допускаются только если встречаются отдельно (или с унарной операцией) в части ADDRESS инструкции MIXAL, например:

 
* OK: отдельная ссылка вперёд 
         STA  -S1(1:5)
* ERROR: ссылка вперёд в выражении
         LDX  2-S1
S1       LD1  2000


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.4 W-выражения

Помимо описанных выше (see section 2.2.3 Выражения) выражений, ассемблер MIXAL может обрабатывать в качестве операндов директив ORIG, EQU, CON и END (see section 2.2.2 Директивы MIXAL) так называемые w-выражения. Общий вид w-выражения таков:

 
     WEXP = EXP[(EXP)][,WEXP]
где EXP обозначает выражение, а квадратные скобки отмечают необязательные элементы. Таким образом, w-выражение состоит из выражения, за которым следует необязательное выражение в круглых скобках, а затем любое число аналогичных конструкций, разделённых запятыми. Примеры w-выражений:

 
2000
235(3)
S1+3(S2),3000
S1,S2(3:5),23

W-выражения вычисляются слева направо следующим образом:

  • Вначале общему результату `w' присвоить значение 0.
  • Взять первое выражение разделённого запятыми списка и вычислить его. Например, при вычислении w-выражения `S1+2(2:4),2000(S2)', в первую очередь вычисляется `S1+2'. Пусть `S1' равно 265230, тогда `S1+2 = 265232 = + 00 01 00 48 16'.
  • Вычислить выражение в круглых скобках, сводя его к спецификации поля вида `L:R'. В нашем предыдущем примере выражение в круглых скобках уже имеет нужный вид: 2:4.
  • Подставить вместо байтов общего результата `w', обозначенных спецификацией поля, байты из значения предыдущего выражения. В нашем примере `w = + 00 00 00 00 00', и мы должны подставить вместо второго, третьего и четвёртого байтов байты из 265232. Мы берём три младших байта: 00 48 и 16 и ставим их во вторую, третью и четвёртую позиции `w', получая `w = + 00 00 48 16 00'.
  • Повторить эту операцию для остальных выражений, работая в новым значением `w'. В нашем примере, если, скажем `S2 = 1:1', мы должны подставить вместо первого байта `w' младший байт 2000, т.е. 16 (поскольку 2000 = + 00 00 00 31 16), и поэтому мы получим `265232(1:4),2000(1:1) = + 16 00 48 16 00 = 268633088'.

Ещё один пример -- в w-выражении

 
1(1:2),66(4:5)
мы сначала возьмём два младших байта 1 (00 и 01) и поместим их в первую и вторую позицию результата (получая `+ 00 01 00 00 00'), а потом возьмем два байта из 66 (01 и 02) и поместим их в четвёртую и пятую позиции результата, получая `+ 00 01 00 01 02' (262210). Процесс повторяется для каждого нового разделённого запятыми примера. Например,

 
1(1:1),2(2:2),3(3:3),4(4:4) = 01 02 03 04 00

Как указано выше, w-выражения могут встречаться только в операндах директив MIXAL, принимающих константное значений (ORIG, EQU, CON и END). Ссылки вперёд в w-выражениях не допускаются (т.е., все символы, встречающиеся в w-выражении должны быть определены до их использования).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.5 Локальные символы

Помимо определённых пользователем символов, программисты на MIXAL могут использовать так называемые локальные символы, т.е. символы вида [1-9][HBF]. Локальный символ nB ссылается на адрес, где в последний раз в качестве метки служило nH, а nF -- на следующее появление nH. В отличие от определённых пользователем символов, nH может встречаться в части LABEL различных инструкций MIXAL сколько угодно раз. Следующий код даёт пример использования локальных символов:

 
* строка 1
1H    LDA  100
* строка 2: 1B ссылается на адрес строки 1, 3F ссылается на адрес строки 4
      STA  3F,2(1B//2)
* строка 3: переопределение 1H
1H    STZ
* строка 4: 1B ссылается на адрес строки 3
3H    JMP  1B

Имейте в виду, что локальный символ B никогда не ссылается на определение его собственной строки. Так, в следующей программе:

 
               ORIG 1999
ST              NOP
3H              EQU 69
3H              ENTA 3B локальный символ 3B ссылается на 3H в предыдущей строке
                HLT
                END ST
содержимым `rA' будет 69, а не 2001. При использовании локальных символов в сочетании и псевдоинструкцией ORIG существует особый трюк. Рассмотрим(9):

 
               ORIG 1999 
ST              NOP
3H              CON 10
                ENT1 *
                LDA 3B
** rI1 = 2001, rA = 10. До сих пор всё нормально!
3H              ORIG 3B+1000
** в этой точке 3H равно 2003
** а счётчик положений равен 3000.
                ENT2 *
                LDX 3B
** rI2 содержит 3000, rX содержит 2003.
                HLT
                END ST


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.6 Литеральные константы

MIXAL допускает введение литеральных констант, которые автоматически помещаются ассемблером в память по адресам после конца программы. Литеральные константы обозначаются =wexp=, где wexp -- w-выражение (see section 2.2.4 W-выражения). Например, код:

 
L         EQU   5
          LDA   =20-L=

вынуждает ассемблер добавить после конца программы инструкцию, содержащую 15 (`20-L') и ассемблировать вышеприведённый код как инструкцию LDA a, где a обозначает адрес, по которому помещается значение 15. Другими словами, скомпилированный код эквивалентен следующему:

 
L         EQU  5
          LDA  a
...
a         CON  20-L    
          END  start


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated on June, 9 2003 using texi2html