# Кросс Ассемблер БК Турбо 8.

Сделан на основе алгоритмов Turbo 8DK для Andos.

Комплект: |

1. BKTurbo8.exe - кросс компилятор, линковщик.
2. BKbin2obj.exe - конвертер массивов данных в объектные модули чтобы прилинковывать их к скомпилированным ассемблерным программам.
3. ARIFM.ASM - модуль выполнения команд расширенной арифметики, при необходимости, скомпилировать в объектный файл и слинковать со своей программой.
4. BKTurbo8.??? - этот файл документации.
5. Примеры применения и использования.

Максимальная длина исходного текста не ограничена.

Максимальная длина получаемой программы - 0177000 байтов.

Оригинальная система программирования на языке Ассемблера Turbo8DK являлась дальнейшим развитием ассемблеров серии TURBO (MicroWS, TURBO4H, TURBO5M, TURBO6M) и предназначалась для работы на БК10 с дополнительным ОЗУ 16К и на БК11.

Кросс ассемблер БКТурбо8 предназначен для компиляции ассемблерных программ и создания исполняемых бинарных модулей, которые потом можно запускать на БК-0010(-01) и БК-0011(М).

Кросассемблер системонезависимыи и вообще ни от чего не зависимый. При успешной компиляции создаётся бинарник, который будет работать так и там, как и где задумано разработчиком компилируемой программы.

Генерируется .bin файл, у которого первым словом идёт адрес загрузки, вторым - размер файла, совместимый с эмуляторами. Этот файл можно закинуть в образ с помощью BKDE. Так же возможно генерация .raw файла без заголовка .bin для нужд пользователя.

### Некоторые особенности ассемблера серии Turbo:

1. В арифметике над метками введено деление на 2, что удобно для работы с массивами слов.
2. Отсутствуют не сильно нужные псевдокоманды .TTYIN, .TTYOUT, .ENABL, .DSABL и присвоение имён регистрам
3. Добавлена псевдокоманда .ADDR.
4. При трансляции проверяется чётность адреса команды и величина аргумента .BLKB и .BLKW.
5. Программа транслируется с адреса, указанного ключом командной строки "-s" или псевдокомандой .LA.
6. Во всех случаях правильно работает арифметика над метками.
7. Реализована регистронезависимость для меток, команд ассемблера, псевдокоманд, имён регистров и вообще всего, что не является строковым аргументом псевдокоманд .ASCII, .ASCIZ, .RAD50, операторов ' и ".
8. В присваиваниях, арифметических выражениях, перечислениях между аргументами допускаются пробелы и табуляции для улучшения наглядности и читабельности текста.

### Недостатки и ограничения:

1. Объектный модуль кросс ассемблера имеет собственный формат и не совместим вообще ни с чем, что самое досадное – с оригинальным форматом Turbo8DK.
2. Отсутсвует пакетная обработка из файлов, содержащих списки обрабатываемых файлов. Приходится писать портянки из однородной копипасты в bat файлах.

### Отличия от оригинальной программы и дополнения.

1. Длина метки ничем не ограничена, буквально. Т.е. ограничена объёмом типа std::string. Надо бы ввести какие-то разумные ограничения, но пока нет смысла, будем надеяться на благоразумность пользователей.
2. Присваивания типа name = <выражение> можно использовать в любом месте текста, а не только вначале, но по-прежнему в выражении можно использовать только уже определённые ранее метки и константы.
3. Можно писать так: .byte <выражение>, но при этом метки и константы выражения должны быть определены, а результат должен вмещаться в байт, иначе ошибка.
4. Можно писать так: .blkb <выражение> / .blkw <выражение>, но при этом метки и константы выражения должны быть определены, иначе ошибка.
5. Добавлена псевдокоманда .org <выражение>. Она выравнивает текущий указатель адреса по результату выражения. Допускается нечётное значение. Если результат меньше текущего указателя - ничего не происходит.
6. Точку (указатель на текущий адрес) теперь можно использовать в модулях, которые компилируются в режиме CL.
7. Введены C-подобные комментарии // (аналогично ; комментарию) и многострочный комментарий /**/. (Просто так. В качестве эксперимента, что и как ещё можно расширить и улучшить при используемых алгоритмах.)

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

Имеется два режима работы.

- Режим компиляции, с созданием объектных модулей и исполняемого файла.
- Режим линковки объектных модулей.

### 1. Режим компиляции.

BKTurbo8 [-i<c>][-v][-r][-l[name]][-o[name]][-t[name]][-s<0addr>] <cmd> <file_1 *[ file_n]>

-i<c> (--input <c>) - задать кодировку исходного файла.
| Возможные кодировки:

- a - автоопределение (по умолчанию)
- k - KOI8-R
- o - OEM CP866
- w - ANSI CP1251
- 8 - UTF8
- u - UNICODE UTF16LE

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

Если в тексте очень мало русских букв, то кодировка очень часто определяется неверно. UTF8 без BOM тоже как правило определяется неверно.

-v (--verbose) - вывод большего количества информации на экран.
| На данный момент дополнительно выводится таблица меток программы.
-r (--raw) - создавать просто бинарный массив, не использовать формат .bin.
-l[name] (--listing [name]) - генерировать lst файл.
| Если имя файла задано, то используется оно для генерации листинга, если нет - то берётся имя файла исходного текста.
-o[name] (--object [name]) - генерировать объектный файл.
| Если имя файла задано, то используется оно для генерации листинга, если нет - то берётся имя файла исходного текста.
-t[name] (--table [name]) - создавать особый объектный файл, в котором содержатся только глобальные метки.
| Создаётся файл с именем name_tbl.obj – чтобы ни с чем не перепутать. Это необходимо в экзотических случаях, когда собираются отдельные оверлейные модули, работающие в заданных окнах БК11, но при этом использующие подпрограммы из основного тела программы, расположенной в странице 0.
-s<0addr> (--address <0addr>) - задать начальный адрес компиляции.
| Адрес задаётся в восьмеричном виде. Этот адрес не имеет приоритета, и если в тексте программы используется псевдокоманда .LA, то применяется адрес псевдокоманды.
<cmd> - команда компиляции:
| CO - полная компиляция. В результате при отсутствии ошибок создаётся бинарный исполняемый файл и опционально заданные соответствующими ключами объектные файлы. CL - компиляция в объектный файл для дальнейшей линковки с другими объектными файлами. В результате при отсутствии ошибок всегда создаётся объектный файл. Бинарный файл не создаётся.

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

