Архитектура процессоров семейства Кронос

Скачать PDF Скачать PDF


               - Сибирское отделение  АН СССР -

               - Институт систем информатики -


:::::      ::::
:::::      ::::
 :::      :::
 :::     ::
 :::    ::
 ::: : :        ::::::       :::    :::   :::    :::       :::
 :::    ::      ::    ::   ::: :::  :::   :::  ::: :::   ::: :::
 :::     :::    ::     :: ::     ::  ::   ::  ::     :: ::
 :::      :::   ::     :: ::     ::  :::::::  ::     :: ::
:::::      :::: :::  :::   ::: :::  :::   :::  ::: :::   ::: :::
:::::      :::: ::::::       :::    :::   :::    :::       :::
                ::
                ::
                ::  АРХИТЕКТУРА ПРОЦЕССОРОВ СЕМЕЙСТВА КРОНОС

                         Новосибирск - 90

                          СОДЕРЖАНИЕ

Введение . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Часть I. Виртуальная Модула-2 машина . . . . . . . . . . . . 6
  1. Составные части виртуальной машины  . . . . . . . . . . 6
     1.1. Процессор  . . . . . . . . . . . . . . . . . . . . 6
     1.2. Арифметический стек. . . . . . . . . . . . . . . . 7
     1.3. Процесс и его дескриптор . . . . . . . . . . . . . 7
     1.4. Память . . . . . . . . . . . . . . . . . . . . . . 8
  2. Структуры в памяти  . . . . . . . . . . . . . . . . . . 8
     2.1. Модуль, готовый к исполнению . . . . . . . . . . . 8
     2.2. Сегмент кода и процедурная таблица . . . . . . . . 9
     2.3. Область глобальных данных  . . . . . . . . . . . . 9
     2.4. Строковый пул  . . . . . . . . . . . . . . . . . .10
     2.5. Область связей . . . . . . . . . . . . . . . . . .10
     2.6. Процедурный стек . . . . . . . . . . . . . . . . .11
          2.6.1. Область локальных данных. . . . . . . . . .12
     2.7. Еще раз о дескрипторе процесса . . . . . . . . . .13
  3. М-код . . . . . . . . . . . . . . . . . . . . . . . . .13
     3.1. Способы адресации. . . . . . . . . . . . . . . . .13
     3.2. Непосредственные операнды. . . . . . . . . . . . .14
     3.3. Функции и назначение команд. . . . . . . . . . . .15
  4. Прерывания  . . . . . . . . . . . . . . . . . . . . . .16
     4.1. Типы прерываний  . . . . . . . . . . . . . . . . .16
     4.2. Вектора прерываний . . . . . . . . . . . . . . . .17
     4.3. Пространство векторов прерываний . . . . . . . . .17
     4.4. Маска прерываний . . . . . . . . . . . . . . . . .17
Часть II. Интерпретатор M-кода . . . . . . . . . . . . . . .18
Часть III. Описание системы команд  . . . . . . . . . . . . 32
		LI0..LI0F      	00h..0Fh	34
		LIB            	10h	  	34
		LID            	11h	  	34
		LIW            	12h	  	34
		LIN            	13h	  	35
		LLA            	14h	  	35
		LGA            	15h	  	35
		LSA            	16h	  	36
		LEA            	17h	  	36
		JFLC          	18h	 	37
		JFL            	19h	  	37
		JFSC          	1Ah	 	37
		JFS            	1Bh	  	37
		JBLC          	1Ch	 	38
		JBL            	1Dh	  	38
		JBSC          	1Eh	 	38
		JBS            	1Fh	  	38
		LLW            	20h	  	39
		LGW            	21h	  	39
		LEW            	22h	  	39
		LSW            	23h	  	40
		LLW4..LLW0F   	24h..2Fh  	40
		SLW            	30h	  	40
		SGW            	31h	  	41
		SEW            	32h	  	41
		SSW            	33h	  	41
		SLW4..SLW0F   	34h..3Fh  	41
		LXB            	40h	  	42
		LXW            	41h	  	42
		LGW2..LGW0F   	42h..4Fh  	42
		SXB            	50h	  	42
		SXW            	51h	  	43
		SGW2..SGW0F   	52h..5Fh  	43
		LSW0..LSW0F   	60h..6Fh  	43
		SSW0..SSW0F   	70h..7Fh  	44
		QUIT          	81h	 	44
		GETM          	82h	 	44
		SETM          	83h	 	44
		TRAP          	84h	 	45
		TRA            	85h	  	45
		TR            	86h		45
		IDLE          	87h	 	46
		ADD            	88h	  	46
		SUB            	89h	  	46
		MUL            	8Ah	  	47
		DIV            	8Bh	  	47
		SHL            	8Ch	  	47
		SHR            	8Dh	  	48
		ROL            	8Eh	  	48
		ROR            	8Fh	  	48
		IO0..IO4       	90h..94h	49
		ARRCMP      	95h		49
		WM            	96h		50
		BM            	97h		50
		FADD          	98h	 	51
		FSUB          	99h	 	51
		FMUL          	9Ah	 	51
		FDIV          	9Bh	 	52
		FCMP          	9Ch	 	52
		FABS          	9Dh	 	53
		FNEG          	9Eh	 	53
		FFCT          	9Fh	 	53
		LSS            	0A0h	 	54
		LEQ            	0A1h	 	54
		GTR            	0A2h	 	54
		GEQ            	0A3h	 	55
		EQU            	0A4h	 	55
		NEQ            	0A5h	 	55
		ABS            	0A6h	 	55
		NEG            	0A7h	 	56
		OR            	0A8h	  	56
		AND            	0A9h	 	56
		XOR            	0AAh	 	57
		BIC            	0ABh	 	57
		IN            	0ACh	  	58
		BIT            	0ADh	 	58
		NOT            	0AEh	 	59
		MOD            	0AFh	 	59
		DECS          	0B0h		59
		DROP          	0B1h		59
		LODFV        	0B2h		60
		STORE        	0B3h		60
		STOFV        	0B4h		60
		COPT          	0B5h		61
		CPCOP        	0B6h		61
		PCOP          	0B7h		62
		FOR1          	0B8h		62
		FOR2          	0B9h		63
		ENTC          	0BAh		63
		XIT            	0BBh	 	65
		ADDPC        	0BCh		65
		JMP            	0BDh	 	65
		ORJP          	0BEh		65
		ANDJP        	0BFh		66
		MOVE          	0C0h		66
		CHKNIL      	0C1h		67
		LSTA          	0C2h		67
		COMP          	0C3h		67
		GB            	0C4h	  	68
		GB1            	0C5h	 	68
		CHK            	0C6h	 	68
		CHKZ          	0C7h		68
		ALLOC        	0C8h		69
		ENTR          	0C9h		69
		RTN            	0CAh	 	70
		NOP            	0CBh	 	70
		CX            	0CCh	  	70
		CI            	0CDh	  	71
		CF            	0CEh	  	71
		CL            	0CFh	  	72
		CL0..CL0F      	0D0h..0DFh 	72
		INCL          	0E0h		73
		EXCL          	0E1h		73
		INL            	0E2h	 	73
		QUOT          	0E3h		73
		INC1          	0E4h		74
		DEC1          	0E5h		74
		INC            	0E6h	 	75
		DEC            	0E7h	 	75
		STOT          	0E8h		75
		LODT          	0E9h		76
		LXA            	0EAh	 	76
		LPC            	0EBh	 	76
		BBU            	0ECh	 	76
		BBP            	0EDh	 	77
		BBLT          	0EEh		77
		PDX            	0EFh	 	78
		SWAP          	0F0h		78
		LPA            	0F1h	 	79
		LPW            	0F2h	 	79
		SPW            	0F3h	 	79
		SSWU          	0F4h		79
		RCHK          	0F5h		80
		RCHZ          	0F6h		80
		CM            	0F7h	  	80
		CHKBX        	0F8h		81
		BMG            	0F9h	 	81
		ACTIV        	0FAh		85
		USR            	0FBh	 	85
		SYS            	0FCh	 	86
		NII            	0FDh	 	86
		INVLD        	0FFh		86
Часть IV. Иллюстрации к архитектуре процессоров . . . . . . 87
1. Операторы  . . . . . . . . . . . . . . . . . . . . . . . 88
   1.1. Присваивание  . . . . . . . . . . . . . . . . . . . 88
   1.2. Доступ к глобальным переменным  . . . . . . . . . . 88
   1.3. Доступ к внешним переменным . . . . . . . . . . . . 89
   1.4. Условный оператор (IF) . . . . . . . . . . . . . . .89
   1.5. Оператор цикла (LOOP) . . . . . . . . . . . . . . . 89
   1.6. Оператор цикла (REPEAT) . . . . . . . . . . . . . . 90
   1.7. Оператор цикла (FOR) . . . . . . . . . . . . . . . .91
   1.8. Оператор выбора (CASE) . . . . . . . . . . . . . . .92
2. Процедуры  . . . . . . . . . . . . . . . . . . . . . . . 93
   2.1. Описание и вызов примитивной процедуры  . . . . . . 93
   2.2. Работа с локалами процедуры . . . . . . . . . . . . 94
   2.3. Вложенные процедуры . . . . . . . . . . . . . . . . 94
   2.4. Вызов внешней процедуры . . . . . . . . . . . . . . 95
   2.5. Размещение мультизначений . . . . . . . . . . . . . 96
   2.6. Работа с процедурными значениями . . . . . . . . .  97
   2.7. Передача параметров . . . . . . . . . . . . . . . . 98
   2.8. Вызов функции (на непустом стеке)  . . . . . . . . 100
3. Выражения . . . . . . . . . . . . . . . . . . . . . . . 101
   3.1. Индексация словных массивов . . . . . . . . . . . .101
   3.2. Индексация байтовых массивов  . . . . . . . . . . .101
   3.3. Индексация байтовых массивов с контролем границ  . 102
   3.4. Проверка принадлежности диапазону . . . . . . . . .103
   3.5. Работа с объектами типа BITSET. . . . . . . . . . .103
   3.6. Команды ANDJP и ORJP . . . . . . . . . . . . . . . 103
Индекс-таблица системы команд. . . . . . . . . . . . . . . 104


                           ВВЕДЕНИЕ


     Архитектура процессоров семейства КРОНОС ориентирована на
поддержку  языков  высокого  уровня  (Си,  Модула-2,  Паскаль,
Оккам),  что дает возможность реализовать новейшие концепции в
области  использования  ЭВМ.  Наличие  32-разрядного машинного
слова  позволяет использовать процессоры семейства для решения
вычислительных  задач.  Широкое  адресное  пространство  (до 2
миллиардов  слов) дает возможность создания виртуальной памяти
для  объектно-ориентированных  моделей  вычислений и тем самым
поддерживает   разработку  систем  искусственного  интеллекта.
Наличие  механизма  прерываний  по  событиям, по синхронизации
процессов,  а  также  компактность  кода  программ позволяет с
уверенностью утверждать, что процессоры семейства КРОНОС могут
успешно применяться в системах реального времени.
     Любой  процессор  семейства  может быть использован как в
составе отдельной ЭВМ, так и в мультипроцессорных комплексах.

     В настоящее время семейство включает три разработки: 2.2,
2.5,   2.6.  У  всех  процессоров  одна  система  команд;  они
полностью   совместимы   программно   и  различаются  лишь  по
внутреннему   функциональному   устройству,  быстродействию  и
конструктивному исполнению.
     Логику  функционирования всех блоков процессора реализует
блок  микропрограммного управления. Две шины данных объединяют
арифметико-логическое   устройство,  блок  регистров,  быстрый
аппаратный  стек  на  7  слов,  устройства  выборки  команд  и
ввода/вывода.
     Двухшинная  внутренняя  структура  процессоров  позволяет
выполнять  бинарные  операции  на  стеке (сложение, вычитание,
логические И, ИЛИ и т.д.) за один такт. Таким образом, за один
такт  исполняется  большинство  команд,  что отвечает основным
идеям  RISC-архитектуры.  Микропрограммное управление упрощает
устройство  процессоров и дает возможность реализовать сложные
команды типа вызова процедуры.
     Все  узлы  процессоров  выполнены на советских ТТЛ и ТТЛШ
микросхемах  широкого  применения  серий 155, 531, 1802, 1804,
589, 556.

--------------------------------------------------------------
Процессор       |  Кронос 2.2   |  Кронос 2.5   |   Кронос 2.6
--------------------------------------------------------------
                |               |               |
Конструктив     | Электроника-60|    Intel      | Евромеханика
                |               |               |
Количество плат |       1       |       2       |      22
                |               |               |
Шина            |    Q-bus 22   |   Multibus-1  |  локальная3
                |               |               |
Ширина          |               |               |
микрокоманды,   |               |               |
бит             |       56      |      64       |       64
                |               |               |
Объем           |               |               |
микропрограмм,  |               |               |
Кслов           |        2      |       2       |        4
                |               |               |
Прямо адресуемая|               |               |
память          |     4 Мбайт   |  2,5 Мбайт1   |    8 Гбайт
                |               |               |
Тактовая        |               |               |
частота, мГц    |       4       |       3       |        3
                |               |               |
Число простых   |               |               |
операций над    |               |               |
стеком, млн/сек |      0,6      |       1       |       1,5
                |               |               |
--------------------------------------------------------------

1) Существенным  отличием  Кронос 2.5 является наличие локальной
памяти  объемом  0,5-2  Мбайт  -  в зависимости от применяемых
микросхем. Остальная память - на шине Multibus-1 (до 1 Мбайт).
2) В  минимальный комплект входят:  плата обрабатывающего тракта
(АЛУ,  стек,  регистры),  плата  микропрограммного управления,
плата  локальной  памяти  (0.5-2  Мбайт),  плата адаптера шины
ввода/вывода.
3) Все  устройства  объединены локальной синхронной 32-разрядной
шиной.   Сам   процессор   не   зависит   от  конкретной  шины
ввода/вывода.  Настройка  на  конкретную  шину  производится с
помощью соответствующего адаптера. К локальной шине могут быть
добавлены   платы   памяти,  адаптера  межпроцессорной  связи,
контроллера к локальной сети и накопителя на магнитных дисках,
плата  памяти  кода  (при  разделении  плат  кода  и  данных),
bitmap-дисплея и т.д..


            ЧАСТЬ I. ВИРТУАЛЬНАЯ  МОДУЛА-2  МАШИНА


     Виртуальная  Модула-2  машина  (ВМ2М)  и ее программный и
аппаратный   интерпретаторы  обеспечивают  процесс  исполнения
программ.   В  данном  разделе  будет  охарактеризован  M-код,
пояснена   его  интерпретация  и  проиллюстрированы  отдельные
команды.
     Механизм ввода/вывода существенно зависит от конфигурации
конкретного оборудования и здесь не рассматривается.
     Основные отличия ВМ2М от традиционных машин:
     1)   вычисление  выражений  на  быстром  стеке  небольшой
аппаратно  фиксированной  глубины.  Освобождение  этого  стека
(копирование  в память) при вызове процедур-функций;
     2)  разделение  кода  и  области  данных любого процесса,
следствием  чего  является повторно-входимость всех программ и
даже их отдельных частей (модулей);
     3) отказ от абсолютной адресации в сегменте кода. Наличие
таблицы смещений начал процедур упрощает вызовы процедур;
     4)  развитые  виды адресации отражают понятия современных
языков    программирования.   Имеется   адресация   локальных,
глобальных,  внешних  объектов и объектов статически вложенных
процедур;
     5)   специальные   команды  упрощают  реализацию  циклов,
вызовов, выбирающих операторов и других сложных конструкций;
     6)   таблица   раздельно  загруженных  модулей  позволяет
организовать динамическое связывание и загрузку программ;
     7) имеются команды для работы с мультизначениями.

     Для понимания этого раздела требуется знакомство с языком
программирования   Модула-2.   В   дальнейшем  считается,  что
читатель знаком со следующими понятиями Модулы-2:
     ПРОГРАММА
     МОДУЛЬ
     ИМПОРТ-ЭКСПОРТ ОБ'ЕКТОВ
     ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ
     ПРОЦЕДУРА
     ЛОКАЛЬНАЯ ПРОЦЕДУРА
     ЛОКАЛЬНЫЕ ПЕРЕМЕННЫЕ


     1. Составные части виртуальной машины

     ВМ2М   состоит   из   процессора,   стека   для  хранения
обрабатываемых  данных и вычисления выражений (арифметического
стека), дескриптора исполняемого процесса и памяти.


     1.1. Процессор

     Процессор   ВМ2М    -    устройство   для   интерпретации
инструкций управления (М-кода).


     1.2. Арифметический стек

     А-стек  (арифметический  стек, стек выражений, expression
stack)  -  быстрый  стек  небольшой,  аппаратно  фиксированной
глубины, шириной в одно слово (здесь и далее: ширина машинного
слова  32  бита),  над  которым  определены операции помещения
слова  на  стек  (Push)  и  снятия  слова  с верхушки стека со
счеркиванием    (Pop).   Переполнение   и   исчерпание   стека
отслеживаются   аппаратно   с   возбуждением  соответствующего
прерывания.

                        |-----------|  \
                        |-----------|   |
                        |-----------|   |
                        |-----------|   |
                        |-----------|   | 7 слов
                        |-----------|   |
                        |-----------|   |
                        |___________|  /
                         <-1 слово->

     Рис.1. А-стек (стек выражений)


     1.3. Процесс и его дескриптор

     В каждый момент времени ВМ2М выполняет некоторый процесс.
Процесс  -  это  последовательность  операций  при  выполнении
программы и данные, используемые этими операциями.
     Дескриптор  процесса  -   8  слов  в  памяти,  содержащих
указатели на специальные информационные структуры, связанные с
процессом.   Эти  указатели  в  совокупности  определяют  весь
контекст  процесса,  т.е.  всю информацию, необходимую для его
исполнения  виртуальной  машиной.


--------------------------------------------------------------
      | RFE |  T  |  H  |  S  |  M  | PC  |  L  |  G  |
--------------------------------------------------------------
      |<----------------- 8 слов -------------------->|

     Рис.2. Дескриптор процесса

     В  терминах  Модулы-2  дескриптор  процесса  представляет
собой запись:
TYPE Process_Descriptor = RECORD
                            G, L, PC, M, S, H, T, RFE: WORD;
                          END;

     Каждое из полей дескриптора имеет специальное назначение,
описанное  ниже.  В  дальнейшем  поля дескриптора процесса для
удобства изложения называются регистрами процессора (например,
"Process_Descriptor.G" будем называть "G-регистр").
     Примечание.   Существующие  реализации  ВМ2М  (процессоры
семейства   КРОНОС)   действительно  имеют  специализированные
регистры,  во  время  работы  содержащие копии соответствующих
полей   дескриптора   текущего   процесса.   При  переключении
процессов  текущее  содержимое  этих  регистров  копируется  в
память по адресу, содержащемуся в P-регистре.


     1.4. Память

     Память в ВМ2М представляется линейной последовательностью
слов    размером    32   бита.   Каждому   слову   сопоставлен
тридцатиодноразрядный  номер  - адрес слова. Адресуется только
все слово целиком. Адреса бывают только положительные.


          адрес: 0FFFFF               адрес: 1        адрес: 0
       _______________        _______________________________
 .... | 3 | 2 | 1 | 0 | .... | 3 | 2 | 1 | 0 | 3 | 2 | 1 | 0 |
       ---------------        -------------------------------
                      1 байт |   |           |<-- 1 слово--->|
                      ------>|   |<-


     Рис.3. Память ВМ2М.


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



     2. Структуры в памяти

Во  время  работы ВМ2М в памяти размещены некоторые структуры,
устройство и взаимодействие которых описаны в этом разделе.


     2.1. Модуль, готовый к исполнению

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



     2.2. Сегмент кода и процедурная таблица

     Сегмент  кода  занимает  непрерывный кусок памяти и имеет
следующую  структуру.  В начале сегмента находится процедурная
таблица,   занимающая   до   256   слов.  Процедурная  таблица
устанавливает  соответствие между номером процедуры и байтовым
смещением  от  начала  сегмента до начала кода соответствующей
процедуры  (в  нулевом слове - смещение 0-й процедуры, в n-м -
смещение  n-й). Внутри модуля процедура идентифицируется своим
номером  в  процедурной  таблице  модуля. При исполнении любой
процедуры  модуля указатель на начало сегмента кода содержится
в  F-регистре  процессора.  В  другом  регистре - PC (Programm
Counter)- содержится байтовое смещение от начала сегмента кода
до байта, содержащего следующую за исполняемой в данный момент
команду.


                                  сюда указывает F-регистр
                                  _________________________
                                                           \
       код процедур          процедурная таблица            V
-------------------------|------------------------------------
 |  ...   |  |  |  |  |  |   ...    | смещ. 1   | смещ. 0   |
-------------------------|------------------------------------
         1 байт |  |                |<-1 слово->|           ^
         ------>|  |<-                                      |
                                                            |
                                       начало сегмента кода_|


     Рис.4. Сегмент кода


     2.3. Область глобальных данных

     Область   глобальных   данных   одного   модуля  занимает
непрерывный  кусок памяти и представляется последовательностью
слов.   При   этом   однословные   данные   хранятся   в   них
непосредственно,  а структурные данные могут быть представлены
в виде ссылки на специально отведенные для них области памяти.
     На  начало  области  глобальных  данных  текущего  модуля
указывает   G-регистр  процессора.  Таким  образом,  доступ  к
глобальным   переменным   модуля   организуется   индексно  по
содержимому  G-регистра,  т.е.  глобальное  слово  с номером 3
находится  в  ячейке  памяти  с  адресом  [G]+3 (здесь и далее
запись [REG] обозначает содержимое регистра "REG"). Первые два
слова    области    глобальных   данных   заняты   специальной
информацией:  в  нулевом слове области содержится указатель на
начало  сегмента кода данного модуля (копия F-регистра), в 1-м
слове - указатель на начало строкового пула.
.PAGE

       сюда указывает G-регистр
       _________________________
                                \
                                 V
-------------------------------------|------------------------
 ... |  G3  |  G2  |   G1   |   G0   | область связей модуля
-------------------------------------|------------------------
глобальные данные     |        |
модуля                |        V
                      |  --------------
                      |  |сегмент кода|
                      |  |модуля      |
                      |  --------------
                      V
                --------------
                |строкоый пул|
                --------------

     Рис.5.   Область   глобальных  данных  модуля.  Стрелками
изображены указатели.


     2.4. Строковый пул

     Строковый   пул   занимает  непрерывный  кусок  памяти  и
содержит   в  себе  структурные  константы  (строки,  массивы,
записи).   На  начало  строкового  пула  указывает  1-е  слово
области глобальных данных модуля.

            этот адрес содержится в 1-м слове ОГД
            _____________________________________
                                                 \
                                                  V
--------------------------------------------------------------
            | ... константы структурных типов ... |
--------------------------------------------------------------

     Рис.6. Строковый пул модуля


     2.5. Область связей

     Область  связей  с  внешними  модулями  (локальная  DFT -
Data   Frame   Table)  занимает  непрерывный  кусок  памяти  и
представляется  массивом  слов,  каждое  из  которых  содержит
ссылку  на  некоторое  слово, в котором находится указатель на
начало  области  глобальных  данных  соответствующего внешнего
модуля.   Таким   образом,   внешние  модули  идентифицируются
индексом  в локальной DFT модуля, т.е. адрес ссылки на область
глобальных  данных  внешнего  модуля  с  номером i находится в
элементе  DFT[i]. Сам модуль имеет в локальной DFT номер 0, то
есть  как  бы  является сам для себя внешним. Это позволяет, в
частности,  корректно  выполнять  вызов  формальных  процедур,
значениями которых являются локальные процедуры этого модуля.
     Локальная   DFT   располагается   непосредственно   перед
областью   глобальных   данных  модуля,  т.е.  элемент  DFT[i]
находится  по  адресу  [G]-i-1  памяти. Заметим, что при такой
организации  информации  для доступа к статически существующим
внешним  объектам  (процедурам,  переменным), достаточно знать
только адрес начала области глобальных данных данного модуля и
два смещения.

сюда указывает G-регистр
__________________
                  \
                   V      0           ...         i
-------------------|------------------------------------------
область глобальных | адрес ссылки на| ... |адрес ссылки на|
данных модуля      | ОГД модуля 0   |     |ОГД модуля i   |
-------------------|------------------------------------------
                          |            |           |
                          |            |           |
                          |            |           V
                          |            V     ______________
                          |           ...    |адрес начала|
                          V                  |ОГД модуля i|
                    ______________           --------------
                    |адрес начала|                 |
                    |ОГД модуля 0|                 V
                    --------------          ----------------
                          |                 | ОГД модуля i |
                          V                 ----------------
                   ----------------
                   | ОГД модуля 0 |
                   ----------------

     Рис.7. Область связей модуля



     2.6. Процедурный стек

     Процедурный  стек  (P-стек)  занимает  непрерывный  кусок
памяти   и  используется  для   размещения   локальных  данных
процедур,  организации  вызовов  и  возвратов  из  процедур  и
размечен  тремя  регистрами процессора. S-регистр указывает на
вершину  P-стека,  т.е.  первое  свободное  на  P-стеке слово.
Н-регистр   указывает   на  последнее  слово  области  памяти,
отведенной  под  P-стек  (предел  увеличения  [S]).  L-регистр
указывает   на  начало  области  локальных  данных  процедуры,
исполняемой  в данный момент. Перекрытие регистров S и H (т.е.
ситуация, когда [S] >= [H]) называется переполнением P-стека и
отслеживается   аппаратно   с   возбуждением  соответствующего
прерывания.
.PAGE

       H-регистр ------>|           |
                        |           |
                        |           |
                        |           |
                        |           |
       S-регистр ------>|-----------|
                        |           |
                        |  Область  |
                        | локальных |
                        |  данных   |
                        |           |
       L-регистр------->|___________|
                         <-1 слово->



     Рис.8.   P-стек   (процедурный   стек)  и  его  разметка.