В конец файла листинга записывается таблица глобальных меток, а так же список ссылок на неопределённые метки, если они есть.

<file_1 *[ file_n]> - список исходных файлов, перечисленных через пробел.
| Допускаются маски файлов.

### 2. Режим линковки.

BKTurbo8 [-v][-r][-l[name]][-o[name]][-t[name]][-s<0addr>] LI <outfile> <file_1 *[ file_n]>

| Ключ -i не используется. Ключи -v, -r, -l, -o, -t и -s имеют тот же смысл, что и в режиме компиляции.
Команда линковки - LI
| Команда линковки - LI, за командой следует обязательное имя выходного файла <outfile>, маска файла не допускается. А затем список файлов объектных модулей. Листинг при этом не создаётся, потому что не из чего, но если задан ключ -l, в файл листинга сохраняется список меток, а так же список ссылок на неопределённые метки, если они есть.
<file_1 *[ file_n]> - список исходных файлов, перечисленных через пробел.
| Допускаются маски файлов.

## АССЕМБЛЕР

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

    МЕТКА: КОМАНДА(ПСЕВДОКОМАНДА) ОПЕРАНДЫ ;КОММЕНТАРИЙ

    МЕТКА1: МЕТКА2: //КОММЕНТАРИЙ

Примеры использования многострочного комментария:

     /*
    Пример многострочного
    комментария
    */

    Mov R0,R1 /*пересылка*/ inc R0

Да, вот так, комментарий /**/ можно использовать как инлайн комментарий, и за ним может располагаться команда. Однако этот комментарий нельзя использовать внутри команды и её операндов.

МЕТКА: - Имя, определяемое пользователем, которому соответствует адрес трансляции. Длина метки ничем не ограничена, метка ограничивается двоеточием (:), пробелы между меткой и двоеточием недопустимы. Метка может содержать латинские буквы 'A'..'Z', цифры '0'..'9', а также знаки '_', '.', '$'.

Глобальная метка - любое допустимое слово, начинающееся с символов 'A'..'Z' или '_'.

Локальная метка - любое допустимое слово, начинающееся с цифры '0'..'9'. В отличие от MACRO-11, где локальные метки состоят только из цифр и завершаются знаком '$', здесь в локальной метке могут быть и буквы, и остальные допустимые знаки. Ещё одно хорошее отличие - возможен переход по локальной метке вперёд через глобальную.

Метка не может начинаться с символов '.' и '$', но потом эти символы можно использовать в неограниченном количестве в обоих типах меток.

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

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

Если при трансляции встречается ранее определённая метка или присваивание, то выдаётся сообщение об ошибке.

Метку можно поставить перед любой командой или псевдокомандой. Если её поставить перед псевдокомандой .END, то её адрес будет следующим после последнего адреса программы.

Пример:

    START:STOP:  BIC  #177770, R0
                 CALL RE
                 . . . . .
    RE:          CMP  R0 , #7

Здесь метки START и STOP имеют одно и то же значение, и обращение может производиться по любой из них. Метка RE глобальная, так как команда CALL ... состоит из двух слов.

## ПРЯМОЕ ПРИСВАИВАНИЕ.

Присваивает имени определённое значение. Имя принимает абсолютное значение. Присваивание допустимо в любом месте текста программы, однако значения меток, которые являются аргументами присваивания, должны быть определены на момент присваивания.

Пример:

    START=1000

    STOP = START + 2000

## ИМЕНА РЕГИСТРОВ.

Обращение к регистру по его имени:

R0 R1 R2 R3 R4 R5 SP PC

К регистрам SP и PC можно обращаться так же и по именам R6 и R7 соответственно. Эта возможность оставлена на всякий случай, для частичной совместимости с другими диалектами ассемблеров БК, например Micro.

## ВЫРАЖЕНИЯ.

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

1. Запись восьмеричных и десятичных констант.

   Точка - признак, что константа десятичная ( 64. == 100 ).

   MOV #10., R1 аналогично MOV #12, R1

2. Запись положительных и отрицательных чисел.

   MOV #16,R1 или MOV #-2,R1, MOV -2(R4),R3.

3. Запись одного кода ASCII, как число.

   MOV #'A,R1 то же, что MOV #101,R1

   Можно использовать в любом случае вместо числа, например:

   TRAP '& вместо TRAP 46.

4. Запись двух кодов ASCII, как число.

   MOV #"AB,R1 (два байта)

5. Точка - значение адреса первого слова команды.

   Удобно для задания смещения для перехода.

   ПРИМЕЧАНИЕ: точка может быть использована в качестве любого аргумента команды, даже можно использовать точку с именами меток при трансляции объектного модуля (CL).

   Примеры:

       START:  MOV   R2,R1
               BCS   .-2   ; переход на метку START.
               HALT
       ST:     MOV   RC,R1
               ADD   (PC)+,R1
               .WORD END-.
       END:    .END

   Чтобы не использовать точку, этот текст можно записать в следующем виде:

       ST:     MOV   PC,R1
               ADD   (PC)+,R1
               .WORD @END+2
       END:    .END

   Или можно использовать псевдокоманду .ADDR

               .ADDR R1,END

6. Использование арифметики над метками:

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

   Пример:

               SUMA = 101
               SUMB = 102
               .WORD SUMB - SUMA + 3
               .END

   В этом случае по директиве .WORD запишется число '4'.

   Пример:

               MET = 100
               SUM = 40
               MOV #MET - SUM + MET , R1
               .END

   В этом случае в регистр R1 записывается число '140'.

   Пример:

               .ADDR R0, START
               MOV  #140000, R1
               MOV  #/END - /START, R2
       1$:     MOV  (R0)+,(R1)+
               SOB  R2,1$
       START:  . . . . .
               . . . . .
       END:    .END

   Здесь массив от метки START до метки END пересылается на адрес 140000. Знак деления ( / ) означает, что адрес метки делится на 2, что в результате даёт в R2 длину массива в словах.

   Пересылка словами в два раза быстрее, чем байтами. Использование деления возможно только с именами меток при непосредственной адресации (27) и в псевдокоманде .WORD. По директиве .ADDR мы получаем в R0 абсолютный адрес метки START, даже если программа перемещаемая.

7. Запись байта числа в строку букв.

       .ASCII /ABC/<12><15> ; в строку дописать коды ПС,ВК

8. Получение смещения к метке.

       .WORD @START

Добавлен, но не до конца протестирован на ошибки при обработке некорректных данных продвинутый парсер чисел. Кромер обычной записи восьмеричных и десятичных чисел с точкой на конце добавлено:

- С-подобная префиксная форма записи
  - 0x abcd - 16-ричное число
  - 0d 9999 - десятичное число (не знаю зачем, но такое возможно)
  - 0b 1111 - двоичное число

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

- префиксная форма из MACRO-11
  - ^x abcd, ^h abcd - 16-ричное число
  - ^d 9999 - десятичное число
  - ^b 1111 - двоичное число
  - ^o 7777 - восьмеричное число (просто до кучи, чтобы всё было)
  - ^f 12.3 - число с плавающей точкой однословное.
  - ^r ABC- три символа в кодировке RADIX-50 (самая недоработанная пока функция)
- Ещё добавлены две макрокоманды .FLT2 и .FLT4 из MACRO-11 для записи чисел с плавающей точкой в 2 слова и в 4. Формат плавающего числа классический, в простой и экспоненциальной форме. Алгоритм взят из кроссассемблера MACRO-11 и тоже не тестировался на корректность, может он вообще неправильные числа делает. Надо потом как-нибудь проверить.

## МЕТОДЫ АДРЕСАЦИИ, КОМАНДЫ.

Методы адресации аналогичны системе команд ЭЛЕКТРОНИКИ-60.

Пример написания | Код адресации
--- | ---
CLR MET | 67
MOV #MET,R1 | 27
CLR @#MET | 37
CLR @MET | 77
CLR MET(R1) | 6n
CLR @MET(R1) | 7n
CLR R1 | 0n
CLR (R1) CLR @R1 | 1n
CLR -(R1) | 4n
CLR @-(R1) | 5n
CLR (R1)+ | 2n
CLR @(R1)+ | 3n

Обозначения в тексте:
ss | поле источника (6 бит)
dd | поле приёмника (6 бит)
R | регистр общего назначения (3 бита)
xx | смещение (8 бит), +127 .. -128
n | цифра (3 бита)
M | маска (4 бита)
nn | число (6 бит)
\ | резервный/неизвестный код
eis | EIS инструкция
fis | FIS инструкция
fpu | FPU инструкция
cis | CIS инструкция
src | операнд - источник
dst | операнд - приёмник
offset | смещение
CC | коды условий (биты в слове состояния процессора)
PC=R7=регистр | счётчик команд
SP=R6=регистр | указатель стека
PSW | слово состояния процессора
:: | каждое двоеточие - произвольная (восьмеричная) цифра
mmg | инструкция диспетчера памяти
si | специальная инструкция: уникальна для указанного процессора
Установки кодов условий:
- | не изменяется
+ | действия над битом в описании конкретной инструкции.
1 | всегда устанавливается в 1
0 | всегда очищается
* | устанавливается/чистится в соответствии с общими правилами: N - устанавливается, если старший бит результата установлен, иначе чистится; Z - устанавливается при нулевом результате, иначе чистится; V - устанавливается при арифметическом переполнении, иначе чистится;
C - устанавливается при переносе из старшего разряда, иначе очищается;

Двухоперандные:

Команда | Мнемоника | Флаги | Описание
--- | --- | --- | ---
N | Z | V | C
MOV[B] S,D | [1]1ssdd | * | * | 0 | - | пересылка: (dst)<-(src); MOVB ss,Rn (пересылка в регистр общего назначения), единственная среди байтовых инструкций, распространяет знаковый бит источника в старшем байте приёмника; при пересылке байта в регистр результат всегда пересылается в младший байт регистра. Все остальные байтовые пересылки работают с байтами в точности как словные со словами.
CMP[B] S,D | [1]2ssdd | * | * | + | + | сравнение src с dst и установка кодов условий PSW: (src) - (dst); V = 1, если операнды были разных знаков, и знак приёмника был тот же, что и знак результата (разности операндов), иначе чистится; C = 0, если был перенос из старшего разряда, иначе устанавливается.

Операция не изменяет исходных операндов.