Стрелками изображены указатели.


     2.6.1. Область локальных данных

     Область  локальных данных текущей процедуры располагается
на  P-стеке  и  представляет  собой  последовательность  слов,
содержащих  локальные переменные непосредственно или ссылки на
начала  участков памяти, отведенных для переменных структурных
типов.  Доступ  к  локальным данным осуществляется индексно по
L-регистру,  т.е  локальное  слово  с  номером  i находится по
адресу  [L]+i в памяти. Специальные команды облегчают доступ к
локальным словам с номерами 4..255.
     Первые   4   локальных   слова  с  номерами  0..3  заняты
специальной  информацией: в нулевом локальном слове содержится
указатель   на  начало  области  локальных  данных  объемлющей
процедуры  (процедуры,  внутри  которой  текущая  описана  как
локальная  процедура),  или  указатель  на  область глобальных
данных  вызывающего  модуля  (если  процедура  была вызвана из
внешнего  модуля)  -  так  называемая статическая цепочка. 1-е
локальное  слово  указывает на начало области локальных данных
процедуры,  из  которой  произошел вызов текущей (динамическая
цепочка).  2-е  локальное слово содержит значение PC возврата.
3-е  локальное  слово  оставлено  для  возможного  дальнейшего
использования (RFE - Reserved for Future Extension).
.PAGE

                 P-стек

              |           |
              |-----------|
              |   L0FF    | \
              |-----------|  \
              |    ...    |   | локальные данные текущей
              |           |   | процедуры
              |-----------|  /
              |    L4     | /
              |-----------|
              |    L3     | ---  оставлено на всякий случай
              |-----------|
              |    L2     | ---  содержит PC точки вызова
              |-----------|      ---------------------------
              |    L1     |----->|ОЛД вызвавшей  процедуры |
              |-----------|      ---------------------------
 L-регистр--->|    L0     |      ---------------------------
              |___________|----->|ОЛД объемлющей процедуры |
               <-1 слово->       ---------------------------


     Рис.9.  Область  локальных  данных исполняемой процедуры.
Стрелками изображены указатели.


     2.7. Еще раз о дескрипторе процесса

     Итак,  суммируем  информацию  о  дескрипторе процесса. Он
занимает   непрерывный  кусок  памяти  размером  восемь  слов,
содержащих следующее:

     1) G - адрес области глобальных данных;
     2) L - адрес локальных данных;
     3) PC - байтовое смещение команды, подлежащей исполнению;
     4) M - маска прерываний;
     5) S - адрес вершины процедурного стека;
     6) H - адрес границы процедурного стека;
     7) T - причина прерывания;
     8) RFE - для дальнейших расширений.


     3. М-код

     Код  ВМ2М  (М-код)  представляет собой поток байтов, т.е.
код  команды  всегда  занимает  один  байт.  Команды  ВМ2М  не
содержат  в  себе  адресных  полей,  но по коду команды всегда
точно известно, где находятся операнды.


     3.1. Способы адресации

     Различные  команды адресуют данные несколькими способами,
которые иллюстрирует таблица.

--------------------------------------------------------------
 Способ адресации    |     Как вычисляется адрес
--------------------------------------------------------------
 локальный           |     [L] + N
 глобальный          |     [G] + N
 внешний             |     DFT[M]^ + N
 промежуточный       |     [L]^+ N   или  [[L]^]^+ N ...
 косвенный           |     [POP()]^ + N,
--------------------------------------------------------------

где M - номер внешнего модуля, N - индекс объекта, символ  "^"
обозначает операцию разыменования указателя.
     Промежуточный  способ адресации предназначен для работы с
объектами статически объемлющей процедуры.


     3.2. Непосредственные операнды

     Команды   могут   содержать   от   4   бит   до   4  байт
непосредственных   операндов.   Непосредственные   операнды  -
операнды,  следующие  в сегменте кода непосредственно за кодом
команды,  причем  по коду операции всегда однозначно известно,
сколько  байт  непосредственных  операндов следует за ним. При
извлечении  данных  из  потока  команд  и самих команд счетчик
команд (PC) увеличивается на 1..5 байта соответственно.
     M-код имеет четыре типа непосредственных операндов:

     3.2.1.  Полубайтовый  операнд:  последние  4 бита команды
интерпретируются  как непосредственный операнд. Так, например,
имеются команды
    LI0, LI1,...,LI15:
     (*  Load  Immediate  - загрузка непосредственная с кодами
0,1,...,15 и семантикой: *)
    Push(IR MOD 16)
(* где IR - регистр кода команды *)

    SLW4,...,SLW15:
(* Store Local Word *)
    MEM[L + IR MOD 16] := Pop();
(* MEM - физическая или логическая память *)
Таким образом, тело процедуры

    PROCEDURE p; CONST c=2;
      VAR i: INTEGER;
    BEGIN i:=c;
    END p;

реализуется в две следующие однобайтовые команды:

    LI2
    SLW4.


     3.2.2. Байтовый операнд:
     Например,
    LIB:
(* Load Immediate Byte *)
    Push(Next());
(* Next() - операция выборки одного байта из кода *)
     При  замене  описания  константы  в предыдущем примере на
следующее:
    c=153
породится код
    LIB
    153
    SLW4

     3.2.3. Двухбайтовый операнд - представленный следующей за
кодом парой байтов.
     3.2.4.  Словный  операнд  -  представленный  следующей за
кодом четверкой байтов.
     3.2.5.  Cуществуют  команды,  имеющие несколько операндов
различной  длины.


     3.3. Функции и назначение команд

     Команды  ВМ2М условно подразделяются на следующие группы:
арифметико-логические, команды организации управления, команды
для работы с А-стеком, вспомогательные.
     Команды для работы со стеком содержат инструкции загрузки
на стек и записи в память вершины стека.
     Все арифметико-логические операции работают над одним или
двумя  верхними элементами стека и помещают результат на стек.
     Команды  для организации управления представлены обычными
командами  переходов,  условных  и  безусловных,  специальными
командами  для  организации  операторов  FOR  и  CASE, набором
инструкций  вызова  и возврата из процедуры. Сюда же относятся
команды   TRAP   -   программного   прерывания  и  TRANSFER  -
переключения процессов, аналог переключения сопрограмм, дающий
мощное  средство  для  организации  мультипрограммной работы и
синхронизации.
     ВМ2М  имеет  набор  вспомогательных  команд,  облегчающих
обработку   мультизначений,   параметров   процедуры,  команды
ввода/вывода и др..
.PAGE

     4. Прерывания

                         Прерывание  -  прекращение выполнения
                    текущей      команды      или      текущей
                    последовательности  команд  для  обработки
                    некоторого  события;  событие  может  быть
                    вызвано  командой или сигналом от внешнего
                    устройства.      Прерывание      позволяет
                    обработать  возникшее  событие специальной
                    программой   и   вернуться   к  прерванной
                    программе.

                                                  А.Борковский
                                         Англо-русский словарь
                             по программированию и информатике

     В   ВМ2М   прерывания   осуществляются  как  переключения
процессов  с  занесением  в  T-регистр причины прерывания (для
прерываний, возбуждаемых процессором и связанных с процессом).
Производится  переключение  с  прерванного процесса на процесс
обработки   прерывания.  Обрабатывающий  процесс  определяется
номером прерывания.


     4.1.  Типы  прерываний

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

   01h    таймер;
   02h    останов процессора;
   03h    обращение к отсутсвующей памяти;
   04h    авария питания;
   05h    ошибка процессора;
   06h    ошибка ввода вектора прерывания;
   07h    нереализованная команда;
   08h    по вызову процедуры      (П2.2);
   09h    по возврату из процедуры (П2.2);

   0Bh    трассировка (прерывание по каждой команде);
          (П2.5,П2.6)

   40h    переполнение P-стека (S>H);
   41h    переполнение целого или деление на 0;
   42h    переполнение вещественного;
   43h    исчерпание вещественного;
   44h    переполнение адреса (П2.2);

   49h    INVLD команда;
   4Ah    выход из диапазона;
   4Bh    неверный параметр команды (аппаратный ASSERT);
   4Ch    исчерпание или переполнение стека выражений (П2.2).

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


     4.2. Вектора прерываний

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


     4.3.   Пространство  векторов прерываний

     Адрес  вектора  прерывания  может быть вычислен по номеру
этого  прерывания  умножением  на  2, с одним исключением. Все
прерывания с номером, большим 3Fh, происходят по вектору 3Fh.
     Таким  образом,  множество  векторов  прерываний занимает
непрерывный  кусок  памяти с абсолютного адреса 2h (прерывания
нумеруются с единицы) по адрес 7Fh, и называется пространством
векторов прерываний.


     4.4.  Маска  прерываний

     Некоторые   из   прерываний  могут  быть  запрещены.  Это
делается,  например,  с  целью  программной  обработки причины
прерывания  без  возбуждения  такового.  Разрешение прерывания
осуществляется  выставлением  соответствующего  бита  в  маске
прерываний. Маска прерываний хранится в M-регистре процессора.
При этом выставление 0-го бита разрешает прерывания от внешних
устройств,  1-го  бита  -  прерывания от таймера, 31-го бита -
программные  прерывания (все прерывания с номером, большим или
равным 3Fh).

     Более  полное  и  подробное  представление  о  ВМ2М можно
получить,  ознакомившись  с  программой интерпретатора M-кода,
которая также является спецификацией микропрограмм процессоров
Кронос.



               ЧАСТЬ II. ИНТЕРПРЕТАТОР  M-КОДА