BIT[B] S,D | [1]3ssdd | * | * | 0 | - | проверка бит dst по маске src и установка кодов условий: (src)&(dst)
BIC[B] S,D | [1]4ssdd | * | * | 0 | - | очистка бит dst по маске src: (dst)<-~(src)&(dst)
BIS[B] S,D | [1]5ssdd | * | * | 0 | - | установка бит dst по маске src: (dst)<-(src)!(dst)
XOR Rn,D | 074Rdd | * | * | 0 | - | (eis) исключающее 'или': (dst)<- R xor (dst)
ADD S,D | 06ssdd | * | * | + | * | dst<-src+dst; V устанавливается, если оба операнда были одного знака, а результат - противоположного, иначе - чистится
SUB S,D | 16ssdd | * | * | + | + | dst<-dst-src; V устанавливается, если операнды были различных знаков, а знак источника был таким же, как и знак результата, иначе чистится; C чистится, если был перенос из старшего разряда, иначе - устанавливается

Однооперандные:

Команда | Мнемоника | Флаги | Описание
--- | --- | --- | ---
N | Z | V | C
CLR[B] D | [1]050dd | 0 | 1 | 0 | 0 | обнуление приёмника: (dst)<-0 Перед обнулением, как и для всех однооперандных команд, происходит чтение из приёмника
COM[B] D | [1]051dd | * | * | 0 | 1 | побитовое инвертирование операнда: (dst)<-~(dst)
INC[B] D | [1]052dd | * | * | + | - | прибавление 1 к операнду: (dst)<-(dst)+1; V устанавливается если (dst) превышает 077777, иначе чистится
DEC[B] D | [1]053dd | * | * | + | - | вычитание 1 из операнда: (dst)<-(dst)-1; V устанавливается, если (dst) было 100000, иначе чистится.
NEG[B] D | [1]054dd | * | * | + | + | заменяет источник его дополнением до 1 (меняет знак числа): (dst)<- -(dst); V устанавливается, если результат стал 100000, иначе чистится; C чистится, если получен результат 0, иначе устанавливается
ADC[B] D | [1]055dd | * | * | + | + | прибавление к операнду бита переноса (для длинной арифметики): (dst)<-(dst) + c V устанавливается, если (dst) был 077777 и C был установлен, иначе чистится; C устанавливается, если (dst) был 177777 и C был установлен, иначе чистится
SBC[B] D | [1]056dd | * | * | + | + | вычитание из операнда бита переноса (для длинной арифметики): (dst) <- (dst) – c V = 1 если (dst) был 100000, иначе чистится; C = 1 если (dst) был 0, и C был установлен
TST[B] D | [1]057dd | * | * | 0 | 0 | установка битов условий PSW, соответствующих операнду
ROR[B] D | [1]060dd | * | * | + | + | кольцевой сдвиг вправо: вращает все биты операнда на одну позицию вправо; старший бит загружается из бита переноса, младший бит, выдвинутый из операнда, загружается в бит переноса; V = xor(C,N).
ROL[B] D | [1]061dd | * | * | + | + | кольцевой сдвиг влево: вращает все биты операнда на одну позицию влево; младший бит грузится из бита переноса, выдвинутый старший бит загружается в бит переноса; V = xor(C,N).
ASR[B] D | [1]062dd | * | * | + | + | арифметический сдвиг вправо: содержимое операнда сдвигается на одну позицию вправо; старший (знаковый) бит остаётся неизменным; бит переноса грузится содержимым выдвинутого бита; V = xor(C,N). Операцию можно трактовать как целочисленное деление операнда пополам, с остатком, остающимся в бите переноса.
ASL[B] D | [1]063dd | * | * | + | + | арифметический сдвиг влево: содержимое операнда сдвигается на одну позицию влево, младший бит чистится, выдвинутый знаковый бит грузится бит переноса; V = xor(C,N). Операцию можно рассматривать как целочисленное умножение операнда на 2.
SWAB D | 0003dd | + | + | 0 | 0 | обмен байтов в слове: byte1/byte0<-byte0/byte1 N,Z устанавливаются по младшему байту результата
SXT D | 0067dd | - | + | 0 | - | (eis) распространение знака: (dst)<-0 если бит N очищен (dst)<-177777 если бит N установлен Z устанавливается, если бит N очищен
MTPS S | 1064ss | + | + | + | + | запись в слово состояния: PSW<-ss
MFPS D | 1067dd | - | - | - | - | чтение слова состояния: (dst)<-PSW
PUSH[B] S | [1]1ss46 | * | * | 0 | - | это команда MOV[B] S, -(SP),
POP[B] D | [1]126dd | * | * | 0 | - | это команда MOV[B] (SP)+, D

Ветвления:

Команда | Мнемоника | Флаги | Описание
--- | --- | --- | ---
N | Z | V | C
BR MET | 0004xx | - | - | - | - | переход безусловный. Смещение xx автоматически умножается на 2, и складывается с PC: PC<-PC+(2*offset)
BNE MET | 0010xx | - | - | - | - | переход по не нулю: PC<-PC+(2 * offset) if z = 0
BEQ MET | 0014xx | - | - | - | - | переход по нулю: PC<-PC+(2 * offset) if z = 1
BGE MET | 0020xx | - | - | - | - | переход по больше или равно: PC<-PC+(2 * offset) if n xor v = 0
BLT MET | 0024xx | - | - | - | - | переход по меньше: PC<-PC+(2 * offset) if n xor v = 1
BGT MET | 0030xx | - | - | - | - | переход по больше: PC<-PC+(2 * xx) if z!(n xor v) = 0
BLE MET | 0034xx | - | - | - | - | переход по меньше или равно: PC<-PC+(2 * xx) if z!(n xor v) = 1
BPL MET | 1000xx | - | - | - | - | переход, если плюс: PC<-PC+(2 * offset) if n = 0
BMI MET | 1004xx | - | - | - | - | переход, если минус: PC<-PC+(2 * offset) if n = 1
BHI MET | 1010xx | - | - | - | - | переход, если выше: PC<-PC+(2 * offset) if c & z = 0
BLOS MET | 1014xx | - | - | - | - | переход, если ниже или равно: PC<-PC+(2 * offset) if c | z = 1
BVC MET | 1020xx | - | - | - | - | переход, если нет переполнения: PC<-PC+(2 * offset) if v = 0
BVS MET | 1024xx | - | - | - | - | переход, если переполнение: PC<-PC+(2 * offset) if v = 1
BCC MET | 1030xx | - | - | - | - | переход, если не было переноса: PC<-PC+(2 * offset) if c = 0
BCS MET | 1034xx | - | - | - | - | переход, если был перенос: PC<-PC+(2 * offset) if c = 1
BHIS MET | 1030xx | - | - | - | - | переход, если выше или равно: PC<-PC+(2 * offset) if c = 0
BLO MET | 1034xx | - | - | - | - | переход, если ниже: PC<-PC+(2 * offset) if c = 1

Управления:

Команда | Мнемоника | Флаги | Описание
--- | --- | --- | ---
N | Z | V | C
JMP D | 0001dd | - | - | - | - | Переход. Грузит PC из источника, используя адресацию dd. Код адресации 0 (попытка выполнить команду, записанную в регистре общего назначения) на большинстве типов процессоров приводит к TRAP TO 4; PC<-(dst)
SOB Rn,MET | 077Rnn | - | - | - | - | (eis) R<-R - 1; если не 0, то PC<- PC-2*offset
JSR Rn,D | 004Rdd | - | - | - | - | переход на подпрограмму: -(SP)<-R, R<-PC, PC<-(dst)
RTS Rn | 00020R | - | - | - | - | Возврат из подпрограммы. PC <- R, R <- (SP)
MARK n | 0064nn | - | - | - | - | чистка стека: SP<- PC+2*nn, PC<-R5, R5<-(SP)+; nn-число параметров.
TRAP n | 104000-104377 | + | + | + | + | -(SP)<-PSW; -(SP)<-PC; PC<-(34); PSW<-(36) N,Z,V,C: грузятся из вектора прерывания
EMT n | 103400-103777 | + | + | + | + | -(SP)<-PSW; -(SP)<-PC; PC<-(30); PSW<-(32) N,Z,V,C: грузятся из вектора прерывания
NOP | 000240 | - | - | - | - | Ничего не делает, точнее чистит никакие биты условий в PSW (M=0, см. таблицу команд условий).
BPT | 000003 | + | + | + | + | Отладочное прерывание по 14 ячейке. -(SP)<-PSW, -(SP)<-PC, PC<-(14), PSW<-(16) N,Z,V,C: загружаются из вектора прерывания
IOT | 000004 | + | + | + | + | Программное прерывание ввода-вывода по 20 ячейке. -(SP)<-PSW, -(SP)<-PC, PC<-(20), PSW<-(22); N,Z,V,C грузятся из вектора прерывания
WAIT | 000001 | - | - | - | - | Инструкция ожидания прерывания. Процессор останавливается и освобождает системную магистраль до первого незамаскированного прерывания. PC указывает на следующую за WAIT команду. После возврата из прерывания выполнение программы продолжается со следующей за WAIT команды.
RESET | 000005 | - | - | - | - | Сброс внешних устройств. Процессорами, имеющими диспетчер памяти, в моде USER / SUPERVISOR исполняется как NOP. Выставляет сигнал сброса внешних устройств на магистраль. Время выполнения зависит от типа процессора и его тактовой частоты.
HALT | 000000 | - | - | - | - | Выводит процессор из активного режима: прерывается выполнение команд текущей программы, PC указывает на следующую за прерванной команду, PC отображается на консоли, разрешена работа консоли. На разных процессорах реализована различно: 1801ВМ1,2,3, 1811 переводит в программу обслуживания останова.

Для 1801ВМ1 (177716)<-000010|(177716), (177676)<-(PSW), (177674)<-(PC), (PC)<-(160002), (PSW)<-(160004);

* Здесь и далее адреса системных регистров приводятся для главного процессора; предполагается, что системное ПЗУ расположено с адреса 160000.

Для ВМ2 в пользовательском режиме вызывает прерывание в моду HALT по вектору останова, то же в моде HALT при разрешённом HALT, при запрещённых выполняется как NOP. В других процессорах: если нет диспетчера памяти, и процессор соответствует старым стандартам DEC, процессор останавливается, и может быть перезапущен с точки останова, либо с набранного с пульта адреса пультовым переключателем; если есть диспетчер памяти, и команда выполнялась не в моде KERNEL, то происходит прерывание и переход в моду KERNEL по резервной инструкции; в моде KERNEL останавливает процессор, если он не 1801/06 ВМ3. Для них HALT в моде KERNEL переводит процессор в моду HALT: стек пультовой моды устанавливается с адреса 100000 далее в этот стек заносятся PC, PSW; загружает PSW константой 340, включает диспетчер памяти на преобразование адресов в 22-разрядные и стартует с адреса 0 пультового ОЗУ (скрытого от пользователя).

RTI | 000002 | + | + | + | + | Возврат из прерывания. PC<-(SP)+, PSW<-(SP)+, грузит все доступные биты слова состояния из стека
RTT | 000006 | + | + | + | + | (eis) Аналогична RTI, но при установленном бите T в PSW прерывание после нее не возникает до окончания следующей команды.
CALL D | 0047dd | - | - | - | - | это команда JSR PC,D
RETURN | 207 | - | - | - | - | это команда RTS PC

Условия:

Команда | Мнемоника | Флаги | Описание
--- | --- | --- | ---
N | Z | V | C
CL<NZVC> | 00024M | + | + | + | + | чистит биты PSW(N,Z,V,C) по маске из 4 младших битов кода команды.
CLC | 000241 | + | + | + | + | (M=^B 0001)
CLV | 000242 | + | + | + | + | (M=^B 0010)
CLVC | 000243 | + | + | + | + | (M=^B 0011)
CLZ | 000244 | + | + | + | + | (M=^B 0100)
CLZC | 000245 | + | + | + | + | (M=^B 0101)
CLZV | 000246 | + | + | + | + | (M=^B 0110)
CLZVC | 000247 | + | + | + | + | (M=^B 0111)
CLN | 000250 | + | + | + | + | (M=^B 1000)
CLNC | 000251 | + | + | + | + | (M=^B 1001)
CLNV | 000252 | + | + | + | + | (M=^B 1010)
CLNVC | 000253 | + | + | + | + | (M=^B 1011)
CLNZ | 000254 | + | + | + | + | (M=^B 1100)
CLNZC | 000255 | + | + | + | + | (M=^B 1101)
CLNZV | 000256 | + | + | + | + | (M=^B 1110)
CCC | 000257 | + | + | + | + | (M=^B 1111)
SE<NZVC> | 00026M | + | + | + | + | устанавливает биты PSW(N,Z,V,C) по маске из 4 младших битов кода команды.
SEC | 000261 | + | + | + | + | (M=^B 0001)
SEV | 000262 | + | + | + | + | (M=^B 0010)
SEVC | 000263 | + | + | + | + | (M=^B 0011)
SEZ | 000264 | + | + | + | + | (M=^B 0100)
SEZC | 000265 | + | + | + | + | (M=^B 0101)
SEZV | 000266 | + | + | + | + | (M=^B 0110)
SEZVC | 000267 | + | + | + | + | (M=^B 0111)
SEN | 000270 | + | + | + | + | (M=^B 1000)
SENC | 000271 | + | + | + | + | (M=^B 1001)
SENV | 000272 | + | + | + | + | (M=^B 1010)
SENVC | 000273 | + | + | + | + | (M=^B 1011)
SENZ | 000274 | + | + | + | + | (M=^B 1100)
SENZC | 000275 | + | + | + | + | (M=^B 1101)
SENZV | 000276 | + | + | + | + | (M=^B 1110)
SCC | 000277 | + | + | + | + | (M=^B 1111)

Расширенной арифметики:

Команда | Мнемоника | Флаги | Описание
--- | --- | --- | ---
N | Z | V | C
MUL S,Rn | 070Rss | * | * | 0 | + | (eis) Содержимое регистра назначения, и источника, рассматриваемые как целые числа в дополнительном коде, перемножаются и запоминаются в регистре - приёмнике, и следующем (по номеру) регистре, если номер регистра - приёмника чётный. Если номер регистра нечётный, запоминается только младшая часть произведения.
DIV S,Rn | 071Rss | + | + | + | + | (eis) 32-битовое целое в дополнительном коде, находящееся в регистрах Rn, R(n+1), делится на значение операнда - источника. Деление будет произведено так, что остаток будет одного знака с делимым. Номер регистра должен быть чётным. N устанавливается, если результат отрицателен, иначе чистится;

Z устанавливается, если результат нулевой, иначе чистится;

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

C устанавливается, если делимое рано нулю, иначе очищается.

ASH S,Rn | 072Rss | * | * | + | + | (eis) Содержимое регистра сдвигается вправо или влево на число позиций, указанное в операнде - источнике. Счётчиком позиций являются 6 младших бит источника. Отрицательное значение счётчика сдвига означает сдвиг вправо, положительное - влево. При правом сдвиге распространяется старший бит, при левом - младший грузится нулём.

V устанавливается, когда знак регистра менялся во время операции, иначе чистится;

C загружается последним битом, выдвинутым из регистра.

ASHC S,Rn | 073Rss | * | * | + | + | (eis) Содержимое регистра, и регистра с номером, полученным установкой младшего бита в номере указанного регистра, рассматривается как одно 32 - битовое слово, причём в регистре с большим номером содержатся младшие биты, а регистре с меньшим - старшие, сдвигается влево или вправо на число позиций, указанное счётчике сдвига. Счётчиком сдвига являются младшие 6 бит операнда - источника. Отрицательное значение счётчика вызывает сдвиг вправо, положительное - влево. Если номер регистра - приёмника нечётный, правый сдвиг становится вращением. 16-разрядное слово вращается вправо на число позиций, указанное в счётчике сдвига. При правом сдвиге распространяется старший бит, при левом сдвиге младший бит грузится нулём.

V устанавливается, если при сдвиге изменялся знак операнда, иначе чистится;

C загружается последним выдвинутым из 32-битового операнда битом.

FADD Rn | 07500R | * | * | 0 | 0 | (fis)

initial state:
R | => | operand B bits 16-31
|  | operand B bits 0-15
|  | operand A bits 16-31
(R)+6 | => | operand A bits 0-15
After operation floating point stack looks:
R | => | operand B bits 16-31
|  | operand B bits 0-15
|  | result bits 16-31
|  | result bits 0-15
result = A+B

FSUB Rn | 07501R | * | * | 0 | 0 | (fis)

initial state:
R | => | operand B bits 16-31
|  | operand B bits 0-15
|  | operand A bits 16-31
(R)+6 | => | operand A bits 0-15
After operation floating point stack looks:
R | => | operand B bits 16-31
|  | operand B bits 0-15
|  | result bits 16-31
|  | result bits 0-15
result = A-B

FMUL Rn | 07502R | * | * | 0 | 0 | (fis)

initial state:
R | => | operand B bits 16-31
|  | operand B bits 0-15
|  | operand A bits 16-31
(R)+6 | => | operand A bits 0-15
After operation floating point stack looks:
R | => | operand B bits 16-31
|  | operand B bits 0-15
|  | result bits 16-31
|  | result bits 0-15
result = A*B

if the result < 2E-128 then the result is treated as zero.