(*
     00     20      40      60      80     A0     C0     E0

00   LI0    LLW     LXB     LSW0           LSS    MOVE   INCL
01   LI1    LGW     LXW     LSW1    QUIT   LEQ  **CHKNIL EXCL
02   LI2    LEW     LGW2    LSW2    GETM   GTR    LSTA  *INL
03   LI3    LSW     LGW3    LSW3    SETM   GEQ    COMP  *QUOT
04   LI4    LLW4    LGW4    LSW4    TRAP   EQU    GB     INC1
05   LI5    LLW5    LGW5    LSW5    TRA    NEQ    GB1    DEC1
06   LI6    LLW6    LGW6    LSW6    TR     ABS    CHK    INC
07   LI7    LLW7    LGW7    LSW7    IDLE   NEG    CHKZ   DEC

08   LI8    LLW8    LGW8    LSW8    ADD    OR     ALLOC  STOT
09   LI9    LLW9    LGW9    LSW9    SUB    AND    ENTR   LODT
0A   LI0A   LLW0A   LGW0A   LSW0A   MUL    XOR    RTN    LXA
0B   LI0B   LLW0B   LGW0B   LSW0B   DIV    BIC    NOP    LPC
0C   LI0C   LLW0C   LGW0C   LSW0C   SHL    IN     CX   **BBU
0D   LI0D   LLW0D   LGW0D   LSW0D   SHR    BIT    CI   **BBP
0E   LI0E   LLW0E   LGW0E   LSW0E   ROL    NOT    CF   **BBLT
0F   LI0F   LLW0F   LGW0F   LSW0F   ROR    MOD    CL   **PDX

10   LIB    SLW     SXB     SSW0    IO0    DECS   CL0    SWAP
11   LID    SGW     SXW     SSW1    IO1    DROP   CL1    LPA
12   LIW    SEW     SGW2    SSW2    IO2    LODFV  CL2    LPW
13   LIN    SSW     SGW3    SSW3    IO3    STORE  CL3    SPW
14   LLA    SLW4    SGW4    SSW4    IO4    STOFV  CL4    SSWU
15   LGA    SLW5    SGW5    SSW5   *ARRCMP COPT   CL5  **RCHK
16   LSA    SLW6    SGW6    SSW6   *WM     CPCOP  CL6  **RCHZ
17   LEA    SLW7    SGW7    SSW7   *BM     PCOP   CL7  **CM

18   JFLC   SLW8    SGW8    SSW8    FADD   *FOR1  CL8   *CHKBX
19   JFL    SLW9    SGW9    SSW9    FSUB   *FOR2  CL9   *BMG
1A   JFSC   SLW0A   SGW0A   SSW0A   FMUL   *ENTC  CL0A   ACTIV
1B   JFS    SLW0B   SGW0B   SSW0B   FDIV   *XIT   CL0B   USR
1C   JBLC   SLW0C   SGW0C   SSW0C   FCMP   ADDPC  CL0C   SYS
1D   JBL    SLW0D   SGW0D   SSW0D   FABS   JMP    CL0D **NII
1E   JBSC   SLW0E   SGW0E   SSW0E   FNEG   ORJP   CL0E   DOT
1F   JBS    SLW0F   SGW0F   SSW0F   FFCT   ANDJP  CL0F   INVLD

 * -- реализовано только на П2.2.
** -- не реализовано на П2.2.
--------------------------------------------------
(c) COPYRIGHT Kronos Research Group      1985,1986,1987,1989

    Последнее исправление                Oct-1989
.PAGE
MODULE Kronos_Interpreter;  (* Leo 27-Nov-85. (c) Kronos *)
                            (* Ned 30-Aug-87. (c) KRONOS *)

(* Этот интерпретатор является спецификацией аппаратуры. *)

FROM SYSTEM    IMPORT  ADDRESS, WORD, ADR;
FROM KRONOS    IMPORT  ROR, ROL, SHR, SHL;

TYPE CPUs = (Kronos2_2, Kronos2_5, Kronos2_6);

VAR cpu: CPUs;

CONST ESdepth = 7; (* глубина стека выражений *)

TYPE
  BYTE     = [0..255];
  WORD16   = [0..0FFFFh];
  PC_Range = WORD16;
  CodePtr  = POINTER TO ARRAY PC_Range OF BYTE;

VAR
  PC:    PC_Range;    (* счетчик команд *)
  IR:    [0..0FFh];   (* регистр команды *)
  F :    CodePtr;     (* адрес сегмента кода *)
  G :    ADDRESS;     (* адрес сегмента глобальных данных *)
  L :    ADDRESS;     (* адрес сегмента локальных  данных *)
  S :    ADDRESS;     (* адрес вершины  P-стека *)
  H :    ADDRESS;     (* граница P-стека *)
  P :    ADDRESS;     (* адрес дескриптора процесса *)
  M :    BITSET;      (* маска прерываний *)
  Ipt:   BOOLEAN;     (* запрос на прерывание *)
  IptNo: WORD16;      (* номер прерывания *)


CONST  (* номера битов в слове L2 (см. рис.) *)
  ExternalBit   = 1Fh;
  ChangeMaskBit = 1Eh;

CONST
  NonVectBit = 1Fh;
(* бит, маскирующий программные прерывания *)

(* Замечание.  Регистр  H  задает заниженную на ESdepth+1 слов
   границу   стека.   Это   необходимо  для  сохранения  стека
   выражений при переключении процессов (см. SaveExpStack).
*)

VAR MEM: ARRAY ADDRESS OF WORD;
    ByteMEM: ARRAY OF BYTE; (* Наложен на MEM *)

MODULE InstructionFetch;

  IMPORT F, PC, WORD, WORD16, BYTE, MEM, ADDRESS;
  EXPORT Next, Next2, Next4, GetPc;

  PROCEDURE Next(): BYTE;
  BEGIN INC(PC); RETURN INTEGER(F^[PC-1])
  END Next;

  PROCEDURE Next2(): WORD16;
  BEGIN RETURN Next()+Next()*100h
  END Next2;

  PROCEDURE Next4(): WORD;
  BEGIN RETURN Next2()+Next2()*10000h
  END Next4;

  PROCEDURE GetPc(procno: INTEGER): INTEGER;
  (* Выдает PC начала процедуры *)
  BEGIN RETURN MEM[ADDRESS(F)+procno]
  END GetPc;

END InstructionFetch;

MODULE Mask;
  IMPORT M, NonVectBit, BYTE;
  EXPORT NotMasked;

  PROCEDURE NotMasked(N: BYTE): BOOLEAN;
  BEGIN
    IF    (N>=0Fh) & (N<3Fh)  THEN RETURN (0 IN M)
    ELSIF (N< 0Fh) & (N>0)    THEN RETURN (0 IN M) & (N IN M)
    ELSIF (N =3Fh)            THEN RETURN (NonVectBit IN M)
    ELSE ASSERT(FALSE)
    END
  END NotMasked;

END Mask;

MODULE ExpressionStack;
  IMPORT WORD, ESdepth, Ipt, IptNo;
  EXPORT Push, Pop, Empty;

  VAR A: ARRAY [0..ESdepth-1] OF WORD;  sp: [0..ESdepth];

  PROCEDURE Push(X: WORD);
  BEGIN A[sp]:=X;
    IF sp<ESdepth THEN INC(sp) ELSE Ipt:=TRUE; IptNo:=4Ch END;
  END Push;

  PROCEDURE Pop(): INTEGER;
  BEGIN
    IF sp=0 THEN Ipt:=TRUE; IptNo:=4Ch ELSE DEC(sp) END;
    RETURN A[sp];
  END Pop;

  PROCEDURE Empty(): BOOLEAN;
  BEGIN RETURN sp=0 END Empty;

BEGIN sp:=0 END ExpressionStack;

MODULE ProcessSupport;
  IMPORT PC,G,F,H,L,S,P,M, MEM, NotMasked, ESdepth
       , CodePtr, WORD16, ADDRESS;
  FROM ExpressionStack IMPORT Pop, Push, Empty;

  EXPORT SaveExpStack, RestoreExpStack, Transfer, TRAP;

  PROCEDURE SaveExpStack;
    VAR c: CARDINAL; (* счетчик глубины стека *)
  BEGIN c:=0;
    WHILE NOT Empty() DO MEM[S]:=Pop(); INC(S); INC(c) END;
    MEM[S]:=c; INC(S);
  END SaveExpStack;

  PROCEDURE RestoreExpStack;
    VAR c: CARDINAL; (* счетчик глубины стека *)
  BEGIN DEC(S); c:=MEM[S];
    WHILE c>0 DO DEC(c); DEC(S); Push(MEM[S]) END;
  END RestoreExpStack;

  PROCEDURE SaveRegs;
  BEGIN SaveExpStack;
    MEM[P+0]:=G;  MEM[P+1]:=L;
    MEM[P+2]:=PC; MEM[P+3]:=CARDINAL(M);
    MEM[P+4]:=S;  MEM[P+5]:=H+ESdepth+1;
  END SaveRegs;

  PROCEDURE RestoreRegs;
  BEGIN
    G:=MEM[P+0];    F :=CodePtr(MEM[G]);
    L:=MEM[P+1];    PC:=MEM[P+2];  M:=BITSET(MEM[P+3]);
    S:=MEM[P+4];    H:=MEM[P+5]-ESdepth-1;
    RestoreExpStack;
  END RestoreRegs;

  PROCEDURE Transfer(pFrom,pTo: ADDRESS);
    VAR j: CARDINAL;
  BEGIN (* заметьте - pFrom может быть равно pTo *)
    j:=MEM[pTo]; SaveRegs; MEM[pFrom]:=P; MEM[1]:=P;
    P:=j;         RestoreRegs;              MEM[0]:=P;
  END Transfer;

  PROCEDURE TRAP(N: WORD16);
  BEGIN MEM[P+6]:=N;
    IF N>3Fh THEN N:=3Fh END;
    IF NotMasked(N) THEN Transfer(N*2,MEM[N*2+1]) END;
  END TRAP;

END ProcessSupport;

(* Маркировка P-стека перед вызовом процедуры *)

PROCEDURE Mark(X: ADDRESS; External: BOOLEAN);
  VAR i: ADDRESS;
BEGIN i:=S;
  MEM[S]:=X; INC(S); (* статическая  цепочка *)
  MEM[S]:=L; INC(S); (* динамическая цепочка *)
  IF External THEN MEM[S]:=WORD(BITSET(PC)+{ExternalBit})
  ELSE             MEM[S]:=PC
  END; INC(S,2); L:=i;
END Mark;

PROCEDURE ioP2_2;
BEGIN
  ASSERT(IR-90h IN {0..7});
(* см. документацию на П2.2 *)
END ioP2_2;

PROCEDURE ioP2_5;
BEGIN
  ASSERT(IR-90h IN {0..7});
(* Запросы  на  В/В  передаются другим процессорам через общую
   память. См. LABTAM 3000 manuals.
*)
END ioP2_5;

PROCEDURE ioP2_6;
BEGIN ASSERT(IR-90h IN {0..7});
(* Смотря на какой шине. *)
END ioP2_6;

(* Рабочие переменные интерпретатора: *)

VAR i,j,k: CARDINAL;   X,Y  : REAL;
    v,w  : BITSET;     a,b  : CHAR;
    adr,adr1,sz,hi,low: CARDINAL;
    src,trg: INTEGER;
    dyn: POINTER TO
           RECORD
             adr : ADDRESS;
             high: INTEGER;
           END;

PROCEDURE ConsolMicroProgram;
BEGIN
(* Пультовая  микропрограмма  позволяет  произвести  начальную
   загрузку  программы  и  по команде оператора "Go" выполняет
   Transfer(0,1).
*)
END ConsolMicroProgram;

PROCEDURE Interpret;
BEGIN
  CASE IR OF
   00h..0Fh:(* LI0..LI0F  Load Immediate *) Push(IR MOD 10h);

  |10h: (* LIB  Load Immediate Byte *) Push(Next())
  |11h: (* LID  Load Immediate Double byte *) Push(Next2())
  |12h: (* LIW  Load Immediate Word *) Push(Next4())
  |13h: (* LIN  Load Immediate NIL  *) Push(NIL)
  |14h: (* LLA  Load Local  Address *) Push(L+Next())
  |15h: (* LGA  Load Global Address *) Push(G+Next())
  |16h: (* LSA  Load Stack  Address *) Push(Pop()+Next())
  |17h: (* LEA  Load External Addres *)
        i:=G-Next()-1; (* индекс в DFT модуля.*)
        adr:=MEM[i]; (* указатель на элемент большой DFT *)
        Push(MEM[adr]+Next())
  |18h: (* JLFC Jump Long  Forward Condition *)
        IF Pop()=0 THEN PC:=Next2()+PC
        ELSE INC(PC,2) END
  |19h: (* JLF  Jump Long  Forward *) PC:=Next2()+PC;
  |1Ah: (* JSFC Jump Short Forward Condition *)
        IF Pop()=0 THEN PC:=Next()+PC
        ELSE INC(PC) END
  |1Bh: (* JSF  Jump Short Forward *) PC:=Next()+PC;
  |1Ch: (* JLBC Jump Long  Back    Condition *)
        IF Pop()=0 THEN PC:=-Next2()+PC
        ELSE INC(PC,2) END
  |1Dh: (* JLB  Jump Long  Back    *) PC:=-Next2()+PC;
  |1Eh: (* JSBC Jump Short Back    Condition *)
        IF Pop()=0 THEN PC:=-Next()+PC
        ELSE INC(PC) END
  |1Fh: (* JSB  Jump Short Back    *) PC:=-Next()+PC;
  |20h: (* LLW  Load Local  Word *)  Push(MEM[L+Next()])
  |21h: (* LGW  Load Global Word *)  Push(MEM[G+Next()])
  |22h: (* LEW  Load External Word *)
        i:=G-Next()-1; adr:=MEM[MEM[i]]; (* external G *)
        Push(MEM[adr+Next()])
  |23h: (* LSW  Load Stack addressed Word *)  
         Push(MEM[Pop()+Next()])
  |24h..2Fh: (* LLW0..LLW0F Load Local Word *)
        Push(MEM[L+IR MOD 10h])
  |30h: (* SLW  Store Local  Word *)  MEM[L+Next()]:=Pop()
  |31h: (* SLW  Store Global Word *)  MEM[G+Next()]:=Pop()
  |32h: (* SEW  Store External Word *)
        i:=G-Next()-1; adr:=MEM[MEM[i]]; (* external G *)
        MEM[adr+Next()]:=Pop()
  |33h: (* SSW  Store Stack addressed Word *)
        i:=Pop(); MEM[Pop()+Next()]:=i
  |34h..3Fh: (* SLW0..SLW0F  Store Local Word *)
        MEM[L+IR MOD 10h]:=Pop()

  |40h: (* LXB  Load Indexed Byte *)
        i:=Pop(); Push(ByteMEM[Pop()*4+i]);
  |41h: (* LXW  Load Indexed Word *)
        i:=Pop(); Push(MEM[Pop()+i])
  |42h..4Fh: (* LGW02..LGW0F  Load Global Word *)
        Push(MEM[G+IR MOD 10h])
  |50h: (* SXB  Store Indexed Byte *)
        j:=Pop(); i:=Pop(); ByteMEM[Pop()*4+i]:=j;
  |51h: (* SXW  Store Indexed Word *)
        j:=Pop(); i:=Pop(); MEM[Pop()+i]:=j
  |52h..5Fh: (* SGW02..SGW0F  Store Global Word *)
        MEM[G+IR MOD 10h]:=Pop()

  |60h..6Fh: (* LSW00..LSW0F  Load  Stack addressed Word *)
        Push(MEM[Pop()+IR MOD 10h])
  |70h..7Fh: (* SSW00..SSW0F  Store Stack addressed Word *)
        i:=Pop(); MEM[Pop()+IR MOD 10h]:=i

  |80h: TRAP(7h);
  |81h: (* QUIT   Stop processor *) ConsolMicroProgram
  |82h: (* GETM   Get Mask *) Push(M)
  |83h: (* SETM   Set Mask *) M:=BITSET(Pop);
  |84h: (* TRAP interrupt simulation *) TRAP(Pop())
  |85h: (* TRA   Transfer control between process *)
        i:=Pop(); Transfer(Pop(),i)
  |86h: (* TR    Test & Reset *)
        i:=Pop(); Push(MEM[i]); MEM[i]:=0
  |87h: (* IDLE  IDLE process *)
        DEC(PC); REPEAT (* не занимая шины *) UNTIL Ipt
(* В   следующих   шести   командах,   а   также   в  командах
   MOD,NEG,ABS,FOR2,INC,DEC,INC1,DEC1  в  случае  переполнения
   возбуждaeтся прерывание с IptNo=41h.
*)
  |88h: (* ADD  integer ADD *) Push(Pop()+Pop())
  |89h: (* SUB  integer SUB *) i:=Pop(); Push(Pop()-i);
  |8Ah: (* MUL  integer MUL *) Push(Pop()*Pop())
  |8Bh: (* DIV  integer DIV *) i:=Pop(); Push(Pop() DIV i)
  |8Ch: (* SHL  integer SHift Left *)
        i:=Pop(); Push(SHL(Pop(),i))
  |8Dh: (* SHR  integer SHift Right *)
        i:=Pop(); Push(SHR(Pop(),i))

  |8Eh: (* ROL  word ROtate Left  *)
        i:=Pop() MOD 20h; Push(ROL(Pop(),i))
  |8Fh: (* ROR  word ROtate Right *)
        i:=Pop() MOD 20h; Push(ROR(Pop(),i))
  |90h..94h: (* io section *)
        CASE cpu OF
          |Kronos2_2: ioP2_2
          |Kronos2_5: ioP2_5
          |Kronos2_6: ioP2_6
        ELSE
        END

  |95h: (* ARRCMP array compare *)
        sz:=Pop(); adr:=Pop(); adr1:=Pop();
        IF sz<0 THEN Push(sz); TRAP(4Fh)
        ELSIF sz=0 THEN Push(adr1); Push(adr1)
        ELSE LOOP
               IF (adr^ # adr1^) OR (sz=1) THEN
                   Push(adr1); Push(adr); EXIT
               END;
               DEC(sz); INC(adr); INC(adr1);
             END;
        END;

  |96h: (* WM     word move *):
        sz:=Pop(); f:=Pop(); t:=Pop();
        IF t>f THEN
          t:=t+sz-1; f:=f+sz-1;
          WHILE sz>0 DO
            MEM[t]:=MEM[f]; DEC(t); DEC(f); DEC(sz)
          END
        ELSE
          WHILE sz>0 DO
            MEM[t]:=MEM[f]; INC(t); INC(f); DEC(sz)
          END
        END;

  |97h: (* BM     bit  move *)
        sz:=Pop(); -- размер пересылаемой области в битах
        i:=Pop(); src:=Pop(); -- смещение и адрес источника
        j:=Pop(); trg:=Pop(); -- смещение и адрес приемника
        src:=src*32+i;
        trg:=trg*32+j;
        IF src>=trg THEN                   n:=+1
        ELSE INC(src,sz-1); INC(trg,sz-1); n:=-1
        END;
        FOR k:=0 TO sz-1 DO
          i:=trg DIV 32; j:=trg MOD 32;
          IF (src MOD 32) IN BITSET(MEM[src DIV 32]) THEN
            MEM[i]:=INTEGER( BITSET(MEM[i]) + {j} )
          ELSE
            MEM[i]:=INTEGER( BITSET(MEM[i]) - {j} )
          END;
          INC(src,n); INC(trg,n)
        END

(* В  следующих  восьми  командах  (за  исключением  FCMP) при
   исчезновении    порядка   или   переполнении   возбуждаются
   прерывания с IptNo=42h или 43h соответственно.
*)
  |98h: (* FADD  Float ADD *) Push(REAL(Pop())+REAL(Pop()))
  |99h: (* FSUB  Float SUB *)
        X:=REAL(Pop()); Push(REAL(Pop())-X)
  |9Ah: (* FMUL  Float MUL *) Push(REAL(Pop())*REAL(Pop()))
  |9Bh: (* FDIV  Float DIV *)
        X:=REAL(Pop()); Push(REAL(Pop())/X)
  |9Ch: (* FCMP  Float CoMPare *)
        X:=REAL(Pop()); Y:=REAL(Pop());
        IF    X<Y THEN Push(1); Push(0)
        ELSIF X>Y THEN Push(0); Push(1)
        ELSE Push(0); Push(0) END
  |9Dh: (* FABS  Float ABS *) X:=REAL(Pop());
        IF X<0.0 THEN Push(-X) ELSE Push(X) END
  |9Eh: (* FNEG  Float NEG *) Push(-REAL(Pop()))
  |9Fh: (* FFCT  Float FunCTions *) i:=Next();
        IF    i=0 THEN Push(FLOAT(INTEGER(Pop())))
        ELSIF i=1 THEN Push(TRUNC(   REAL(Pop())))
        ELSE DEC(PC); TRAP(7h)
        END;

 |0A0h: (* LSS  int LeSS             *) i:=Pop(); Push(Pop()<i)
 |0A1h: (* LEQ  int Less    or EQual *) i:=Pop(); Push(Pop()<=i)
 |0A2h: (* GTR  int GreaTeR          *) i:=Pop(); Push(Pop()>i)
 |0A3h: (* GEQ  int Greater or EQual *) i:=Pop(); Push(Pop()>=i)
 |0A4h: (* EQU  int EQUal     *) Push(Pop()=Pop())
 |0A5h: (* NEQ  int Not EQual *) Push(Pop()#Pop())
 |0A6h: (* ABS  int ABSolute value *) Push(ABS(Pop()))
 |0A7h: (* NEG  int NEGate         *) Push(-Pop())

 |0A8h: (* OR   logical bit per bit OR *)
        v:=BITSET(Pop()); w:=BITSET(Pop()); Push(w+v)
 |0A9h: (* AND  logical bit per bit AND *)
        v:=BITSET(Pop()); w:=BITSET(Pop()); Push(w*v)
 |0AAh: (* XOR  logical bit per bit XOR *)
        v:=BITSET(Pop()); w:=BITSET(Pop()); Push(w/v)
 |0ABh: (* BIC  logical bit per bit BIt Clear *)
        v:=BITSET(Pop()); w:=BITSET(Pop()); Push(w-v)
 |0ACh: (* IN   membership to bitset *)
        v:=BITSET(Pop()); Push(Pop() IN v)
 |0ADh: (* BIT  setBIT *) i:=Pop();
        IF (i<0) OR (i>=20h) THEN TRAP(4Ah)
        ELSE w:={}; INCL(w,i); Push(w) END

 |0AEh: (* NOT  boolean NOT (not bit per bit!) *) Push(Pop()=0)
 |0AFh: (* MOD  integer MODulo *) i:=Pop(); Push(Pop() MOD i)

 |0B0h: (* DECS  DECriment S register (reverse to ALLOC) *) 
        DEC(S,Pop())
 |0B1h: (* DROP *) i:=Pop();
 |0B2h: (* LODF  reLOaD expr. stack after Function return *)
        i:=Pop(); RestoreExpStack; Push(i)
 |0B3h: (* STORE STORE expr. stack before function call *)
        IF S+ESdepth+1>H THEN DEC(PC); TRAP(40h)
        ELSE SaveExpStack
        END
 |0B4h: (* STOFV STOre expr. stack with Formal function Value
           on top before function call (см. команду CF)
         *)
        IF S+ESdepth+2>H THEN DEC(PC); TRAP(40h)
        ELSE i:=Pop(); SaveExpStack; MEM[S]:=i; INC(S) END
 |0B5h: (* COPT  COPy Top of expr. stack *)
        i:=Pop(); Push(i); Push(i)
 |0B6h: (* CPCOP Character array Parameter COPy *)
        i:=Pop(); (* High *) sz:=(i+4) DIV 4;
        IF S+sz>H THEN Push(i); DEC(PC); TRAP(40h)
        ELSE MEM[L+Next()]:=S; adr:=Pop();
          WHILE sz>0 DO MEM[S]:=MEM[adr]; INC(S); INC(adr) END
        END
 |0B7h: (* PCOP  structure Parameter allocate and COPy *)
        i:=Pop(); (* High *) sz:=i+1;
        IF S+sz>H THEN Push(i); DEC(PC); TRAP(40h)
        ELSE MEM[L+Next()]:=S; adr:=Pop();
          WHILE sz>0 DO MEM[S]:=MEM[adr]; INC(S); INC(adr) END
        END
 |0B8h: (* FOR1  enter  FOR statment *)
        IF S+2>H THEN DEC(PC); TRAP(40h)
        ELSE sz:=Next(); (* =0 up; #0 down *)
          hi:=Pop(); low:=Pop(); adr:=Pop(); k:=Next2()+PC;
          IF ((sz=0) & (low<=hi)) OR ((sz#0) & (low>=hi)) THEN
            MEM[adr]:=low;
            MEM[S]:=adr; INC(S); MEM[S]:=hi; INC(S);
          ELSE (* цикл не исполняется не разу *) PC:=k
          END
        END
 |0B9h: (* FOR2  end of FOR statment *)
        hi:=MEM[S-1]; adr:=MEM[S-2]; sz:=Next();
        IF sz>7Fh THEN sz:=7Fh-sz END; (* шаг [-128..127] *)
        k:=-Next2()+PC;  i:=MEM[adr]+sz;
        IF ((sz>=0) & (i>hi)) OR ((sz<0) & (i<hi)) THEN
          DEC(S,2); (* terminate *)
        ELSE MEM[adr]:=i; PC:=k (* continue *)
        END
 |0BAh: (* ENTC  ENTer Case statment *)
        IF S+1>H THEN DEC(PC); TRAP(40h)
        ELSE PC:=Next2()+PC; (* jump to case table *)
          k:=Pop(); low:=Next2(); hi:=Next2();
          MEM[S]:=PC + 2*(hi-low) + 4; INC(S);
          (* PC для выхода *)
          IF (k>=low) & (k<=hi) THEN
            PC:=PC+2*(k-low+1) (* jump into case table *)
          END;
          PC:=-Next2()+PC (* jump back to variant's code *)
        END
 |0BBh: (* XIT  eXIT from case or control structure *)
        DEC(S); PC:=MEM[S]
 |0BCh: (* ADDPC  add to program counter *)
        Push(Pop()+PC);
 |0BDh: (* JMP *)
        PC:=Pop();
 |0BEh: (* ORJP   short circuit OR  JumP *)
        IF Pop()#0 THEN Push(1); PC:=Next()+PC
        ELSE INC(PC) END
 |0BFh: (* ANDJP  short circuit AND JumP *)
        IF Pop()=0 THEN Push(0); PC:=Next()+PC
        ELSE INC(PC)
        END
 
 |0C0h: (* MOVE   MOVE block *) sz:=Pop();
        i:=Pop(); j:=Pop();
        WHILE sz>0 DO
          MEM[j]:=MEM[i]; INC(i); INC(j); DEC(sz)
        END
 |0C1h: (* CHKNIL check address for NIL *)
        i:=Pop(); Push(i);
        IF i=NIL THEN DEC(PC); TRAP(41h) END
 |0C2h: (* LSTA  Load STring Address *)
        Push(MEM[G+1]+Next2());
 |0C3h: (* COMP  COMPare strings *) i:=Pop()*4; j:=Pop()*4;
        REPEAT a:=CHAR(ByteMEM[i]); b:=CHAR(ByteMEM[j]);
        INC(i); INC(j)
        UNTIL (a=0c) OR (b=0c) OR (a#b); Push(a); Push(b)
 |0C4h: (* GB  Get procedure Base n level down *)
        i:=L; k:=Next();
        WHILE k>0 DO i:=MEM[i]; DEC(k) END; Push(i)
 |0C5h: (* GB1 :=Pop(); i:=Pop(); Push(i);
 |0C6h: (* CHK  array boundary CHecK *)
        hi:=Pop(); low:=Pop(); i:=Pop(); Push(i);
        IF (i<low) OR (i>hi) THEN
          Push(low); Push(hi); TRAP(4Ah)
        END
 |0C7h: (* CHKZ  array boundary CHecK (low=Zero) *)
        hi:=Pop(); i:=Pop(); Push(i);
        IF (i<0) OR (i>hi) THEN Push(hi); TRAP(4Ah) END
 |0C8h: (* ALLOC ALLOCate block *) sz:=Pop();
        IF S+sz>H THEN  Push(sz); DEC(PC); TRAP(40h)
        ELSE Push(S); INC(S,sz) END
 |0C9h: (* ENTR  ENTeR procedure *) sz:=Next();
        IF S+sz>H THEN DEC(PC,2); TRAP(40h)
        ELSE INC(S,sz) END
 |0CAh: (* RTN   ReTurN from procedure *)
        S:=L; L:=MEM[S+1];
        PC:=WORD(BITSET(MEM[S+2])*{0..0Fh});
        IF ExternalBit IN BITSET(MEM[S+2]) THEN
          (* external called *)
          G:=MEM[S]; F:=CodePtr(MEM[G])
        END;
 |0CBh: (* NOP   No OPeration  *)
 |0CCh: (* CX    Call eXternal *)
        IF S+4<=H THEN j:=MEM[G-Next()-1];
          i:=Next(); Mark(G,TRUE);
          G:=MEM[j]; F:=CodePtr(MEM[G]); PC:=GetPc(i);
        ELSE DEC(PC); TRAP(40h) END
 |0CDh: (* CI    Call procedure at Intermediate level *)
        IF S+4<=H THEN
          i:=Next(); Mark(Pop(),FALSE); PC:=GetPc(i);
        ELSE DEC(PC); TRAP(40h) END
 |0CEh: (* CF    Call Formal procedure *)
        IF S+3<=H THEN i:=MEM[S-1]; DEC(S); Mark(G,TRUE);
          k:=i DIV 1000000h; i:=i MOD 1000000h;
          G:=MEM[i]; F:=CodePtr(MEM[G]); PC:=GetPc(k);
        ELSE DEC(PC); TRAP(40h) END
 |0CFh: (* CL    Call Local procedure *)
        IF S+4<=H THEN i:=Next(); Mark(L,FALSE); PC:=GetPc(i);
        ELSE DEC(PC); TRAP(40h) END
 |0D0h..0DFh: (* CL0..CL0F  Call Local procedure *)
        IF S+4<=H THEN Mark(L,FALSE); PC:=GetPc(IR MOD 10h);
        ELSE DEC(PC); TRAP(40h) END
 |0E0h: (* INCL  INCLude in set *)
        i:=Pop(); j:=Pop() + i DIV 32;
        MEM[j]:=INTEGER( BITSET(MEM[j]) + {i MOD 32} );
 |0E1h: (* EXCL  EXCLude from set *)
        i:=Pop();
        j:=Pop() + i DIV 32;
        MEM[j]:=INTEGER( BITSET(MEM[j]) - {i MOD 32} );
 |0E2h: (* INL  membership IN Long set *)
        k:=Pop(); j:=Pop(); i:=Pop();
        IF (i<0) OR (i>=k) THEN Push(0)
        ELSE
          Push( (i MOD 32) IN BITSET(MEM[j+i DIV 32]) );
        END;
 |0E3h: (* QUOT QUOTient commands *)
        i:=Pop(); j:=Pop();
        CASE Next() OF
          |0: Push( j SHRQ i ); -- деление на степень двойки
          |1: Push( j QOU  i ); -- деление с округлением к нулю
          |2: Push( j ANDQ i ); -- модуль по степени двойки
          |3: Push( j REM  i ); -- модуль
        ELSE TRAP(7); DEC(PC,2)
        END;
 |0E4h: (* INC1  INCrement by 1 *) INC(MEM[Pop()])
 |0E5h: (* DEC1  DECrement by 1 *) DEC(MEM[Pop()])
 |0E6h: (* INC   INCrement *) i:=Pop(); INC(MEM[Pop()],i)
 |0E7h: (* DEC   DECrement *) i:=Pop(); DEC(MEM[Pop()],i)
 |0E8h: (* STOT  STOre Top on proc stack *)
        IF S+1>H THEN DEC(PC); TRAP(40h)
        ELSE MEM[S]:=Pop(); INC(S)
        END
 |0E9h: (* LODT  LOaD   Top of proc stack *)
        DEC(S); Push(MEM[S])
 |0EAh: (* LXA   Load indeXed Address *)
        sz:=Pop(); i:=Pop(); adr:=Pop(); Push(adr+i*sz)
 |0EBh: (* LPC   Load Procedure Constant *)
        i:=Next(); j:=Next(); Push(j*1000000h+MEM[G-i-1])

(* Следующие  3  команды  работают  с вырезками битов. Битовый
   адрес - это пара (адрес,битовое смещение). Битовое смещение
   может  быть  больше  32.  Вырезка  может переходить границы
   слова.
*)
 |0ECh: (* BBU  Bit Block Unpack *)
        sz:=Pop();
        IF (sz<1) OR (sz>32) THEN
          Push(sz); DEC(PC); TRAP(4Ah)
        END;
        i:=Pop(); adr:=Pop();
        (* j:=битовая вырезка длиной sz, начиная с
           битового адреса (adr,i)
        *)
        Push(j);
 |0EDh: (* BBP  Bit Block Pack *)
        j:=Pop(); sz:=Pop();
        IF (sz<1) OR (sz>32) THEN
          Push(sz); DEC(PC); TRAP(4Ah)
        END;
        i:=Pop(); adr:=Pop();
        (* Упаковывает sz младших битов из j по битовому
           адресу (adr,i)
        *)
 |0EEh: (* BBLT Bit BLock Transfer *)
        sz:=Pop(); (* Длина может любой, больше 0 *)
        i:=Pop(); adr:=Pop();
        j:=Pop(); adr1:=Pop();
        (* Переслать биты (adr,i) -> (adr1,j) длиной sz *)
        (* Куски не должны перекрываться!!! *)
 |0EFh: (* PDX Prepare Dynamic indeX *)
        i:=Pop();
        dyn:=Pop();
        Push(dyn^.adr); Push(i);
        IF (i<0) OR (i>dyn^.high)
        THEN TRAP(4Ah)
        END;
 |0F0h: (* SWAP *)
        i:=Pop(); j:=Pop(); Push(i); Push(j)
 |0F1h: (* LPA Load Parameter Address *)
        Push(L-Next()-1);
 |0F2h: (* LPW Load Parameter WORD *)
        Push(MEM[L-Next()-1]);
 |0F3h: (* SPW Store Parameter WORD *)
        MEM[L-Next()-1]:=Pop();
 |0F4h: (* SSWU Store Stack Word Undestructive *)
        i:=Pop(); MEM[Pop()]:=i; Push(i)
 |0F5h: (* RCHK  range CHecK *)
        hi:=Pop(); low:=Pop(); i:=Pop(); Push(i);
        Push( (low<=i) & (i<=hi) );
 |0F6h: (* RCHZ range check (low=Zero) *)
        hi:=Pop(); i:=Pop(); Push(i);
        Push( (0<=i) & (i<=hi) );
 |0F7h: (* CM Call procedure from dynamic Module *)
        IF S+4<=H THEN
          i:=Next();
          DEC(S); j:=MEM[S];
          Mark(G,TRUE);
          G:=j; F:=CodePtr(MEM[G]); PC:=GetPc(i);
        ELSE DEC(PC); TRAP(40h)
        END;
 |0F8h: (* CHKBX  CHecK BoX *)
        p0:=Pop(); p1:=Pop();
        x00:=INTEGER(p0^)     MOD 10000h;
        y00:=INTEGER(p0^<<16) MOD 10000h;
        INC(p0);
        x01:=INTEGER(p0^)     MOD 10000h;
        y01:=INTEGER(p0^<<16) MOD 10000h;
        x10:=INTEGER(p1^)     MOD 10000h;
        y10:=INTEGER(p1^<<16) MOD 10000h;
        INC(p1);
        x11:=INTEGER(p1^)     MOD 10000h;
        y11:=INTEGER(p1^<<16) MOD 10000h;
        Push((x10<=x01) & (y10<=y01) & (x00<=x11) & (y00<=y11));
 |0F9h: (* BMG Bit Map Graphic commands *)
        CASE Next() OF
          |0: IN_RECT -- IN RECTangle?
          |1: DVL     -- Display Vertical Lines
          |2: BBLT_G  -- BBLT-loGic
          |3: DCH     -- Display CHar
          |4: CLP     -- CLiPping
          |5: DLN     -- Display  LiNe
          |6: CRC     -- CiRCus
          |7: ARC     -- ARC
          |8: TRF     -- TRiangle Filling
          |9: CRF     -- CiRcus  Filling
        ELSE
          Trap(49h)
        END
 |0FAh: (* ACTIVe process *) Push(P)
 |0FBh: (* USR User defined functions *) i:=Next(); (*  *)
 |0FCh: (* SYS SYStem rarely functions *)
        CASE Next() OF
         |00h: (* PID Processor IDent {2,5,6} *)
               (* Push(PID) *)
               (* Остальные могут быть различными в разных моделях *)
         |02h: (* PM  Processor Model *)
        ELSE TRAP(7h)
        END;
 |0FDh: (* NII Never Implemented Instruction *) TRAP(7h);
 |0FFh: (* INVLD INVaLiD Operation *) TRAP(49h)
  ELSE  (* unimplemented instruction *) TRAP(7h)
  END (*CASE*)
END Interpret;

BEGIN (* "Power On" *)
 (* cpu:=Kronos2_2 | Kronos2_5 | Kronos2_6 *)
 ORIGIN(ByteMEM,ADR(MEM),SIZE(MEM));
 ConsolMicroProgram;
 LOOP
   IF Ipt THEN TRAP(IptNo) END;
   IR:=Next();
   Interpret;
 END (*LOOP*)
END Kronos_Interpreter.


             ЧАСТЬ III. ОПИСАНИЕ  СИСТЕМЫ  КОМАНД


     Данное  описание  не является самостоятельным документом.
Можно   рассматривать   его   как   подробный   и  пространный
комментарий   к   интерпретатору  системы  команд  процессоров
КРОНОС. Здесь опущены определения основных понятий архитектуры
семейства  КРОНОС,  их  можно  найти  в  разделе  "Виртуальная
Модула-2 машина".


     Код команды

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


     Операнды

     После   выборки   кода   команды  определен  алгоритм  ее
исполнения.  Некоторые  операнды команд располагаются на стеке
выражений  (А-стек), другие могут следовать непосредственно за
кодом   команды,   как  последовательность  байтов.  Последние
называются   непосредственными   операндами.  Они  никогда  не
интерпретируются как абсолютные адреса.


     Выборка кода

     Выборка кода производится с помощью процедур Next, Next2,
Next4   (см.  Интерпретатор  системы  команд).  Эти  процедуры
выбирают   из  кода  байт,  два  байта  и  слово,  увеличивая,
соответственно,  счетчик  команд PC на один, два или четыре. В
терминах Модулы-2 эти процедуры выглядят так:

     PROCEDURE Next(): BYTE;
     BEGIN INC(PC); RETURN INTEGER(F^[PC-1])
     END Next;

     PROCEDURE Next2(): WORD16;
     BEGIN RETURN Next()+Next()*100h
     END Next2;

     PROCEDURE Next4(): WORD;
     BEGIN RETURN Next2()+Next2()*10000h
     END Next4;


     Стек выражений

     Стек  выражений  используется  для вычисления выражений и
хранения аргументов команд и результатов их выполнения. Работа
со стеком определяется процедурами Pop (взять со стека) и Push
(положить на стек).

  PROCEDURE Push(X: WORD);
  BEGIN A[sp]:=X;
    IF sp<ESdepth THEN INC(sp) ELSE Ipt:=TRUE; IptNo:=4Ch END;
  END Push;

  PROCEDURE Pop(): INTEGER;
  BEGIN
    IF sp=0 THEN Ipt:=TRUE; IptNo:=4Ch ELSE DEC(sp) END;
    RETURN A[sp];
  END Pop;

     Везде  в  дальнейшем под словами "взять со стека", "брать
со стека" следует понимать действия:
     1)  проверяется, не пуст ли стек выражений; если пуст, то
возбуждается прерывание с номером 4Ch;
     2)  иначе  с  вершины стека выражений считывается слово и
счетчик  стека  уменьшается  на  единицу; таким образом, слово
оказывается счеркнутым.
     Под  словами  "поместить  на  стек",  "загрузить на стек"
следует понимать действия:
     1)   элементу   стека  выражений,  на  который  указывает
счетчик, присваивается то значение, которое загружается;
     2)  если  счетчик  меньше  границы стека выражений, то он
увеличивается   на  единицу,  иначе  вызывается  прерывание  с
номером 4Ch.
     Если  не  указано,  о каком стеке идет речь, то имеется в
виду стек выражений.


     4-битовые непосредственные операнды

     Поскольку  система  команд Кроноса очень маленькая (менее
128  команд),  было  сочтено  возможным использовать 4 младших
бита  в  некоторых  часто  исполняемых командах для 4-битового
непосредственного  операнда.  Такая команда может быть описана
либо   как   множество   из   16-ти   различных   команд  (см.
"Интерпретатор"), либо как просто 4-битовая команда с четырьмя
битами непосредственного операнда.

     Заметим,   что   все   чиcла,   встречающиеся   далее   -
шестнадцатеричные  (и  поэтому снабжены символом 'h' - 'hex').

LI0..LI0F                       00h..0Fh
Load Immediate
Код операции:                   4 бита          0h
Непосредственные операнды:      4 бита          0h..0Fh
Длина команды:                  1 байт
Действие:
     Загружает  на  стек значение, соответствующее 4-м младшим
битам  кода  команды (из отрезка 00h..0Fh), в виде 32-битового
слова с нулями в старших 28 битах (ведущие нули).
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(IR MOD 10h);

LIB                             10h
Load Immediate Byte
Код операции:                   1 байт         10h
Непосредственные операнды:      1 байт         0h..0FFh
Длина команды:                  2 байта
Действие:
     Загружает    значение   непосредственного   операнда   из
диапазона  00h..0FFh  (1  байта кода, следующих за командой) и
помещает  его  на  стек  в  виде  32-битового слова с ведущими
нулями.
     PC увеличивается на 2.

В терминах интерпретатора:
     Push(Next())

LID                             11h
Load Immediate Double Byte
Код операции:                   1 байт          11h
Непосредственные операнды:      2 байта         0h..0FFFFh
Длина команды:                  3 байта
Действие:
     Загружает    значение   непосредственного   операнда   из
диапазона  00h..0FFFFh (2 байта кода, следующих за командой) и
помещает  его  на  стек  в  виде  32-битового слова с ведущими
нулями.
     PC увеличивается на 3.

В терминах интерпретатора:
     Push(Next2())

LIW                             12h
Load Immediate Word
Код операции:                   1 байт          12h
Непосредственные операнды:      4 байта         0h..0FFFFFFFFh
Длина команды:                  5 байт
Действие:
     Загружает    значение   непосредственного   операнда   из
диапазона   00h..0FFFFFFFFh   (4   байта  кода,  следующих  за
командой) и помещает его на стек в виде 32-битового слова.
     PC увеличивается на 5.

Замечание. Числа представляются в двоично-дополнительном коде.
           Диапазон  целых:
           -2**31  <=  x  <=  2**31-1,
           или, в шестнадцатеричном представлении,
           80000000h <= x <=   7FFFFFFFh.
           "-1" представляется как 0FFFFFFFFh.

Замечание. Только  команда  LIW  позволяет  положить  на  стек
           отрицательное  число. Небольшие отрицательные числа
           порождаются  по-другому:  загружаются их абсолютные
           величины и командой NEG изменяется знак.

В терминах интерпретатора:
     Push(Next4())

LIN                             13h
Load Immediate Nil
Код операции:                   1 байт          13h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Загружает  на  стек несуществующий  адрес (NIL).
     PC увеличивается на 1.

Замечание. Значение  NIL  зависит от модели процессора. Это не
           влияет  на  переносимость программного обеспечения.
           Так,  например,  в  Кронос  2.2 NIL равен FFFFFh. В
           этой  модели  этот  адрес  проверяется аппаратно, в
           остальных моделях может быть проверен явно командой
           CHKNIL.

В терминах интерпретатора:
     Push(NIL)

LLA                             14h
Load Local Address
Код операции:                   1 байт          14h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Прибавляет   к  содержимому  L-регистра  непосредственный
операнд   (байт,   следующий  за  кодом  команды)  и  помещает
полученную  сумму  на стек. PC увеличивается на 2. Эта команда
позволяет  загрузить  на стек адрес локальной переменной. Если
смещение   переменной  относительно  L-регистра  больше  0FFh,
задача  решается  комбинированием команд LLA, LI, LIB, LID или
LIW c ADD.

В терминах интерпретатора:
     Push(L+Next())

LGA                             15h
Load Global Address
Код операции:                   1 байт          15h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Прибавляет   к  содержимому  G-регистра  непосредственный
операнд   (байт,   следующий  за  кодом  команды)  и  помещает
полученную  сумму  на стек. PC увеличивается на 2. Эта команда
позволяет  загрузить на стек адрес глобальной переменной. Если
смещение   переменной  относительно  G-регистра  больше  0FFh,
задача  решается  комбинированием команд LGA, LI, LIB, LID или
LIW c ADD.

В терминах интерпретатора:
     Push(G+Next())

LSA                             16h
Load Stack Address
Код операции:                   1 байт          16h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Берет  слово со стека, прибавляет к нему непосредственный
операнд   (байт,  следующий  за  кодом  команды),  и  помещает
полученную  сумму  на стек. PC увеличивается на 2. Эта команда
позволяет   заменить   адрес,  лежащий  на  стеке,  на  адрес,
смещенный  относительно  него.  Это используется для получения
адресов  полей  в тех случаях, когда адрес записи уже загружен
на  стек.  Когда  смещение  поля  больше 0FFh, задача решается
комбинированием команд LSA, LI, LIB, LID или LIW c ADD.

Замечание. LSA XX семантически эквивалентно последовательности
           LIB  XX  ADD.

В терминах интерпретатора:
     Push(Pop()+Next())

LEA                             17h
Load External Address
Код операции:                   1 байт          17h
Непосредственные операнды:      2 байта         0h..0FFh
Длина команды:                  3 байта
Действие:
     Выбирается однобайтовый непосредственный операнд, который
интерпретируется  как номер внешнего модуля, по которому в DFT
модуля  ищется  ссылка  на адрес ОГД внешнего модуля. Слово из
ОГД   внешнего  модуля  со  смещением,  взятым  из  следующего
однобайтового непосредственного операнда, загружается на стек.
     PC увеличивается на 3.

В терминах интерпретатора:
     i:=G-Next()-1;
     adr:=MEM[i];
     Push(MEM[adr]+Next())

JFLC                            18h
Jump Forward Long Condition
Код операции:                   1 байт          18h
Непосредственные операнды:      2 байта         0h..0FFh
Длина команды:                  3 байта
Действие:
     Выбирает  двухбайтовый  непосредственный операнд - размер
(N)  возможного перехода к следующей команде. PC увеличивается
на   3.   Со  стека  берется  значение.  Если  это  0,  то  PC
увеличивается  на N, иначе (при любом не равном нулю значении)
далее будет выполняться следующая команда.

В терминах интерпретатора:
     IF Pop()=0 THEN PC:=Next2()+PC
     ELSE INC(PC,2)
     END

JFL                             19h
Jump Forward Long
Код операции:                   1 байт          19h
Непосредственные операнды:      2 байта         0h..0FFFFh
Длина команды:                  3 байта
Действие:
     Выбирается двухбайтовый непосредственный операнд - размер
(N) перехода к следующей команде. PC увеличивается на 3+N.

В терминах интерпретатора:
     PC:=Next2()+PC;

JFSC                            1Ah
Jump Forward Short Condition
Код операции:                   1 байт          1Ah
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Выбирает  однобайтовый  непосредственный операнд - размер
(N)  возможного перехода к следующей команде. PC увеличивается
на   2.   Со  стека  берется  значение.  Если  это  0,  то  PC
увеличивается на N, иначе (при любом ненулевом значении) далее
будет выполняться следующая команда.

В терминах интерпретатора:
     IF Pop()=0 THEN PC:=Next()+PC
     ELSE INC(PC)
     END

JFS                             1Bh
Jump Forward Short
Код операции:                   1 байт          1Bh
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Выбирается однобайтовый непосредственный операнд - размер
(N) перехода к следующей команде. PC увеличивается на 2+N.

В терминах интерпретатора:
     PC:=Next()+PC;

JBLC                            1Ch
Jump Back Long Condition
Код операции:                   1 байт          1Ch
Непосредственные операнды:      2 байта         0h..0FFFFh
Длина команды:                  3 байта
Действие:
     PC увеличивается на 3.
     При  условии,  что значение, взятое со стека, равно нулю,
PC  уменьшается  на  столько,  сколько  указано в двухбайтовом
непосредственном   операнде.   Иначе   выполняется   следующая
команда.

В терминах интерпретатора:
     IF Pop()=0 THEN PC:=-Next2()+PC
     ELSE INC(PC,2) END

JBL                             1Dh
Jump Back Long
Код операции:                   1 байт          1Dh
Непосредственные операнды:      2 байта         0h..0FFFFh
Длина команды:                  3 байта
Действие:
     PC  увеличивается  на  3  (в  результате  выборки  кода и
двухбайтового    непосредственного   операнда),   после   чего
уменьшается  на  столько,  сколько  указано в непосредственном
операнде.

В терминах интерпретатора:
     PC:=-Next2()+PC;

JBSC                            1Eh
Jump Back Short Condition
Код операции:                   1 байт          1Eh
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     PC  увеличивается  на  2  в  результате выборки команды и
непосредственного операнда.
     При  условии,  что значение, взятое со стека, равно нулю,
PC  уменьшается  на  столько,  сколько  указано в однобайтовом
непосредственном   операнде.   Иначе   выполняется   следующая
команда.

В терминах интерпретатора:
     IF Pop()=0 THEN PC:=-Next()+PC
     ELSE INC(PC) END

JBS                             1Fh
Jump Back Short
Код операции:                   1 байт          1Fh
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     PC  увеличивается  на  2  в  результате  выборки  кода  и
однобайтового    непосредственного    операнда,   после   чего
уменьшается  на  столько,  сколько  указано в непосредственном
операнде.

В терминах интерпретатора:
     PC:=-Next()+PC;

LLW                             20h
Load Local Word
Код  операции:                  1  байт         20h
Непосредственные  операнды:     1 байт          0h..0FFh
Длина  команды:                 2  байта
Действие:
     Загружает  на  стек  слово,  взятое по адресу, смещенному
относительно   L-регистра   на   величину,   равную   значению
непосредственного  операнда.  команда  позволяет  загрузить на
стек  значение  локальной переменной. Если смещение переменной
относительно   L-регистра   больше   0FFh,   задача   решается
комбинированием команд LLA, LIW, LSW c ADD.
     PC увеличивается на 2.

В терминах интерпретатора:
     Push(MEM[L+Next()])

LGW                             21h
Load Global Word
Код операции:                   1 байт          21h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Загружает  на  стек  слово,  взятое по адресу, смещенному
относительно   G-регистра   на   величину,   равную   значению
непосредственного операнда. Эта команда позволяет загрузить на
стек  значение глобальной переменной. Если смещение переменной
относительно   G-регистра   больше   0FFh,   задача   решается
комбинированием команд LGA, LI, LIB, LID или LIW c ADD и LSW.
     PC увеличивается на 2.

В терминах интерпретатора:
     Push(MEM[G+Next()])

LEW                             22h
Load External Word
Код операции:                   1 байт          22h
Непосредственные операнды:      2 байта         0h..0FFh
Длина команды:                  3 байта
Действие:
     Из   сегмента   кода   выбираются  два  операнда.  Первый
соответствует   номеру  внешнего  модуля,  второй  -  смещению
относительно  G-регистра  этого  модуля.  На  стек загружается
внешнее  глобальное  слово  из  указанного  модуля с указанным
смещением.
     PC увеличивается на 3.

В терминах интерпретатора:
     i:=G-Next()-1; adr:=MEM[MEM[i]];
     Push(MEM[adr+Next()])

LSW                             23h
Load Stack addressed Word
Код операции:                   1 байт          23h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Загружает на стек слово c адресом, смещенным относительно
значения,  взятого  со  стека  на  величину,  равную  значению
непосредственного операнда.
     PC увеличивается на 2.
Замечание. Эта  команда  может быть использована для доступа к
           первым 256 словам  записи (RECORD) при компиляции с
           языков высокого уровня.

В терминах интерпретатора:
     Push(MEM[Pop()+Next()])

LLW4..LLW0F                     24h..2Fh
Load Local Word
Код операции:                   4 бита          2h
Непосредственные операнды:      4 бита          4h..0Fh
Длина команды:                  1 байт
Действие:
     Загружает   на   стек  локальное  слово  со  смещением  в
диапазоне от 4h до 0Fh относительно L-регистра.
     PC увеличивается на 1.

Замечание. Первые  четыре  слова  локальной  области  содержат
           специальную  информацию,  поэтому команд LLW0..LLW3
           нет.

Замечание. Данные   команды   являются,   по  существу,  более
           компактной  версией  команды  LLW.  Такое упрощение
           оправдано   исключительно   частым   обращением   к
           первым 12-ти локальным переменным процедур.

В терминах интерпретатора:
     Push(MEM[L+IR MOD 10h])

SLW                             30h
Store Local Word
Код операции:                   1 байт          30h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Присваивает  значение,  взятое со стека, локальному слову
со смещением, указанным в непосредственном операнде.
     PC увеличивается на 2.

В терминах интерпретатора:
     MEM[L+Next()]:=Pop()

SGW                             31h
Store Global Word
Код операции:                   1 байт          31h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Присваивает  значение, взятое сo стека, глобальному слову
со смещением, указанным в непосредственном операнде.
     PC увеличивается на 2.

В терминах интерпретатора:
     MEM[G+Next()]:=Pop()

SEW                             32h
Store  External  Word
Код  операции:                  1 байт          32h
Непосредственные  операнды:     2  байта        0h..0FFh
Длина команды:                  3 байта
Действие:
     Из кода выбираются два операнда - номер внешнего модуля и
смещение  относительно  его  G-регистра.  Значение,  взятое сo
стека,  присваивается внешнему глобальному слову из указанного
модуля с указанным смещением.
     PC увеличивается на 3.

В терминах интерпретатора:
     i:=G-Next()-1; adr:=MEM[MEM[i]]; (* external G *)
     MEM[adr+Next()]:=Pop()

SSW                             33h
Store Stack addressed Word
Код операции:                   1 байт          33h
Непосредственные операнды:      1 байт          0h..0FFh 
Длина команды:                  2 байта
Действие:
     Со  стека берутся значение и адрес. Присваивает указанное
значение  слову,  смещенному относительно указанного адреса на
величину, равную значению непосредственного операнда.
     PC увеличивается на 2.

В терминах интерпретатора:
     i:=Pop(); MEM[Pop()+Next()]:=i

SLW4..SLW0F                     34h..3Fh
Store Local Word
Код операции:                   4 бита          3h
Непосредственные операнды:      4 бита          4h..0Fh
Длина команды:                  1 байт
Действие:
     Присваивает  значение,  взятое сo стека, локальному слову
со смещением в диапазоне от 4h до 0Fh.
     PC увеличивается на 1.

В терминах интерпретатора:
     MEM[L+IR MOD 10h]:=Pop()

LXB                             40h
Load indeXed Byte
Код операции:                   1 байт          40h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     На  стеке - два операнда. Нижний - словный адрес, верхний
-  байтовое  смещение  относительно этого адреса. Оба операнда
счеркиваются  со  стека, и на стек загружается байт, взятый из
памяти  по  указанному  словному  адресу  с указанным байтовым
смещением, дополненный нулями в старших разрядах.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop(); Push(ByteMEM[Pop()*4+i]);

LXW                             41h
Load indeXed Word
Код операции:                   1 байт          41h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     На  стеке - два операнда. Нижний - словный адрес, верхний
-  словное  смещение  относительно  этого адреса. Оба операнда
счеркиваются  со стека, и на стек загружается слово, взятое из
памяти по указанному словному адресу с указанным смещением.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop(); Push(MEM[Pop()+i])

LGW2..LGW0F                     42h..4Fh
Load Global Word
Код операции:                   4 бита          4h
Непосредственные операнды:      4 бита          2h..0Fh
Длина команды:                  1 байт
Действие:
     Загружает   на   стек   глобальное   слово  со  смещением
из диапазона от 2h до 0Fh.
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(MEM[G+IR MOD 10h])

SXB                             50h
Store indeXed Byte
Код операции:                   1 байт          50h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     На  стеке  - три операнда. Нижний - словный адрес, выше -
байтовое смещение относительно этого адреса. Верхний операнд -
слово,  старшие  24  бита  которого игнорируются, а оставшийся
байт  записывается в  память  по  указанному словному адресу с
указанным байтовым смещением. Все три операнда счеркиваются со
стека.
     PC увеличивается на 1.

В терминах интерпретатора:
     j:=Pop(); i:=Pop(); ByteMEM[Pop()*4+i]:=j;

SXW                             51h
Store indeXed Word
Код операции:                   1 байт          51h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     На  стеке  - три операнда. Нижний - словный адрес, выше -
словное  смещение относительно этого адреса. Верхний операнд -
слово, которое  записывается  в  память по указанному словному
адресу с указанным смещением. Все три операнда счеркиваются со
стека.
     PC увеличивается на 1.

В терминах интерпретатора:
     j:=Pop(); i:=Pop(); MEM[Pop()+i]:=j

SGW2..SGW0F                     52h..5Fh
Store Global Word
Код операции:                   4 бита          5h
Непосредственные операнды:      4 бита          2h..0Fh
Длина команды:                  1 байт
Действие:
     Присваивает  значение, взятое сo стека, глобальному слову
со смещением из диапазона от 2h до 0Fh.
     PC увеличивается на 1.

В терминах интерпретатора:
     MEM[G+IR MOD 10h]:=Pop()

LSW0..LSW0F                     60h..6Fh
Load Stack addressed Word
Код операции:                   4 бита          6h
Непосредственные операнды:      4 бита          0h..0Fh
Длина команды:                  1 байт
Действие:
     Загружает  на  стек  из  памяти  слово  со  смещением  из
диапазона 0..0Fh относительно адреса, взятого со стека.
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(MEM[Pop()+IR MOD 10h])

SSW0..SSW0F                     70h..7Fh
Store Stack addressed Word
Код операции:                   4 бита          7h
Непосредственные операнды:      4 бита          0h..0Fh
Длина команды:                  1 байт
Действие:
     Слово,  взятое  со  стека, записывает в память по адресу,
смещенному на 0..0Fh относительно адреса, взятого со стека.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop(); MEM[Pop()+IR MOD 10h]:=i

QUIT                            81h
stop processor
Код операции:                   1 байт          81h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Останов процессора.
     PC увеличивается на 1 байт.

В терминах интерпретатора:
     ConsolMicroProgram

GETM                            82h
GET Mask
Код операции:                   1 байт          82h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Загружает  на  стек  слово,  содержащее  маску прерываний
(М-регистр процессора).
     PC увеличивается на 1 байт.

В терминах интерпретатора:
     Push(M)

SETM                            83h
SET Mask
Код операции:                   1 байт          83h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Заносит  маску  прерываний,  взятую со стека, в М-регистр
процессора.
     PC увеличивается на 1.

В терминах интерпретатора:
     M:=BITSET(Pop());

TRAP                            84h
interrupt simulation
Код операции:                   1 байт          84h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  значение  со стека и возбуждает прерывание с таким
номером.
     PC увеличивается на 1.

В терминах интерпретатора:
     TRAP(Pop())

TRA                             85h
TRAnsfer control between processes
Код операции:                   1 байт          85h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Происходит  переключение двух процессов.
     Состояние   процесса   определяется  состоянием  стека  и
значениями шести регистров (G, L, PC, M, S, H).
     На стеке - два слова. Верхнее содержит адрес указателя на
дескриптор  процесса,  который  требуется  запустить, нижнее -
адрес,   по   которому   нужно  записать  адрес  указателя  на
дескриптор текущего процесса.
     Регистры  текущего  процесса  записываются  в  дескриптор
процесса,  который  лежит  в  памяти  по  адресу, указанному в
регистре P.
     P-регистр   текущего  процесса  записывается  по  адресу,
взятому  в качестве второго операнда со стека.
     Стек  выражений  спасается  на  процедурный стек текущего
процесса.  Для  того,  чтобы  при  спасении стека выражений не
возникло  переполнения  процедурного  стека,  регистр  границы
процедурного стека - H - указывает на (глубину стека выражений
+ 1) слов ниже фактической границы процедурного стека.
     В  верхнем  операнде  содержится  адрес  слова, в котором
лежит    указатель   на   дескриптор   процесса   (P-регистр),
подлежащего  запуску.  По  новому P-регистру восстанавливаются
значения всех регистров процесса. С вершины процедурного стека
восстанавливается стек выражений.
     PC увеличивается на 1.


В терминах интерпретатора:
     i:=Pop(); Transfer(Pop(),i)

TR                              86h
Test & Reset
Код операции:                   1 байт          86h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Загружает  на  стек  слово,  взятое  из памяти по адресу,
взятому со стека. По этому адресу помещается 0.
     PC увеличивается на 1.

Замечание. Команда  выполняется как неделимое действие "чтение
           с   разрушением".   В   случае   работы  нескольких
           процессоров   с   общей  памятью  используется  для
           межпроцессорной  синхронизации  (как,  например,  в
           Кронос-2.5).

В терминах интерпретатора:
     i:=Pop(); Push(MEM[i]); MEM[i]:=0

IDLE                            87h
IDLE process
Код операции:                   1 байт          87h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Уменьшает  PC на 1. Процессор ждет прерывания, не занимая
шину.
     Поскольку  при  чтении  байта  кода  PC  увеличивался  на
единицу,  после выполнения команды IDLE PC остается на прежнем
месте.

Замечание. Любой  процесс,  выполнивший  команду  IDLE,  будет
           продолжать  ее  выполнение  вечно,  пока какой-либо
           другой  процесс  (обработчик  прерываний, например)
           принудительно не увеличит PC процесса, выполнявшего
           команду IDLE.

В терминах интерпретатора:
     DEC(PC); REPEAT (* не занимая шины *) UNTIL Ipt

ADD                             88h
integer ADDition
Код операции:                   1 байт          88h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со стека два целых числа, складывает их и помещает
сумму  на  стек. Если при этом происходит переполнение целого,
возбуждается прерывание с номером 41h.
     PC увеличивается на 1.

Замечание. В процессоре П2.6 после возникновения прерывания по
           переполнению (независимо от того, разрешено оно или
           нет)   на   стек   помещаются   32   младших   бита
           результата арифметической операции.

В терминах интерпретатора:
     Push(Pop()+Pop())

SUB                             89h
integer SUBtraction
Код операции:                   1 байт          89h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека два операнда - сначала вычитаемое, затем
уменьшаемое.  Производит  вычитание  и  помещает  результат на
стек.   Если   произошло   переполнение  целого,  возбуждается
прерывание с номером 41h.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop(); Push(Pop()-i);

MUL                             8Ah
integer MULtiplication
Код операции:                   1 байт          8Ah
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет со стека два целых числа, перемножает их и помещает
произведение на стек. Если в результате произошло переполнение
целого, возбуждается прерывание с номером 41h.
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(Pop()*Pop())

DIV                             8Bh
integer DIVision
Код операции:                   1 байт          8Bh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со стека два целых числа - сначала делитель, затем
делимое,  производит  деление  нацело  и помещает результат на
стек. Округляет в сторону меньшего. Так, (-1 DIV 2)=-1. Если в
результате   произошло   переполнение   целого,   возбуждается
прерывание с номером 41h.
     PC увеличивается на 1.

Замечание. В Кроносе-2.2 округление происходит в сторону нуля.

В терминах интерпретатора:
     i:=Pop(); Push(Pop() DIV i)

SHL                             8Ch
integer SHift Left
Код операции:                   1 байт          8Ch
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Арифметический  сдвиг  влево.  Со  стека берутся величина
сдвига и сдвигаемое слово. Слово сдвигается влево на указанную
величину. В младшие разряды дописывается соответствующее число
нулей.  При несовпадении знаковых разрядов сдвигаемого слова и
результата возбуждается прерывание с номером 41h (переполнение
целого). Результат помещается на стек.
     PC увеличивается на 1.

Замечание. Таким  образом,  команда  SHL  выполняет  умножение
           числа со знаком на степень двойки.

В терминах интерпретатора:
     i:=Pop(); Push(SHL(Pop(),i))

SHR                             8Dh
integer SHift Right
Код операции:                   1 байт          8Dh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Арифметический  сдвиг  вправо.  Со стека берутся величина
сдвига и сдвигаемое слово. Слово сдвигается вправо на величину
сдвига.   Содержимое   знакового   разряда  восстанавливается,
старшие  разряды  заполняются  содержимым  знакового  разряда.
Результат помещается на стек.
     PC увеличивается на 1.

Замечание. Таким  образом, команда SHR выполняет деление числа
           со знаком на степень двойки с округлением в сторону
           меньшего.

В терминах интерпретатора:
     i:=Pop(); Push(SHR(Pop(),i))

ROL                             8Eh
word ROtate Left
Код операции:                   1 байт          8Eh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Циклический сдвиг влево.
     При  циклическом  сдвиге  влево на единицу старший разряд
слова  переносится  вправо  и становится его младшим разрядом.
При циклическом сдвиге на N эта операция повторяется N раз.
     Со  стека  берутся  величина  сдвига  и сдвигаемое слово.
Слово  сдвигается  влево  на  число  разрядов, равное величине
сдвига по модулю 32. Результат помещается на стек.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop() MOD 20h; Push(ROL(Pop(),i))

ROR                             8Fh
word ROtate Right
Код операции:                   1 байт          8Fh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Циклический  сдвиг  вправо.
     При  циклическом  сдвиге вправо на единицу младший разряд
слова переносится влево и становится его старшим разрядом. При
циклическом сдвиге на N эта операция повторяется N раз.
     Со  стека  берутся  величина  сдвига  и сдвигаемое слово.
Слово  сдвигается  вправо  на число разрядов, равное указанной
величине по модулю 32. Результат помещается на стек.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop() MOD 20h; Push(ROR(Pop(),i))

IO0..IO4                        90h..94h
Input-Output
Код операции:                   1 байт          94h
Непосредственные операнды:      зависит от модели процессора
Длина команды:                  зависит от модели процессора
Действие:
     Команды   работы   с  шиной.  Индивидуальны  для  каждого
процессора.

В терминах интерпретатора:
     CASE cpu OF
       |Kronos2_2: ioP2_2
       |Kronos2_5: ioP2_5
       |Kronos2_6: ioP2_6
     END

ARRCMP                          95h
ARRay CoMPare
Код операции:                   1 байт          95h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Команда предназначена для сравнения словных массивов.
     Со  стека  берется  размер  массивов,  затем адрес начала
первого массива, затем адрес начала второго массива.
     Если  размер  оказался  отрицательным  числом,  это число
помещается обратно на стек и возбуждается прерывание с номером
4Fh.  Если  размер  равен  0, на стек дважды загружается адрес
второго массива.
     Иначе  массивы  сравниваются  пословно  до  тех пор, пока
сравнение  не  дойдет  до  пары  последних  слов  или  до пары
неравных  слов,  после  чего адреса этой пары слов грузятся на
стек.
     PC увеличивается на 1.

Замечание. Команда не реализована на П2.2.

В терминах интерпретатора:
     sz:=Pop(); adr:=Pop(); adr1:=Pop();
     IF sz<0 THEN Push(sz); TRAP(4Fh)
     ELSIF sz=0 THEN Push(adr1); Push(adr1)
     ELSE LOOP
            IF (adr^ # adr1^) OR (sz=1) THEN
              Push(adr1); Push(adr); EXIT
            END;
            DEC(sz); INC(adr); INC(adr1);
          END;
     END;

WM                              96h
Word Move
Код операции:                   1 байт          96h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Со  стека берется размер словного сегмента, который будет
передвинут,  затем  адрес,  начиная  с которого двигать, затем
адрес,  начиная  с  которого  писать этот сегмент. Допускается
перекрытие областей источника и приемника.
     PC увеличивается на 1.

Замечание. Команда реализована только на Кронос-2.6.

В терминах интерпретатора:
     sz:=Pop(); f:=Pop(); t:=Pop();
     IF t>f THEN
       t:=t+sz-1; f:=f+sz-1;
       WHILE sz>0 DO
         MEM[t]:=MEM[f]; DEC(t); DEC(f); DEC(sz)
       END
     ELSE
       WHILE sz>0 DO
         MEM[t]:=MEM[f]; INC(t); INC(f); DEC(sz)
       END
     END;

BM                              97h
Bit Move
Код операции:                   1 байт          97h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Со  стека берутся размер пересылаемого битового сегмента,
битовое  смещение  и  словный  адрес  пересылаемого  сегмента,
битовое смещение и словный адрес, куда пересылается сегмент, и
производится   пересылка.   Допускается   перекрытие  областей
источника и приемника.
     PC увеличивается на 1.

Замечание. Команда не реализована на П2.2.

В терминах интерпретатора:
     sz:=Pop(); -- размер пересылаемой области в битах
     i:=Pop(); src:=Pop(); -- смещение и адрес источника
     j:=Pop(); trg:=Pop(); -- смещение и адрес приемника
     src:=src*32+i;
     trg:=trg*32+j;
     IF src>=trg THEN                   n:=+1
     ELSE INC(src,sz-1); INC(trg,sz-1); n:=-1
     END;
     FOR k:=0 TO sz-1 DO
       i:=trg DIV 32; j:=trg MOD 32;
       IF (src MOD 32) IN BITSET(MEM[src DIV 32]) THEN
         MEM[i]:=INTEGER( BITSET(MEM[i]) + {j} )
       ELSE
         MEM[i]:=INTEGER( BITSET(MEM[i]) - {j} )
       END;
       INC(src,n); INC(trg,n)
     END

FADD                            98h
Float ADDition
Код операции:                   1 байт          98h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет   со   стека  два  вещественных  числа,  производит
сложение и помещает сумму на стек. Если произошло переполнение
вещественного, на стек загружается 0 и возбуждается прерывание
с номером 42h.
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(REAL(Pop())+REAL(Pop()))

FSUB                            99h
Float SUBtraction
Код операции:                   1 байт          99h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет   со   стека   два  вещественных  числа  -  сначала
вычитаемое, затем уменьшаемое. Производит вычитание и помещает
разность  на  стек. Если произошло переполнение вещественного,
на стек загружается 0 и возбуждается прерывание с номером 42h.
     PC увеличивается на 1.

В терминах интерпретатора:
     X:=REAL(Pop()); Push(REAL(Pop())-X)

FMUL                            9Ah
Float MULtiplication
Код операции:                   1 байт          9Ah
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Перемножает  два  вещественных  числа,  взятых  со стека.
Произведение  помещает  на  стек.  Если произошло переполнение
вещественного, возбуждается прерывание с номером 42h.
     Если  результат  меньше  2  в  степени -128, возбуждается
прерывание с номером 43h (исчезновение порядка).
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(REAL(Pop())*REAL(Pop()))


FDIV                            9Bh
Float DIVision
Код операции:                   1 байт          9Bh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет со стека два вещественных числа - сначала делитель,
затем  делимое,  производит  деление  и  помещает результат на
стек.  Если произошло переполнение вещественного, возбуждается
прерывание с номером 42h.
     Если  результат  меньше  2  в  степени -128, возбуждается
прерывание с номером 43h (исчезновение порядка).
     PC увеличивается на 1.

В терминах интерпретатора:
     X:=REAL(Pop()); Push(REAL(Pop())/X)

FCMP                            9Ch
Float CoMPare
Код операции:                   1 байт          9Ch
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Cравнивает  два  взятых со стека вещественных числа. Если
верхнее меньше нижнего, на стек помещаются последовательно 1 и
0;   если   верхнее   больше   нижнего,   на  стек  помещаются
последовательно 0 и 1; если они равны, то на стек помещаются 0
и 0.
 _____              _____         _____          _____
|  X  |   FCMP     |  0  |       |  1  |        |  0  |
|  Y  |  ------>   |  1  |       |  0  |        |  0  |

                    X < Y         X > Y          X = Y

     PC увеличивается на 1.

Замечание. Комбинации команд
           FCMP EQU
           FCMP NEG
           FCMP LSS
             ....

           дают    возможность   осуществить  любое  сравнение
           вещественных чисел.

В терминах интерпретатора:
     X:=REAL(Pop()); Y:=REAL(Pop());
     IF    X<Y THEN Push(1); Push(0)
     ELSIF X>Y THEN Push(0); Push(1)
     ELSE Push(0); Push(0) END

FABS                            9Dh
Float ABSolute
Код операции:                   1 байт          9Dh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со стека вещественное число и помещает на стек его
абсолютное значение.
     PC увеличивается на 1.

Замечание. Команда никогда не возбуждает прерываний 42h, 43h.

В терминах интерпретатора:
     X:=REAL(Pop());
     IF X<0.0 THEN Push(-X) ELSE Push(X) END

FNEG                            9Eh
Float NEGative
Код операции:                   1 байт          9Eh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со стека вещественное число и помещает на стек его
противоположное значение.
     PC увеличивается на 1.

Замечание. Команда никогда не возбуждает прерываний 42h, 43h.

В терминах интерпретатора:
     Push(-REAL(Pop()))

FFCT                            9Fh
Float FunCTion
Код операции:                   1 байт          9Fh
Непосредственные операнды:      1 байт
Длина команды:                  2 байта
Действие:
     Если  значение  непосредственного операнда равно 0, то со
стека  берется  целое  число,  преобразуется  в вещественное и
помещается  на  стек;  если в следующем за командой байте кода
лежит  1,  то  со стека берется вещественное число, у которого
отсекается затем дробная часть. Полученное таким образом целое
число помещается на стек.
     В этих случаях PC увеличивается на 2.
     Если  в  следующем за командой байте кода не 0 и не 1, PC
уменьшается на 1 и возбуждается прерывание с номером 7h.

В терминах интерпретатора:
     i:=Next();
     IF    i=0 THEN Push(FLOAT(INTEGER(Pop())))
     ELSIF i=1 THEN Push(TRUNC(   REAL(Pop())))
     ELSE DEC(PC); TRAP(7h)


     END;

LSS                             0A0h
integer LeSS
Код операции:                   1 байт          0Ah
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Сравниваются  два  целых  числа,  взятых  со  стека. Если
нижнее меньше верхнего, на стек помещается 1, иначе 0.
     PC увеличивается на 1.

Замечание. Поскольку   сравнение  не  осуществляет  вычитания,
           прерывание  41h  (переполнение  целого)  никогда не
           возбуждается.

В терминах интерпретатора:
     i:=Pop(); Push(Pop()<i)

LEQ                             0A1h
integer Less or EQual
Код операции:                   1 байт          0A1h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Сравниваются  два  целых  числа,  взятых  со  стека. Если
нижнее  меньше или равно верхнему, на стек помещается 1, иначе
0.
     PC увеличивается на 1.

Замечание. Поскольку   сравнение  не  осуществляет  вычитания,
           прерывание  41h  (переполнение  целого)  никогда не
           возбуждается.

В терминах интерпретатора:
     i:=Pop(); Push(Pop()<=i)

GTR                             0A2h
integer GreaTeR
Код операции:                   1 байт          0A2h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Сравниваются  два  целых  числа,  взятых  со  стека. Если
нижнее больше верхнего, на стек помещается 1, иначе 0.
     PC увеличивается на 1.

Замечание. Поскольку   сравнение  не  осуществляет  вычитания,
           прерывание  41h  (переполнение  целого)  никогда не
           возбуждается.

В терминах интерпретатора:
     i:=Pop(); Push(Pop()>i)

GEQ                             0A3h
integer Greater or EQual
Код операции:                   1 байт          0A3h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Сравниваются  два  целых  числа,  взятых  со  стека. Если
нижнее  больше или равно верхнему, на стек помещается 1, иначе
0.
     PC увеличивается на 1.

Замечание. Поскольку   сравнение  не  осуществляет  вычитания,
           прерывание  41h  (переполнение  целого)  никогда не
           возбуждается.

В терминах интерпретатора:
     i:=Pop(); Push(Pop()>=i)

EQU                             0A4h
integer EQUal
Код операции:                   1 байт          0A4h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Сравниваются  два  целых числа, взятых со стека. Если они
равны между собой, на стек помещается 1, иначе 0.
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(Pop()=Pop())

NEQ                             0A5h
integer NOt eQual
Код операции:                   1 байт          0A5h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Сравниваются  два  целых числа, взятых со стека. Если они
не равны между собой, на стек помещается 1, иначе 0.
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(Pop()#Pop())

ABS                             0A6h
integer ABSolute
Код операции:                   1 байт          0A6h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека  целое  число  и  помещает  на  стек его
абсолютное значение.
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(ABS(Pop()))


NEG                             0A7h
integer NEGative
Код операции:                   1 байт          0A7h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека  целое  число  и  помещает  на  стек его
противоположное значение.
     PC увеличивается на 1.

Замечание. Если  операнд  на  стеке  равен  min(INTEGER), то в
           результате    выполнения    команды    возбуждается
           прерывание с номером 41h (переполнение целого).

В терминах интерпретатора:
     Push(-Pop())

OR                              0A8h
logical bit per bit OR
Код операции:                   1 байт          0A8h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со стека два слова и помещает на стек результат их
сложения,  то  есть  слово,  в  котором  биты выставлены в тех
позициях, что в первом и/или во втором слове.
     Результат  действия  команды  может быть проиллюстрирован
следующей таблицей:

                            | 0 | 1
                         ---+---+----
                          0 | 0 | 1
                         ---+---+---
                          1 | 1 | 1


     PC увеличивается на 1.

В терминах интерпретатора:
     v:=BITSET(Pop()); w:=BITSET(Pop()); Push(w+v)

AND                             0A9h
logical bit per bit AND
Код операции:                   1 байт          0A9h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека  два слова и помещает на стек результат их
перемножения,  то  есть  слово, в котором единицы только в тех
позициях, где были единицы в обоих словах.
     Результат  действия  команды  может быть проиллюстрирован
следующей таблицей:

                            | 0 | 1
                         ---+---+----
                          0 | 0 | 0
                         ---+---+---
                          1 | 0 | 1

     PC увеличивается на 1.

В терминах интерпретатора:
     v:=BITSET(Pop()); w:=BITSET(Pop()); Push(w*v)

XOR                             0AAh
logical bit per bit XOR
Код операции:                   1 байт          0AAh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека  два  слова  и  помещает на стек результат
деления нижнего на верхнее, то есть слово, в котором единицы в
тех  позициях, где биты не совпали в первом и втором словах, и
нули - где совпали.
     Результат  действия  команды  может быть проиллюстрирован
следующей таблицей:

                            | 0 | 1
                         ---+---+----
                          0 | 0 | 1
                         ---+---+---
                          1 | 1 | 0

     PC увеличивается на 1.

В терминах интерпретатора:
     v:=BITSET(Pop()); w:=BITSET(Pop()); Push(w/v)

BIC                             0ABh
logical bit per bit BIt Clear
Код операции:                   1 байт          0ABh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека  два  слова и помещает на стек результат
вычитания  верхнего  из  нижнего,  то  есть  нижнее  слово,  у
которого  единицы  заменились  на  нули  в тех позициях, где у
верхнего были единицы.
     Результат  действия  команды  может быть проиллюстрирован
следующей таблицей:

                            | 0 | 1
                         ---+---+----
                          0 | 0 | 0
                         ---+---+---
                          1 | 1 | 0

     Обратите  внимание,  что  действие  команды несимметрично
относительно   операндов.   В   таблице  биты  верхнего  слова
изображены в верхней горизонтали, биты нижнего слова - в левой
вертикали.
     PC увеличивается на 1.

В терминах интерпретатора:
     v:=BITSET(Pop()); w:=BITSET(Pop()); Push(w-v)

IN                              0ACh
IN bitset?
Код операции:                   1 байт          0ACh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека  слово и номер позиции, и помещает на стек
единицу,  если  соответствующий  бит в слове имеет значение 1,
иначе помещает ноль.
     PC увеличивается на 1.

Замечание. Команда   возбуждает  прерывание  4Ah,  если  номер
           позиции не в диапазоне 0..31.

В терминах интерпретатора:
     v:=BITSET(Pop()); Push(Pop() IN v)

BIT                             0ADh
set BIT
Код операции:                   1 байт          0ADh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     В  слове,  в  котором  все  биты  равны  нулю, выставляет
единицу в позиции, равной значению, взятому со стека, и помещает
полученное таким образом слово на стек.
     PC увеличивается на 1.

Замечание. Команда   возбуждает  прерывание  4Ah,  если  номер
           позиции не в диапазоне 0..31.

В терминах интерпретатора:
     i:=Pop();
     IF (i<0) OR (i>=20h) THEN TRAP(4Ah)
     ELSE w:={}; INCL(w,i); Push(w) END

NOT                             0AEh
boolean NOT (not bit per bit!)
Код операции:                   1 байт          0AEh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Если  значение,  взятое со стека, равно нулю, помещает на
стек  единицу,  в  противном  случае  ноль  (эквивалентно паре
команд LI0 EQU).
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(Pop()=0)

MOD                             0AFh
integer MODule
Код операции:                   1 байт          0AFh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со стека два целых числа. Результат взятия нижнего
числа по модулю верхнего помещает на стек.
     PC увеличивается на 1.

Замечание. Здесь  взятие  по модулю - арифметическая операция,
           определяемая формулой:
               X MOD N - X - (X DIV N) * N,
           где  DIV - деление с округлением в сторону меньшего
           для  П2.6  и  в  сторону  нуля  для младших моделей
           процессора. См. также команду QUOT.

В терминах интерпретатора:
     i:=Pop(); Push(Pop() MOD i)

DECS                            0B0h
DECrement S-register
Код операции:                   1 байт          0B0h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Действие,   обратное   действию  ALLOC:  берет  со  стека
значение i и на i слов уменьшает S-регистр.
     PC увеличивается на 1.

В терминах интерпретатора:
     DEC(S,Pop())

DROP                            0B1h
DROP
Код операции:                   1 байт          0B1h
Непосредственные операнды:      0 байт
Длина  команды:                 1 байт
Действие:
     Счеркивает слово со стека.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop();

LODF                            0B2h
reLOaD expression stack after Function return
Код операции:                   1 байт          0B2h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Cо стека берется слово, затем из памяти загружается ранее
спасенный стек, и сверху на стек грузится взятое слово.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop(); RestoreExpStack; Push(i)

STORE                           0B3h
STORE expression stack after function call
Код операции:                   1 байт          0B3h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Если величина значения S-регистра, увеличенная на глубину
стека  выражений  +  1,  превышает  значение  границы  P-стека
(H-регистр),  то  PC  уменьшается  на  единицу  и возбуждается
прерывание с номером 40h. Такая проверка производится несмотря
на то, что H-регистр дает заниженную на размер стека выражений
плюс    единица    границу    P-стека,   поскольку  этот запас
предназначается   для  сохранения  стека  выражений  в  случае
переключения процессов.
     Иначе  стек  выражений  записывается  в память, начиная с
адреса  S,  и следом записывается размер сохраненного стека. В
этом  случае  в результате выполнения команды PC увеличивается
на 1.

В терминах интерпретатора:
     IF S+ESdepth+1>H THEN DEC(PC); TRAP(40h)
     ELSE SaveExpStack
     END

STOFV                           0B4h
STORE expression stack with Formal function value on top
Код операции:                   1 байт          0B4h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Если величина значения S-регистра, увеличенная на глубину
стека  выражений  и  еще на двойку, превышает значение границы
P-стека   (H-регистр),   то   PC   уменьшается  на  единицу  и
возбуждается  прерывание с номером 40h.
     Иначе  со  стека  берется  значение, затем стек выражений
записывается в память, начиная с адреса S, следом записывается
размер  спасенного стека, а за ним взятое со стека значение. В
этом  случае  в результате выполнения команды PC увеличивается
на 1.

Замечание. Команда    STOFV    необходима    для   корректного
           использования команды CF (см.).


В терминах интерпретатора:
     IF S+ESdepth+2>H THEN DEC(PC); TRAP(40h)
     ELSE i:=Pop(); SaveExpStack; MEM[S]:=i; INC(S) END

COPT                            0B5h
COPy Top of expression stack
Код операции:                   1 байт          0B5h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека  значение  и затем загружает его на стек
дважды (дублирует вершину стека).
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop(); Push(i); Push(i)

(* Будем   понимать  под  словами  "откат  команды"  следующие
   действия:
   1)  операнды,  взятые  со  стека в ходе выполнения команды,
   помещаются обратно на стек;
   2)  PC  возвращается  в положение, предшествовавшее выборке
   исполняемой команды;
   3) возбуждается прерывание с указанным номером.
*)

CPCOP                           0B6h
Character array Parameter COPy
Код операции:                   1 байт          0B6h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Со  стека  берется  верхняя  граница  байтового массива и
вычисляется размер массива в словах. Если значение S-регистра,
увеличенное  на  размер  массива в словах,  превышает  границу
P-стека, происходит откат команды с прерыванием номер 40h.
     Иначе  из  кода  выбирается  непосредственный  операнд  -
смещение,  и в память с этим смещением относительно L-регистра
записывается  текущее  значение  S-регистра  (для  того, чтобы
запомнить,  откуда  будет  начинаться  копия массива). Затем с
начала   свободной   области  памяти  (S-регистр)  поэлементно
копируется  массив,  адрес  которого  берется со стека, до тех
пор,  пока  не  исчерпается  размер  массива. В этом случае PC
увеличивается на 2, S-регистр увеличивается на размер массива.

В терминах интерпретатора:
     i:=Pop(); (* High *) sz:=(i+4) DIV 4;
     IF S+sz>H THEN Push(i); DEC(PC); TRAP(40h)
     ELSE MEM[L+Next()]:=S; adr:=Pop();
       WHILE sz>0 DO MEM[S]:=MEM[adr]; INC(S); INC(adr) END
     END

PCOP                            0B7h
structure Parameter allocate and COPy
Код операции:                   1 байт          0B7h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Со   стека  берется  верхняя  граница  словного  массива,
увеличивается  на  единицу  для  получения  его  размера. Если
значение  S-регистра, увеличенное на размер массива, превышает
границу   P-стека  (H-регистр),  происходит  откат  команды  с
прерыванием номер 40h.
     Иначе  из  кода  выбирается  непостредственный  операнд -
смещение,  и в память с этим смещением относительно L-регистра
записывается  текущее  значение  S-регистра  (для  того, чтобы
запомнить,  откуда  будет  начинаться  копия массива). Затем с
начала  свободной  области  памяти  записывается массив, адрес
которого  берется  со  стека,  до тех пор, пока не исчерпается
размер.  В  этом  случае  PC  увеличивается  на 2, а S-регистр
увеличивается на размер массива.

В терминах интерпретатора:
     i:=Pop(); (* High *) sz:=i+1;
     IF S+sz>H THEN Push(i); DEC(PC); TRAP(40h)
     ELSE MEM[L+Next()]:=S; adr:=Pop();
       WHILE sz>0 DO MEM[S]:=MEM[adr]; INC(S); INC(adr) END
     END


FOR1                            0B8h
enter FOR statement
Код операции:                   1 байт          0B8h
Непосредственные операнды:      3 байта   0h..0FFh, 0h..0FFFFh
Длина команды:                  4 байта
Действие:
     Если  S-регистр,  увеличенный  на  2,  превышает  границу
P-стека, происходит откат команды с  прерыванием номер 40h.
     Иначе  со  стека  берется верхняя и нижняя границы цикла,
адрес  переменной цикла. Из кода выбирается шаг цикла - если в
следующем  байте  0,  шаг  положительный,  если  не  0  -  шаг
отрицательный.   Если   условия  цикла  не  выполняются  сразу
(конечное  значение  меньше  начального при положительном шаге
или  начальное  меньше  конечного  при отрицательном шаге), PC
изменяется   на   столько,   сколько  указано  в  двухбайтовом
непосредственном   операнде,  плюс  4.  Иначе  нижняя  граница
записывается  по  адресу  переменной  цикла,  адрес  и верхняя
граница размещаются на P-стеке для команды FOR2. В этом случае
PC увеличивается в результате выполнения команды на 4.

Замечание. Команда реализована только на Кронос-2.2.

В терминах интерпретатора:
     IF S+2>H THEN DEC(PC); TRAP(40h)
     ELSE sz:=Next(); (* =0 up; #0 down *)
       hi:=Pop(); low:=Pop(); adr:=Pop(); k:=Next2()+PC;
       IF ((sz=0) & (low<=hi)) OR ((sz#0) & (low>=hi)) THEN
         MEM[adr]:=low;
         MEM[S]:=adr; INC(S); MEM[S]:=hi; INC(S);
       ELSE (* цикл не исполняется не разу *) PC:=k
       END
     END

FOR2                            0B9h
end of FOR statement
Код операции:                   1 байт          0B9h
Непосредственные операнды:      3 байта   0h..0FFh, 0h..0FFFFh
Длина команды:                  4 байта
Действие:
     Если   значение   шага  цикла,  взятое  из  однобайтового
непосредственного  операнда, больше 7Fh, ему переприсваивается
отрицательное  значение,  равное (7Fh-шаг) (шаг цикла всегда в
промежутке [-128..127]).
     Если   возможна  еще  одна  итерация,  то  есть  значение
переменной  цикла,  измененное  на  шаг, не выходит за верхнюю
границу,  то  значение  переменной  цикла изменяется на размер
шага,     PC    уменьшается    на    значение    двухбайтового
непосредственного операнда.
     Иначе  S-регистр сдвигается на 2 слова назад, счеркивая с
P-стека значение верхней границы и адрес переменной цикла.

Замечание. Команда реализована только на Кронос-2.2.

В терминах интерпретатора:

     hi:=MEM[S-1];
     adr:=MEM[S-2];
     sz:=Next();
     IF sz>7Fh THEN
       sz:=7Fh-sz    (* шаг [-128..127] *)
     END;
     k:=-Next2()+PC;
     i:=MEM[adr]+sz;
     IF ((sz>=0) & (i>hi)) OR ((sz<0) & (i<hi)) THEN
       DEC(S,2); (* terminate *)
     ELSE MEM[adr]:=i; PC:=k (* continue *)
     END

ENTC                            0BAh
ENTer Case statement
Код операции:                   1 байт          0BAh
Непосредственные операнды:      2 байта         0h..0FFFFh
Длина команды:                  3 байта +  размер таблицы
Действие:
     Выбор   нужной   альтернативы   из   таблицы  альтернатив
выбирающего оператора (CASE) и передача управления на ее код.
     Если  S-регистр,  увеличенный  на  2,  превышает  границу
P-стека, происходит откат команды с  прерыванием номер 40h.
     Иначе  выбирает  двухбайтовый непостредственный операнд и
осуществляет  переход  на  таблицу  альтернатив. Далее из кода
выбираются  минимальное  и  максимальное значения альтернатив,
представленные   двухбайтовыми  непосредственными  операндами;
вычисляется точка выхода из оператора CASE по формуле:
     PC'- PC + 2(high-low),
где   high   и  low  -  максимальное  и  минимальное  значения
альтернатив    соответственно.    Полученное    значение   PC'
записывается на P-стек.
     Затем со стека берется параметр оператора CASE. В случае,
если его значение не лежит в границах значений альтернатив, PC
остается  неизменным.  Иначе  осуществляется переход в таблицу
альтернатив по формуле:
     PC' = PC + 2(i-low +1),
где  i  -  значение параметра CASE; low - минимальное значение
альтернатив.
     Далее   из   кода   выбирается   двухбайтовое   смещение,
определяющее  переход  на  код  альтернативы. PC изменяется по
формуле:
     PC' = PC - offset.


                                        Стеки до ENTC

          ENTC xxxx     ----  (*1*)    E-стек   P-стек
     ---> Alt 0             |
    |     ... XIT           |          |   |   |     |
   -+---> Alt 1             | (*8*)    |   |   |     |    ___
  | |     ... XIT           |          | 1 |   |     |<--| S |
  | |                       |           ~~~    |     |    ~~~
  | |     ...               |
  | |                       |           Стеки после ENTC
 -+-+---> Alt n             |
| | |     ... XIT           |          |   |   |     |    ___
| | |  -> Alt ELSE          |          |   |   |     |<--| S |
| | | |   ... XIT ----------+--------- |   |   | PC' |    ~~~
| | | |                     |        |  ~~~    |     |
| | | |   <Lo><Hi>  <-------  (*2*)  |
| | | |                       (*3,4*)|
| | |  -  <ELSE offset>       (*5*)  |
| |  ----  <Alt0 offset>             |
|  ------  <Alt1 offset>      (*6*)  |
|           ...........              |
 --------  <AltN offset>             |
                                     |
           <Continue code>  <-- PC' --

Замечание. Команда реализована только на Кронос-2.2.

В терминах интерпретатора:
     IF S+1>H THEN DEC(PC); TRAP(40h)
     ELSE PC:=Next2()+PC; (* jump to case table *)
       k:=Pop(); low:=Next2(); hi:=Next2();
       MEM[S]:=PC + 2*(hi-low) + 4; INC(S);(*PC for exit*)
       IF (k>=low) & (k<=hi) THEN
         PC:=PC+2*(k-low+1) (* jump into case table *)
       END;
       PC:=-Next2()+PC (* jump back to variant's code *)
     END

XIT                             0BBh
eXIT from case or control structure
Код операции:                   1 байт          0BBh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Выход  в  точку  в коде, помеченную при входе в структуру
управления   (ENTC   или   ENTS).  PC  устанавливается  равным
значению, взятому с P-стека.

Замечание. Команда реализована только на Кронос-2.2.

В терминах интерпретатора:
     DEC(S); PC:=MEM[S]

ADDPC                            0BCh
ADD Program Counter
Код операции:                   1 байт          0BCh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Грузит  на  стек  PC,  сложенный  с  величиной, взятой со
стека.
     PC увеличивается на 1.

Замечание. ADDPC не реализована в П2.2.

В терминах интерпретатора:
     Push(Pop()+PC);

JMP                              0BDh
JuMP
Код операции:                   1 байт          0BDh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     PC присваивается значение, взятое со стека.

Замечание. JMP не реализована в П2.2.

В терминах интерпретатора:
        PC:=Pop();

ORJP                            0BEh
short circuit OR JumP
Код операции:                   1 байт          0BEh
Непосредственные операнды:      1 байт
Длина команды:                  2 байта
Действие:
     PC увеличивается на 1 в результате выборки кода команды.
     Если  значение, взятое со стека, не равно нулю, помещает на
стек  единицу.  PC увеличивается на столько, сколько указано в
однобайтовом  непосредственном  операнде плюс единица (за счет
выборки этого операнда).
     Иначе  увеличивает  PC  на единицу. Таким образом, в этом
случае PC в процессе выполнения команды увеличивается на два.

В терминах интерпретатора:
     IF Pop()#0 THEN Push(1); PC:=Next()+PC
     ELSE INC(PC)
     END

ANDJP                           0BFh
short circuit AND JumP
Код операции:                   1 байт          0BFh
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     PC увеличивается на 1 в результате выборки кода команды.
     Если  значение,  взятое со стека, равно нулю, помещает на
стек  ноль.  PC  увеличивается  на  столько, сколько указано в
однобайтовом  непосредственном  операнде плюс единица (за счет
выборки этого операнда).
     Иначе  увеличивает  PC  на  единицу.  В  этом случае PC в
процессе выполнения команды увеличивается на два.

В терминах интерпретатора:
     IF Pop()=0 THEN Push(0); PC:=Next()+PC
     ELSE INC(PC)
     END

MOVE                            0C0h
MOVE block
Код операции:                   1 байт          0Ch
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Со  стека берется размер словного сегмента, который будет
передвинут,  затем  адрес,  начиная  с которого двигать, затем
адрес,  начиная  с  которого  писать  этот сегмент. Передвижка
происходит пословно, поэтому в случае определенного перекрытия
сегментов  хвост передвигаемого сегмента может испортиться еще
до  того,  как его перенесли (см. текст на Модуле). Аккуратный
сдвиг выполняется командой WM (96h).
     Сдвиг  перекрывающихся  областей памяти в сторону младших
адресов  производится корректно; сдвиг в сторону старших можно
использовать для заполнения области одинаковыми значениями.
     PC увеличивается на 1.

В терминах интерпретатора:
     sz:=Pop();
     i:=Pop(); j:=Pop();
     WHILE sz>0 DO
       MEM[j]:=MEM[i]; INC(i); INC(j); DEC(sz)
     END

CHKNIL                             0C1h
CHecK address for NIL
Код операции:                   1 байт          0C1h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     PC  увеличивается  на  1 . Если на стеке лежит NIL, то PC
уменьшается на 1 и возбуждается прерывание.

Замечание. Команда не реализована на Кронос-2.2.

В терминах интерпретатора:
     i:=Pop(); Push(i);
     IF i=NIL THEN DEC(PC); TRAP(41h) END;

LSTA                            0C2h
Load STring Address
Код операции:                   1 байт          0C2h
Непосредственные операнды:      2 байта         0h..0FFFFh
Длина команды:                  3 байта
Действие:
     Грузит  на  стек  адрес  структуры,  полученный сложением
смещения,  взятого из двухбайтового непосредственного операнда
и содержимого 1-го слова области глобальных данных.
     PC увеличивается на 3.

В терминах интерпретатора:
     Push(MEM[G+1]+Next2());

COMP                            0C3h
COMPare strings
Код операции:                   1 байт          0C3h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со стека словные адреса двух строк, преобразует их
в  байтовые,  и  читает  из  памяти  по  два  байта, начиная с
указанных адресов, до тех пор, пока один из байтов не окажется
равным 0, либо до тех пор, пока они не окажутся разными. Тогда
на стек загружается последний прочитанный байт сначала второй,
затем  первой  строки с ведущими нулями. Полученные результаты
можно сравнить командами EQU, NEQ, LSS и т.д..
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop()*4; j:=Pop()*4;
     REPEAT
       a:=CHAR(ByteMEM[i]); b:=CHAR(ByteMEM[j]);
       INC(i); INC(j)
     UNTIL (a=0c) OR (b=0c) OR (a#b); Push(a); Push(b)

GB                              0C4h
Get procedure Base n level down
Код операции:                   1 байт          0C4h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байт
Действие:
     Осуществляет  проход  по  статической  цепочке на столько
уровней, сколько указано в непосредственном операнде, и грузит
на   стек   адрес  области  локальных  данных  соответствующей
статически объемлющей процедуры.
     PC увеличивается на 2.

В терминах интерпретатора:
     i:=L; k:=Next();
     WHILE k>0 DO i:=MEM[i]; DEC(k) END; Push(i)

GB1                             0C5h
Get procedure Base 1 level down
Код операции:                   1 байт          0C5h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет из памяти и грузит на стек начало области локальных
данных статически объемлющей процедуры.
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(MEM[L])

CHK                             0C6h
range boundary CHecK
Код операции:                   1 байт          0C6h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека  два значения, которые рассматривает как
верхнюю  и  нижнюю  границу  соответственно;  берет  и  грузит
обратно  следующий  элемент  стека, чтобы узнать его значение;
если  оно не лежит в пределах границ, помещает границы обратно
на стек и возбуждает прерывание 4Ah.
     PC увеличивается на 1.

В терминах интерпретатора:
     hi:=Pop(); low:=Pop(); i:=Pop(); Push(i);
     IF (i<low) OR (i>hi) THEN
       Push(low); Push(hi); TRAP(4Ah)
     END

CHKZ                            0C7h
array boundary CHecK (low=Zero)
Код операции:                   1 байт          0C7h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет   со  стека  значение,  которое  интерпретирует как
верхнюю  границу; в качестве нижней границы подразумевается 0.
Берет  и  грузит обратно следующий элемент стека, чтобы узнать
его  значение;  если  оно  не  лежит в пределах границ, помещает
верхнюю границу обратно на стек и возбуждает прерывание 4Ah.
     PC увеличивается на 1.

В терминах интерпретатора:
     hi:=Pop(); i:=Pop(); Push(i);
     IF (i<0) OR (i>hi) THEN Push(hi); TRAP(4Ah) END

ALLOC                           0C8h
ALLOCate block
Код операции:                   1 байт          0C8h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека  размер  отводимой памяти в словах. Если
S-регистр,  увеличенный  на размер, превышает границу P-стека,
происходит откат команды с  прерыванием номер 40h.
     Иначе   на  стек  грузится  текущее  значение  S-регистра
(начало  отводимой памяти), S-регистр увеличивается на столько
слов, каков размер отведенной памяти.
     В этом случае PC увеличивается на 1.

В терминах интерпретатора:
     sz:=Pop();
     IF S+sz>H THEN  Push(sz); DEC(PC); TRAP(40h)
     ELSE Push(S); INC(S,sz) END

ENTR                            0C9h
ENTeR procedure
Код операции:                   1 байт          0C9h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Выбирает  из  кода  размер  сегмента  локальных  данных в
словах.  Если  S-регистр,  увеличенный  на  размер,  превышает
границу  P-стека, происходит откат команды с прерыванием номер
40h.
     Иначе   увеличивает   S-регистр   на   размер  локального
сегмента.  В  этом  случае  в результате выполнения команды PC
увеличивается на 2.

В терминах интерпретатора:
     sz:=Next();
     IF S+sz>H THEN DEC(PC,2); TRAP(40h)
     ELSE INC(S,sz) END

RTN                             0CAh
ReTurN from procedure
Код операции:                   1 байт          0CAh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Восстанавливаются значение S-регистра до вызова процедуры
(т.е.   освобождается   память,   занятая  в  ходе  выполнения
процедуры),  значение  L-регистра  процедуры,  из которой была
вызвана  данная  процедура,  значение  PC  и,  если вызывалась
процедура  из  внешнего модуля, восстанавливается указатель на
область  глобальных  данных  исполняемого  модуля  и  по  нему
F-регистр.

В терминах интерпретатора:
     S:=L; L:=MEM[S+1]; PC:=WORD(BITSET(MEM[S+2])*{0..0Fh});
     IF ExternalBit IN BITSET(MEM[S+2]) THEN
       (* called from external module *)
       G:=MEM[S]; F:=CodePtr(MEM[G])
     END;

NOP                             0CBh
No OPeration
Код операции:                   1 байт          0CBh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     PC увеличивается на 1.
     При исполнении этой команды больше ничего не делается.

CX                              0CCh
Call eXternal
Код операции:                   1 байт          0CCh
Непосредственные операнды:      2 байта         0h..0FFh
Длина команды:                  3 байта
Действие:
     Вызов внешней процедуры.
     Если  значение  S-регистра, увеличенное на 4, превосходит
границу  P-стека, происходит откат команды с прерыванием номер
40h.
     Из  кода  выбираются  два  однобайтовых  непосредственных
операнда.  Первый интерпретируется как номер внешнего модуля в
локальной  DFT,  из  которого вызывается процедура, а второй -
как номер процедуры. После этого производится разметка P-стека
для  вызова  указанной  процедуры,  то  есть  в  нулевое слово
области локальных данных заносится G-регистр (для последующего
восстановления  командой  RTN),  в первое слово - указатель на
область  локальных  данных той процедуры, из которой произошел
вызов  (выстраивается динамическая цепочка), во второе слово -
PC  точки  вызова  с пометкой в 31-м бите о том, что вызов был
внешним  (для последующего восстановления PC). Затем по ссылке
восстанавливается   G-регистр   внешнего  модуля,  по  нему  -
F-регистр, PC устанавливается на начало вызванной процедуры.

В терминах интерпретатора:
     IF S+4<=H THEN j:=MEM[G-Next()-1]; (* big DFT *)
       i:=Next(); Mark(G,TRUE);
       G:=MEM[j]; F:=CodePtr(MEM[G]); PC:=GetPc(i);
     ELSE DEC(PC); TRAP(40h)
     END

CI                              0CDh
Call procedure at Intermediate level
Код операции:                   1 байт          0CDh
Непосредственные операнды:      1 байт          0h..0FFh 
Длина команды:                  2 байта
Действие:
     Если  значение  S-регистра, увеличенное на 4, превосходит
границу  P-стека, происходит откат команды с прерыванием номер
40h.
     Иначе      выбирается      непосредственный      операнд,
интерпретируемый  как  номер  вызываемой процедуры, после чего
производится  разметка P-стека для вызова процедуры, то есть в
нулевое слово области локальных данных заносится слово, взятое
со  стека  (например,  указатель  на  область локальных данных
процедуры,  статически  объемлющей  ту,  из которой происходит
вызов,  для  обеспечения  доступа  к  ее  локальным  данным  -
строится  статическая  цепочка), в первое слово - указатель на
область  локальных  данных той процедуры, из которой произошел
вызов  (строится  динамическая  цепочка), во второе слово - PC
точки  вызова (для последующего восстановления PC при возврате
из  процедуры).  Затем PC устанавливается на начало вызываемой
процедуры.

В терминах интерпретатора:
     IF S+4<=H THEN
       i:=Next(); Mark(Pop(),FALSE); PC:=GetPc(i);
     ELSE DEC(PC); TRAP(40h) END

CF                              0CEh
Call Formal procedure
Код операции:                   1 байт          0CEh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Если  значение  S-регистра, увеличенное на 3, превосходит
границу  P-стека, происходит откат команды с прерыванием номер
40h.
     Иначе   с   вершины  P-стека  берется  слово,  в  котором
содержится  процедурное  значение  вызываемой процедуры, после
чего  производится  разметка  P-стека для вызова процедуры, то
есть  в  нулевое  слово  области  локальных  данных  заносится
G-регистр (выстраивается  статическая цепочка), в первое слово
-  указатель  на  область  локальных  данных той процедуры, из
которой  произошел  вызов  (динамическая  цепочка),  во второе
слово  -  PC  точки  вызова  с пометкой в 31-м бите о том, что
вызов  был  внешним, поскольку формальная процедура может быть
как  локальной, так и внешней (для последующего восстановления
PC).  Затем PC устанавливается на начало вызываемой процедуры.
Старший  байт процедурного значения интерпретируется как номер
процедуры,  три младшие - как адрес входа в глобальную DFT. По
этому  адресу  вычисляется  адрес  глобальных данных модуля, в
котором  содержится вызываемая процедура, по нему - F-регистр.
PC устанавливается на начало процедуры.

Замечания. Ссылка  на  адрес своей области глобальных данных в
           0-м  слове  локальной  DFT модуля необходима, чтобы
           команда  CF  выполнялась  корректно для собственных
           локальных процедур модуля.

В терминах интерпретатора:
     IF S+3<=H THEN i:=MEM[S-1]; DEC(S); Mark(G,TRUE);
       k:=i DIV 1000000h; i:=i MOD 1000000h;
       G:=MEM[i]; F:=CodePtr(MEM[G]); PC:=GetPc(k);
     ELSE DEC(PC); TRAP(40h)
     END

CL                              0CFh
Call Local procedure
Код операции:                   1 байт          0CFh
Непосредственные операнды:      1 байт          0h..0FFh 
Длина команды:                  2 байта
Действие:
     Если  значение S-регистра, увеличенное на 4, не превышает
границы   P-стека   (Н-регистр),  выбирается  непосредственный
операнд,  интерпретируемый  как  номер  вызываемой  процедуры,
затем  производится  разметка  P-стека  для  вызова  локальной
процедуры:  в  нулевое  и  первое  слова,  начиная с адреса S,
заносится  дважды  значение  L-регистра;  во  второе  слово  -
текущее значение PC, после чего в L-регистр заносится значение
S-регистра,  затем  значение S-регистра увеличивается на 4, PC
устанавливается на начале процедуры, номер которой был взят из
кода.
     Иначе происходит откат команды с прерыванием номер 40h.

В терминах интерпретатора:
     IF S+4<=H THEN i:=Next(); Mark(L,FALSE); PC:=GetPc(i);
     ELSE DEC(PC); TRAP(40h) END

CL0..CL0F                       0D0h..0DFh
Call Local procedure
Код операции:                   4 бита          0Dh
Непосредственные операнды:      4 бита          0h..0Fh
Длина команды:                  1 байт
Действие:
     Команды  для  вызова  локальных  процедур  с  номерами из
диапазона 0h..0Fh (см. CL).

В терминах интерпретатора:
     IF S+4<=H THEN Mark(L,FALSE); PC:=GetPc(IR MOD 10h);
     ELSE DEC(PC); TRAP(40h) END

INCL                            0E0h
INCLude in set
Код операции:                   1 байт          0E0h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Со стека берется значение N, которое интерпретируется как
номер бита. Он может превышать 31.
     Затем  со  стека  берется  адрес  слова,  и в N-й битовой
позиции  относительно  этого  адреса  выставляется единица. PC
увеличивается на 1.

В терминах интерпретатора:
     i:=Pop(); j:=Pop() + i DIV 32;
     MEM[j]:=INTEGER( BITSET(MEM[j]) + {i MOD 32} );

EXCL                            0E1h
EXCLude from set
Код операции:                   1 байт          0E1h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Со стека берется значение N, которое интерпретируется как
номер бита. Он может превышать 31.
     Затем  со  стека  берется  адрес  слова,  и в N-й битовой
позиции   относительно  этого  адреса  выставляется  ноль.  PC
увеличивается на 1.

В терминах интерпретатора:
        i:=Pop(); j:=Pop() + i DIV 32;
        MEM[j]:=INTEGER( BITSET(MEM[j]) - {i MOD 32} );


INL                             0E2h
membership IN Long set
Код операции:                   1 байт          0E2h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Со  стека  берутся  размер  множества  в битах адрес и номер
бита.  Номер бита может быть произвольным числом. Если номер бита
меньше  нуля  либо  не  меньше  размера  множества,  то  на  стек
помещается   значение   0.   Иначе   значение,   извлеченное   из
соответствующей  битовой  позиции  относительно  взятого  адреса,
расширяется ведущими нулями до слова и помещается на стек.
     PC увеличивается на 1.

Замечание. Команда не реализована на П2.2.

В терминах интерпретатора:
     k:=Pop(); j:=Pop(); i:=Pop();
     IF (i<0) OR (i>=k) THEN Push(0)
     ELSE
       Push( (i MOD 32) IN BITSET(MEM[j+i DIV 32]) );
     END;

QUOT                            0E3h
QUOTient  commands
Код операции:                   1 байт          0E3h
Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Со  стека  берутся два операнда и выбирается однобайтовый
непосредственный операнд из кода.
     PC увеличивается на 2.
     Если значение непосредственного операнда:
     - 0, то командой осуществляется деление на степень двойки
       с  округлением  к  нулю;  при  этом  делимое  -  нижний
       операнд, степень - верхний.
     - 1,  то командой осуществляется деление нижнего операнда
       на верхний с округлением к нулю;

       Определим операцию "взятие по модулю" формулой:
       X MOD N = X - (X QOU N) * N,                        (1)
       где  QOU  -  деление  с округлением к нулю.

     - 2,  то  команда  является операцией "взятие по модулю",
       определяемой  формулой (1), где N - степень двойки; при
       этом делимое - нижний операнд, степень - верхний;
     - 3,  то  команда  является операцией "взятие по модулю",
       определяемой  формулой  (1),  при  этом  нижний операнд
       берется по модулю верхнего;
     - любое  другое,  то PC откатывается назад и возбуждается
       прерывание с номером 7h.

Замечание. Команда не реализована для П2.2.

В терминах интерпретатора:

     i:=Pop(); j:=Pop();
     CASE Next() OF
       |0: Push( j SHRQ i ); -- деление на степень двойки
       |1: Push( j QOU  i ); -- деление с округлением к нулю
       |2: Push( j ANDQ i ); -- модуль по степени двойки
       |3: Push( j REM  i ); -- модуль
     ELSE TRAP(7); DEC(PC,2)
     END;

INC1                            0E4h
INCrement by 1
Код операции:                   1 байт          0E4h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Увеличивает  на  единицу  значение,  лежащее  в памяти по
адресу, взятому со стека.
     PC увеличивается на 1.

В терминах интерпретатора:
     INC(MEM[Pop()])

DEC1                            0E5h
DECrement by 1
Код операции:                   1 байт          0E5h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Уменьшает  на  единицу  значение,  лежащее  в  памяти  по
адресу, взятому со стека.
     PC увеличивается на 1.

В терминах интерпретатора:
     DEC(MEM[Pop()])

INC                             0E6h
INCrement
Код операции:                   1 байт          0E6h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека целое число и адрес. Значение, лежащее в
памяти  по  указанному  адресу,  увеличивает на вышеупомянутое
число.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop(); INC(MEM[Pop()],i)

DEC                             0E7h
DECrement
Код операции:                   1 байт          0E7h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет  со  стека целое число и адрес. Значение, лежащее в
памяти по указанному адресу, уменьшает на указанное число.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop(); DEC(MEM[Pop()],i)

STOT                            0E8h
STOre Top on procedure stack
Код операции:                   1 байт          0E8h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Если  значение  S-регистра,  увеличенное  на 1, превышает
границу  P-стека, происходит откат команды с прерыванием номер
40h.
     Иначе  со  стека  выражений берется слово и помещается на
P-стек.
     PC увеличивается на 1.

В терминах интерпретатора:
     IF S+1>H THEN DEC(PC); TRAP(40h)
     ELSE MEM[S]:=Pop(); INC(S)
     END

LODT                            0E9h
LOaD Top of procedure stack
Код операции:                   1 байт          0E9h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Значение  с  вершины  P-стека  (элемент  с  адресом  S-1)
загружается на стек выражений. Значение S-регистра уменьшается
на 1.
     PC увеличивается на 1.

В терминах интерпретатора:
     DEC(S); Push(MEM[S])

LXA                             0EAh
Load indeXed Address
Код операции:                   1 байт          0EAh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     По  взятым  со  стека размеру элемента (в словах), номеру
элемента  и  адресу  структуры  (например,  массива) вычисляет
адрес элемента и помещает его на стек.
     PC увеличивается на 1.

В терминах интерпретатора:
     sz:=Pop(); i:=Pop(); adr:=Pop(); Push(adr+i*sz)

LPC                             0EBh
Load Procedure Constant
Код операции:                   1 байт          0EBh
Непосредственные операнды:      2 байта         0h..0FFh 
Длина команды:                  3 байта
Действие:

     Из  кода  выбираются  два  однобайтовых  непосредственных
операнда. Первый интерпретируется как номер модуля в локальной
DFT,  второй  -  как  номер  процедуры.  Номера  упаковываются
следующим  образом: в старший байт помещается номер процедуры,
в  младшие  три  -  элемент  локальной DFT с указанным номером
модуля. Полученное слово грузится на стек.
     PC увеличивается на 3.

В терминах интерпретатора:
     i:=Next(); j:=Next(); Push(j*1000000h+MEM[G-i-1])

BBU                             0ECh
Bit Block Unpack
Код операции:                   1 байт          0ECh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Со стека берется размер битовой вырезки. Если он меньше 1
или  больше  32,  происходит откат команды с прерыванием номер
4Ah.
     Иначе  формируется  битовая вырезка указанного размера, с
битовым смещением, взятым со стека, и начинающаяся со словного
адреса,  взятого со стека. Вырезка дополняется ведущими нулями
до слова и грузится на стек.
     PC увеличивается на 1.

Замечание. Команда не реализована на Кронос-2.2.

В терминах интерпретатора:
     sz:=Pop();
     IF (sz<1) OR (sz>32) THEN
       Push(sz); DEC(PC); TRAP(4Ah)
     END;
     i:=Pop(); adr:=Pop();
     (* j:=битовая вырезка длиной sz, начиная с
        битового адреса (adr,i)
     *)
     Push(j);

BBP                             0EDh
Bit Block Pack
Код операции:                   1 байт          0EDh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     PC увеличивается на 1.
     Со  стека  берется  битовое  значение  и его размер. Если
размер  меньше  1  или  больше 32, размер грузится на стек, PC
уменьшается на 1 и возбуждается прерывание с номером 4Ah.
     Иначе  указанное  размером  число младших битов вырезки с
битовым  смещением, взятым со стека, упаковывается по словному
адресу, взятому со стека.

Замечание. Команда не реализована на Кронос-2.2.

В терминах интерпретатора:
     j:=Pop(); sz:=Pop();
     IF (sz<1) OR (sz>32) THEN
       Push(sz); DEC(PC); TRAP(4Ah)
     END;
     i:=Pop(); adr:=Pop();
     (* Упаковывает sz младших битов из j по  битовому  адресу
     (adr,i)*)

BBLT                            0EEh
Bit BLock Transfer
Код операции:                   1 байт          0EEh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Со  стека  берутся  битовый размер пересылаемого сегмента
(может  быть  больше  32),  битовое  смещение  и словный адрес
пересылаемого сегмента, битовое смещение и словный адрес, куда
пересылается сегмент, и производится пересылка.
     PC увеличивается на 1.

Замечание. В случае перекрытия  сегментов можно получить самый
           неожиданный  результат.  Ожидаемый  результат  даст
           использование команды BM (97h).

Замечание. Команда не реализована на Кронос-2.2.

В терминах интерпретатора:
     sz:=Pop();
     i:=Pop(); adr:=Pop();
     j:=Pop(); adr1:=Pop();
     (* Переслать sz битов (adr,i) -> (adr1,j) *)

PDX                             0EFh
Prepare Dynamic indeX
Код операции:                   1 байт          0EFh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     PC увеличивается на 1.
     Со  стека  берутся  два операнда, нижний интерпретируется
как  указатель  на  дескриптор  массива,  верхний - как индекс
элемента  массива.  Дескриптор массива - пара слов в памяти, в
первом  из них лежит адрес начала массива, во втором - верхняя
граница массива.
     На  стек грузится адрес начала массива и индекс элемента.
Если  индекс  оказался  меньше  0  или  больше,  чем  граница,
указанная  в  дескрипторе,  возбуждается  прерывание с номером
4Ah.

Замечание. Команда не реализована на Кронос-2.2.

В терминах интерпретатора:
     i:=Pop(); dyn:=Pop();
     Push(dyn^.adr); Push(i);
     IF (i<0) OR (i>dyn^.high)
       THEN TRAP(4Ah)
     END

SWAP                            0F0h
SWAP
Код операции:                   1 байт          0F0h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Меняет местами два верхних элемента стека.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop(); j:=Pop(); Push(i); Push(j)

LPA                             0F1h
Load Parameter Address
Код операции:                   1 байт          0F1h
Непосредственные операнды:      1 байт          0h..0FFh 
Длина команды:                  2 байта
Действие:
     Грузит на стек величину, равную значению L-регистра минус
значение непосредственного операнда минус единица.
     PC увеличивается на 2.

В терминах интерпретатора:
     Push(L-Next()-1);

LPW                             0F2h
Load Parameter Word
Код операции:                   1 байт          0F2h
Непосредственные операнды:      1 байт          0h..0FFh 
Длина команды:                  2 байта
Действие:
     Грузит  на  стек  слово,  лежащее по адресу, вычисленному
следующим   образом:   значение   L-регистра   минус  значение
непосредственного операнда минус единица.
     PC увеличивается на 2.

В терминах интерпретатора:
     Push(MEM[L-Next()-1]);

SPW                             0F3h
Store Parameter Word
Код операции:                   1 байт          0F3h
Непосредственные операнды:      1 байт          0h..0FFh 
Длина команды:                  2 байта
Действие:
     Берет  со  стека  слово  и  записывает в память по адресу,
равному  значению  L-регистра минус значение непосредственного
операнда минус единица.
     PC увеличивается на 2.

В терминах интерпретатора:
     MEM[L-Next()-1]:=Pop();

Замечание. Три   вышеописанные   команды   LPA,   LPW   и  SPW
           поддерживают способ адресации, позволяющий работать
           с  процедурными  параметрами, положенными на P-стек
           до вызова процедуры.

SSWU                            0F4h
Store Stack Word Undestructive
Код операции:                   1 байт          0F4h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет со стека слово и записывает его в память по адресу,
взятому  со  стека,  после  чего  снова загружает это слово на
стек.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Pop(); MEM[Pop()]:=i; Push(i)

RCHK                            0F5h
Range CHecK
Код операции:                   1 байт          0F5h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Со  стека  берутся два операнда, которые интерпретируются
как  верхняя  (верхний  операнд)  и  нижняя  (нижний  операнд)
границы  отрезка.  Если  число,  лежащее  на стеке, выходит за
границы отрезка, на стек грузится 0 (FALSE), иначе - 1 (TRUE).
     PC увеличивается на 1.

Замечание. Команда не реализована на Кронос-2.2.

В терминах интерпретатора:
     hi:=Pop(); low:=Pop(); i:=Pop(); Push(i);
     Push( (i>=low) & (i<=hi) );

RCHZ                            0F6h
Range CHeck (low=Zero)
Код операции:                   1 байт          0F6h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Со  стека  берется  операнд, который интерпретируется как
верхняя граница отрезка. Нижней границей служит 0. Если число,
лежащее на стеке, выходит за границы отрезка, на стек грузится
0 (FALSE), иначе - 1 (TRUE).
     PC увеличивается на 1.

Замечание. Команда не реализована на Кронос-2.2.

В терминах интерпретатора:
     hi:=Pop(); i:=Pop(); Push(i);
     Push( (i>=0) & (i<=hi) );

CM                              0F7h
Call procedure from dynamic Module
Код операции:                   1 байт          0F7h

Непосредственные операнды:      1 байт          0h..0FFh
Длина команды:                  2 байта
Действие:
     Если   позволяет   размер  процедурного  стека,  из  кода
выбирается   непосредственный  операнд,  интерпретируемый  как
номер  процедуры.  Осуществляется  вызов процедуры с указанным
номером  из  модуля,  G-регистр  которого  взят  с  P-стека (с
которого   он   при   этом   счеркивается).  Разметка  P-стека
производится  так же, как в случае вызова формальной процедуры
(см. CF). PC устанавливается на начало вызываемой процедуры.
     Иначе происходит откат команды с прерыванием номер 40h.

Замечание. Команда не реализована на Кронос-2.2.

В терминах интерпретатора:
     IF S+4<=H THEN
       i:=Next();
       DEC(S); j:=MEM[S];
       Mark(G,TRUE);
       G:=j; F:=CodePtr(MEM[G]); PC:=GetPc(i);
     ELSE DEC(PC); TRAP(40h)
     END;

CHKBX                             0F8h
CHecK Boxes
Код операции:                   1 байт          0F8h
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Берет со стека два операнда, которые интерпретируются как
указатели   на   упакованные   прямоугольники.   Прямоугольник
определяется  диагональю, проведенной из левого нижнего угла в
правый верхний. Координаты каждого конца диагонали упакованы в
слово,  в  котором  старшие  16 битов определяют координату по
вертикали,   младшие  16  -  по  горизонтали.  Все  координаты
положительные  (в  диапазоне  0..0FFFFh).  Если прямоугольники
пересекаются, на стек помещается 1 (TRUE), иначе - 0 (FALSE).
     PC увеличивается на 1.

Замечание. Команда реализована только на Кронос-2.6.

В терминах интерпретатора:
     p0:=Pop(); p1:=Pop();
     x0b:=INTEGER( BITSET(p0^)     *{0..15});
     y0b:=INTEGER((BITSET(p0^)<<16)*{0..15});
     INC(p0);
     x0e:=INTEGER( BITSET(p0^)     *{0..15});
     y0e:=INTEGER((BITSET(p0^)<<16)*{0..15});
     x1b:=INTEGER( BITSET(p1^)     *{0..15});
     y1b:=INTEGER((BITSET(p1^)<<16)*{0..15});
     INC(p1);
     x1e:=INTEGER( BITSET(p1^)     *{0..15});
     y1e:=INTEGER((BITSET(p1^)<<16)*{0..15});
     Push( (x1b<=x0e) & (y1b<=y0e) & (x0b<=x1e) & (y0b<=y1e) );

BMG                             0F9h
BitMap Graphic commands
Код операции:                   1 байт          0F9h
Непосредственные операнды:      1 байт          0h..0FFh 
Длина  команды:                 2 байта
Действие:
     Команда  для  поддержки  bitmap-графики. Поскольку точное
описание   команды   на   языке   Модула-2  весьма  обширно  и
представляет  интерес  только  для  специального изучения, оно
выделено в самостоятельный документ "Интерпретатор графических
команд".  Здесь приводится лишь поверхностное описание функций
команды BMG.
     Команда   реализована   на   Кронос-2.6  и  с  некоторыми
ограничениями на Кронос-2.5.
     Для   применения   команды   рекомендуется   использовать
соответствующую библиотеку графики.
     Команда  выбирает  байт  из  кода.  Если полученное целое
число выходит из диапазона [0..9], то происходит откат PC на 2
и   возбуждается   прерывание   номером   49h.   Иначе   число
интерпретируется как номер одной из описанных ниже подкоманд и
соответствующая подкоманда исполняется.
     Все  параметры  передаются  командам либо непосредственно
через  стек,  либо  через  указатели,  размещенные  на  стеке,
которые  указывают  на  массив параметров в памяти. В описании
операнды перечисляются в том порядке, в котором они берутся со
стека.
     Команды   осуществляют   операции   над  областью  памяти
(битовой      картой),     определенной     так     называемым
bitmap-дескриптором (BMD).
     Bitmap-дескриптор представляет собой запись из пяти слов,
первое  из  которых  -  горизонтальный  размер битовой карты в
битах,  второе  -  вертикальный  размер битовой карты в битах,
третье  -  число  слов в одной строке изображения, четвертое -
адрес  битовой  карты,  пятое  -  шаблон,  который  использует
подкоманда DLN (см. ниже).

Код:        0
Подкоманда: IN_RECT (IN RECTangle?)
Действие:   проверка  принадлежности  точки  прямоугольнику  с
            диагональю,  проведенной  из левого нижнего угла в
            правый верхний, с координатами (0,0) и (w,h).
Операнды  на  стеке:
            1,2)   горизонтальная  и  вертикальная  координаты
            точки;
            3,4)   горизонтальная  и  вертикальная  координаты
            правого верхнего угла прямоугольника.
Результат на стеке:
            FALSE    (0)   -   если   точка   не   принадлежит
            прямоугольнику; TRUE (1) - если принадлежит.

Код:        1
Подкоманда: DVL (Display Vertical Lines)
Действие:   построение  на  битовой  карте изображения отрезка
            вертикальной  линии  указанной  длины  в указанной
            моде  от  указанной  точки  в  сторону  увеличения
            адресов.
Операнды на стеке:
            1)  режим,  в  котором будет строиться изображение
            отрезка  (REPLACE,  OR,  XOR,  BIC),  определяется
            операндом, равным 0,1,2 или 3 соответственно.
            2) указатель на BMD;
            3,4) координаты точки по горизонтали и вертикали;
            5) длина линии.
Результат на стеке: нет.

Код:        2
Подкоманда: BBLT_G (BBLT-Graphic)
Действие:   команда  BBLT  с  режимами:  производит логические
            операции  (REPLACE, OR, XOR, BIC)  над  приемником
            и источником, являющимися массивами битов.
Операнды на стеке:
            1)   режим,   указывающий,  какая  операция  будет
            произведена  над приемником и источником (REPLACE,
            OR,  XOR,  BIC),  определяется  операндом,  равным
            0,1,2 или 3 соответственно.
            2) операнды, аналогичные операндам команды BBLT.
Результат на стеке: нет.

Код:     3
Подкоманда: DCH   (Display   CHar)
Действие:   построение  на битовой карте изображения символа с
            указанной кодировкой из указанного шрифта.
Операнды на стеке:
            1)  режим,  в  котором  будет  изображаться символ
            (REPLACE,  OR,  XOR, BIC), определяется операндом,
            равным 0, 1, 2 или 3 соответственно;
            2) указатель на BMD;
            3,4)   координаты  символа  по  горизонтали  и  по
            вертикали;
            5) указатель на дескриптор шрифта;
            6)   кодировка   символа,   изображение   которого
            требуется построить.
Результат на стеке: нет.

Код:     4
Подкоманда:  CLP (CLiPping)
Действие:   клипирование   отрезка  прямой  прямоугольником  c
            диагональю,  проведенной  из левого нижнего угла в
            правый верхний, с координатами (0,0) и (w,h).
Операнды на стеке:
            1)  указатель  на  массив из 4-х параметров. Перед
            выполнением  команды  в  эти  4  слова должны быть
            занесены  координаты  концов отрезка. Если отрезок
            пересекается с прямоугольником, то команда заносит
            в них координаты концов клипированного отрезка.
            2,3)   горизонтальная  и  вертикальная  координаты
            правого верхнего угла прямоугольника.
Результат на стеке:
            TRUE, если отрезок пересекается с прямоугольником,
            иначе FALSE.

Код:        5
Подкоманда: DLN   (Display   LiNe)
Действие:   построение  на  битовой  карте изображения отрезка
            произвольной прямой по двум точкам.
Операнды на стеке:
            1)  режим,  в  котором  будет изображаться отрезок
            (REPLACE,  OR,  XOR, BIC), определяется операндом,
            равным 0,1,2 или 3 соответственно;
            2) указатель на BMD;
            3,4)   горизонтальная  и  вертикальная  координаты
            одного конца отрезка;
            5,6)   горизонтальная  и  вертикальная  координаты
            другого конца отрезка.