FDIV Rn | 07503R | * | * | 0 | 0 | (fis)

initial state:
R | => | operand B bits 16-31
|  | operand B bits 0-15
|  | operand A bits 16-31
(R)+6 | => | operand A bits 0-15
After operation floating point stack looks:
R | => | operand B bits 16-31
|  | operand B bits 0-15
|  | result bits 16-31
|  | result bits 0-15
result = A/B

if the result < 2E-128 then the result is treated as zero.

ПРИМЕЧАНИЕ: Нельзя использовать относительную адресацию (67,77) при обращении к внешним, по отношению к транслируемой программе, адресам при трансляции в перемещаемом формате. Нужно использовать абсолютную адресацию.

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

Примеры:

    MOV   R0,@#177714 ;Ограничений нет.
    MOV   R0,177714   ;Можно транслировать только в абсолютном формате (CO).

Если нужно транслировать по CL, то можно сделать таким образом:

    PORT=177714 ;Перед началом программы.
    . . . .
    . . . .
    MOV R0,PORT

ПСЕВДОКОМАНДЫ.

.LA выражение | - псевдокоманда, задающая адрес начала трансляции неперемещаемой программы, эта команда должна быть самой первой командой. Её допустимо подавать после начальных присвоений.
.BLKB выражение | - резервирование количества байт, которое получается в результате вычисления выражения.
.BLKW выражение | - резервирование количества слов, которое получается в результате вычисления выражения.
| ПРИМЕЧАНИЕ: Если аргумент этих псевдокоманд слишком велик, то возможно сообщение об ошибке (см. в начале описания). В качестве аргумента можно использовать арифметическое выражение, в составе которого есть имена переменных и метки, значения которых должны быть определены, иначе будет ошибка 111.
.WORD N,N,...,N | - где N - допустимое арифметическое выражение. Запись слова (число или имя). Если нужно записать смещение к метке, то это делается (MET-.) или (@MET), что означает из адреса метки вычесть текущее значение счетчика. Операнды разделяются запятыми.

Пример:

    .WORD 1, -1 , @START, START - . , START + STOP - END, 'A, "BC

.BYTE N,N,...,N | - где N - допустимое арифметическое выражение. Запись байта (число).
    .BYTE 1, -177776, 'A, 'B, A$END-A$BGN, BLKLEN