Результат на стеке: нет.

Замечание.  Подкоманда  DLN  не  отслеживает  выход отрезка за
            границы битовой карты.

Код:     6
Подкоманда:  CRC (CiRCus)
Действие:   реализует  тело цикла изображения на битовой карте
            окружности с указанными центром и радиусом. Строит
            на  битовой  карте  8  точек,  принадлежащих  этой
            окружности.
Операнды на стеке:
            1)  режим,  в  котором будет строиться изображение
            (REPLACE,  OR,  XOR, BIC), определяется операндом,
            равным 0,1,2 или 3 соответственно;
            2) указатель на BMD;
            3)   указатель   на   массив  параметров  (радиус,
            0 и радиус, поделенный надвое).
            4,5)   горизонтальная  и  вертикальная  координаты
            центра окружности.
Результат на стеке: нет.

Код:     7
Подкоманда:  ARC  (ARC)
Действие:   реализует  тело цикла изображения на битовой карте
            дуги  окружности  с указанными центром, радиусом и
            углом, заданным двумя точками.
Операнды на стеке:
            1)  режим,  в  котором будет строиться изображение
            (REPLACE,  OR,  XOR, BIC), определяется операндом,
            равным 0,1,2 или 3 соответственно;
            2) указатель на BMD;
            3) указатель на массив параметров.
Результат на стеке: нет.

Код:     8
Подкоманда: TRF  (TRiangle  Filling)
Действие:   поддерживает    процедуру    заполнения   области,
            ограниченной  прямыми. Вычисляет координаты точек,
            между   которыми   нужно  провести  горизонтальную
            линию, чтобы закрасить область.
Операнды на стеке:
            указатель   на  массив  параметров.  В  результате
            выполнения  команды  в  него заносятся вычисленные
            координаты.
Результат на стеке: нет.

Код:     9
Подкоманда: CRF (CiRcus  Filling)
Действие:   поддерживает процедуру заполнения круга. Вычисляет
            координаты  точек,  между  которыми нужно провести
            горизонтальную линию, чтобы закрасить круг.
Операнды на стеке:
            указатель   на  массив  параметров.  В  результате
            выполнения  команды  в  них  заносятся вычисленные
            координаты.
Результат на стеке: нет.

В терминах интерпретатора:
     CASE Next() OF
       |0: IN_RECT
       |1: DVL
       |2: BBLT_G
       |3: DCH
       |4: CLP
       |5: DLN
       |6: CRC
       |7: ARC
       |8: TRF
       |9: CRF
     ELSE
       Trap(49h)
     END;

ACTIV                           0FAh
ACTIVe process
Код операции:                   1 байт          0FAh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     Загружает  на  стек  адрес дескриптора активного процесса
(содержимое P-регистра процессора).
     PC увеличивается на 1.