При записи числа надо учитывать, что, например, -1=177777 и в байт это число записать нельзя, а -177776=2 и в байт записать можно. То же касается арифметических выражений, если результат умещается в байт, то всё нормально, иначе - ошибка, причём на момент вычисления все метки должны быть определены, иначе - ошибка 111.
.EVEN | - если содержание счётчика команд нечётное, то добавляется нуль, иначе игнорируется.
.ASCII /.../ | - запись строки символов в память. Строка может ограничиваться знаками (/ ' "). Знаки в начале и конце строки должны быть одинаковыми. Символ в числовой форме заключается в угловые скобки. Пример:
    .ASCII /ВЫХОД В МОНИТОР ?/<40><40>"Да/Нет:"<12>
В первом случае для ограничения строки использована дробная черта, во втором, поскольку она есть в строке, использованы кавычки.
.ASCIZ /.../ | - то же с добавлением в конце строки нуля.
.RAD50 /.../ | - запись строки в коде RADIX-50 в память, причём в поле операнда допустимо наличие пробелов.
    .RAD50 /HALT/
.PRINT #TXT | - расшифровывается как:
    MOV #TXT,R1
    CLR R2
    EMT 20
.ADDR Rn,МЕТ | - получение в регистре Rn абсолютного адреса метки МЕТ, расшифровывается как:
    MOV   PC,Rn
    ADD   (PC)+,Rn
    .WORD @MET+2
Пример:
    START:  .ADDR R1,TEXT
            CLR R2
            EMT 20
            HALT
    TEXT:   .ASCIZ <234>/ERROR !/<234>
            .EVEN
Аналогично .PRINT #TEXT, но .PRINT #TEXT нельзя использовать в перемещаемой программе.
.ORG выражение | - выравнивает текущий указатель адреса по результату выражения. Допускается нечётное значение. Если результат меньше текущего указателя - ничего не происходит.
.END | - оператор завершения программы.

## Примеры работы с блоком расширенной арифметики.

Для организации работы с блоком расширенной арифметики необходимо перед его использованием в программе инициализировать его.

Это делается внесением в текст команды CALL ARIFM, после чего возможно написание программ с использованием мнемоники команд расширенной арифметики.

После трансляции такой программы её необходимо связать линкером с объектным модулем ARIFM.OBJ командой:

BKTurbo8 LI NAME prog.obj arifm.obj

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

На БК11М с КНГМД с прошивкой 326 вместо этого можно в начале программы сделать:

MOV #164040,@#10.

Правда, эмулятор расширенной арифметики в БК11 не обрабатывает чисел с плавающей запятой.

DIV | - деление 32 разрядного слова RnRn+1 на число. Регистр в команде должен быть чётным.
    MOV #75.,R1
    CLR R0
    DIV #10.,R0 ;Деление числа 75. на 10.,
    HALT ;в R0 - результат, в R1 - остаток.
MUL | - умножение регистра на число. Причём если номер регистра нечётный, то сохраняется младшая часть результата.
    MOV #7,R1
    MUL #10.,R1 ;умножение 7*10=70 в регистре R1.
    HALT
ASH | - арифметический сдвиг регистра вправо, влево на (-32 +32) позиции в зависимости от значения 5 бита аргумента сдвига. При 1 в 5 бите - сдвиг вправо, при нуле - влево.
    ASH #5,R1  ; сдвиг регистра R1 на 5 позиций влево.
ASHC | - арифметический сдвиг двойного слова, причём регистр с нечётным номером содержит младшую часть слова, а с чётным старшую, остальное аналогично команде ASH.
FMUL | - умножение чисел с плавающей запятой. B←A*B - результат на место аргумента B.
FDIV | - деление чисел с плавающей запятой. B←A/B - результат на место аргумента B. Если делитель ( B ) равен нулю, то результат в стек не записывается.
FADD | - сложение чисел с плавающей запятой, регистр указывает на адрес нахождения аргументов. B←A+B - результат помещается на место аргумента B.
FSUB | - вычитание чисел с плавающей запятой. B←A-B - результат в B.
           FSUB  R5    ;R5 указывает на адрес MET
          HALT
    MET:  .WORD A1,A2 ;два слова аргумента A
          .WORD B1,B2 ;два слова аргумента B

Формат чисел с плавающей запятой:

                  ┌──┬─────────────────┬─────────────┐
    ПЕРВОЕ СЛОВО :│15│14 . . . . . . 07│06 . . . . 00│
                  └──┴─────────────────┴─────────────┘
                    S      Порядок      ст. мантиссы

                  ┌──────────────────────────────────┐
    ВТОРОЕ СЛОВО :│15. . . . . . . . . . . . . . . 00│
                  └──────────────────────────────────┘
                          младшая часть мантиссы
                   S - знак числа.

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

## КОМПИЛЯЦИЯ

Компиляция исходного текста может производиться в двух форматах выдачи:

1. Трансляция с получением объектного модуля. (Режим CL)
2. Трансляция с получением загрузочного модуля. (Режим CO)

Объектный модуль позиционно независим и может быть затем связан с другими модулями или привязан сам по любому адресу, задаваемому ключом –s в командной строке.

Трансляция объектного модуля производится командой CL, с целью дальнейшей связки в виде загрузочного модуля командой LI, причём буквально с любого адреса, задаваемого ключом –s в командной строке.

Загрузочный модуль транслируется по адресу, установленному псевдокомандой .LA или задаваемому ключом –s в командной строке.

При компиляции в режиме CO опционально получается скомпонованный объектный файл, в котором остаются ссылки на метки из внешних модулей. Затем эти объектники можно скомпоновать в виде набора оверлейных модулей, собранных в один файл, которые работают в заданных страницах в заданных окнах БК-0011(М).

Это такая фича БК, ДВКшникам и УНКЦшникам не понять, а БКшникам приходится с этим жить.

ОШИБКИ ПРИ ТРАНСЛЯЦИИ

100 - Нет места для меток.

101 - Псевдокоманда .LA должна быть первой в тексте.

102 - Ошибка длины или направления перехода в команде SOB.

103 - Недопустимый символ в строке.

104 - Отсутствие метки.

105 - Ошибка или отсутствие числового аргумента.

106 - Неправильная псевдокоманда.

107 - Неправильная ассемблерная инструкция.

108 - Отсутствует символ после '.

109 - Отсутствуют или недостаточно символов после ".

110 - Ошибка длины перехода по оператору ветвления.

111 - Недопустимое использование имени метки.

112 - Ошибка аргумента MARK.

113 - Ошибка в имени регистра.

114 - Ошибка в псевдокоманде.

115 - Ошибка в команде.

116 - Метка уже определена ранее.

117 - Аргумент .BLKB слишком велик.

118 - Аргумент .BLKW слишком велик.

119 - Аргумент .ORG слишком велик.

120 - Нечётный адрес команды.

121 - Отсутствует .END

122 - Неопределённая метка в непосредственном выражении.

123 - Любые метки в выражении запрещены.

124 - Отсутствует переход у команды SOB.

125 - Ошибка аргумента TRAP.

126 - Ошибка аргумента EMT.

127 - Ошибка или неверный метод адресации.

128 - Отсутствует второй операнд.

129 - Переполнение байтового аргумента.

130 - Неожиданный конец строкового аргумента.

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

При трансляции текста выдаётся номер ошибки, номер строки и при возможности сама строка, в которой возникла ошибка.

### Конвертер бинарных объектов в объектные модули кросс ассемблера Turbo8.

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

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

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

Тут надо конкретики добавить. А ещё разобраться с алгоритмами работы с картинками.

Автор приносит свою благодарность:

А. Надежину: | за ANDOS, TURBO4 и еще много прекрасных программ.
А. Надежину: | за терпение, с которым он давал советы начинающему программисту-любителю.
А. Надежину: | за подарок - TURBO6M.
С. Камневу: | за великолепную сервисную оболочку DiskMASTER и ряд полезных советов.
В. Ретуновскому & А. Суханову: | за TRACER.
С. Клименкову: | за PARADISE.
М. Королеву: | за DESS, READER14 и MKDOS, с которой и начал автор работу с БК.
Д. Бутырскому: | за TURBO7MK, который хоть и не был в числе предшественников, но из которого была заимствована одна идея.
Д. Романову: | за систему VorteX, в которой было написано данное описание, и с которой вообще автор провёл много приятных минут.
П. Суходольскому: | за АОН вообще и РУСЬ14 в частности.
В. Тукову, | благодаря которому автор познакомился с БК.
И, конечно, В. Коренкову, "отцу-основателю" серии ассемблеров TURBO, и авторам TURBO4, TURBO5, TURBO6, без которых этой работы не было бы вообще.
Хотелось бы также поблагодарить своего кота Василия за моральную поддержку (не очень мешал).
Автор ассемблера Turbo8DK
Крылов Дмитрий Константинович 398-83-12 Москва, сентябрь 1995 г.

Ну а я по традиции присоединяюсь к благодарностям и в свою очередь благодарю Крылова Дмитрия Константиновича за ассемблер Turbo8DK, которым только и пользовался я, после появления дисковода у моей БКшки, и так привык к нему, что вот написал кросс ассемблер на его основе.

© gid 2012-2017