В терминах интерпретатора:
     Push(P)

USR                             0FBh
USeR defined functions
Код операции:                   1 байт          0FBh
Непосредственные операнды:      1 байт          0h..0FFh 
Длина команды:                  2 байта
Действие:
     Команда  оставлена  для дальнейшего возможного расширения
системы команд.
     PC увеличивается на 1.

В терминах интерпретатора:
     i:=Next(); (*  *)

SYS                             0FCh
rarely SYStem functions
Код операции:                   1 байт          0FCh
Непосредственные операнды:      1 байт          0h..0FFh 
Длина команды:                  2 байта
Действие:
     Если  в  значение  непосредственного операнда равно 0, то
грузит  на  стек  слово,  идентифицирующее процессор. Если 2 -
модель процессора. Иначе возбуждается прерывание с номером 7h.
     PC увеличивается на 2.

В терминах интерпретатора:
     CASE Next() OF
       |00h: (* PID Processor IDent *)
             (* Push(PID) *)
       |02h: (* PM Processor Model *)
             (* Push(PM) *)
     (* Остальные могут быть различными в разных моделях *)
     ELSE TRAP(7h)
     END;

NII                             0FDh
Never Implemented Instruction
Код операции:                   1 байт          0FDh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     При  исполнении  этой  команды  возбуждается прерывание с
номером 7h. PC увеличивается на 1.

Замечание. Команда не реализована на Кронос-2.2.

В терминах интерпретатора:
     TRAP(7h);

INVLD                           0FFh
INVaLiD command
Код операции:                   1 байт          0FFh
Непосредственные операнды:      0 байт
Длина команды:                  1 байт
Действие:
     При вызове этой команды возбуждается прерывание с номером
49h. PC увеличивается на 1.

В терминах интерпретатора:
     TRAP(49h)


      ЧАСТЬ IV. ИЛЛЮСТРАЦИИ  К  АРХИТЕКТУРЕ  ПРОЦЕССОРОВ


     Данный  раздел  может  быть  использован  как  пособие по
архитектуре   семейства  процессоров  КРОНОС,  системе  команд
(М-код) и работе Модула-2 компилятора.
     Будем вести изложение в следующей форме:

   _______________________________________________________
   |                          |                          |
   |    Текст    программы    |    Генерируемый код      |
   |                          |                          |
   |      на  Модуле - 2      |     с комментариями      |
   |__________________________|__________________________|
   |                          |                          |
   |                          |                          |


     Заметим,  что  приведенный  код является иллюстративным и
поэтому может отличаться от кода, порождаемого текущей версией
компилятора. Причины следующие:
     1)  в  примерах не отражены оптимизации, которые повышают
эффективность кода, но затрудняют восприятие примера;
     2)  в  некоторых  примерах  приведено несколько вариантов
генерации,   а   в   текущей  версии  компилятора  реализован,
естественно, какой-то один;
     3)  опущены  команды  динамического  контроля  (например,
контроля границ массивов).

     В   примерах   используются   мнемоники   команд  М-кода.
Формальное  описание команд приведено в интерпретаторе М-кода.


                         1. ОПЕРАТОРЫ

     1.1. Присваивание


 MODULE   M;

 VAR  G:INTEGER;
      B:BITSET;

 BEGIN

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | G:=1;                            LI1 SGW2             |
 | G:=G+255;                        LGW2 LIB FF ADD SGW2 |
 - - - - - - - - - - - - - - - - - - |- - -\-/- -|- -|- --
                                     |      |    |   |
                                     G     255  '+'  G:=


 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | B:={0..31};                      LIW FFFFFFFF SGW3    |
 - - - - - - - - - - - - - - - - - - - \-/- - - - -|- - --
 END M.                                 |          |
                                      {0..31}       B:=


     1.2. Доступ к глобальным переменным


 MODULE  M;

 VAR  G2,G3,G4, ... ,G255:INTEGER;
      G256: INTEGER;


 BEGIN
 - - - - - - - - - - - - - - - - - - - - - - -
 | G2  :=  G2;                      LGW02  SGW02 |
 | G255:=G255;                      LGW FF SGW FF| (1.2.1)
 | G256:=G256;                           ---     | (1.2.2)
 - - - - - - - - - - - - - - - - - - - - - - -
 END M.

Примечание 1.2.1. К первым 14 глобалам с номерами 2..15 доступ
           однобайтовый,  к  глобалам  с  номерами  16..255  -
           двухбайтовый.

Примечание   1.2.2.   Это  не  компилируется  текущей  версией
           компилятора, но может порождаться так:

      LGA FF LSW1      LGA FF SSW1


     1.3. Доступ к внешним переменным

     Внешними  переменными  называются  глобальные  переменные
других модулей.

 DEFINITION MODULE M;
   VAR i: INTEGER;
 END M.
                       номер модуля М в локальной DFT модуля N
 MODULE N;                           | Номер
 FROM M IMPORT i;                    | переменной i в модуле М
 BEGIN                               |  |
 - - - - - - - - - - - - - - - - - - |- |- - - - - - --
 | i:=i;                         LEW 01 02  SEW 01 02 |
 - - - - - - - - - - - - - - - - - - - - - - - - - - --
 END N.

     Подробнее  о  локальной  DFT  можно  узнать  из примеров,
относящихся к процедурам (см. раздел 2).


     1.4. Условный оператор (IF)

 MODULE M;

 VAR bool :BOOLEAN;                  +--->      LGW2
     G3,G4:INTEGER;                  | (1.4.1) JSFC 04  --+
 BEGIN                               |                    |
  - - - - - - - - - - - - - - - - - -          LI3 SGW3   |
 |IF bool THEN G3:=3 ELSE G4:=4 END;                      |
  - - - - - - - - - - - - - - - - - -  (1.4.2) JSF 02   --|--+
 END M.                              |      ______________|  |
                                     |      |-->LI4 SGW4     |
                                     |      _________________|
                                     +--->  +-->

Примечание  1.4.1. Если на А-стеке 0, то PC увеличивается на 4
           байта,      пропуская      TRUE-альтернативу.     0
           интерпретируется как FALSE, #0 - TRUE.


Примечание    1.4.2.    Безусловный    переход    (если   есть
           FALSE-альтернатива).


     1.5. Оператор цикла (LOOP)

     Генерация LOOP-цикла переходом (как реализовано в текущей
версии):


MODULE M;


BEGIN                           -->      - - - - - - - - -
  - - - - - - - - - - - - - - --/         |--> JSF 02  --|--|
  | LOOP   EXIT END;                                     |  |
  - - - - - - - - - - - - - - --\              JSB 04  --|--|
END  M.                         -->      - - - - - - - - -
                                          |-->

     Если   тело   цикла   большое,   то  переход  может  быть
двухбайтовым.

 MODULE M;
 VAR G2:INTEGER;
 BEGIN
 - - - - - - - - - - -> |-->|---------------|
 | LOOP                 |   | код для CASE  |
 |   CASE G2 OF         |   | размером более|
 |   0..127: G2:=0      |   | 255 байтов    |   |- -> (1.5.1)
 |   END;               |   |_______________|   |
 | END;                 |---- JLB    offset     |
 - - - - - - - - - - ->          |_____|_____|--|
 END M.

Примечание 1.5.1.  Двухбайтовое смещение для переходов длиннее
           255 байт.

     Генерация LOOP-цикла с помощью команд ENTS и XIT:

 MODULE M;

 VAR G2:INTEGER;
                                     G2:=0
 BEGIN                                 |
 - - - - - - - - - - - - - - - - - - -/-\- - - -
 | G2:=0;                           LI0 SGW2    |
 | LOOP                            ENTS 000C    |  (1.5.2)
 - - - - - - - - - - - - - - - - - - - - - - - -
                            __________________________________
                            |     G2    1    +   G2:=        |
 - - - - - - - - - - - ->   |     |     |    |    |          |
 |   G2:=G2+1;              |--> LGW2  LI1  ADD  SGW2        |
 |                                                           |
 |   IF G2>5 THEN EXIT END;    LGW2 LI5 GTR JSFC 01 XIT JSB 0C
 - - - - - - - - - - - ->        |    |   |
   END;                          G2   5   >
 END M.

Примечание 1.5.2.  ENTS  кладет  на  вершину  P-стека  текущее
           значение  PC  + значение следующих за командой двух
           байтов. XIT берет с верхушки P-стека новое значение
           PC, совершая переход.

     1.6. Оператор цикла (REPEAT)

 MODULE M;
   VAR G2:INTEGER; bool: BOOLEAN;
 BEGIN
  - - - - - - - - - - - - - - - - ->     _____________________
  | REPEAT G2:=1 UNTIL bool;             |--> LI1  SGW2      |
  - - - - - - - - - - - - - - - - ->          LGW3 JSBC 05 --|
 END M.



     1.7. Оператор цикла (FOR)

 MODULE M;

  VAR i,G3:INTEGER;

 BEGIN



                                        i:=0
                                        / | \

                                   -->LGA 02  LI0
                                  /   LIB 127        -- 127
                                 /            - - - -
  -- - - - - - - - - - - - - - -      FOR1 00| 00 06|--(1.7.1)
  |FOR i:=0 TO 127 BY 2 DO G3:=i             |offset|
  -- - - - - - - - - - - - - - -              - - - -
   END;                          \    LGW2 SGW3       -- G3:=i
 END M.                           \           - - - -
                                   -->FOR2 02| 00 06|--(1.7.2)
                                           | |offset|
                                           |  - - - -
                                      шаг цикла


Примечание 1.7.1.  FOR1  берет  со  стека  конечное  значение,
           начальное  значение,  адрес  параметра  цикла. Знак
           шага  - следующий байт кода. Если в следующем байте
           0,   шаг   положительный,   если   не   0   -   шаг
           отрицательный.  Если  условия  цикла не выполняются
           сразу  (конечное  значение  меньше  начального  при
           положительном   шаге   или  наоборот),  тело  цикла
           обходится   с   помощью   указанного  размера  тела
           (offset); иначе начальное значение присваивается по
           указанному   адресу   параметра  цикла,  на  P-стек
           помещаются   адрес   параметра   цикла  и  конечное
           значение, после чего выполняется тело цикла.

Примечание 1.7.2. FOR2 по параметрам, взятым с P-стека, и шагу
           цикла  определяет  возможность  еще одной итерации.
           Если она возможна, увеличивает значения, лежащие по
           указанному  адресу  на 'шаг' и осуществляет переход
           назад  на  указанное  число  байтов (offset). Иначе
           счеркивает  с  P-стека  параметры (адрес переменной
           цикла и конечное значение).

     1.8. Оператор выбора (CASE)


 MODULE M;

   VAR G2,G3:  INTEGER;

 BEGIN


 - - - - - - - - - ->                  LGW2
 | CASE G2 OF                          ENTC 0009 - - |
 |  |1..2: G3:=2            |- - - - ->LI2 SGW3  XIT |
 |  |5   : G3:=3        |---|--------->LI3 SGW3  XIT | (1.8.1)
 | ELSE    G3:=4        |   |   |----->LI4 SGW3  XIT |
 | END;                 |   |   |   _ _ _ _ _ _ _ _ _|
 - - - - - - - - - ->   |   |   |   |
                        |   |   |   |->0001 0005       (1.8.2)
 END M.                 |   |   |
                        |   |   |   смещение  альтернатива
                        |   |   |       |        |
                        |   |   |------0009 -- ELSE
                        |   |- -|- - - 0011 -- 1
                        |   |- -|- - - 0013 -- 2
                        |       |------000F -- ELSE
                        |       |------0011 -- ELSE
                        -------------- 0016 -- 5


Примечание 1.8.1.  ENTC выбирает двухбайтовое смещение из кода
           и переходит в таблицу выбора.


Примечание 1.8.2.  Из  кода  выбираются  минимальное  (lo=1) и
           максимальное  (hi=5)  значения  альтернатив.  Затем
           вычисляется  PC  точки  выхода PC'=PC+2*(hi-lo)+4 и
           записывается  на P-стек. Затем с А-стека выбирается
           значение  параметра  i и подготавливается переход к
           нужной  альтернативе:  PC:=PC+2*(i-lo+1).  В случае
           i>hi  или  i<lo  PC остается неизменным. Теперь все
           готово  к переходу: из кода выбирается двухбайтовое
           смещение  delta, определяющее переход PC:=PC-delta.
           После   выполнения   группы   операторов  выбранной
           альтернативы   выполняется   команда  XIT,  которая
           осуществляет   выход   из   CASE  путем  выполнения
           PC:=PC'. PC' берется командой XIT с P-стека.



                          2. ПРОЦЕДУРЫ


     2.1. Описание и вызов примитивной процедуры


 MODULE M;

 PROCEDURE P; (* процедура 1 *)

       - - - - - - - - - - - - - - - - - -
 BEGIN | RETURN END P;              RTN  |
       - - - - - - - - - - - - - - - - - -

 BEGIN        (* процедура 0 *)
  - - - - - - - - - - - - - - - - - - - -
  | P;                              CL1 | (2.1.1)
  - - - - - - - - - - - - - - - - - -|- -
 END M.                              |
                        вызов локальной процедуры 1


Примечание 2.1.1. CL1 маркирует P-стек следующим образом:

                P-стек--> |          |
                          |__________|
      L в точке входа --> |          | <-- S в точке вызова
                          |    L     |
      статическая     --> |__________| \
          и           --> |    L     |__\ значения регистров
      динамическая        |__________|  / в точке вызова
        цепочки           |    PC    | /
                          |__________|
                          |не трогает|<-- см. команды SETM,RTN
                          |__________|
      S  в точке входа--> |          |
                          |          |

           После  маркировки  в L засылается значение S, а в S
           значение  S+4. По номеру процедуры (в данном случае
           -  1) из процедурной таблицы (см. Примечание 2.1.2)
           извлекается смещение до начала кода соответствующей
           процедуры  и  засылается  в РС, после чего начинают
           исполняться  команды  тела  процедуры. RTN берет из
           области связей процедуры значение РС и L в точке их
           вызова и засылает их в регистры РС и L. В регистр S
           засылается  значение  L  в  точке возврата (которое
           является старым значением S в точке вызова).

Примечание  2.1.2.  Процедурная  таблица  - таблица, по номеру
           процедуры    указывающая   смещение   начала   кода
           процедуры  относительно начала кода модуля. Нулевая
           процедура - инициализирующая часть модуля.


     2.2. Работа с локалами процедуры

 MODULE M;
 PROCEDURE P; (* процедура 1 *)
                         число локальных переменных процедуры
                                         |
       - - - - - - - - - - - - - - - - - |- - - --
 VAR   |L4: INTEGER;                ENTR 01      | (2.2.1)
 BEGIN |L4:=0; RETURN               LI0 SLW4 RTN |
       - - - - - - - - - - - - - - - - - - |- - --
 END P;                                    |
                                  первые четыре слова (0..3)
                                  заняты под область связей

 BEGIN        (* процедура 0 *)
 - - - - - - - - - - - - - - - - - - - - - -
 |P;                                CL1    |
 - - - - - - - - - - - - - - - - - - - - - -
 END M.

Примечание 2.2.1. ENTR 01 передвигает регистр S на одно слово:

        |___________| <-- L                 |__________| <-- L
       0|           |          ENTR 01     0|          |
       1| с в я з и |        ---------->   1| с в я з и|
       2|           |                      2|          |
       3|___________|                      3|__________|
        |           | <-- S                4|__________|
                                            |          | <-- S

           После   этого   становится   возможным  работать  с
           локальной    переменной    командами    LLW,    SLW
           (аналогичными   командам   LGW,  SGW),  адресующими
           данные относительно L-регистра.



     2.3. Вложенные процедуры


 MODULE M;


 PROCEDURE p1;  (* процедура 1*)
   VAR p1L4:INTEGER;


   PROCEDURE p2; (* процедура  2*)
.PAGE
                                кладет      на     А-стек
                                L-регистр    охватывающей
   VAR p2L4:INTEGER;            процедуры p1
   BEGIN                             |
      - - - - - - - - - - - - - - - -|- - - - - - - ---
      |p1L4:=12;                    GB1  LI12  SSW4   |
      |p2L4:=11;                    LI11 SLW4  RTN    |
      - - - - - - - - - - - - - - - - - - - - - - - - -
   END p1;               номер процедуры в процедурной таблице
 BEGIN                                         |
   - - - - - - - - - - -- - - - - - - - - - - -|- - -
   |p1L4:=2;                       LI2  SLW4   |     |
   |p2;                            LLA 00  CI 02 RTN | (2.3.1)
   - - - - - - - - - - -- - - - - - - -|- -|- - - - -
 END p1;                               |   |
                       Значение L-регистра |
                                           |
                команда вызова процедуры промежуточного уровня

 BEGIN
 - - - - - - - - - - - - - - - - - - - - -
 |p1;                               CL1  |
 - - - - - - - - - - - - - - - - - - - - -
 END M.


     2.4. Вызов внешней процедуры


 DEFINITION MODULE N;

 PROCEDURE proc1;

 END N.


 MODULE M;

 FROM N IMPORT proc1;


                                    номер модуля
                                      |
 PROCEDURE p1;                        | номер процедуры модуля
 BEGIN                                |  |
 - - - - - - - - - - - - - - - - - - -| -|- - -
 |  proc1;                        CX 01 01 RTN |  (2.4.1)
 - - - - - - - - - - - - - - - - - - - - - - - -
 END p1;

 END M.


Примечание 2.4.1.  В области связей модуля элемент с номером 1
           соответствует  модулю  N  и после загрузки модуля в
           память  ссылается на слово, содержащее адрес начала
           области  глобальных данных модуля N, в первом слове
           которой  содержится F-регистр модуля N, позволяющий
           добраться до его сегмента кода.

           CX   помещает   в   нулевое  слово  области  связей
           процедуры    G-регистр   модуля,   вызвавшего   эту
           процедуру,  и помечает, выставляя признак во втором
           локальном слове, что вызов был внешним. Команда RTN
           анализирует  этот  признак и в случае необходимости
           восстанавливает значение G-регистра.


     2.5. Размещение мультизначений


 MODULE M;

 PROCEDURE p;

     - - - - - - - - - - - - - - - - - - - - - - - - -
 VAR |i: INTEGER;                   ENTR 02           |
     |A: ARRAY [0..15] OF INTEGER;  LIB 10 ALLOC SLW5 |(2.5.1)
     - - - - - - - - - - - - - - - - - - - - - - - - -

 BEGIN

   - - - - - - - - - - - - - - - - - - - - - - - - - -
   |i:=0;                       LI0  SLW4   |        |
   |                                                 |
   |                             A    i              |
   |                             |    |              |
   |A[i]:=1;                    LLW5 LLW4 LI1 SXW    | (2.5.2)
   - - - - - - - - - - - - - - - - - - - - - - - - - - (2.5.3)
END p;

END M.


Примечание  2.5.1. ALLOC берет с А-стека размер мультизначения
           (массив  или  запись),  кладет  на  А-стек значение
           регистра  S  и  передвигает S на взятый размер, тем
           самым  отводя  нужное  число  слов  на  P-стеке для
           мультизначения.    После    этого   адрес   массива
           запоминается в нужном локальном слове.

Примечание 2.5.2. Индексация без контроля границ. По умолчанию
           контроль границ включен.

Примечание  2.5.3.  При  возврате  из  процедуры  команда  RTN
           пeреставяет  S  в  L,  и  тем самым освобождает всю
           память,  занятую  локалами,  в  том числе и память,
           выделенную на P-стеке командой ALLOC.



     2.6. Работа с процедурными значениями


 MODULE M;

 TYPE proc1=PROCEDURE (INTEGER);

 PROCEDURE P(p1 : proc1);
 (* процедура # 1 *)

                       сохранить А-стек на P-стеке
                          | загрузить процедурное значениe P1
                          | из локального слова 4 процедуры Р
                          |     |
 BEGIN                    |     |  записать на P-стек значение
                          |     |     |             с  А-стека
   - - - - - - - - - - - -|- - -|- - -|- - - - - - - - - -
   |p1(1);              SLW4   LLW4  STOT  LI1  CF  RTN  |
   - - - - - - - - - - - - - - - - - - - - -|- -|- - - - -
 END P;                                     |   |
                                       параметр |
                                              вызов формальной
                                                     процедуры

 PROCEDURE p(w: INTEGER); (* процедура # 2 *)
 BEGIN
   - - - - - - - - - - - - - - - - - - - - - - - -
   |                                SLW4     RTN |
   - - - - - - - - - - - - - - - - - - - - - - - -
 END p;

 VAR v: proc1;         номер модуля =0, т.к. проц. собственная
                                         | номер процедуры
 BEGIN                                   |  |
   - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   |v:=p;                            LPC 00 02  SGW2      |
   |v(5);                            LGW2  STOT  LI5  CF  |
   |P(v);                            LGW2  CL1            |
   |P(p);                            LPC 00 02  CL1       |
   - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 END M.


                           |<--  о д н о   с л о в о -->|
                           |____________________________|
 Процедурное значение:     | 31..24 | 23 . . . . . . .0 |
                           -----|-------------|----------
                                |             |
                              номер     24-разрядный адрес
                            процедуры   G-регистра модуля

     Процедурные   связи  при  вызове  процедуры  командой  CF
(аналогично CX):

                      L'-->   |          |
                              .          .
                              |----------|
                      S', L-->| G-регистр|
                              |__________|
                              |    L'    |
                              .----------.
                      S -->   .          .
                              |          |



     2.7. Передача параметров

 MODULE M;

 TYPE String=ARRAY [0..255] OF CHAR;

 PROCEDURE P(i: INTEGER; S: String; VAR w: ARRAY OF CHAR);
   VAR k,j:INTEGER;
 BEGIN
 (* сохранение параметров и размещение переменных *)
 - - - - - - - - - - - - - - - - - - - - - - - - - -
 |                                STORE ENTR 01    |  (2.7.1)
 - - - - - - - - - - - - - - - - - - - - - - - - - -
 (* копирование массива S, переданного по значению *)
 - - - - - - - - - - - - - - - - - - - - - - - - - -
 |k:=HIGH(S);                       LIB FF  SLW8   |
 |j:=HIGH(w);                       LLW4 SLW9 RTN  |  (2.7.2)
 |                                   |    |        |
 |                                  HIGH  j        |
 - - - - - - - - - - - - - - - - - - - - - - - - - -
 END P;

 VAR
     - - - - - - - - - - - - - -- - - - - - - -  - -
     |str8:ARRAY[0..7] OF CHAR;  LI2 ALLOC SGW2    |
     |str :String;               LIB 40 ALLOC SGW3 |
     - - - - - - - - - - - - - -- - - - - - - - -  -
BEGIN
                     загрузка на А-стек адреса константы 'abc'
                               |
 - - - - - - - - -  - - - - - -|- - - - - - - - - - -
 |P(1,'abc',str8);        LI1 LSTA 0001 LGW2 LI7 CL1 |
 |                                                   |
 |str:='def';             LGW3 LSTA *ind* LI1 MOVE   | (2.7.3)
 |                                                   |
 |P(2,str,str);           LI2 LGW3 LGW3 LIB FF CL1   |
 - - - - - - - - -  - - - - - - - - - - - - - - - - -
 END M.


Примечание  2.7.1.  STORE записывает А-стек на P-стек, выделяя
           на  P-стеке память под локалы: 4-е слово - HIGH(w),
           5-e  слово  -  w(адрес), 6-е слово - S (адрес), 7-е
           слово   -   i,  8-e  слово  -  число  параметров  -
           используется   для   локала   k.  Команда  ENTR  01
           завершает отведение памяти; 9-е слово отводится для
           j :



 А-стек             |__________|                |__________|
 перед вызовом      |  HIGH(w) |      L ------> |__________|
 процедуры p :      |----------|                |__________|
                    |    w     |                |__________|
                    |----------|                |__________|
                    |    S     |          --> 4 | HIGH(w)  |
                    |----------|          |     |----------|
                    |    i     |          |   5 |    w     |
                    |----------|          |     |----------|
                                          |   6 |    S     |
                                  STORE   |     |----------|
                                          |   7 |    i     |
                                          |     |----------|
                                          |   8 |          | k
                                          -->   |----------|
                                  ENTR 1 ---> 9 |          | j
                                                |__________|
                                       S -----> |          |


Примечание  2.7.2.  Здесь  приведена  группа  команд,  которая
           копирует  переданный по значению массив S. Приводим
           три возможных вырианта кода:


           I)  LIB 40        II)  LLW6           III)  LLW6
               ALLOC              LIB FF               LIB 3F
               COPT               CPCOP 06             PCOP 06
               LLW6
               LIB 40
               MOVE
               SLW6

           Очевидна целесообразность введения в систему команд
           CPCOP  и  PCOP,  предназначенных  для  размещения и
           копирования мультипараметров.


Примечание  2.7.3. LSTA *ind* по относительному смещению *ind*
           в   строковом   пуле   грузит   на   А-стек   адрес
           соответствующей  строковой  константы.



     2.8. Вызов функции (на непустом стеке)

 MODULE M;

 PROCEDURE f(i,j: INTEGER): INTEGER;
 BEGIN
 - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | RETURN  i+j               STORE LLW5 LLW4 ADD RTN |
 - - - - - - - - - - - - - - - - - - - - - - - - - - -
 END f;

 PROCEDURE p(i,j: INTEGER);
   VAR k:INTEGER;
 BEGIN
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | k:=i+j;                      STORE LLW5 LLW4 ADD SLW6 RTN |
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 END p;
 VAR v: PROCEDURE(INTEGER,INTEGER): INTEGER;
 BEGIN
 - - - - - - - - - - - -- - - - - - - - - - - - - - - -
 | p(1,f(2,3));   LI1     STORE LI2 LI3 CL1 LODFV CL2 |
 | v:=f;          LPC 00 01 SGW2                      |
 | p(1,v(2,3));   LI1 LGW2 STOFV LI2 LI3 CF LODFV CL2 |(2.8.1)
 |                                                    |
 - - - - - - - - - - - - - - - - - - - - -  - - - - - -
 END M.

Примечание  2.8.1.  Последовательность  команд LI1 LI2 CL1 CL2
           была  бы  неверна,  поскольку  CL1  в  точке  входа
           забирает со стека все значения (STORE), в том числе
           и 1, предназначающуюся не для нее (!).


                          3. ВЫРАЖЕНИЯ


     3.1. Индексация словных массивов


MODULE M;

VAR x: ARRAY [0..3] OF INTEGER;
    i: INTEGER;

BEGIN
- - - - - - - - - - - - - - - - - - - - - -
|  x[i]:=1;    LGW2 LGW3 LI3 CHKZ LI1 SXW |-- с контролем
|  i:=x[1];    LGW2 LI1  LXW SGW3         |   границ
- - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - -
|  x[i]:=1;      LGW2 LGW3 LI1 SXW  | -- без контроля границ
|  i:=x[1];      LGW2 LI1  LXW SGW3 |    (3.1.1)
- - - - - - - - - - - - - - - - - - -
END M.


Примечание 3.1.1.  Компилятор  может  использовать константную
           индексацию, например:

           - - - - - - - - - - - - - - - - - - - - -
           |    i:=x[1]        LGW2 LSW1     SGW2  |
           - - - - - - - - - - - - - - - - - - - - -

           и  таким  образом,  контроль  границ  становится не
           нужен.


     3.2. Индексация байтовых массивов


 MODULE M;
     - - - - - - - - - - - - - - - - - - - - - - -
 VAR | A:ARRAY [0..0Fh] OF CHAR;  LI4 ALLOC SGW2-|--(3.2.1)
     - - - - - - - - - - - - - - - - - - - - - - -
       i:INTEGER;                                   (3.2.2)


 BEGIN
 - - - - - - - - - - - - - - - - - - - - - - -
 |i:=0;                             LI0 SGW3 |
 - - - - - - - - - - - - - - - - - - - - - - -





                               HIGH    i   '>='
 - - - - - - - - - - - - ->      |     |     |
 | WHILE HIGH(A)>=i DO       |->LI0F  LGW3  GEQ JSFC 014------
 | A[i]:='*';                |  LGW2 LGW3 LIB 2A SXB         |
 | INC(i);                   |  LGA 03 INC1                  |
 | A[i-1]:= A[i-1]; END;     |  LGW2 LGW3 LI1 SUB            |
 - - - - - - - - - - - - ->  |  LGW2 LGW3 LI1 SUB            |
 END M.                      |    |    |   |   |             |
                             |    A[   i   1  '-'            |
                             |   LXB  SXB JSB 019            |
                              \_______________/              |
                                                             |
                                         <--------------------
                                                     (3.2.3)

Примечание 3.2.1.  В  глобальном   слове  2 адрес размещенного
           массива.

Примечание 3.2.2. Литерные массивы пакуются.

Примечание 3.2.3.  LXB и SXB работают аналогично LXW и SXW, но
           читают  и  пишут соответствующий байт, а  не слово.
           0 <байтовый адрес> LXB  и  0 < байтовый адрес > SXB
           осуществляют абсолютную байтовую адресацию памяти.


     3.3. Индексация байтовых массивов с контролем границ


 MODULE M;

 VAR A:ARRAY [0..0Fh] OF CHAR;
     i:INTEGER;



 BEGIN i:=0;
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  |WHILE  i#HIGH(A) DO -> LIW3 LI0F NEQ JSFC 0E             |
  |  A[i]:=A[i+1];     -> LGW2 LGW3 LI0F CHKZ               |
  |                       LGW2 LGW3 LI1 ADD LI0F            |
  |                        |     |   |   |    |             |
  |                        A     i   1  '+'  HIGH(A)        |
  |                                                         |
  |END (*WHILE *)         CHKZ LXB SXB JSB 013              |
  |                        |                                |
  |                       (3.3.1)                           |
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Примечание  3.3.1.  CHKZ  проверяет,  лежит  ли второй элемент
           А-стека  между  0  и  верхним  элементом  (задающим
           границу);  если  это  так,  то  счеркивает границу,
           иначе возбуждает TRAP(4Ah).




     3.4. Проверка принадлежности диапазону

 MODULE M;
 VAR i: INTEGER;
 VAR x:[10h..20h];
 BEGIN
    - - - - - -  - - - - - - - - - - - - - - - - - - - - - - -
   |x:=i;                        LGW2 LIB 10 LIB 20 CHK SGW3 |
   - - - - - - - - - - - - - - - - - - - - - - - - - | - - - -
 END M.                                              |
                                                  (3.4.1)

Примечание 3.4.1. CHK проверяет принадлежность диапазону. Если
           бы  в  тексте  было  x:=13h,  проверку  произвел бы
           компилятор и породил код LIB13 SGW2.


     3.5. Работа с объектами типа BITSET

 MODULE M;
 VAR b1, b2:BITSET;
 BEGIN
   - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   |b1:={}; b2:={1};                LI0  SGW2  LI2  SGW3 |
   |b1:=b1+b2;                      LGW2  LGW3  OR  SGW3 |
   (*     *                                     AND
          /                                     XOR
          -                                     BIC      *)

   |         INCL(b1,2);            LGA 2  LI2  INCL     |
   |         EXCL(b1.2);            LGA 2  LI2  EXCL     |
  (* 2 IN b1                        LI2  LGW2   IN       *)
   - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 END M.

     3.6. Команды ANDJP и ORJP

 MODULE M;
 .
 .
 BEGIN
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  |IF FALSE AND TRUE THEN END;   LI0  ANDJP 1  LI1  JSFC  |
  |IF TRUE OR FALSE  THEN END;   LI1  ORJP 1   LI0  JSFC  |
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 END M.                                                (3.6.1)

Примечание 3.6.1.  Компилятор  вместо  этого   смешного  кода,
           оптимизируя, не породит ничего.


                ИНДЕКС-ТАБЛИЦА СИСТЕМЫ КОМАНД


Мнемоника        Код       Страница описания


ABS             0A6h            55        
ACTIV           0FAh            85
ADD             88h             46
ADDPC           0BCh            65
ALLOC           0C8h            69
AND             0A9h            56
ANDJP           0BFh            66
ARRCMP          95h             49
BBLT            0EEh            77
BBP             0EDh            77
BBU             0ECh            76
BIC             0ABh            57
BIT             0ADh            58
BM              97h             50
BMG             0F9h            81
CF              0CEh            71
CHK             0C6h            68
CHKBX           0F8h            81
CHKNIL          0C1h            67
CHKZ            0C7h            68
CI              0CDh            71
CL              0CFh            72
CL0..CL0F       0D0h..0DFh      72
CM              0F7h            80
COMP            0C3h            67
COPT            0B5h            61
CPCOP           0B6h            61
CX              0CCh            70
DEC             0E7h            75
DEC1            0E5h            74
DECS            0B0h            59
DIV             8Bh             47
DROP            0B1h            59
ENTC            0BAh            63
ENTR            0C9h            69
EQU             0A4h            55
EXCL            0E1h            73
FABS            9Dh             53
FADD            98h             51
FCMP            9Ch             52
FDIV            9Bh             52
FFCT            9Fh             53
FMUL            9Ah             51
FNEG            9Eh             53
FOR1            0B8h            62
FOR2            0B9h            63
FSUB            99h             51
GB              0C4h            68
GB1             0C5h            68
GEQ             0A3h            55
GETM            82h             44
GTR             0A2h            54
IDLE            87h             46
IN              0ACh            58
INC             0E6h            75
INC1            0E4h            74
INCL            0E0h            73
INL             0E2h            73
INVLD           0FFh            86
IO0..IO4        90h..94h        49
JBL             1Dh             38
JBLC            1Ch             38
JBS             1Fh             38
JBSC            1Eh             38
JFL             19h             37
JFLC            18h             37
JFS             1Bh             37
JFSC            1Ah             37
JMP             0BDh            65
LEA             17h             36
LEQ             0A1h            54
LEW             22h             39
LGA             15h             35
LGW             21h             39
LGW2..LGW0F     42h..4Fh        42
LI0..LI0F       00h..0Fh        34
LIB             10h             34
LID             11h             34
LIN             13h             35
LIW             12h             34
LLA             14h             35
LLW             20h             39
LLW4..LLW0F     24h..2Fh        40
LODFV           0B2h            60
LODT            0E9h            76
LPA             0F1h            79
LPC             0EBh            76
LPW             0F2h            79
LSA             16h             36
LSS             0A0h            54
LSTA            0C2h            67
LSW             23h             40
LSW0..LSW0F     60h..6Fh        43
LXA             0EAh            76
LXB             40h             42
LXW             41h             42
MOD             0AFh            59
MOVE            0C0h            66
MUL             8Ah             47
NEG             0A7h            56
NEQ             0A5h            55
NII             0FDh            86
NOP             0CBh            70
NOT             0AEh            59
OR              0A8h            56
ORJP            0BEh            65
PCOP            0B7h            62
PDX             0EFh            78
QUIT            81h             44
QUOT            0E3h            73
RCHK            0F5h            80
RCHZ            0F6h            80
ROL             8Eh             48
ROR             8Fh             48
RTN             0CAh            70
SETM            83h             44
SEW             32h             41
SGW             31h             41
SGW2..SGW0F     52h..5Fh        43
SHL             8Ch             47
SHR             8Dh             48
SLW             30h             40
SLW4..SLW0F     34h..3Fh        41
SPW             0F3h            79
SSW             33h             41
SSW0..SSW0F     70h..7Fh        44
SSWU            0F4h            79
STOFV           0B4h            60
STORE           0B3h            60
STOT            0E8h            75
SUB             89h             46
SWAP            0F0h            78
SXB             50h             42
SXW             51h             43
SYS             0FCh            86
TR              86h             45
TRA             85h             45
TRAP            84h             45
USR             0FBh            85
WM              96h             50
XIT             0BBh            65
XOR             0AAh            57