IPB

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в эту темуОткрыть новую тему
> Исходники ПЗУ: КНГМД 326ая прошивка ПЗУ
SuperMax
сообщение 20.6.2022, 17:53
Сообщение #1


Администратор
*****

Группа: Root Admin
Сообщений: 6 282
Регистрация: 7.1.2006
Из: Красноярск
Пользователь №: 1



Код

                                  - 1 -
                                         В каждой глупости есть
                                      своя доля логики, особен-
                                      но, если там ее найти.


   Уважаемые  читатели! Вы держите в руках текст 326 прошивки в
блоке КНГМД. Он получен дизассемблированием  программы, зашитой
в микросхеме  КР1801РЕ2-326. Этот текст появился на свет благо-
даря дизассемблеру  DIZAKS4 v4 17.04.88 (KSA corp.), текстовому
редактору EDALT3E (фирма ALTEC), моему  желанию, ну, и конечно,
дисководу.
   На сегодня все больше  и  больше людей приобретают дисководы
и подключают их к БК. Но очень мало тех, кто знает, как работа-
ет их любимый дисковод. У нас на БК стало дурной традицией сде-
лать что-нибудь  хорошее, а всю информацию, как  и  с  чем  это
едят, припрятать или раздать  очень  узкому  кругу лиц. Кстати,
это повелось  с  выпуска самой БК. Ее пустили  в  продажу, а ни
схем, ни описания  принципов работы не опубликовали. Думаю, что
если бы это сделали, то в 1989 году мы  бы уже имели на БК дис-
ковод, расширение памяти, и, следовательно, много хороших прог-
рамм. Точно так же произошло с контроллером дисковода. Господин
Саяпин написал драйвер для работы с НГМД, а информацию по этому
драйверу никому  не  дал. Кстати, я его  в  этом не виню, может
быть, эту информацию у него  никто и не просил. Имеются, конеч-
но, какие-то обрывки, но полной  информации все же нет. Вот по-
чему я принялся за эту каторжную  работу. Понять и прокомменти-
ровать эту программу было довольно сложно, так как в своем рас-
поряжении я имел всего лишь распределение ячеек  в  рабочей об-
ласти драйвера, известное по руководству системного программис-
та для БК0011.
   Конечно, это не исходник, но я думаю, что с помощью  данного
текста Вы сможете кое-что узнать об этой прошивке и составить о
ней собственное мнение. Думаю, что Вы поймете, что эта програм-
ма далека от совершенства, что многие  операции можно было сде-
лать лучше, и что в некоторых случаях  применялись не самые хо-
рошие алгоритмы.
   Самое главное, что теперь это положение не изменить, так как
эта прошивка стала стандартной для БК, и ее изменение  приведет
к несовместимости некоторых  программ  с  новой зашивкой. Хотя,
конечно, это относится только  к  таким программам, которые ис-
пользуют подпрограммы зашивки не через стандартные точки входа.
   Вот вроде и все что я хотел сказать по этому поводу. Сидите,
разбирайтесь. Огромная просьба  к  тем, кто заметит  допущенные
неточности, ошибки  или  имеет сказать что-нибудь интересное по
этому поводу - позвоните мне, и мы с Вами поговорим об этом.

   Москва 1993 г.                 Гаршенин К.В. (095)4675093

   Дополнения и исправления внесли:

                           Войлуков А.А, Рузаков А.С. - 1992
                           "Black beards"             - 1992
                           Dale Publishing co.        - 1992-94








                              - 2 -


  Регистр состояния КНГМД (177130).

  Формат регистра по записи.
┌──────┬─────────────────────────────────────────┐
│разряд│               назначение                │
├──────┼─────────────────────────────────────────┤
│  00  │Выбор накопителя с номером 0             │
│  01  │Выбор накопителя с номером 1             │
│  02  │Выбор накопителя с номером 2             │
│  03  │Выбор накопителя с номером 3             │
│  04  │Включение электродвигателя               │
│  05  │Выбор головки накопителя: 0=верх. 1=нижн.│
│  06  │Направление шага                         │
│  07  │Шаг                                      │
│  08  │Признак "НАЧАЛО ЧТЕНИЯ"                  │
│  09  │Признак "ЗАПИСЬ МАРКЕРА"                 │
│  10  │Переключение схемы прекоррекции          │
│11-15 │Не используются                          │
└──────┴─────────────────────────────────────────┘

  Формат регистра по чтению.
┌────────┬──────────────────────────────────────┐
│ разряд │             назначение               │
├────────┼──────────────────────────────────────┤
│   00   │Признак "дорожка 00"                  │
│   01   │Признак готовности накопителя         │
│   02   │Запрет записи                         │
│   07   │Требование съема информации с регистра│
│        │данных или записи в него нового кода  │
│   14   │В режиме чтения признак  записи цикли-│
│        │ческого контрольного кода на диск     │
│   15   │Индекс                                │
│3-6 8-13│Не используются                       │
└────────┴──────────────────────────────────────┘

   Регистр данных КНГМД (177132).
   Все разряды регистра доступны по чтению и записи.


   Драйвер НГМД размещен в ПЗУ, находящемся в контроллере НГМД,
и доступен при подключении контроллера к микро-ЭВМ.
   Для работы драйвера необходима  область ОЗУ размером 66 байт
для размещения параметров и рабочих ячеек.

















                              - 3 -


   Формат рабочей оласти драйвера:
┌───────┬────┬──────┬────────┬────────────────────────────────┐
│Смеще- │Дли-│Симво-│Началь- │        Назначение ячейки       │
│ние от │на, │личес-│ное зна-│                                │
│начала │байт│кое   │чение   │                                │
│области│    │имя   │        │                                │
├───────┼────┼──────┼────────┼────────────────────────────────┤
│   0   │ 2  │CSRW  │ 000000 │Копия по записи РС КНГМД        │
│   2   │ 2  │CURTRK│    -   │Адрес текущей дорожки           │
│   4   │ 4  │TRKTAB│ 177777 │Таблица текущих дорожек (*)     │
│  10   │ 2  │TDOWN │ 020000 │Задержка опускания головки      │
│  12   │ 2  │TSTEP │    -   │Задержка перехода дорожки       │
│  14   │ 1  │TRKCOR│ 000036 │Дорожка начала предкомпенсации  │
│  15   │ 1  │BRETRY│ 000030 │Число попыток повтора при ошибке│
│  16   │ 1  │FLAGS │ 000000 │Рабочая ячейка драйвера (**)    │
│  17   │ 1  │FILLB │    -   │Код заполнения при форматиров.  │
│  20   │ 2  │FLGPTR│    -   │Указатель на байт признаков     │
│  22   │ 4  │FLGTAB│ 000000 │Таблица признаков (***)         │
│  26   │ 2  │ADDR  │    -   │Адрес буфера ОЗУ                │
│  30   │ 2  │WCNT  │    -   │Число слов для пересылки        │
│  32   │ 1  │SIDE  │    -   │Номер стороны диска             │
│  33   │ 1  │TRK   │    -   │Номер дорожки                   │
│  34   │ 1  │UNIT  │    -   │Номер привода                   │
│  35   │ 1  │SECTOR│    -   │Номер сектора                   │
│  36   │ 2  │WRTVAR│ (****) │Записываемое значение при форм. │
│  40   │ 2  │MARKER│ (****) │Буфер маркера при записи        │
│  42   │ 2  │FREE  │ (****) │Размер пустого остатка сектора  │
│  44   │ 2  │INTIME│ (****) │Время от перепада индекса       │
│  46   │ 2  │BUF4  │ (****) │Буфер @#4                       │
│  50   │ 2  │BUFSP │ (****) │Буфер SP                        │
│  52   │ 2  │BUFPSW│ (*+**) │Буфер PSW                       │
│  54   │ 1  │CRETRY│ (****) │Счетчик повторов по BRETRY      │
│  55   │ 1  │TURNS │ (****) │Число оборотов диска на операцию│
│  56   │ 1  │SECRET│ (****) │Число повторных поисков сектора │
│  57   │ 1  │ERRNUM│ (****) │Буфер для номера ошибки         │
│  60   │ 2  │MAXSEC│ 000012 │Число секторов на дорожке       │
│  62   │ 2  │HOLTIN│    -   │Время задержки после индекса    │
│  64   │ 2  │SECLEN│ 000400 │Длина сектора в словах (*****)  │
└───────┴────┴──────┴────────┴────────────────────────────────┘

   (*) Старший бит каждого  байта при установке в 1 задает воз-
врат соответствующего дисковода  к  дорожке 00 перед  операцией
позиционирования (для случая, когда положение  головки  заранее
неизвестно).

   (**) Флаги имеют следующие значения:

   Бит 0 (001) - разрешение читать/записывать скрытые данные
   Бит 2 (004) - двигатель уже был включен перед операцией
   Бит 4 (020) - признак записи информации на диск
   Бит 5 (040) - текущее состояние индекса
   Бит 6 (100) - отмена двойного шага при возврате на 00.








                              - 4 -


   (***) Таблица признаков содержит по одному байту на привод и
используется для обработки нестандартных дисков. В каждом байте
используется четыре бита для указания параметров операции.
   Бит 0 - при установке драйвер производит пропуск дорожек при
поиске, т.е. фактически обрабатываются лишь четные дорожки. Эта
возможность используется для обработки на 80-дорожечном  диско-
воде 40-дорожечных дисков;
   Бит 1 - при установке драйвер  производит  обращение  только
к нижней стороне диска. Эта возможность используется  при  под-
ключении  одностороннего  дисковода, а также  при  обработке на
двустороннем дисководе односторонних дисков;
   Бит 2 - при  установке  обрабатываются  сектора  длиной 2000
байт, иначе - 1000 байт (Внимание! Работа  с  секторами  длиной
2000 байт организована неверно!);
   Бит 3 - при установке начало первого сектора задается задер-
жкой HOLTIN от индекса, в противном случае - своим заголовком.

   (****) Значения заносятся в процессе работы драйвера.

   (*****) Внимание! Следите, чтобы  при  записи  ячейка SECLEN
содержала соответствующее значение, в противном случае портится
разметка диска!


   Перед самым первым вызовом драйвера  нужно  инициализировать
рабочую область. Это делает специальная  подпрограмма инициали-
зацми.
   После завершения операций обмена с диском драйвер  оставляет
двигатель дисковода включенным. Для  остановки  двигателя  про-
грамма  пользователя  должна  обнулить  ячейки @#177130 и CSRW.
Просьба не выключать двигатель командой RESET, думайте  о  тех,
кто имеет БК0010+ДОЗУ32Кб.


   Диагностика ошибок в драйвере НГМД.

   При возникновении ошибки бит С в слове состояния  процессора
устанавливается в 1 и в байт @#52 помещается код ошибки:

    1  При чтении - ошибка CRC в зоне данных
       При записи - установлена защита записи
    2  Ошибка CRC в зоне заголовка сектора
    3  Нет позиционирования на нулевую дорожку
    4  Ошибка позиционирования
    5  Не найден сектор
    6  Нет диска или диск не вращается
    7  Прерывание по вектору 4 во время операции
   10  Не найден адресный маркер
   11  Не найден маркер данных
   12  Недопустимые  параметры команды или нестандартный формат
       диска
   13  Попытка считывания скрытых данных  без  соответствующего
       разрешения





ъ                              - 5 -


   Драйвер имеет несколько точек входа:

   160000   Автоматическая загрузка
   160002   Загрузка с выбранного привода
   160004   Чтение-запись по номеру блока
   160006   Чтение-запись по номеру сектора
   160010   Инициализация рабочей области драйвера
   160012   Форматирование дорожки


   Автоматическая загрузка

   Вызов:
          JSR PC,@#160000

   Можно также произвести загрузку непосредственно из пускового
монитора:
   <СТОП>С160000<ВВОД>
   Входные параметры отсутствуют.
   Действие: производится попытка загрузить операционную систе-
му с привода 0. Если попытка загрузки  была неудачной, то драй-
вер пытается  загрузить систему с 1 привода. Если  все  попытки
оказались неудачными, драйвер возвращает  управление с установ-
ленным битом "C" процессора.
   Алгоритм загрузки:
   1. Инициализируется  рабочая область драйвера в ОЗУ (базовый
адрес 2000) с параметрами для НГМД 6022;
   2. В ОЗУ, начиная с адреса 1000, считывается сектор 1 дорож-
ки 0 выбранного дисковода;
   3. В следующих случаях:

      - в приводе нет диска;
      - привод не защелкнут;
      - привод неисправен;
      - диск не отформатирован;
      - ошибка чтения;
      - отсутствует начальный загрузчик,

   попытка загрузки  считается неудачной. При успешной загрузке
драйвер передает управление по адресу 1000, при этом в R0 поме-
щается номер привода, с которого производилась загрузка.
   Драйвер прошивки 253 пытается  загрузиться с приводов 0...3.
Поскольку он использует EMT 0,16,122, их необходимо  перехваты-
вать. EMT 112 заменяется на NOP, ЕМТ 0 восстанавливает стек.


   Загрузка с выбранного привода

   Вызов:
          MOV #N,R0
          JSR PC,@#160002

   ИЗ ВСТРОЕННЫХ МОНИТОРОВ БК ВЫБОРОЧНАЯ ЗАГРУЗКА НЕВОЗМОЖНА.
   Действие аналогично предыдущему пункту, но загрузка  начина-
ется сразу с выбранного привода, и при неудачной загрузке попы-
ток загрузиться с других приводов не предпринимается.




                              - 6 -


   Чтение-запись логического блока

   Вызов:
          JSR PC,@#160004   ;BCC WORK или BCS ERROR
   Входные параметры:

          R0 - номер блока на диске;
          R1 - длина пересылаемого массива в словах;
          R2 - начальный адрес массива данных;
          R3 - базовый адрес рабочей области драйвера;
          в рабочей области: UNIT - номер привода.

   Блок  является логической единицей информации на внешних но-
сителях и равен 1000 байт. В используемом формате записи размер
блока совпадает  с  размером сектора. Первый сектор нулевой до-
рожки нижней  стороны  соответствует блоку 0. Вычисление номера
сектора и дорожки по номеру блока производится  с  учетом уста-
новленных признаков в таблице FLGTAB. Алговитм этого вычисления
совпадает с алгоритмом драйвера MY для микроЭВМ ДВК.
   Длина  массива данных задает число слов, подлежащих пересыл-
ке, а также тип операции: положительное - чтение, отрицательное
- запись. При записи пересылаемое число слов равно  абсолютному
значению длины. Если заданное число слов превышает размер  сек-
тора, осуществляется автоматический переход к следующему секто-
ру, а если необходимо, то и на другую сторону  и  дорожку. Если
при записи число  слов  не  кратно  размеру сектора, то остаток
последнего сектора заполняется нулями.
   Перед самым первым вызовом драйвера поля CSRW, TRKTAB, FLAGS
в рабочей области  должны быть заполнены значениями, указанными
в таблице, и не должны изменяться программой пользователя. Поля
TDOWN, TSTEP, TRKCOR, BRETRY, FLGTAB   рекомендуется  заполнять
значениями, указанными в таблице, однако они могут быть измене-
ны в зависимости от конкретных условий.
   Возврат из драйвера осуществляется командой RTS PC, содержи-
мое регистров (кроме R3) не сохраняется.
   Возникновение прерывания  по  вектору 4 при записи  на  диск
приводит к появлению  сбоя  в  секторе, в который производилась
запись. Сбой может быть устранен повторной записью этого секто-
ра.


   Чтение-запись по номеру сектора и дорожки

   Вызов:
          JSR PC,@#160006
   Входные параметры:

          R3     - адрес рабочей области;
          ADDR   - начальный адрес массива данных;
          WCNT   - длина массива данных;
          SIDE   - номер стороны (0 - нижняя, 1 - верхняя);
          TRK    - номер дорожки;
          UNIT   - номер привода (0...3);
          SECTOR - номер сектора (1...12).

   Действие аналогично предыдущему пункту.




                              - 7 -


   Инициализация рабочей области

   Эта точка входа является вспомогательной и служит для облег-
чения написания программ, использующих драйвер НГМД.
   Вызов:
          JSR PC,@#160010
   Входной параметр:

          R3 - базовый адрес рабочей области.

   Действие: заполняются следующие поля рабочей области:

          CSRW   - 0
          TRKTAB - 177777,177777
          TDOWN  - 10000
          TSTEP  - 10000
          TRKCOR - 30. (253); 32. (326)
          BRETRY - 30. (253); 20. (326)
          FLAGS  - 0
          FLGTAB - 0,0
          MAXSEC - 12 (только 326)


   Форматирование дорожки

   Вызов:
          JSR PC,@#160012
   Входные параметры:

          R3    - базовый адрес рабочей области;
          FILLB - код заполнения секторов при форматировании;
          SIDE  - номер стороны;
          TRK   - номер дорожки;
          UNIT  - номер привода.

   Действие: форматируется указанная дорожка с указанной сторо-
ны, поле данных всех секторов заполняется кодом FILLB.


   Команды расширенной арифметики

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









                              - 8 -


   Мнемоника команд расширенной арифметики реализована в ассем-
блерах MICRO Коренкова В.С., TURBO Надежина А.М:

1. MUL   S,Rn  Деление
2. DIV   S,Rn  Умножение
3. FMUL  Rn    Умножение с плавающей запятой
4. FDIV  Rn    Деление с плавающей запятой
5. FADD  Rn    Сложение чисел с плавающей запятой
6. FSUB  Rn    Вычитание чисел с плавающей запятой
7. ASH   S,Rn  Арифметический сдвиг на заданное число бит
8. ASHC  S,Rn  Арифметический сдвиг двойного слова на заданное
               число бит

   Автор  не  стал  комментировать блок расширенной арифметики,
т.к. его основной  целью  было  комментирование работы драйвера
дисковода.


   Описание команд расширенной арифметики.

   DIV S,D

   Деление 32-разрядного слова RnRn+1 на число или регистр. Ре-
гистр результата (D) в команде должен быть четным.

      MOV #75.,R1
      CLR R0
      DIV #10.,R0  ;Деление числа 75. на 10.
                   ;R0 - результат, R1 - остаток.


   MUL S,D

   Умножение регистра  на  число. Если номер регистра нечетный,
сохраняется младшая часть результата. Регистр результата (D)
должен быть нечетным.

      MOV #7,R1
      MUL #10.,R1  ;умножение 7*10.=70. в регистре R1.


   ASH S,D

   Арифметический  сдвиг  регистра  вправо/влево на (-32...+32)
позиции  в  зависимости от значения 5-го бита аргумента сдвига.
При 1 в 5 бите - сдвиг вправо, при 0 - влево.

      ASH #5,R1    ;сдвиг регистра R1 на 5 позиций влево.


   ASHC S,D

   Арифметический сдвиг двойного слова, причем регистр с нечет-
ным номером содержит младшую часть слова, а с четным - старшую,
остальное аналогично команде ASH.





                              - 9 -


   FADD Rn

   Сложение чисел с плавающей запятой. Регистр указывает на ад-
рес нахождения аргументов. A←A+B - результат помещается на мес-
то аргумента A.


   FSUB Rn

   Вычитание чисел с плавающей запятой. A←A-B - результат в A.

      FSUB R5      ;R5 указывает на адрес MET
      HALT
MET: A            ;два слова аргумента A
      B            ;два слова аргумента B


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

Первое слово :  15  14        07  06                 00
                 ├───┼─────────┼───┼──────────────────┤
                 S   Порядок        ст. часть мантиссы

Второе слово :  15                                   00
                 ├────────────────────────────────────┤
                          младшая часть мантиссы


   FMUL Rn

   Умножение  чисел  с  плавающей запятой. A←A*B - результат на
месте аргумента A.


   FDIV Rn

   Деление чисел с плавающей запятой. A←A/B - результат на мес-
те  аргумента A. Если  делитель (B) равен  нулю, то результат в
стек не записывается.
   Подробнее  об  использовании  команд  расширенной арифметики
можно узнать в документациях к программам MICRO или TURBO.

Коренков Василий Семенович                 тел. (095) 4359514
Надежин Алексей                            тел. (095) 1803002
ъ                              - 10 -


        BR   BOOT0    ;Aвтоматическая загрузка         160000
        BR   BOOT1    ;Загрузка с выбранного привода   160002
        BR   RWBLK    ;Чтение-запись по номеру блока   160004
        BR   RWSEC    ;Чтение-запись по номеру сектора 160006
        BR   INIT     ;Инициализация рабочей области   160010
        JMP  FORMAT   ;Форматирование дорожки          160012
        JMP  EXT      ;Расширенная арифметика          160016

            *** 160022 П/п автоматической загрузки ***

BOOT0:  CLR  R0       ;Начнем с нулевого привода
        CALL BOOT     ;Пробуем загрузиться
        MOV  #1,R0    ;Там не получилось, попробуем с первого
        CALL BOOT     ;Загружаем...
        BR   STOP     ;Загрузчика нигде нет, выходим

           *** 160042 Загрузка с выбранного привода ***

BOOT1:  MOV  #1000,SP ;Установим стек
        CALL BOOT     ;Попробуем загрузиться

     *** 160052 Остановка двигателя НГМД и выход из п/п ***

STOP:   CLR  (R3)
        CLR  @#177130
        CLR  @#177760
        RET

        *** 160066 П/п загрузки и запуска загрузчика ***

BOOT:   MOV  #2000,R3     ;Установим адрес рабочей области
        CALL INIT         ;   и инициализируем ее
        MOVB R0,34(R3)    ;Занесем номер привода
        CLR  R0           ;Читаем нулевой блок
        MOV  #400,R1      ;   длиной 400 слов (1000 байт)
        MOV  #1000,R2     ;   с адреса 1000
        CALL RWBLK        ;Прочитаем...
        BCS  1$           ;   не получилось - выход
        CMP  @#1000,#240  ;Загрузчик начинается с NOP?
        BNE  1$           ;Нет - выход
        CMP  @#1002,#5    ;Вторая команда - RESET?
        BEQ  1$           ;Да - диск не системный, выход
        MOVB 34(R3),R0    ;Вспомним, откуда это мы загрузились
        CALL @#1000       ;Запускаем загрузчик...
1$:     RET               ;Вот и все

          *** 160154 Чтение-запись по номеру сектора ***

RWSEC:  BR   SUBRW

        *** 160156 П/п инициализации рабочей области ***

INIT:   CLR  (R3)         ;Очистим копию РС КНГМД
        MOV  #177777,4(R3);Заполним таблицу текущих дорожек
        MOV  #177777,6(R3)
        MOV  #23420,10(R3);Время опускания головки
        MOV  #23420,12(R3);Время перехода дорожки
        MOVB #40,14(R3)   ;Дорожка начала предкомпенсации


                              - 11 -


        MOVB #24,15(R3)   ;Число повторов при ошибке
        CLRB 16(R3)       ;Очистим флаги
        CLR  22(R3)       ;   и таблицу признаков
        CLR  24(R3)
        MOV  #12,60(R3)   ;Занесем число секторов на дорожке
        RET

        *** 160250 П/п чтения-записи по номеру блока ***

   Входные параметры:
      R0 - номер блока
      R1 - длина массива в словах (отрицательная - запись)
      R2 - адрес начала массива
      R3 - адрес рабочей области

RWBLK:  MOV  #10,R4
        MOVB 60(R3),R5;число секторов на дорожке
        SWAB R5       ;делим ст. байт R0 на ст. байт R5
1$:     CMP  R5,R0
        BHI  2$
        SUB  R5,R0
        SEC
2$:     ROL  R0       ;Частное накапливается в мл. байте R0
        SOB  R4,1$
        MOVB R0,R4    ;В мл. байте номер дорожки, сохраним его
        CLRB R0
        SWAB R0       ;Получили остаток от деления
        INC  R0       ;Номер сектора на единичку больше
        CLRB 32(R3)   ;Пока мы на нижней стороне
        CMP  R0,60(R3);Этот сектор за пределами дорожки?
        BLE  3$       ;Нет - полный порядок
        INCB 32(R3)   ;Да - значит, он на другой стороне
        SUB  60(R3),R0;   и номер у него другой
3$:     CALL SETPTR   ;Установим указатель на байт признаков
        BITB #2,@20(R3);Диск односторонний?
        BEQ  4$       ;Нет - оставим все как есть
        ASRB 32(R3)   ;Да - сторона всегда 0,
        ROLB R4       ;   а дорожка уже другая
4$:     MOVB R4,33(R3);Запишем результаты: дорожка,
        MOVB R0,35(R3);   сектор,
        MOV  R1,30(R3);   число слов,
        MOV  R2,26(R3);   адрес буфера

       *** 160372 П/п чтения-записи по номеру сектора ***

   Входные параметры:
      R3 - базовый адрес рабочей области
      ADDR, WCNT, SIDE, TRK, UNIT, SECTOR - соответственно

SUBRW:  MOV  SP,50(R3)    ;Сохраняем SP,
        MFPS 52(R3)       ;   PSW,
        MOV  #4,R0
        MOV  (R0),46(R3)  ;   @#4 в соответствующих буферах
        MOV  PC,(R0)      ;Переназначаем вектор @#4 на себя,
        ADD  #1076,(R0)   ;   теперь он равен 161512
        TSTB 35(R3)       ;Какой сектор нужен?
        BEQ  ERR12        ;Нулевых у нас нет, ошибка 12
        CMPB 35(R3),60(R3);Сектор больше максимального?
        BGT  ERR12        ;Таких тоже нет, ошибка 12

                              - 12 -


        CLRB @#52         ;Пока ошибок нет
        BICB #30,16(R3)   ;Пока не записываем
        TST  30(R3)       ;Сколько слов будем пересылать?
        BEQ  QUIT         ;0 - ничего делать не надо, выход
        BPL  READ         ;больше 0 - будем читать

              *** 160460 П/п записи массива ***

        NEG  30(R3)       ;Нормализуем длину
        BISB #20,16(R3)   ;Установим признак записи
        MOV  #175641,40(R3);Запомним маркер данных
        BITB #1,16(R3)    ;Записываем скрытно?
        BEQ  1$           ;Нет - идем дальше
        MOV  #174241,40(R3);Да - запомним специальный маркер
1$:     CALL ENGINE       ;Включим двигатель, запомним привод
        BIT  #4,(R4)      ;Защита записи есть?
        BEQ  MAIN         ;Нет - продолжить работу
        MOV  #1,R0        ;Есть - ошибка 1
        BR   ERR

               *** 160536 П/п чтения массива ***

READ:   CALL ENGINE       ;Включим двигатель, запомним привод
        MOV  #400,64(R3)  ;Сектора стандартной длины
        BITB #4,@20(R3)   ;А они ли нам нужны?
        BEQ  MAIN         ;Да - продолжить работу
        MOV  #1000,64(R3) ;Нет - секторы удвоенной длины

         *** Основная часть п/п чтения/записи массива ***

MAIN:   CALL GOTRK        ;Спозиционируем на нужную дорожку
        CALL CORR         ;Включим схему прекоррекции
        MOVB 15(R3),54(R3);Число попыток - в буфер

               *** Получение заголовка сектора ***

        MOVB #10,57(R3)   ;Предполагаем ошибку 10
        MOVB #24,55(R3)   ;На операцию отводим 20. оборотов
1$:     CALL FINDH        ;Найдем маркер заголовка
        BCC  3$           ;Нашли - идем дальше
2$:     MOVB 57(R3),R0    ;Не нашли - выходим с ошибкой
        BR   ERR
3$:     TSTB (R4)         ;Информация получена?
        BPL  3$           ;Нет - подождем
        MOV  (R5),R0      ;Теперь прочитаем ее
4$:     TSTB (R4)         ;Хотим еще информации!
        BPL  4$           ;Дождемся ее появления
        MOV  (R5),R1      ;   и заберем ее
        CALL TSTCRC       ;Проверим CRC
        BNE  5$           ;Ошибки нет - идем дальше
        MOVB #2,57(R3)    ;Ошибка 2!
        DECB 54(R3)       ;Остались еще попытки?
        BNE  1$           ;Да - повторим чтение
        BR   2$           ;Видно, не судьба! Выходим с ошибкой
5$:     BIC  #177774,R1   ;Выделяем код длины сектора
        BITB #4,@20(R3)   ;Какие сектора нам были нужны?
        BNE  LONG         ;Длинные - посмотрим...
        CMPB R1,#2        ;Короткие. А на диске какие?
        BEQ  WORK         ;Тоже короткие. Порядок, идем дальше
ъ                              - 13 -


        DECB 54(R3)       ;Как там дела с попытками?
        BNE  1$           ;Есть еще - повторим все сначала

               *** 160724 Выход с ошибкой ***

ERR12:  MOV  #12,R0   ;Выходим с ошибкой 12
ERR:    JMP  ERROR    ;Идем на обработку и выход
QUIT:   JMP  EXIT     ;Идем на нормальный выход

LONG:   CMPB R1,#2    ;Нужны длинные сектора, а какие здесь?
                      ;   ОШИБКА: На самом деле код длинных
                      ;            секторов - 3, а не 2
        BNE  ERR12    ;Длинные - выходим с ошибкой 12

                *** Собственно п/п чтения ***

WORK:   MOVB 15(R3),54(R3);Восстановим счетчик по BRETRY
        MOVB #6,56(R3)    ;На поиск сектора - 6 попыток
        CLR  42(R3)       ;Остаток сектора отсутствует
        CMP  30(R3),64(R3);Читать надо больше одного сектора?
        BHI  1$           ;Да - идем читать
        MOV  64(R3),42(R3)
        SUB  30(R3),42(R3);Вычислим длину остатка
1$:     MOVB #5,57(R3)    ;Прогнозируем ошибку 5
2$:     MOVB #24,55(R3)   ;На операцию отводим 20. оборотов
3$:     CALL FINDH        ;Ищем маркер заголовка
        BCC  4$           ;Нашли - идем дальше
        MOVB 57(R3),R0    ;Кончились обороты - выходим
        BR   ERR          ;   с ошибкой
4$:     TSTB (R4)         ;Готовность данных есть?
        BPL  4$           ;Нет - подождем
        CMP  32(R3),(R5)  ;Нужная дорожка и сторона?
        BEQ  5$           ;Да - идем дальше
        DECB 56(R3)       ;Минус одна попытка
        BEQ  6$           ;Кончились - выход с ошибкой
        CALL GOTO00       ;Спозиционируем на дорожку 00,
        CALL GOTRK        ;   вернемся на нужную
        BR   3$           ;   и попытаемся еще раз
6$:     MOV  #4,R0        ;Выходим с ошибкой 4
        BR   ERR
5$:     TSTB (R4)         ;Ждем готовности данных
        BPL  5$           ;Не готовы - повторять...
        MOV  (R5),R1      ;Получим номер сектора,
        SWAB R1           ;   поместим его в младший байт
        CMPB 35(R3),R1    ;Этот сектор ищем?
        BEQ  7$           ;Да - будем его читать
        MOV  64(R3),R0    ;Нет - возьмем длину данных,
        ADD  #27,R0       ;   прибавим длину заголовка
        CALL FICT         ;   и пропустим их
        BR   3$           ;Повторим процедуру еще раз
7$:     CALL TSTCRC       ;Проверим CRC
        BNE  8$           ;Совпала - идем дальше
        MOVB #2,57(R3)    ;Если что, это будет ошибка 2
        DECB 54(R3)       ;Одной попыткой меньше
        BNE  2$           ;Еще остались - поищем снова
        MOVB 57(R3),R0    ;Нет - выходим с ошибкой
        BR   ERROR
8$:     MOV  64(R3),R1    ;Получим длину сектора
        SUB  42(R3),R1    ;Вычислим длину используемой части

                              - 14 -


               *** 161176 Чтение сектора ***

        BITB #20,16(R3);Будем записывать?
        BEQ  9$       ;Нет - значит, читать
        JMP  WRSEC    ;Да - идем на запись сектора
9$:     CALL FINDS    ;Ищем зону синхронизации
        TSTB 56(R3)   ;Нашли?
        BEQ  11$      ;Нет - пробуем снова
        CALL STREAD   ;Начинаем чтение!
        MOV  #1130,R0 ;
10$:    TSTB (R4)     ;Данные готовы?
        BMI  12$      ;Да - посмотрим их
        SOB  R0,10$   ;Больше ждать нельзя?
11$:    MOVB #11,57(R3);Да - прогнозируем ошибку 11
        DECB 54(R3)   ;Одной попыткой меньше
        BNE  2$       ;Попытки есть - повторим операцию
        MOVB 57(R3),R0;Кончились - выйдем с ошибкой
        BR   ERROR
12$:    TST  (R5)     ;Пропустим маркер A1A1
13$:    TSTB (R4)     ;Готовность данных есть?
        BPL  13$      ;Нет - ждем
        MOV  (R5),R0  ;Прочитаем данные
        CMP  #120773,R0;Обычный сектор?
        BEQ  14$      ;Да - идем дальше
        CMP  #120770,R0;Скрытый сектор?
        BNE  11$      ;Что-то иное - ошибка
        BITB #1,16(R3);Можно читать скрытые данные?
        BNE  14$      ;Да - будем читать
        MOV  #13,R0   ;Нельзя - выходим с ошибкой 13
        BR   ERROR
14$:    CALL RDSEC    ;Прочитаем сектор
        CALL TSTCRC   ;Проверим CRC
        BNE  NEXT     ;Совпала - посмотрим следующий сектор
        MOVB #1,57(R3);Не совпала - ошибка 1
        DECB 54(R3)   ;Попытки кончились?
        BNE  2$       ;Нет - попробуем еще раз
        MOVB 57(R3),R0;Кончились - выходим с ошибкой
        BR   ERROR

           *** 161362 Мультисекторные операции **+

NEXT:   SUB  64(R3),30(R3);Сектор обработали, вычтем из длины
        BLE  EXIT         ;Массив кончился - выход
        INCB 35(R3)       ;Нет - следующий сектор
        CMPB 35(R3),60(R3);Конец дорожки?
        BLOS 3$           ;Нет - продолжим обработку
        BIT  #40,(R3)     ;Верхняя сторона?
        BNE  1$           ;Да - следующая дорожка
        BITB #2,@20(R3)   ;Диск односторонний?
        BNE  1$           ;Да - продолжим обработку
        MOVB #1,32(R3)    ;Нет - установим верхнюю сторону
        BIS  #40,(R3)
        BR   2$           ;Перейдем к обработке
1$:     INCB 33(R3)       ;Следующая дорожка
        CALL GOTRK        ;Спозиционируем на нее
        CLRB 32(R3)       ;Установим нижнюю сторону
        BIC  #40,(R3)
2$:     MOVB #1,35(R3)    ;Теперь сектор будет первым
        CALL CORR         ;Переключить прекоррекцию

                              - 15 -


3$:     ADD  64(R3),26(R3);Получим новый начальный адрес
        ADD  64(R3),26(R3)
        JMP  WORK         ;Идем на чтение очередного сектора

      *** 161512 Обработка прерывания по вектору 4 ***

        TST  (R5)     ;Сбросить данные
        MOV  #7,R0    ;Заносим код ошибки 7

                 *** Выход с ошибкой ***

ERROR:  MOVB R0,@#52  ;Код ошибки - на место!
        MOVB #1,56(R3);Установим бит C в буфере
        BR   EXIT1    ;Идем на выход

                 *** Выход без ошибки ***

EXIT:   CLRB 56(R3)   ;Сбросим бит C в буфере
EXIT1:  MOV  46(R3),@#4;Восстановить вектор 4
        MTPS 52(R3)   ;Восстановить PSW
        CCC           ;Сбросить все признаки
        RORB 56(R3)   ;Бит C - из буфера в PSW
        MOV  50(R3),SP;Восстановить SP
        RET           ;Возврат

              *** 161566 П/п проверки CRC ***

TSTCRC: TSTB (R4)         ;Ждем готовности данных
        BPL  TSTCRC
        MOV  #17,R2       ;CRC появится не позже 15. циклов
1$:     BIT  #40000,(R4)  ;CRC сошлась?
        BNE  2$           ;Да - выход
        SOB  R2,1$        ;Нет - очередной цикл
2$:     RET               ;Если бит Z=1, то произошла ошибка

          *** 161610 П/п чтения сектора в буфер ***

   Входные параметры: R1 - число слов для пересылки

RDSEC:  MTPS #340     ;Маскируем прерывания
        MOV  26(R3),R2;Получим адрес буфера
1$:     TSTB (R4)     ;Ожидаем данные
        BPL  1$
        MOV  (R5),R0  ;Читаем два байта,
        SWAB R0       ;   делаем из них нормальное слово,
        MOV  R0,(R2)+ ;   которое суем в буфер
        SOB  R1,1$    ;Читаем заказанное число слов
        MOV  42(R3),R1;Получаем длину остатка
        BEQ  3$       ;Остатка нет - сразу выходим
2$:     TSTB (R4)     ;Ждем данные
        BPL  2$
        TST  (R5)     ;Вхолостую читаем остаток
        SOB  R1,2$    ;   требуемой длины
        MTPS 52(R3)   ;Восстанавливаем PSW
3$:     RET




ъ                              - 16 -


      *** 161660 П/п поиска синхропоследовательности ***

FINDS:  TST  (R5)         ;Сбрасываем прочитанное значение
        MOVB #144,56(R3)  ;Будем искать 100. циклов
1$:     TSTB (R4)         ;Ждем готовности
        BPL  1$
        MOV  (R5),R0      ;Получим прочитанные данные
        BEQ  2$           ;Это 0 - на выход
        INC  R0           ;Это 177777?
        BEQ  2$           ;Да - на выход
        DECB 56(R3)       ;Циклы кончились?
        BNE  1$           ;Нет - повторяем поиск
2$:     RET

     *** 161714 П/п чтения двух слов (не используется) ***

01$:    TSTB (R4)     ;Ждем готовности
        BPL  01$
        MOV  (R5),R0  ;Получаем первое слово
02$:    TSTB (R4)     ;Ждем готовности
        BPL  02$
        MOV  (R5),R1  ;Получаем второе слово
        RET

              *** 161732 П/п запуска чтения ***

STREAD: BIS  #400,(R3);Установим признак "начало чтения"
        MOV  (R3),(R4);   и запишем в регистр
        BIC  #400,(R3);Снимем признак
        MOV  #10,R0
1$:     SOB  R0,1$    ;Небольшая задержка...
        MOV  (R3),(R4);   и снова запишем в регистр
        RET

   *** 161756 П/п поиска начала индекса (не используется) ***

01$:    TST  (R4)     ;Индекс есть?
        BMI  01$      ;Да - ждем исчезновения
        BIS  #400,(R3);Установим признак "начало чтения"
        MOV  (R3),(R4);   и запишем в регистр
02$:    TST  (R4)     ;Индекса еще нет?
        BPL  02$      ;Да - ждать появления
        MOV  62(R3),R0
03$:    SOB  R0,03$   ;Задержимся...
        BIC  #400,(R3);Сбросим признак "начало чтения"
        MOV  (R3),(R4);   и запишем в регистр
        RET

          *** 162012 П/п поиска адресного маркера ***

FINDH:  MOV  #17,R0
1$:     TST  (R5)     ;Вхолостую прочитаем
        SOB  R0,1$    ;   15. слов
        CLR  44(R3)   ;Начинаем ожидание индекса
        BICB #40,16(R3);Пока индекса нет
2$:     BITB #10,@20(R3);Сектор задан задержкой?
        BEQ  7$       ;Нет - обрабатывать
        CMPB 35(R3),#1;Да - нужен первый сектор?
        BNE  7$       ;Второй и далее задаются заголовками

                              - 17 -


        BIS  #400,(R3);Установим признак "начало чтения"
        MOV  (R3),(R4);   и перешлем в регистр
3$:     TST  (R4)     ;Индекс есть?
        BMI  3$       ;Да - ждем исчезновения
4$:     TST  (R4)     ;Индекс есть?
        BPL  4$       ;Нет - ждем появления
        DECB 55(R3)   ;Один оборот окончен
        BNE  5$       ;Не кончились - продолжаем
        SEC           ;Кончились - выходим с битом C
        BR   18$
5$:     MOV  62(R3),R0;Получим задержку после индекса
6$:     SOB  R0,6$
        BR   12$      ;Сектор, похоже, найден, идем дальше
7$:     CALL INDEX    ;Проверим наличие диска и обороты
        BCS  18$      ;Обороты кончились - выходим
        BEQ  7$       ;Какие данные? Нули пропустим
        COM  R0       ;177777?
        BEQ  7$       ;Да - тоже пропустим
8$:     CALL INDEX    ;Проверим наличие диска и обороты
        BCS  18$      ;Обороты кончились - выходим
        BEQ  9$       ;Какие данные? Нули - синхро
        COM  R0       ;177777?
        BNE  8$       ;Нет - пропустим

              *** Проверка адресного маркера ***

9$:     MOV  #3,R1
10$:    MOV  (R5),R0      ;Читаем данные
        BEQ  11$          ;Нули - продолжаем
        COM  R0           ;177777?
        BNE  7$           ;Нет - повторяем поиск
11$:    SOB  R1,10$       ;Да - повторяем 3 раза
12$:    CALL STREAD       ;Запускаем на чтение
        MOV  #74,R0       ;ОШИБКА! Здесь должно быть 2000
13$:    TSTB (R4)         ;Готовность есть?
        BMI  14$          ;Есть - считываем данные
        SOB  R0,13$       ;Нет - ждем
        BR   2$           ;Надоело ждать - повторяем поиск
14$:    TST  (R5)         ;Пропускаем A1A1
15$:    TSTB (R4)         ;Ждем готовности
        BPL  15$
        MOV  (R5),R0      ;Есть - берем данные
        CMP  #120776,R0   ;Адресный маркер (A1FE)?
        BEQ  17$          ;Да - нормальный выход
        CMP  #120773,R0   ;Нет - маркер данных (A1FB)?
        BEQ  16$          ;Да - пропускаем сектор
        CMP  #120770,R0   ;Нет - маркер скрытых данных (A1F8)?
        BNE  2$           ;Нет - повторяем поиск сначала
16$:    CALL FRESEC       ;Да - пропускаем сектор
        BR   2$           ;Повторяем поиск сначала
17$:    CLC
18$:    RET

  *** 162246 П/п проверки наличия диска и числа оборотов ***

INDEX:  TST  (R4)         ;Индекс есть?
        BPL  2$           ;Нет - идем проверять
        BITB #40,16(R3)   ;Индекс есть - он уже был?
        BNE  3$           ;Был - идем увеличивать время

                              - 18 -


        CLR  44(R3)       ;Только что появился - очистим время
        BISB #40,16(R3)   ;   и запомним факт появления
        DECB 55(R3)       ;Закончился последний оборот?
        BNE  1$           ;Нет - нормальный выход
        SEC               ;Да - выход с ошибкой
        RET
1$:     CLC
        MOV  (R5),R0      ;Забираем данные
        RET
2$:     BITB #40,16(R3)   ;Индекса нет - а он был?
        BEQ  3$           ;Нет и не было - идем считать время
        CLR  44(R3)       ;Только что исчез - очистим время
        BICB #40,16(R3)   ;   и запомним факт исчезновения
        BR   1$           ;Нормально выходим
3$:     INC  44(R3)       ;Еще один такт индекс не менялся
        CMP  44(R3),#60000;Ну сколько можно! Пора кончать?
        BLOS 1$           ;Не пора - нормальный выход
        MOV  #6,R0        ;Терпение кончилось -
        JMP  ERROR        ;   значит, диска нет - ошибка 6

             *** 162364 П/п выбора устройства ***

ENGINE: MOV  #177130,R4   ;Заполняем рабочие регистры
        MOV  R4,R5        ;   адресами РС и
        TST  (R5)+        ;   РД КНГМД
        BICB #4,16(R3)    ;Очистим признак работы двигателя
        BIT  #20,(R3)     ;Двигатель уже включен?
        BEQ  1$           ;Нет - включим
        BISB #4,16(R3)    ;Да - установим признак
1$:     BIS  #20,(R3)     ;Включим двигатель
        MOV  (R3),(R4)    ;   и запишем в регистр
        BIC  #57,(R3)     ;Сбросим все другие режимы
        TSTB 32(R3)       ;Сторона верхняя?
        BEQ  2$           ;Да - идем дальше
        BIS  #40,(R3)     ;Нет - включим нижнюю
2$:     BICB #177774,34(R3);Сбросим лишние биты
        MOVB 34(R3),R1    ;Получим номер привода
        MOV  PC,R0        ;Получим базовый адрес
        ADD  #56,R0       ;   таблицы масок для приводов
        ADD  R1,R0        ;Получим адрес нужной маски
        BISB (R0),(R3)    ;Установим бит нужного привода
        ADD  R3,R1        ;Получим базовый адрес
        ADD  #4,R1        ;   таблицы TRKTAB
        MOV  R1,2(R3)     ;Настроим указатель CURTRK
        CALL SETPTR       ;Настроим указатель FLGPTR
        BITB #4,16(R3)    ;Мотор включен только что?
        BNE  5$           ;Нет - выходим
        CLR  R1           ;Да - подождем раскручивания
3$:     SOB  R1,3$
4$:     SOB  R1,4$
5$:     MOV  (R3),(R4)    ;Записываем установки в регистр
        MOV  10(R3),R1    ;Подождем опускания головки
6$:     SOB  R1,6$
        RET






                              - 19 -


         *** Таблица масок для включения приводов ***

        .B:1  ;A:
        .B:2  ;B:
        .B:4  ;C:
        .B:10 ;D:

        *** 162540 П/п настройки указателя FLGPTR ***

SETPTR: CLR  20(R3)       ;Очистим указатель FLGPTR
        BICB #177774,34(R3);Отбросим лишние биты
        MOVB 34(R3),20(R3);Перешлем номер привода в FLGPTR
        ADD  R3,20(R3)    ;Прибавляя базовый адрес FLGTAB,
        ADD  #22,20(R3)   ;   получаем искомый адрес
        RET

            *** 162574 П/п позиционирования ***

GOTRK:  TSTB 33(R3)   ;Нужна дорожка 00?
        BEQ  GOTO00   ;Да - позиционируем прямо на нее
        TSTB @2(R3)   ;Положение головки известно?
        BPL  1$       ;Да - будем искать требуемую
        CALL GOTO00   ;Нет - придется сориентироваться
1$:     CMPB @2(R3),33(R3);Нужная дорожка совпадает с текущей?
        BEQ  3$       ;Да - так что же мы тут делаем?
        BHI  2$       ;Нет - искомая ближе к центру?
        CALL GOUP     ;Да - шагнем к центру
        BR   1$       ;Проверим, дошли ли
2$:     CALL GODOWN   ;Нет - шагнем к периферии
        BR   1$       ;Проверим, дошли ли
3$:     MOV  #23420,R0;Подождем успокоения головки
4$:     SOB  R0,4$    ;Теперь можно и выйти
        RET

                  *** Шаг к центру ***

GOUP:   INCB @2(R3)   ;Номер дорожки станет на 1 больше
        BMI  1$       ;Таких дорожек нет - выходим с ошибкой
        BIS  #100,(R3);Все в порядке - шагать будем вперед
        BR   STEP     ;Пойдем шагать
1$:     MOV  #4,R0    ;Выход с ошибкой 4
        JMP  ERROR

                *** Шаг к периферии ***

GODOWN: DECB @2(R3)   ;Номер дорожки станет на 1 меньше
        BIT  #1,(R4)  ;Дошли до дорожки 00?
        BEQ  1$       ;Нет - можно шагать
        CLRB @2(R3)   ;Дошли: теперь текущая - 00
        RET           ;   и можно выйти
1$:     BIC  #100,(R3);Шагать будем назад
STEP:   MOV  #310,R0  ;Подготовим задержку
        MOV  (R3),(R4);Перешлем направление шага в регистр
3$:     SOB  R0,3$    ;Подождем, пока контроллер "переварит"
        BIS  #200,(R3);Установим признак шага
        MOV  (R3),(R4);   и запишем в регистр
        MOV  12(R3),R0;Получим задержку перехода дорожки
4$:     SOB  R0,4$    ;   и задержимся
                               - 20 -


        BITB #1,@20(R3);Двойной шаг?
        BEQ  6$       ;Нет - можно выходить
        BITB #100,16(R3);Мы возвращаемся на 00?
        BNE  6$       ;Да - возвращаться надо одинарным шагом
        MOV  (R3),(R4);Нет - придется шагнуть еще
        MOV  12(R3),R0;Получим задержку перехода дорожки
5$:     SOB  R0,5$    ;   и задержимся
6$:     BIC  #200,(R3);Очистим признак шага
        RET

          *** 163004 П/п возврата на дорожку 00 ***

GOTO00: MOVB #200,@2(R3)  ;Установим счетчик дорожек
        BISB #100,16(R3)  ;Возвращаться надо одинарным шагом
1$:     CALL GOUP         ;Шагнем к периферии
        BIT  #1,(R4)      ;Дошли до 00?
        BNE  2$           ;Да - выходим
        TSTB @2(R3)       ;На какой дорожке должны находиться?
        BNE  1$           ;Не на нулевой - еще шагнем
        MOV  #3,R0        ;На нулевой, а ее нет - ошибка 3
        BICB #100,16(R3)  ;Сбросим режим одинарного шага
        JMP  ERROR        ;Выходим с ошибкой
2$:     CLRB @2(R3)       ;Дошли - текущая теперь нулевая
        BICB #100,16(R3)  ;Сбросим режим одинарного шага
        RET

              *** 163072 П/п пропуска сектора ***

FRESEC: MOV  64(R3),R0;Получим длину сектора
FICT:   TST  (R4)     ;Индекс есть?
        BMI  4$       ;Да - ждем начала оборота
1$:     TST  (R4)     ;Индекс все еще есть?
        BMI  3$       ;Да - оборот завершен
2$:     TSTB (R4)     ;Данные готовы?
        BPL  1$       ;Нет - снова
        TST  (R5)     ;Прочитаем данные вхолостую
        SOB  R0,1$    ;   требуемое число раз
        BR   6$       ;   и выйдем
3$:     DECB 55(R3)   ;Все обороты вышли?
        BNE  5$       ;Нет - попытаемся снова
        MOV  #5,R0    ;Да - выходим с ошибкой 5
        JMP  ERROR
4$:     TST  (R4)     ;Индекс исчез?
        BPL  2$       ;Да - оборот начался
5$:     TSTB (R4)     ;Данные готовы?
        BPL  4$       ;Нет - проверим индекс
        TST  (R5)     ;Прочитаем данные вхолостую
        SOB  R0,4$    ;   требуемое число раз
6$:     RET           ;   и вернемся к основной работе


              *** 163154 П/п записи сектора ***

   Входные параметры:
      R1 - число слов для записи

WRSEC:  MOV  26(R3),R2;Получим начальный адрес массива
        MOV  #13,R0   ;В маркере будет 11. 4E4E
        MTPS #340     ;При записи нам не мешать!

                              - 21 -


        CALL WRMAR    ;Запишем маркер данных
1$:     TSTB (R4)     ;Готовность есть?
        BPL  1$       ;Нет - ждем
        MOV  (R2)+,(R5);Запишем первое слово данных
        MOV  (R3),(R4);Снимем признак записи маркера
        BR   3$       ;   и пойдем записывать данные
2$:     TSTB (R4)     ;Готовность есть?
        BPL  2$       ;Нет - дождемся
        MOV  (R2)+,(R5);Запишем слово данных
3$:     SOB  R1,2$    ;   и так до конца
        MOV  42(R3),R1;Получим длину пустого остатка сектора
        BEQ  5$       ;Остатка нет - выходим сразу
4$:     TSTB (R4)     ;Готовность есть?
        BPL  4$       ;Дожидаемся
        MOV  #0,(R5)  ;Записываем нули
        SOB  R1,4$    ;   в нужном количестве
5$:     BIT  #40000,(R4);Ждем записи CRC
        BEQ  5$
        MOV  #47116,(R5);Записываем 4E4E
6$:     TSTB (R4)     ;Готовность есть?
        BPL  6$       ;Нет - ждем
        TST  (R5)     ;Прекращаем запись
        MTPS 52(R3)   ;Восстанавливаем PSW
        JMP  NEXT     ;Продолжаем запись массива

          *** 163266 П/п записи маркера данных ***

   Входные данные:
      R0 - число записываемых слов 4Е4Е

WRMAR:  MOV  #47116,(R5)  ;Запишем 4E4E
        BR   2$           ;Идем на повтор записи
1$:     TSTB (R4)         ;Готовность есть?
        BPL  1$           ;Нет - дождемся
        MOV  #47116,(R5)  ;Запишем 4E4E
2$:     SOB  R0,1$        ;Повторим заданное число раз
        MOV  #6,R0        ;Запишем 12. нулевых байтов
3$:     TSTB (R4)         ;Готовность есть?
        BPL  3$           ;Нет - ожидаем
        MOV  #0,(R5)      ;Записываем нули
        SOB  R0,3$        ;   в нужном количестве
        BIS  #1000,(R3)   ;Подготовим признак записи маркера
4$:     TSTB (R4)         ;Контроллер готов?
        BPL  4$           ;Нет - ждем
        MOV  #120641,(R5) ;Записываем маркер A1A1
        MOV  (R3),(R4)    ;Передаем признак в контроолер
        BIC  #1000,(R3)   ;Заранее снимем признак
5$:     TSTB (R4)         ;Готовность есть?
        BPL  5$           ;Нет - ожидаем
        MOV  40(R3),(R5)  ;Записываем маркер из буфера
        RET

         *** 163360 П/п установки прекоррекции ***

CORR:   BIC  #2000,(R3)   ;Снимем прекоррекцию
        CMPB 14(R3),@2(R3);Надо включать на текущей дорожке?
        BHI  1$           ;Нет - пропустим
        BIS  #2000,(R3)   ;Пора - включим


                              - 22 -


1$:     MOV  (R3),(R4)    ;Перешлем управляющее слово
        MOV  #310,R0
2$:     SOB  R0,2$        ;Подождем, пока контроллер воспримет
        RET

             *** 163412 П/п форматирования ***

FORMAT: MOV  SP,50(R3)    ;Сохраним SP,
        MFPS 52(R3)       ;   PSW,
        MOV  #4,R0
        MOV  (R0),46(R3)  ;  @#4 в соответствующих буферах
        MOV  PC,(R0)      ;Переназначаем вектор @#4 на себя,
        ADD  #176056,(R0) ;   теперь он равен 161512
        CALL ENGINE       ;Запустим двигатель
        CALL GOTRK        ;Спозиционируем на нужную дорожку
        CALL CORR         ;Установим прекоррекцию
        BIT  #4,(R4)      ;Защита записи включена?
        BEQ  2$           ;Нет - начнем форматировать
        MOV  #1,R0        ;Да - ошибка 1
1$:     JMP  ERROR        ;Выходим с ошибкой
2$:     SWAB 32(R3)       ;Обмениваем номера стороны и дорожки
        MOVB 17(R3),36(R3);Делаем слово-заполнитель
        MOVB 17(R3),37(R3);   из байта-заполнителя
        MOVB 60(R3),R1    ;Получим длину сектора
        MOV  #1001,R2     ;Запомним номер сектора и код длины
        MOV  #1750,R0     ;Время ожидания индекса
3$:     TST  (R4)         ;Индекс есть?
        BPL  5$           ;Исчез - начнем записывать
        SOB  R0,3$        ;Есть - ждем исчезновения
4$:     TST  (R5)         ;Так и не исчез - прекратим запись
        MOV  #6,R0        ;Диск не вращается - ошибка 6
        SWAB 32(R3)       ;Вернем все на место
        BR   1$           ;Выходим с ошибкой


             *** Запись на дорожку кода 4E4E ***

5$:     MOV  #6200,R0 ;Установим максимальную длину
        MTPS #340     ;При записи нам не мешать!!!
        MOV  #47116,(R5);Записываем 4E4E
6$:     TST  (R4)     ;Индекс появился?
        BMI  8$       ;Да - начнем запись
7$:     TSTB (R4)     ;Готовность есть?
        BPL  7$       ;Нет - ждем
        MOV  #47116,(R5);Записываем 4E4E
        SOB  R0,6$    ;И так до конца дорожки
        BR   4$       ;Однако, дорожка длинная, ошибка!
8$:     MOV  #20,R0   ;В маркере будет 16. 4E4E (GAP1)
        MOV  #177241,40(R3);Адресный маркер (FEA1) - в буфер
9$:     CALL WRMAR    ;Записываем адресный маркер
10$:    TSTB (R4)     ;Готовность есть?
        BPL  10$      ;Нет - ожидаем
        MOV  32(R3),(R5);Записываем номер стороны и дорожки
        MOV  (R3),(R4);Перешлем управляющее слово
11$:    TSTB (R4)     ;Готовность есть?
        BPL  11$      ;Нет - дождемся
        MOV  R2,(R5)  ;Записываем номер сектора и код длины
        MOV  #13,R0   ;В маркере будет 11. 4E4E (GAP2)
        MOV  #175641,40(R3);Маркер данных (FBA1) - в буфер

                              - 23 -


12$:    BIT  #40000,(R4) ;Ждем записи CRC
        BEQ  12$
        CALL WRMAR    ;Записываем маркер данных
        MOV  64(R3),R0;Получаем длину сектора
        DEC  R0       ;Одно слово запишем сейчас
13$:    TSTB (R4)     ;Готовность есть?
        BPL  13$      ;Нет - ожидаем
        MOV  36(R3),(R5);Записываем заполнитель
        MOV  (R3),(R4);Перешлем управляющее слово
14$:    TSTB (R4)     ;Готовность есть?
        BPL  14$      ;Нет - дождемся
        MOV  36(R3),(R5);Записываем заполнитель
        SOB  R0,14$   ;И так до конца сектора
        INC  R2       ;Увеличим номер сектора
        MOV  #22,R0   ;В маркере будет 18. 4E4E (GAP3)

;Примечание. Если увеличить GAP3 до 24-27 слов, то запись будет
;производиться  так  же  быстро, как и чтение (обычно заголовок
;очередного сектора проскакивает, и дорожка  записывается не за
;один, а за 10. оборотов). Однако при превышении этой величиной
;определенного значения конец последнего  сектора дорожки может
;наложиться на ее же начало.

        BIT  #4,@20(R3);Сектора длинные?
        BEQ  15$      ;Нет - все нормально
        MOV  #72,R0   ;Да - будет 116. 4E4E (можно увеличить
                      ;                       до 75)
15$:    MOV  #177241,40(R3);Адресный маркер (FEA1) - в буфер
16$:    BIT  #40000,(R4);Ждем записи CRC
        BEQ  16$
        SOB  R1,9$    ;И так все сектора до конца дорожки

               *** Окончание записи дорожки ***

17$:    TSTB (R4)     ;Готовность есть?
        BPL  17$      ;Нет - ждем
        MOV  #47116,(R5);Запишем 4E4E
        TST  (R4)     ;Индекс есть?
        BPL  17$      ;Нет - продолжим запись до появления
18$:    TSTB (R4)     ;Готовность есть?
        BPL  18$      ;Нет - дождемся
        MOV  #47116,(R5);Запишем 4E4E
        TST  (R5)     ;Прекратим запись
        MTPS 52(R3)   ;Восстановим PSW
        SWAB 32(R3)   ;Вернем все на место
        JMP  EXIT     ;Выходим


              *** Конец текста драйвера НГМД ***

EXT:        *** Драйвер расширенной арифметики ***











--------------------
Живы будем - Не помрем !
Пользователь в онлайне!Карточка пользователяОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
SuperMax
сообщение 20.6.2022, 17:53
Сообщение #2


Администратор
*****

Группа: Root Admin
Сообщений: 6 282
Регистрация: 7.1.2006
Из: Красноярск
Пользователь №: 1



Тоже но файлом
Прикрепленный файл  326.txt ( 106.05 килобайт ) Кол-во скачиваний: 280



--------------------
Живы будем - Не помрем !
Пользователь в онлайне!Карточка пользователяОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
SuperMax
сообщение 20.6.2022, 21:39
Сообщение #3


Администратор
*****

Группа: Root Admin
Сообщений: 6 282
Регистрация: 7.1.2006
Из: Красноярск
Пользователь №: 1



Еще один вариант

Код
;
; Input MD5   : 5015228EEEB238E65DA8EDCD1B6DFAC7

; File Name   : DISK_327v12.ROM
; Format      : Binary file
; Base Address: 0000h Range: E000h - F000h Loaded length: 1000h

; Processor:        K1801VM1
; Target assembler: Turbo8DK Assembler
.LA 160000
ERRFDD=52   ;адрес, куда сохраняется номер ошибки
;ячейки рабочей области драйвера дисковода
CSRW=0       ;копия по записи регистра состояния КНГМД
CURTRK=2   ;адрес текущей дорожки (адрес одного из следующих байтов из таблицы)
TRKTAB=4   ;таблица текущих дорожек
TDOWN=10   ;задержка опускания головки
TSTEP=12   ;задержка перехода с дорожки на дорожку
TRKCOR=14   ;дорожка начала предкомпенсации
BRETRY=15   ;число попыток повтора при ошибке
FLAGS=16   ;рабочая ячейка драйвера
FILLB=17   ;код заполнения при форматировании
FLGPTR=20   ;указатель на байт признаков (адрес одного из следующих байтов из таблицы)
FLGTAB=22   ;таблица признаков
ADDR=26       ;адрес начала массива данных в ОЗУ (обязательно четный)
WCNT=30       ;количество слов для пересылки
SIDE=32       ;номер стороны диска
TRK=33       ;номер дорожки
UNIT=34       ;номер привода
SECTOR=35   ;номер сектора
WRTVAR=36   ;значение, записываемое при форматировании
MARKER=40   ;буфер маркера при записи
FREE=42       ;длина пустого остатка сектора
INTIME=44   ;счетчик длительности индекса
BUF4=46       ;буфер для сохранения вектора 4
BUFSP=50   ;буфер для сохранения SP
BUFPSW=52   ;буфер для сохранения PSW
CRETRY=54   ;счетчик повторов при ошибке
TURNS=55   ;число оборотов диска при поиске сектора
SECRET=56   ;число повторных попыток поиска сектора
ERRNUM=57   ;буфер для номера ошибки
MAXSEC=60   ;число секторов на дорожке
HOLTIN=62   ;время задержки после индекса
SECLEN=64   ;длина сектора в словах


START:    BR        BOOT0   ; BOOT0:  Автоматическая загрузка
        BR        BOOT1   ; BOOT1:  Загрузка с выбранного привода
        BR        RWBLK   ; RWBLK:  Чтение-запись по номеру блока
        BR        RWSEC   ; RWSEC:  Чтение-запись по номеру сектора
        BR        INIT   ; INIT:   Инициализация рабочей области
        JMP        FORMAT   ; FORMAT: Форматирование дорожки
        JMP        EXT       ; EXT:    Расширенная арифметика
; BOOT0: П/п автоматической загрузки
BOOT0:    CLR        R0       ; Начнем с нулевого привода
        CALL    BOOT   ; Пробуем загрузиться, попутно выполняя инициализационные действия, с приводов 0,1,2
        MOV        #3, R0   ; Там не получилось, пробуем с привода 3
        CALL    BOOTC   ; Загружаем стандартным загрузчиком
        BR        STOP   ; Загрузчика нигде нет, выходим
; BOOT1: Загрузка с выбранного привода
BOOT1:    NOP       ; здесь была установка стека,
        NOP       ; но ее занопили
        CALL    BOOTC   ; Загружаем стандартным загрузчиком
; STOP: Остановка двигателя НГМД и выход из п/п
STOP:    CLR        (R3)
        CLR        @#177130
        CLR        @#177660
        RETURN
; BOOTC: П/п загрузки и запуска загрузчика
BOOTC:    JMP        BOOTC$   ; пойдем, начальные действия, а потом продолжим с BOOTN
        .WORD    0       ; это сделано, чтобы  создать точку входа в отладчик

1$:        JMP        DEBUGR   ;идем отлаживать
        BR        1$       ;1600100 - точка входа в отладчик
; ───────────────────────────────────────────────────────────────────────────
; продолжение загрузчика с дисковода
BOOTN:    CLR        R0               ; Читаем нулевой блок
        MOV        #400, R1       ;    длиной 400 слов (1000 байт)
        MOV        #1000, R2       ;    с адреса 1000
        CALL    RWBLK           ; Прочитаем...
        BCS        1$               ;    не получилось - выход
        CMP        @#1000, #240   ; Загрузчик начинается с NOP?
        BNE        1$               ; Нет - выход
        CMP        @#1002, #5       ; Вторая команда - RESET?
        BEQ        1$               ; Да - диск не системный, выход
        MOVB    UNIT(R3), R0   ; Вспомним, откуда это мы загрузились
        JMP        RUNLDR           ; пойдем запускать то, что загрузили

1$:        RETURN                   ; Вот и все
; RWSEC: Чтение-запись по номеру сектора
RWSEC:    BR        SUBRW

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; INIT: П/п инициализации рабочей области
INIT:    CLR        (R3)               ; Очистим копию РС КНГМД
        MOV        #177777, TRKTAB(R3)   ; Заполним таблицу текущих дорожек
        MOV        #177777, TRKTAB+2(R3)
        MOV        #10000., TDOWN(R3)   ; Время опускания головки
        MOV        #10000., TSTEP(R3)   ; Время перехода дорожки
        MOVB    #32., TRKCOR(R3)   ; Дорожка начала предкомпенсации
        MOVB    #20., BRETRY(R3)   ; Число повторов при ошибке
        CLRB    FLAGS(R3)           ; Очистим флаги
        CLR        FLGTAB(R3)           ;    и таблицу признаков
        CLR        FLGTAB+2(R3)
        MOV        #10., MAXSEC(R3)   ; Занесем число секторов на дорожке = 10
        RETURN
; End of function INIT


; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; RWBLK: П/п чтения-записи по номеру блока
;Входные параметры:
;R0 - номер блока на диске
;R1 - длина пересылаемого массива в словах (>0 - чтение <0 - запись)
;R2 - начальный адрес массива в словах
;R3 - базовый адрес рабочей области драйвера
;UNIT - номер привода (0 - А)
RWBLK:    MOV        #10, R4
        MOVB    MAXSEC(R3), R5       ; число секторов на дорожке
        SWAB    R5                   ; делим ст. байт R0 на ст. байт R5
1$:        CMP        R5, R0
        BHI        2$
        SUB        R5, R0
        SEC
2$:        ROL        R0                   ; Частное накапливается в мл. байте R0
        SOB        R4, 1$
        MOVB    R0, R4               ; В мл. байте номер дорожки, сохраним его
        CLRB    R0
        SWAB    R0                   ; Получили остаток от деления
        INC        R0                   ; Номер сектора на единичку больше
        CLRB    SIDE(R3)           ; Пока мы на нижней стороне
        CMP        R0, MAXSEC(R3)       ; Этот сектор за пределами дорожки?
        BLE        3$                   ; Нет - полный порядок
        INCB    SIDE(R3)           ; Да - значит он на другой стороне
        SUB        MAXSEC(R3), R0       ;    и номер у него другой
3$:        CALL    SETPTR               ; Установим указатель на байт признаков
        BITB    #2, @FLGPTR(R3)       ; Диск односторонний?
        BEQ        4$                   ; Нет - оставим все как есть
        ASRB    SIDE(R3)           ; Да - сторона всегда 0,
        ROLB    R4                   ;    а дорожка уже другая
4$:        MOVB    R4, TRK(R3)           ; Запишем результаты: дорожка,
        MOVB    R0, SECTOR(R3)       ;    сектор,
        MOV        R1, WCNT(R3)       ;    число слов,
        MOV        R2, ADDR(R3)       ;    адрес буфера
; SUBRW: П/п чтения-записи по номеру сектора
;Входные параметры:
;R3 - базовый адрес рабочей области драйвера
;ADDR - начальный адрес массива в словах
;WCNT - длина пересылаемого массива в словах (>0 - чтение <0 - запись)
;SIDE - номер стороны (0-нижняя, 1- верхняя)
;TRK - номер должки
;UNIT - номер привода (0 - А)
;SECTOR - номер сектора (1-10.)
SUBRW:    MOV        SP, BUFSP(R3)       ; Сохраняем SP,
        MFPS    BUFPSW(R3)           ;    PSW,
        MOV        #4, R0
        MOV        (R0), BUF4(R3)       ;    @#4 в соответствующих буферах
        MOV        PC, (R0)           ; Переназначаем вектор @#4 на себя,
        ADD        #VECT4-., (R0)       ;    теперь он равен VECT4
        TSTB    SECTOR(R3)           ; Какой сектор нужен?
        BEQ        ERR12               ; Нулевых у нас нет, ошибка 12
        CMPB    SECTOR(R3), MAXSEC(R3)   ; Сектор больше максимального?
        BGT        ERR12               ; Таких тоже нет, ошибка 12
        CLRB    @#ERRFDD           ; Пока ошибок нет
        BICB    #30, FLAGS(R3)       ; Пока не записываем
        TST        WCNT(R3)           ; Сколько слов будем пересылать?
        BEQ        QUIT               ; 0 - ничего делать не надо, выход
        BPL        READ               ; больше 0 - будем читать
; П/п записи массива
        NEG        WCNT(R3)           ; Нормализуем длину
        BISB    #20, FLAGS(R3)       ; Установим признак записи
        MOV        #175641, MARKER(R3)   ; Запомним маркер данных
        BITB    #1, FLAGS(R3)       ; Записываем скрытно?
        BEQ        1$                   ; Нет - идем дальше
        MOV        #174241, MARKER(R3)   ; Да - запомним специальный маркер
1$:        CALL    ENGINE               ; ENGINE: Включим двигатель, запомним привод
        BIT        #4, (R4)           ; Защита записи есть?
        BEQ        MAIN               ; Нет - продолжить работу
        MOV        #1, R0               ; Есть - ошибка 1
        BR        ERR
; ───────────────────────────────────────────────────────────────────────────
; READ: П/п чтения массива
READ:    CALL    ENGINE               ; ENGINE: Включим двигатель, запомним привод
        MOV        #400, SECLEN(R3)   ; Сектора стандартной длины
        BITB    #4, @FLGPTR(R3)       ; А они ли нам нужны?
        BEQ        MAIN               ; Да - продолжить работу
        MOV        #1000, SECLEN(R3)   ; Нет - сектора удвоенной длины
; MAIN: Основная часть п/п чтения/записи массива
MAIN:    CALL    GOTRK               ; GOTRK: Позиционируем на нужную дорожку
        CALL    CORR               ; CORR: Включим схему предкоррекции
        MOVB    BRETRY(R3), CRETRY(R3)   ; Число попыток - в буфер
; Получение заголовка сектора
        MOVB    #10, ERRNUM(R3)       ; Предполагаем ошибку 10
        MOVB    #20., TURNS(R3)       ; На операцию отводим 20. оборотов

1$:        CALL    FINDH               ; FINDH: Найдем маркер заголовка
        BCC        2$                   ; Нашли - идем дальше
3$:        MOVB    ERRNUM(R3), R0       ; Не нашли - выходим с ошибкой
        BR        ERR
; ───────────────────────────────────────────────────────────────────────────
2$:        TSTB    (R4)               ; Информация получена?
        BPL        2$                   ; Нет - подождем
        MOV        (R5), R0           ; Теперь прочитаем ее
4$:        TSTB    (R4)               ; Хотим еще информации!
        BPL        4$                   ; Дождемся ее появления
        MOV        (R5), R1           ;    и заберем ее
        CALL    TSTCRC               ; TSTCRC: Проверим CRC
        BNE        5$                   ; Ошибки нет - идем дальше
        MOVB    #2, ERRNUM(R3)       ; Ошибка 2!
        DECB    CRETRY(R3)           ; Остались еще попытки?
        BNE        1$                   ; Да - повторим чтение
        BR        3$                   ; Видно, не судьба! Выходим с ошибкой
; ───────────────────────────────────────────────────────────────────────────
5$:        BIC        #177774, R1           ; Выделяем код длины сектора
        BITB    #4, @FLGPTR(R3)       ; Какие сектора нам были нужны?
        BNE        LONG               ; LONG: Длинные - посмотрим...
        CMPB    R1, #2               ; Короткие. А на диске какие?
        BEQ        WORK               ; WORK: Тоже короткие. Порядок, идем дальше
        DECB    CRETRY(R3)           ; Как там дела с попытками?
        BNE        1$                   ; Есть еще - повторим все сначала
; ERR12: Выход с ошибкой
ERR12:    MOV        #12, R0               ; Выходим с ошибкой 12
ERR:    JMP        ERROR               ; ERROR: Идем на обработку и выход
; ───────────────────────────────────────────────────────────────────────────
QUIT:    JMP        EXIT               ; EXIT: Идем на нормальный выход
; ───────────────────────────────────────────────────────────────────────────
LONG:    CMPB    R1, #2               ; Нужны длинные сектора, а какие здесь?
       ;    ОШИБКА: На самом деле код длинных секторов (1024 байта на сектор) - 3, а не 2
       ;вот сколько прошивок ни посмотрел, везде так. никто это не исправляет, значит это не ошибка,
       ;а фича такая - принципиальная неподдерживаемость длинных секторов
        BNE        ERR12               ; ERR12: Длинные - выходим с ошибкой 12
; WORK: Собственно п/п чтения
WORK:    MOVB    BRETRY(R3), CRETRY(R3)   ; Восстановим счетчик по BRETRY
        MOVB    #6, SECRET(R3)       ; На поиск сектора - 6 попыток
        CLR        FREE(R3)           ; Остаток сектора отсутствует
        CMP        WCNT(R3), SECLEN(R3)   ; Читать нужно больше одного сектора?
        BHI        1$                   ; Да - идем читать
        MOV        SECLEN(R3), FREE(R3)
        SUB        WCNT(R3), FREE(R3)   ; Вычислим длину остатка
1$:        MOVB    #5, ERRNUM(R3)       ; Прогнозируем ошибку 5
2$:        MOVB    #20., TURNS(R3)       ; На операцию отводим 20. оборотов
3$:        CALL    FINDH               ; FINDH: Ищем маркер заголовка
        BCC        4$                   ; Нашли - идем дальше
        MOVB    ERRNUM(R3), R0       ; Кончились обороты - выходим
        BR        ERR                   ;    с ошибкой
; ───────────────────────────────────────────────────────────────────────────
4$:        TSTB    (R4)               ; Готовность данных есть?
        BPL        4$                   ; Нет - подождем
        CMP        SIDE(R3), (R5)       ; Нужная дорожка и сторона?
        BEQ        5$                   ; Да - идем дальше
        DECB    SECRET(R3)           ; Минус одна попытка
        BEQ        6$                   ; Кончились - выход с ошибкой
        CALL    GOTO00               ; GOTO00: Позиционируем на дорожку 00,
        CALL    GOTRK               ; GOTRK:  вернемся на нужную
        BR        3$                   ;    и попытаемся еще раз
; ───────────────────────────────────────────────────────────────────────────
6$:        MOV        #4, R0               ; Выходим с ошибкой 4
        BR        ERR                   ; ERR
; ───────────────────────────────────────────────────────────────────────────
5$:        TSTB    (R4)               ; Ждем готовности данных
        BPL        5$                   ; Не готовы - повторять...
        MOV        (R5), R1           ; Получим номер сектора
        SWAB    R1                   ;    поместим его в младший байт
        CMPB    SECTOR(R3), R1       ; Этот сектор ищем?
        BEQ        7$                   ; Да - будем его читать
        MOV        SECLEN(R3), R0       ; Нет - возьмем длину данных,
        ADD        #27, R0               ;    прибавим длину заголовка
        CALL    FICT               ; FICT:   и пропустим их
        BR        3$                   ; Повторим процедуру еще раз
; ───────────────────────────────────────────────────────────────────────────
7$:        CALL    TSTCRC               ; TSTCRC: Проверим CRC
        BNE        8$                   ; Совпала - идем дальше
        MOVB    #2, ERRNUM(R3)       ; Если что, это будет ошибка 2
        DECB    CRETRY(R3)           ; Одной попыткой меньше
        BNE        2$                   ; Еще остались - поищем снова
        MOVB    ERRNUM(R3), R0       ; Нет - выходим с ошибкой
        BR        ERROR
; ───────────────────────────────────────────────────────────────────────────
8$:        MOV        SECLEN(R3), R1       ; Получим длину сектора
        SUB        FREE(R3), R1       ; Вычислим длину используемой части
; Чтение сектора
        BITB    #20, FLAGS(R3)       ; Будем записывать?
        BEQ        9$                   ; Нет - значит, читать
        JMP        WRSEC               ; Да - идем на запись сектора
; ───────────────────────────────────────────────────────────────────────────
9$:        CALL    FINDS               ; FINDS: Ищем зону синхронизации
        TSTB    SECRET(R3)           ; Нашли?
        BEQ        10$                   ; Нет - пробуем снова
        CALL    STREAD               ; STREAD: Начинаем чтение!
        MOV        #600., R0
12$:    TSTB    (R4)               ; Данные готовы?
        BMI        11$                   ; Да - посмотрим их
        SOB        R0, 12$               ; Больше ждать нельзя?

10$:    MOVB    #11, ERRNUM(R3)       ; Да - прогнозируем ошибку 11
        DECB    CRETRY(R3)           ; Одной попыткой меньше
        BNE        2$                   ; Попытки есть - повторим операцию
        MOVB    ERRNUM(R3), R0       ; Кончились - выйдем с ошибкой
        BR        ERROR
; ───────────────────────────────────────────────────────────────────────────
11$:    TST        (R5)               ; Пропустим маркер A1A1
13$:    TSTB    (R4)               ; Готовность данных есть?
        BPL        13$                   ; Нет - ждем
        MOV        (R5), R0           ; Прочитаем данные
        CMP        #120773, R0           ; Обычный сектор?
        BEQ        14$                   ; Да - идем дальше
        CMP        #120770, R0           ; Скрытый сектор?
        BNE        10$                   ; Что-то иное - ошибка
        BITB    #1, FLAGS(R3)       ; Можно читать скрытые данные?
        BNE        14$                   ; Да - будем читать
        MOV        #13, R0               ; Нельзя - выходим с ошибкой 13
        BR        ERROR
; ───────────────────────────────────────────────────────────────────────────
14$:    CALL    RDSEC               ; RDSEC: Прочитаем сектор
        CALL    TSTCRC               ; TSTCRC: Проверим CRC
        BNE        NEXT               ; Совпала - посмотрим следующий сектор
        MOVB    #1, ERRNUM(R3)       ; Не совпала - ошибка 1
        DECB    CRETRY(R3)           ; Попытки кончились?
        BNE        2$                   ; Нет - попробуем еще раз
        MOVB    ERRNUM(R3), R0       ; Кончились - выходим с ошибкой
        BR        ERROR
; ───────────────────────────────────────────────────────────────────────────
; Мультисекторные операции
NEXT:    SUB        SECLEN(R3), WCNT(R3)   ; Сектор обработали, вычтем из длины
        BLE        EXIT               ; Массив кончился - выход
        INCB    SECTOR(R3)           ; Нет - следующий сектор
        CMPB    SECTOR(R3), MAXSEC(R3)   ; Конец дорожки?
        BLOS    1$                   ; Нет - продолжим обработку
        BIT        #40, (R3)           ; Верхняя сторона?
        BNE        2$                   ; Да - следующая дорожка
        BITB    #2, @FLGPTR(R3)       ; Диск односторонний?
        BNE        2$                   ; Да - продолжим обработку
        MOVB    #1, SIDE(R3)       ; Нет - установим верхнюю сторону
        BIS        #40, (R3)
        BR        3$                   ; Перейдем к обработке
; ───────────────────────────────────────────────────────────────────────────
2$:        INCB    TRK(R3)               ; Следующая дорожка
        CALL    GOTRK               ; Позиционируем на нее
        CLRB    SIDE(R3)           ; Установим нижнюю сторону
        BIC        #40, (R3)
3$:        MOVB    #1, SECTOR(R3)       ; Теперь сектор будет первым
        CALL    CORR               ; Переключить предкоррекцию

1$:        ADD        SECLEN(R3), ADDR(R3)   ; Получим новый начальный адрес
        ADD        SECLEN(R3), ADDR(R3)
        JMP        WORK               ; WORK: Идем на чтение очередного сектора
; ───────────────────────────────────────────────────────────────────────────
; Обработка прерывания по вектору 4
VECT4:    TST        (R5)               ; Сбросить данные
        MOV        #7, R0               ; Заносим код ошибки 7
; ERROR: Выход с ошибкой
ERROR:    MOVB    R0, @#ERRFDD       ; Код ошибки - на место!
        MOVB    #1, SECRET(R3)       ; Установим бит C в буфере
        BR        EXIT1               ; EXIT1: Идем на выход
; ───────────────────────────────────────────────────────────────────────────
; EXIT: Выход без ошибки
EXIT:    CLRB    SECRET(R3)           ; Сбросим бит C в буфере
EXIT1:    MOV        BUF4(R3), @#4       ; Восстановить вектор 4
        MTPS    BUFPSW(R3)           ; Восстановить PSW
        CCC                           ; Сбросить все признаки
        RORB    SECRET(R3)           ; Бит C - из буфера в PSW
        MOV        BUFSP(R3), SP       ; Восстановить SP
        RETURN                       ; Возврат


; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; TSTCRC: П/п проверки CRC
TSTCRC:    TSTB    (R4)               ; Ждем готовности данных
        BPL        TSTCRC
        MOV        #15., R2           ; CRC появится не позже 15. циклов
1$:        BIT        #40000, (R4)       ; CRC сошлась?
        BNE        2$                   ; Да - выход
        SOB        R2, 1$               ; Нет - очередной цикл
2$:        RETURN                       ; Если бит Z=1, то произошла ошибка
; End of function TSTCRC


; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; RDSEC: П/п чтения сектора в буфер; R1 - число слов для пересылки
RDSEC:    MTPS    #340               ; Маскируем прерывания
        MOV        ADDR(R3), R2       ; Получим адрес буфера
1$:        TSTB    (R4)               ; Ожидаем данные
        BPL        1$
        MOV        (R5), R0           ; Читаем два байта,
        SWAB    R0                   ; делаем из них нормальное слово,
        MOV        R0, (R2)+           ;    которое помещаем в буфер
        SOB        R1, 1$               ; Читаем заказанное число слов
        MOV        FREE(R3), R1       ; Получаем длину остатка
        BEQ        2$                   ; Остатка нет - сразу выходим
3$:        TSTB    (R4)               ; Ждем данные
        BPL        3$
        TST        (R5)               ; Вхолостую читаем остаток
        SOB        R1, 3$               ;    требуемой длины
        MTPS    BUFPSW(R3)           ; Восстанавливаем PSW
2$:        RETURN
; End of function RDSEC


; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; FINDS: П/п поиска синхропоследовательности
FINDS:    TST        (R5)               ; Сбрасываем прочитанное значение
        MOVB    #100., SECRET(R3)   ; Будем искать 100. циклов
1$:        TSTB    (R4)               ; Ждем готовности
        BPL        1$
        MOV        (R5), R0           ; Получим прочитанные данные
        BEQ        2$                   ; Это 0 - на выход
        INC        R0                   ; Это 177777?
        BEQ        2$                   ; Да - на выход
        DECB    SECRET(R3)           ; Циклы кончились?
        BNE        1$                   ; Нет - повторяем поиск
2$:        RETURN
; End of function FINDS
; ───────────────────────────────────────────────────────────────────────────
; П/п чтения двух слов (не используется)
11$:    TSTB    (R4)               ; Ждем готовности
        BPL        11$
        MOV        (R5), R0           ; Получаем первое слово
12$:    TSTB    (R4)               ; Ждем готовности
        BPL        12$
        MOV        (R5), R1           ; Получаем второе слово
        RETURN

; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; STREAD: П/п запуска чтения
STREAD:    BIS        #400, (R3)           ; Установим признак "начало чтения"
        MOV        (R3), (R4)           ;    и запишем в регистр
        BIC        #400, (R3)           ; Снимем признак
        MOV        #10, R0
        SOB        R0, .               ; Небольшая задержка...
        MOV        (R3), (R4)           ;    и снова запишем в регистр
        RETURN
; End of function STREAD

; ───────────────────────────────────────────────────────────────────────────
; П/п поиска начала индекса (не используется)
11$:    TST        (R4)               ; Индекс есть?
        BMI        11$                   ; Да - ждем исчезновения
        BIS        #400, (R3)           ; Установим признак "начало чтения"
        MOV        (R3), (R4)           ;    и запишем в регистр
12$:    TST        (R4)               ; Индекса еще нет?
        BPL        12$                   ; Да - ждать появления
        MOV        HOLTIN(R3), R0
        SOB        R0, .               ; Задержимся...
        BIC        #400, (R3)           ; Сбросим признак "начало чтения"
        MOV        (R3), (R4)           ;    и запишем в регистр
        RETURN

; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; FINDH: П/п поиска адресного маркера
FINDH:    MOV        #15., R0
1$:        TST        (R5)               ; Вхолостую прочитаем
        SOB        R0, 1$               ;    15. слов
        CLR        INTIME(R3)           ; Начинаем ожидание индекса
        BICB    #40, FLAGS(R3)       ; Пока индекса нет
FH2$:    BITB    #30, @FLGPTR(R3)   ; Сектор задан задержкой?
        BEQ        3$                   ; Нет - обрабатывать
        CMPB    SECTOR(R3), #1       ; Да - нужен первый сектор?
        BNE        3$                   ; Второй и далее задаются заголовками
        MOV        #1474, HOLTIN(R3)   ;чудо-код, независимо от того,
        BR        4$                   ;как задан сектор и какой нужен сектор
; ───────────────────────────────────────────────────────────────────────────
3$:        MOV        #1474, HOLTIN(R3)   ;выставляем вот такую задержку
4$:        BR        5$
; ───────────────────────────────────────────────────────────────────────────
; продолжение п/п загрузки и запуска загрузчика
BOOTC$:    MOV        #2000, R3       ; Установим адрес рабочей области
        CALL    INIT           ; INIT:  и инициализируем ее
        MOVB    R0, UNIT(R3)   ; Занесем номер привода
        JMP        BOOTN           ; пойдем продолжать обычную загрузку  на своем привычном месте
; ───────────────────────────────────────────────────────────────────────────

5$:        CALL    INDEX               ; INDEX: Проверим наличие диска и обороты
        BCS        6$                   ; Обороты кончились - выходим
        BEQ        5$                   ; Какие данные? Нули пропустим
        COM        R0                   ; 177777?
        BEQ        5$                   ; Да - тоже пропустим
7$:        CALL    INDEX               ; INDEX: Проверим наличие диска и обороты
        BCS        6$                   ; Обороты кончились - выходим
        BEQ        8$                   ; Какие данные? Нули - синхро
        COM        R0                   ; 177777?
        BNE        7$                   ; Нет - пропустим
; Проверка адресного маркера
8$:        MOV        #3, R1
9$:        MOV        (R5), R0           ; Читаем данные
        BEQ        10$                   ; Нули - продолжаем
        COM        R0                   ; 177777?
        BNE        5$                   ; Нет - повторяем поиск
10$:    SOB        R1, 9$               ; Да - повторяем 3 раза
        CALL    STREAD               ; STREAD: Запускаем на чтение
        MOV        HOLTIN(R3), R0       ; берем задержку
11$:    TSTB    (R4)               ; Готовность есть?
        BMI        12$                   ; Есть - считываем данные
        SOB        R0, 11$               ; Нет - ждем
        BR        FH2$               ; Надоело ждать - повторяем поиск
; ───────────────────────────────────────────────────────────────────────────
12$:    TST        (R5)               ; Пропускаем A1A1
13$:    TSTB    (R4)               ; Ждем готовности
        BPL        13$
        MOV        (R5), R0           ; Есть - берем данные
        CMP        #120776, R0           ; Адресный маркер (A1FE)?
        BEQ        14$                   ; Да - нормальный выход
        CMP        #120773, R0           ; Нет - маркер данных (A1FB)?
        BEQ        15$                   ; Да - пропускаем сектор
        CMP        #120770, R0           ; Нет - маркер скрытых данных (A1F8)?
        BNE        FH2$               ; Нет - повторяем поиск сначала
15$:    CALL    FRESEC               ; FRESEC: Да - пропускаем сектор
        BR        FH2$               ; Повторяем поиск сначала
; ───────────────────────────────────────────────────────────────────────────
14$:    CLC
6$:        RETURN
; End of function FINDH


; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; INDEX: П/п проверки диска и числа оборотов
INDEX:    TST        (R4)               ; Индекс есть?
        BPL        1$                   ; Нет - идем проверять
        BITB    #40, FLAGS(R3)       ; Индекс есть - он уже был?
        BNE        2$                   ; Был - идем увеличивать время
        CLR        INTIME(R3)           ; Только что появился - очистим время
        BISB    #40, FLAGS(R3)       ;    и запомним факт появления
        DECB    TURNS(R3)           ; Закончился последний оборот?
        BNE        3$                   ; Нет - нормальный выход
        SEC                           ; Да - выход с ошибкой
        RETURN
; ───────────────────────────────────────────────────────────────────────────
3$:        CLC
        MOV        (R5), R0           ; Забираем данные
        RETURN
; ───────────────────────────────────────────────────────────────────────────
1$:        BITB    #40, FLAGS(R3)       ; Индекса нет - а он был?
        BEQ        2$                   ; Нет и не было - идем считать время
        CLR        INTIME(R3)           ; Только что исчез - очистим время
        BICB    #40, FLAGS(R3)       ;    и запомним факт исчезновения
        BR        3$                   ; Нормально выходим
; ───────────────────────────────────────────────────────────────────────────
2$:        INC        INTIME(R3)           ; Еще один такт индекс не менялся
        CMP        INTIME(R3), #60000   ; Ну сколько можно! Пора кончать?
        BLOS    3$                   ; Не пора - нормальный выход
        MOV        #6, R0               ; Терпение кончилось -
        JMP        ERROR               ; ERROR:   значит диска нет - ошибка 6
; End of function INDEX


; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; ENGINE: П/п выбора устройства
ENGINE:    MOV        #177130, R4           ; Заполняем рабочие регистры
        MOV        R4, R5               ;    адресами PC
        TST        (R5)+               ;    РД КНГМД
        BICB    #4, FLAGS(R3)       ; Очистим признак работы двигателя
        BIT        #20, (R3)           ; Двигатель уже включен?
        BEQ        1$                   ; Нет - включим
        BISB    #4, FLAGS(R3)       ; Да - установим признак
1$:        BIS        #20, (R3)           ; Включим двигатель
        MOV        (R3), (R4)           ;    и запишем в регистр
        BIC        #57, (R3)           ; Сбросим все другие регистры
        TSTB    SIDE(R3)           ; Сторона верхняя?
        BEQ        2$                   ; Да - идем дальше
        BIS        #40, (R3)           ; Нет - включим нижнюю
2$:        BICB    #177774, UNIT(R3)   ; Сбросим лишние биты
        MOVB    UNIT(R3), R1       ; Получим номер привода
        MOV        PC, R0               ; Получим базовый адрес
        ADD        #DMASK-., R0       ;    таблицы масок для приводов
        ADD        R1, R0               ; Получим адрес нужной маски
        BISB    (R0), (R3)           ; Установим бит нужного привода
        ADD        R3, R1               ; Получим базовый адрес
        ADD        #TRKTAB, R1           ;    таблицы TRKTAB
        MOV        R1, CURTRK(R3)       ; Настроим указатель CURTRK
        CALL    SETPTR               ; SETPTR: Настроим указатель FLGPTR
        BITB    #4, FLAGS(R3)       ; Мотор включен только что?
        BNE        3$                   ; Нет - выходим
        CLR        R1                   ; Да - подождем раскручивания
        SOB        R1, .
        SOB        R1, .
3$:        MOV        (R3), (R4)           ; Записываем установки в регистр
        MOV        TDOWN(R3), R1       ; Подождем опускания головки
        SOB        R1, .
        RETURN
; End of function ENGINE
; ───────────────────────────────────────────────────────────────────────────
; Таблица масок для включения приводов
DMASK:    .BYTE    1,2,4,10

; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; SETPTR: П/п настройки указателя FLGPTR
SETPTR:    CLR        FLGPTR(R3)           ; Очистим указатель FLGPTR
        BICB    #177740, UNIT(R3)   ; Отбросим лишние биты (вот это и есть поддержка винта? в других-то местах по-прежнему все сбрасывается)
        MOVB    UNIT(R3), FLGPTR(R3)   ; Перешлем номер привода в FLGPTR
        CALL    SETPT1               ; продолжим обработку и там всё равно отбросим ненужные биты, в FLGTAB ведь только 4 байта
        ADD        #FLGTAB, FLGPTR(R3)   ;    получаем искомый адрес
        RETURN
; End of function SETPTR


; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; GOTRK: П/п позиционирования
GOTRK:    TSTB    TRK(R3)               ; Нужна дорожка 00?
        BEQ        GOTO00               ; Да - позиционируем прямо на нее
        TSTB    @CURTRK(R3)           ; Положение головки известно?
        BPL        1$                   ; Да - будем искать требуемую
        CALL    GOTO00               ; Нет - придется сориентироваться
1$:        CMPB    @CURTRK(R3), TRK(R3)   ; Нужная дорожка совпадает с текущей?
        BEQ        2$                   ; Да - так что же мы тут делаем?
        BHI        3$                   ; Нет - искомая ближе к центру?
        CALL    GOUP               ; Да - шагаем к центру
        BR        1$                   ; Проверим, дошли ли
; ───────────────────────────────────────────────────────────────────────────
3$:        CALL    GODOWN               ; Нет - шагнем к периферии
        BR        1$                   ; Проверим, дошли ли
; ───────────────────────────────────────────────────────────────────────────
2$:        MOV        #10000., R0           ; Подождем успокоения головки
        SOB        R0, .
        RETURN                       ; Теперь можно и выйти
; End of function GOTRK


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; GOUP: Шаг к центру
GOUP:    INCB    @CURTRK(R3)           ; Номер дорожки станет на 1 больше
        BMI        1$                   ; Таких дорожек нет - выходим с ошибкой
        BIS        #100, (R3)           ; Все в порядке - шагать будем вперед
        BR        3$                   ; Пойдем шагать
; ───────────────────────────────────────────────────────────────────────────
1$:        MOV        #4, R0               ; Выход с ошибкой 4
        JMP        ERROR
; End of function GOUP


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; GODOWN: Шаг к периферии
GODOWN:    DECB    @CURTRK(R3)           ; Номер дорожки станет на 1 меньше
        BIT        #1, (R4)           ; Дошли до дорожки 00?
        BEQ        2$                   ; Нет - можно шагать
        CLRB    @CURTRK(R3)           ; Дошли: теперь текущая - 00
        RETURN                       ;    и можно выйти
; ───────────────────────────────────────────────────────────────────────────
2$:        BIC        #100, (R3)           ; Шагать будем назад
3$:        MOV        #200., R0           ; Подготовим задержку
        MOV        (R3), (R4)           ; Перешлем направление шага в регистр
        SOB        R0, .               ; Подождем, пока контроллер "переварит"
        BIS        #200, (R3)           ; Установим признак шага
        MOV        (R3), (R4)           ;    и запишем в регистр
        MOV        TSTEP(R3), R0       ; Получим задержку перехода дорожки
        SOB        R0, .               ;    и задержимся
        BITB    #1, @FLGPTR(R3)       ; Двойной шаг?
        BEQ        4$                   ; Нет - можно выходить
        BITB    #100, FLAGS(R3)       ; Мы возвращаемся на 00?
        BNE        4$                   ; Да - возвращаться надо одинарным шагом
        MOV        (R3), (R4)           ; Нет - придется шагнуть еще
        MOV        TSTEP(R3), R0       ; Получим задержку перехода дорожки
        SOB        R0, .               ;    и задержимся
4$:        BIC        #200, (R3)           ; Очистим признак шага
        RETURN
; End of function GODOWN


; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; GOTO00: П/п возврата на дорожку 00
GOTO00:    MOVB    #200, @CURTRK(R3)   ; Установим счетчик дорожек
        BISB    #100, FLAGS(R3)       ; Возвращаться надо одинарным шагом
1$:        CALL    GODOWN               ; GODOWN: Шагнем к периферии
        BIT        #1, (R4)           ; Дошли до 00?
        BNE        2$                   ; Да - выходим
        TSTB    @CURTRK(R3)           ; На какой дорожке должны находиться?
        BNE        1$                   ; Не на нулевой - еще шагнем
        MOV        #3, R0               ; На нулевой, а ее нет - ошибка 3
        BICB    #100, FLAGS(R3)       ; Сбросим режим одинарного шага
        JMP        ERROR               ; Выходим с ошибкой
; ───────────────────────────────────────────────────────────────────────────
2$:        CLRB    @CURTRK(R3)           ; Дошли - текущая теперь нулевая
        BICB    #100, FLAGS(R3)       ; Сбросим режим одинарного шага
        RETURN
; End of function GOTO00


; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; FRESEC: П/п пропуска сектора
FRESEC:    MOV        SECLEN(R3), R0       ; Получим длину сектора

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

FICT:    TST        (R4)               ; Индекс есть?
        BMI        1$                   ; Да - ждем начала оборота
2$:        TST        (R4)               ; Индекс все еще есть?
        BMI        3$                   ; Да - оборот завершен
4$:        TSTB    (R4)               ; Данные готовы?
        BPL        2$                   ; Нет - снова
        TST        (R5)               ; Прочитаем данные вхолостую
        SOB        R0, 2$               ;    требуемое число раз
        BR        5$                   ;    и выйдем
; ───────────────────────────────────────────────────────────────────────────
3$:        DECB    TURNS(R3)           ; Все обороты вышли?
        BNE        6$                   ; Нет - попытаемся слова
        MOV        #5, R0               ; Да - выходим с ошибкой 5
        JMP        ERROR
; ───────────────────────────────────────────────────────────────────────────
1$:        TST        (R4)               ; Индекс исчез?
        BPL        4$                   ; Да - оборот начался
6$:        TSTB    (R4)               ; Данные готовы?
        BPL        1$                   ; Нет - проверим индекс
        TST        (R5)               ; Прочитаем данные вхолостую
        SOB        R0, 1$               ;    требуемое число раз
5$:        RETURN                       ;    и вернемся к основной работе
; End of function FICT
; End of function FRESEC

; ───────────────────────────────────────────────────────────────────────────
; WRSEC: П/п записи сектора
; Входные параметры: R1 - число слов для записи
WRSEC:    MOV        ADDR(R3), R2       ; Получим начальный адрес массива
        MOV        #11., R0           ; В маркере будет 11. 4E4E
        MTPS    #340               ; При записи нам не мешать!
        CALL    WRMAR               ; Запишем маркер данных

1$:        TSTB    (R4)               ; Готовность есть?
        BPL        1$                   ; Нет - ждем
        MOV        (R2)+, (R5)           ; Запишем первое слово данных
        MOV        (R3), (R4)           ; Снимем признак записи маркера
        BR        2$                   ;    и пойдем записывать данные
; ───────────────────────────────────────────────────────────────────────────
3$:        TSTB    (R4)               ; Готовность есть?
        BPL        3$                   ; Нет - дождемся
        MOV        (R2)+, (R5)           ; Запишем слово данных
2$:        SOB        R1, 3$               ;    и так до конца
        MOV        FREE(R3), R1       ; Получим длину пустого остатка сектора
        BEQ        4$                   ; Остатка нет - выходим сразу
5$:        TSTB    (R4)               ; Готовность есть?
        BPL        5$                   ; Дожидаемся
        MOV        #0, (R5)           ; Записываем нули
        SOB        R1, 5$               ;    в нужном количестве
4$:        BIT        #40000, (R4)       ; Ждем записи CRC
        BEQ        4$
        MOV        #47116, (R5)       ; Записываем 4E4E
6$:        TSTB    (R4)               ; Готовность есть?
        BPL        6$                   ; Нет - ждем
        TST        (R5)               ; Прекращаем запись
        MTPS    BUFPSW(R3)           ; Восстанавливаем PSW
        JMP        NEXT               ; NEXT: Продолжаем запись массива

; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; WRMAR: П/п записи маркера данных
; Входные данные: R0 - число записываемых слов 4E4E
WRMAR:    MOV        #47116, (R5)       ; Запишем 4E4E
        BR        1$                   ; Идем на повтор записи
; ───────────────────────────────────────────────────────────────────────────
2$:        TSTB    (R4)               ; Готовность есть?
        BPL        2$                   ; Нет - дождемся
        MOV        #47116, (R5)       ; Запишем 4E4E
1$:        SOB        R0, 2$               ; Повторим заданное число раз
        MOV        #6, R0               ; Запишем 12. нулевых байтов
3$:        TSTB    (R4)               ; Готовность есть?
        BPL        3$                   ; Нет - ожидаем
        MOV        #0, (R5)           ; Записываем нули
        SOB        R0, 3$               ;    в нужном количестве
        BIS        #1000, (R3)           ; Подготовим признак записи маркера
4$:        TSTB    (R4)               ; Контроллер готов?
        BPL        4$                   ; Нет - ждем
        MOV        #120641, (R5)       ; Записываем маркер A1A1
        MOV        (R3), (R4)           ; Передаем признак в контроллер
        BIC        #1000, (R3)           ; Заранее снимем признак
5$:        TSTB    (R4)               ; Готовность есть?
        BPL        5$                   ; Нет - ожидаем
        MOV        MARKER(R3), (R5)   ; Записываем маркер из буфера
        RETURN
; End of function WRMAR


; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; CORR: П/п установки прекоррекции
CORR:    BIC        #2000, (R3)           ; Снимем прекоррекцию
        CMPB    TRKCOR(R3), @CURTRK(R3)   ; Надо включать на текущей дорожке?
        BHI        1$                   ; Нет - пропустим
        BIS        #2000, (R3)           ; Пора - включим
1$:        MOV        (R3), (R4)           ; Перешлем управляющее слово
        MOV        #200., R0
        SOB        R0, .               ; Подождем, пока контроллер воспримет
        RETURN
; End of function CORR

; ───────────────────────────────────────────────────────────────────────────
; FORMAT: П/п форматирования
FORMAT:    MOV        SP, BUFSP(R3)       ; Сохраним SP,
        MFPS    BUFPSW(R3)           ;    PSW,
        MOV        #4, R0
        MOV        (R0), BUF4(R3)       ;  @#4 в соответствующих буферах
        MOV        PC, (R0)           ; Переназначаем вектор @#4 на себя,
        ADD        #VECT4-., (R0)       ;    теперь он равен 161512
        CALL    ENGINE               ; Запустим двигатель
        CALL    GOTRK               ; Позиционируем на нужную дорожку
        CALL    CORR               ; Установим прекоррекцию
        BIT        #4, (R4)           ; Защита записи включена?
        BEQ        1$                   ; Нет - начинаем форматировать
        MOV        #1, R0               ; Да - ошибка 1
2$:        JMP        ERROR               ; Выходим с ошибкой
; ───────────────────────────────────────────────────────────────────────────
1$:        SWAB    SIDE(R3)           ; Обмениваем номера стороны и дорожки
        MOVB    FILLB(R3), WRTVAR(R3)   ; Делаем слово-заполнитель
        MOVB    FILLB(R3), WRTVAR+1(R3)   ;    из байта-заполнителя
        MOVB    MAXSEC(R3), R1       ; Получим длину сектора
        MOV        #1001, R2           ; Запомним номер сектора и код длины
        MOV        #1000., R0           ; Время ожидания индекса
3$:        TST        (R4)               ; Индекс есть?
        BPL        4$                   ; Исчез - начинаем записывать
        SOB        R0, 3$               ; Есть - ждем исчезновения
5$:        TST        (R5)               ; Так и не исчез - прекратим запись
        MOV        #6, R0               ; Диск не вращается - ошибка 6
        SWAB    SIDE(R3)           ; Вернем все на место
        BR        2$                   ; Выходим с ошибкой
; ───────────────────────────────────────────────────────────────────────────
; Запись на дорожку кода 4E4E
4$:        MOV        #6200, R0           ; Установим максимальную длину
        MTPS    #340               ; При записи нам не мешать
        MOV        #47116, (R5)       ; Записываем 4E4E
6$:        TST        (R4)               ; Индекс появился?
        BMI        7$                   ; Да - начинаем запись
8$:        TSTB    (R4)               ; Готовность есть?
        BPL        8$                   ; Нет - ждем
        MOV        #47116, (R5)       ; Записываем 4E4E
        SOB        R0, 6$               ; И так до конца дорожки
        BR        5$                   ; Дорожка длинная, ошибка!
; ───────────────────────────────────────────────────────────────────────────
7$:        MOV        #16., R0           ; В маркере будет 16. 4E4E (GAP1)
        MOV        #177241, MARKER(R3)   ; Адресный маркер (FEA1) - в буфер
9$:        CALL    WRMAR               ; WRMAR: Записываем адресный маркер
10$:    TSTB    (R4)               ; Готовность есть?
        BPL        10$                   ; Нет - ожидаем
        MOV        SIDE(R3), (R5)       ; Записываем номер стороны и дорожки
        MOV        (R3), (R4)           ; Перешлем управляющее слово
11$:    TSTB    (R4)               ; Готовность есть?
        BPL        11$                   ; Нет - дождемся
        MOV        R2, (R5)           ; Записываем номер сектора и код длины
        MOV        #11., R0           ; В маркере будет 11. 4E4E (GAP2)
        MOV        #175641, MARKER(R3)   ; Маркер данных (FBA1) - в буфер
12$:    BIT        #40000, (R4)       ; Ждем записи CRC
        BEQ        12$
        CALL    WRMAR               ; WRMAR: Записываем маркер данных
        MOV        SECLEN(R3), R0       ; Получаем длину сектора
        DEC        R0                   ; Одно слово запишем сейчас
13$:    TSTB    (R4)               ; Готовность есть?
        BPL        13$                   ; Нет - ожидаем
        MOV        WRTVAR(R3), (R5)   ; Записываем заполнитель
        MOV        (R3), (R4)           ; Перешлем управляющее слово
14$:    TSTB    (R4)               ; Готовность есть?
        BPL        14$                   ; Нет - дождемся
        MOV        WRTVAR(R3), (R5)   ; Записываем заполнитель
        SOB        R0, 14$               ; И так до конца сектора
        INC        R2                   ; Увеличим номер сектора
        MOV        #24., R0           ; В маркере будет 24. 4E4E (GAP3)
;    Примечание. Если увеличить GAP3 до 24-27 слов, то запись будет производиться так
; же быстро, как и чтение (обычно заголовок очередного сектора проскакивает, и дорожка
; записывается не за один, а за 10 оборотов). Однако при превышении этой величиной
; определенного значения конец последнего сектора дорожки может наложиться на ее
; же начало.
        BIT        #4, @FLGPTR(R3)       ; Сектора длинные?
        BEQ        15$                   ; Нет - все нормально
        MOV        #72, R0               ; Да - будет 116. 4E4E (можно увеличить до 75)
15$:    MOV        #177241, MARKER(R3)   ; Адресный маркер (FEA1) - в буфер
16$:    BIT        #40000, (R4)       ; Ждем записи CRC
        BEQ        16$
        SOB        R1, 9$               ; И так все сектора до конца дорожки
; Окончание записи дорожки
17$:    TSTB    (R4)               ; Готовность есть?
        BPL        17$                   ; Нет - ждем
        MOV        #47116, (R5)       ; Запишем 4E4E
        TST        (R4)               ; Индекс есть?
        BPL        17$                   ; Нет - продолжим запись до появления
18$:    TSTB    (R4)               ; Готовность есть?
        BPL        18$                   ; Нет - дождемся
        MOV        #47116, (R5)       ; Запишем 4E4E
        TST        (R5)               ; Прекратим запись
        MTPS    BUFPSW(R3)           ; Восстановим PSW
        SWAB    SIDE(R3)           ; Вернем все на место
        JMP        EXIT               ; EXIT: Выходим

; ───────────────────────────────────────────────────────────────────────────
; Драйвер расширенной арифметики
; ───────────────────────────────────────────────────────────────────────────

; эмуляция прерывания по вектору 4
EXT$V4:    MOV        @#6, -(SP)       ; в стек PS вектора 4
        BIS        #1, (SP)       ; установим там бит С
        MOV        @#4, -(SP)       ; в стек адрес вектора 4
        RTI                       ; и переходим.
       ; в стеке остались PS/PC выхода из вектора 10.
       ; они будут использоваться при выходе из вектора 4
       ; или, если там стек напрямую инициализируется, то они не нужны
; ───────────────────────────────────────────────────────────────────────────
;точка входа в драйвер расширенной арифметики.
;вход - прерывание по вектору 10
EXT:    MOV        #6, -(SP)
        ADD        SP, (SP)       ; тут получается значение стека до возникновения прерывания
                               ; это нужно, если для передачи параметров fis использовался SP
        MOV        R5, -(SP)
        MOV        R4, -(SP)
        MOV        6(SP), R5       ; берём адрес возврата из прерывания
        MOV        -(R5), R4       ; получаем опкод, вызвавший прерывание
        MOV        R3, -(SP)
        MOV        R2, -(SP)
        MOV        R1, -(SP)
        MOV        R0, -(SP)
        MOV        R4, R0           ; опкод
        MOV        R0, R1           ; ещё раз
        CMP        R0, #75000       ; это fis ?
        BHIS    FLOAT$           ; скорее всего да, пойдём проверим
        JMP        EXTAR$           ; нет, может eis? пойдём проверим
; ───────────────────────────────────────────────────────────────────────────
        ADD        #6, SP           ; мусор
ERRCM$:    CALL    RESTR$           ; восстановим регистры
        JMP        EXT$V4           ; и сделаем якобы прерывание по вектору 4

; ███████████████ S U B R O U T I N E ███████████████████████████████████████
;п/п установки признаков и восстановления регистров
RSTRS$:    BIC        #17, 22(SP)       ; чистим поле признаков в PS возврата из прерывания
        BIS        R5, 22(SP)       ; и устанавливаем там свои

; ███████████████ S U B R O U T I N E ███████████████████████████████████████
;п/п восстановления регистров
RESTR$:    MOV        (SP)+, 14(SP)   ; берём адрес возврата из RESTR$ или RSTRS$, и сохраняем его
                               ; на месте значения 6+SP
        MOV        (SP)+, R0       ; восстанавливаем все регистры
        MOV        (SP)+, R1
        MOV        (SP)+, R2
        MOV        (SP)+, R3
        MOV        (SP)+, R4
        MOV        (SP)+, R5
        RETURN                   ; и выходим из п/п. Теперь в стеке только PC PS
                               ; для выхода из прерывания
; End of function RESTR$
; End of function RSTRS$

; ███████████████ S U B R O U T I N E ███████████████████████████████████████
;умножение R0:R1 = R3:R4 * R5
IMUL32:    CLR        R1               ; тут накапливается результат
        CLR        R0
        ROR        R5               ; B.hi >> 1
        BR        1$

2$:        ASR        R5
1$:        BCS        3$               ; если 1, то пойдём делать сложение
        BNE        4$               ; если 0, но ещё есть биты, то пойдём просто сдвигать
        BR        5$               ; если всё - то выход.

3$:        ADD        R4, R1           ; R0:R1 += R3:R4
        ADC        R0
        ADD        R3, R0
4$:        ASL        R4               ; R3:R4 <<= 1
        ROL        R3
        BR        2$               ; и повторим

5$:        RETURN                   ; как-то не оптимально. можно 2 слова сэкономить
; End of function IMUL32

; ───────────────────────────────────────────────────────────────────────────
FLOAT$:    CMP        R0, #75040       ; точно fis ?
        BLO        1$               ; да
        JMP        ERRCM$           ; нет - другие не эмулируемые опкоды
; ───────────────────────────────────────────────────────────────────────────
1$:        BIC        #177747, R0       ; определим тип опкода
        ASR        R0
        ASR        R0               ; номер опкода * 2
        BIC        #177770, R1       ; определим номер используемого регистра
        ASL        R1               ; регистр * 2
        ADD        SP, R1           ; это адрес в стеке, где сохранено значение регистра
        MOV        R1, -(SP)       ; и сохраним его в стеке. Туда результат ещё писать надо будет
        MOV        (R1), R1       ; достанем значение регистра
        MOV        (R1)+, R2       ; B.hi
        MOV        (R1)+, R3       ; B.lo
        MOV        (R1)+, R4       ; A.hi
        MOV        (R1)+, R5       ; A.lo
        MOV        R1, -(SP)       ; и снова сохраним
        ADD        PC, R0
        ADD        #OFSTBL-., R0
        ADD        (R0), PC       ; и пойдём обрабатывать конкретную операцию
OFSTBL:    .WORD    FADD$-OFSTBL   ; 75000
        .WORD    FSUB$-OFSTBL   ; 75010
        .WORD    FMUL$-OFSTBL   ; 75020
        .WORD    FDIV$-OFSTBL   ; 75030
; ───────────────────────────────────────────────────────────────────────────
;деление A = A / B
FDIV$:    CLR        -(SP)           ; флаг знака результата
        MOV        R2, R0           ; сохраним порядок B
        BGT        1$               ; если больше 0 - переход туда
        BLT        2$               ; если меньше 0 - переход туда
        JMP        FERR$           ; если равно 0 - ошибка, на 0 делить нельзя
; ───────────────────────────────────────────────────────────────────────────
2$:        INC        (SP)           ; отмечаем смену знака результата
1$:        MOV        R4, R1           ; сохраним порядок A
        BEQ        F3$               ; если это 0, то результат деления == 0
        BPL        4$               ; если больше 0 - переход
        INC        (SP)           ; отмечаем смену знака результата
4$:        CALL    SEPAR           ; разделяем мантиссу и порядок
        SUB        R0, R1           ; res.exp = A.exp - B.exp
        ADD        #37600, R1       ; ?
        MOV        R1, -(SP)       ; сохраняем
        MOV        #100, R1       ; начальное значение, бит, по которому будет выход из цикла
        CLR        R0
        BR        5$               ; и идём просто делить R4:R5 на R2:R3
; ───────────────────────────────────────────────────────────────────────────
6$:        ASL        R5
        ROL        R4
5$:        SUB        R3, R5
        SBC        R4
        SUB        R2, R4
        BMI        7$
8$:        SEC
        ROL        R1
        ROL        R0
        BCC        6$
        BR        9$
; ───────────────────────────────────────────────────────────────────────────
10$:    ASL        R5
        ROL        R4
        ADD        R3, R5
        ADC        R4
        ADD        R2, R4
        BPL        8$
7$:        CLC
        ROL        R1
        ROL        R0
        BCC        10$
9$:        MOV        R0, R2           ; вот результат
        MOV        R1, R3           ; тут R1 == R3
        JMP        NRRT$           ; и по идее, R1 не нужен, при сдвиге вправо
; ───────────────────────────────────────────────────────────────────────────
F3$:    TST        (SP)+
        CLR        R2
        CLR        R3
        JMP        FL$NZ$           ; установка признаков N и Z
; ───────────────────────────────────────────────────────────────────────────
;умножение A = A * B
FMUL$:    CLR        -(SP)           ; флаг знака
        MOV        R2, R0           ; сохраним порядок B
        BEQ        F3$               ; если это 0, то результат умножения == 0
        BPL        1$               ; если > 0, то переход
        INC        (SP)           ; иначе результат будет отрицательный
1$:        MOV        R4, R1           ; сохраним порядок A
        BEQ        F3$               ; если это 0, то результат умножения == 0
        BPL        2$               ; если > 0, то переход
        INC        (SP)           ; иначе результат будет отрицательный, или, если B было <0, то положительный
2$:        CALL    SEPAR           ; разделяем мантиссу и порядок
        ADD        R0, R1           ; res.exp = A.exp + B.exp
        SUB        #40000, R1       ; ?
        MOV        R1, -(SP)       ; порядок результата
        MOV        R5, -(SP)       ; A.m.lo ->
        MOV        R4, -(SP)       ; A.m.hi ->
        MOV        R3, -(SP)       ; B.m.lo ->
        MOV        R4, R3           ; A.m.hi
        MOV        R5, R4           ; A.m.lo
        MOV        R2, R5           ; B.m.hi
        CALL    IMUL32           ; умножение R0:R1 = R3:R4 * R5
                               ; умножаем A.m на B.m.hi
        MOV        R1, -(SP)       ; результат сохраним
        MOV        R0, -(SP)
        MOV        4(SP), R5       ; B.m.lo
        BEQ        3$               ; если 0, незачем умножать
        MOV        6(SP), R4       ; А.m.hi
        CLR        R3
        CALL    IMUL32           ; умножение R0:R1 = R3:R4 * R5
                               ; умножаем A.m.hi на B.m.lo
        ADD        R1, 2(SP)       ; складываем с предыдущем результатом
        ADC        (SP)
        ADD        R0, (SP)
        MOV        10(SP), R4       ; A.m.lo
        BEQ        3$               ; если 0, незачем умножать
        MOV        4(SP), R5       ; B.m.lo
        CLR        R3
        CALL    IMUL32           ; умножение R0:R1 = R3:R4 * R5
                               ; умножаем A.m.lo на B.m.lo
        ADD        R0, 2(SP)       ; складываем с предыдущем результатом
        ADC        (SP)
                               ; что-то не пойму логику.
                               ; res = A.m * B.m.hi + (A.m.hi + A.m.lo) * B.m.lo
3$:        CLR        R2
        BISB    1(SP), R2       ; берём старший байт ст слова результата
        MOV        2(SP), R1       ; берём мл слово результата
        SWAB    R1               ; переставляем байты
        MOVB    (SP)+, (SP)       ; замещаем младший байт мл слова младшим байтом ст слова результата
        MOV        (SP)+, R3       ; и достаём это
        SWAB    R3               ; переставляем байты
                               ; в результате получается res = R2:R3:R1
                               ; в старшем байте R2 - 0, в младшем байте R1 - незначащий мусор
        ADD        #6, SP           ; освобождаем стек
        JMP        NRLT$

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

SEPAR:    BIC        #100177, R0       ; выделяем порядок B (B.exp)
        BIC        #100177, R1       ; выделяем порядок A (A.exp)
        BIC        #177600, R2       ; выделяем мантиссу B (B.m)
        BIC        #177600, R4       ; выделяем мантиссу A (A.m)
        BIS        #200, R2       ; добавляем подразумеваемый бит в B.m
        BIS        #200, R4       ; добавляем подразумеваемый бит в A.m
        RETURN
; End of function SEPAR

; ───────────────────────────────────────────────────────────────────────────
;вычитание A = A - B - это A + (-B)
FSUB$:    TST        R2               ; B == 0 ?
;тут таки не учитывается, что если порядок 0, то в мантиссе может быть
;любой мусор, он должен просто игнорироваться.
        BEQ        FADD$           ;да, пойдём, прибавим 0
        ADD        #100000, R2       ;иначе, поменяем знак B = -B
;сложение A = A + B
FADD$:    MOV        R2, R0           ; что мы там прибавляем?
        BNE        1$               ; не ноль
        MOV        R4, R2           ; а если 0, то просто
        MOV        R5, R3           ; res = A
        BR        FL$NZ$           ; установка признаков N и Z
; ───────────────────────────────────────────────────────────────────────────
1$:        MOV        R4, R1           ; а если A == 0, то res = B
        BEQ        FL$NZ$           ; установка признаков N и Z
        BIC        #177600, R2       ; оставляем в R2:R3 только мантиссу B (B.m)
        BIS        #200, R2       ; добавляем подразумеваемый бит
        TST        R0               ; а число B какое?
        BPL        2$               ; положительное
        NEG        R3               ; отрицательное - поменяем знак мантиссы
        ADC        R2
        NEG        R2
2$:        BIC        #177600, R4       ; оставляем в R4:R5 только мантиссу A (A.m)
        BIS        #200, R4       ; добавляем подразумеваемый бит
        TST        R1               ; а число A какое?
        BPL        3$               ; положительное
        NEG        R5               ; отрицательное - поменяем знак мантиссы
        ADC        R4
        NEG        R4
3$:        BIC        #100177, R0       ; это порядок B (B.exp)
        BIC        #100177, R1       ; это порядок A (A.exp)
        CLR        -(SP)           ; флаг знака
        MOV        R0, -(SP)       ; B.exp
        SUB        R1, R0           ; B.exp = B.exp - A.exp
        BHI        4$               ; если B.exp > A.exp
        BLO        5$               ; если B.exp < A.exp
       ;если B.exp == A.exp
        CLR        R1               ; B.exp = A.exp = 0
        BR        6$

;B.exp < A.exp
5$:        MOV        R1, (SP)       ; вместо B.exp поместим A.exp
        NEG        R0               ; A.exp - B.exp
        MOV        R2, R1           ; B.m <--> A.m
        MOV        R4, R2           ; меняем местами мантиссы A и B
        MOV        R1, R4
        MOV        R3, R1
        MOV        R5, R3
        MOV        R1, R5
;B.exp > A.exp
4$:        CLR        R1               ; tmp = 0 (вытесненные биты из выровненной мантиссы)
        CMP        R0, #6000
        BLE        7$               ; B.exp - A.exp <= 24.
        CLR        R4               ; если больше, то A.m = 0
        CLR        R5
        BR        6$
;B.exp - A.exp <= 24.
7$:        ASL        R0
        SWAB    R0               ; разность B.exp - A.exp в мл байт
;выравниваем мантиссы в соответствии с порядками.
8$:        ASR        R4               ; и двигаем A.m вправо
        ROR        R5
        ROR        R1               ; а сюда принимаем биты
        SOB        R0, 8$

6$:        ADD        R5, R3           ; res.m = B.m + A.m
        ADC        R2
        ADD        R4, R2
        BPL        9$               ; если >= 0, переход
        NEG        R1               ; иначе меняем знак
        ADC        R3
        ADC        R2
        NEG        R3
        ADC        R2
        NEG        R2
        INC        2(SP)           ; и фиксируем этот факт

9$:        MOV        R3, R4           ; проверяем, что получилось
        BIS        R1, R4
        BIS        R2, R4
        BNE        NRRT$           ; что-то получилось - переход
        CMP        (SP)+, (SP)+   ; все нули, освобождаем стек
        BR        FL$NZ$           ; установка признаков N и Z
; ───────────────────────────────────────────────────────────────────────────
; сдвигаем мантиссу вправо
NRRT$:    CMP        R2, #400       ; res.hi умещается в мл байт?
        BLO        NRLT$           ; да
        ASR        R2               ; нет, двигаем вправо
        ROR        R3
        ROR        R1
        ADD        #200, (SP)       ; считаем кол-во сдвигов (это добавка к порядку)
        BR        NRRT$           ; и так пока не станет умещаться.
; ───────────────────────────────────────────────────────────────────────────
; сдвигаем мантиссу влево
NRLT$:    TSTB    R2               ; старший бит мантиссы == 1 ?
        BMI        1$               ; да
2$:        SUB        #200, (SP)       ; нет - считаем кол-во сдвигов
        ASL        R1               ; двигаем влево
        ROL        R3
        ROLB    R2
        BPL        2$               ; и так, пока старший бит мантиссы не станет 1

1$:        ASL        R1               ; округляем до двухсловного числа
        ADC        R3
        ADCB    R2
        BCC        3$               ; переполнения не случилось?
        ADD        #200, (SP)       ; случилось - скорректируем порядок.
3$:        MOV        (SP)+, R4       ; достаём порядок из стека
        BPL        4$               ; если >=0, то переход
        CLR        R5               ; а иначе - переполнение
        ROL        R4               ; двигаем порядок влево
        BPL        F6$               ; если стало >=0, то V
        BR        F5$               ; иначе N и V
       ;по идее, тут ещё и C должно формироваться, если С==1, но нет.
; ───────────────────────────────────────────────────────────────────────────
4$:        ROR        (SP)+           ; достаём знак результата
        BCC        6$               ; если +, то переход
        BIS        #100000, R2       ; если -, то формируем знаковый бит
6$:        BIC        #200, R2       ; очищаем подразумеваемый бит мантиссы
        BIS        R4, R2           ; помещаем порядок на место

;установка признаков N и Z
FL$NZ$:    CLR        R5               ; тут формируются признаки
        TST        R2               ; res.hi == 0 ?
        BNE        1$               ; нет
        BIS        #4, R5           ; да - формируем Z
1$:        BPL        2$               ; res.hi >= 0 или просто переход после bis
        BIS        #10, R5           ; res.hi < 0 - формируем N
2$:        MOV        (SP)+, R1       ; конец блока параметров
        MOV        (SP)+, R0       ; адрес в стеке, где хранится значение используемого регистра
        MOV        R3, -(R1)       ; сохраняем res на место A
        MOV        R2, -(R1)
        MOV        R1, (R0)       ; а адрес res - в регистр
        SUB        SP, R0           ; а теперь проверим, какой это был регистр
        CMP        R0, #14
        BLO        3$               ; если это R0-R5, то всё как обычно
        BEQ        4$               ; если это SP
        ADD        #4, 16(SP)       ; если это PC - то он должен указывать за res,
                               ; а не на него, как все остальные регистры
3$:        CALL    RSTRS$           ; установим признаки из R5 и восстановим регистры
        RTI
; ───────────────────────────────────────────────────────────────────────────
4$:        CALL    RSTRS$           ; установим признаки из R5 и восстановим регистры
        MOV        (SP)+, 2(SP)   ; переместим PS/PC в стеке на место B,
        MOV        (SP)+, 2(SP)   ; оно всё равно не нужно
        RTI                       ; и выходим. Изящно получается со стеком в качестве буфера
; ───────────────────────────────────────────────────────────────────────────

FERR$:    BIS        #1, R5           ; формируем C
F5$:    BIS        #10, R5           ; формируем N
F6$:    BIS        #2, R5           ; формируем V
        CMP        (SP)+, (SP)+   ; убираем из стека флаг знака и конец блока параметров fis
        MOV        (SP)+, R0       ; достаём адрес в стеке, где хранится значение используемого регистра
        SUB        SP, R0           ; проверим, какой это был регистр
        CMP        R0, #16           ; это PC?
        BNE        1$               ; нет
        ADD        #10, 16(SP)       ; да - передвинем его за блок параметров
1$:        CALL    RSTRS$           ; установим признаки из R5 и восстановим регистры
        MOV        @#246, -(SP)   ; эмулируем возникновение прерывания по ошибке
        MOV        @#244, -(SP)   ; СППЗ
        RTI                       ; если кто об этом не знал, ему же хуже.
; ───────────────────────────────────────────────────────────────────────────

EXTAR$:    CMP        R0, #70000       ; точно eis?
        BHIS    1$               ; да
        JMP        ERRCM$           ; нет - другие не эмулируемые опкоды
; ───────────────────────────────────────────────────────────────────────────
1$:        BIC        #170777, R0       ; выделим код опкода
        SWAB    R0               ; вот он уже умноженный на 2
        MOV        R1, R2
        BIC        #177770, R1       ; выделим регистр источника
        ROL        R1               ; *2
        ASR        R2
        ASR        R2
        MOV        R2, R3
        BIC        #177761, R2    ; выделим код адресации источника *2
        ASR        R3
        ASR        R3
        ASR        R3
        BIC        #177761, R3    ; выделим регистр приёмника *2
        MOV        #2, R4
        BIS        R3, R4           ; а это R+1 приёмника
        ADD        SP, R3           ; находим адрес в стеке, где находится содержимое регистров приёмника
        ADD        SP, R4
        MOV        R1, -(SP)       ; регистр источника сохраним
        ADD        SP, R1           ; находим адрес в стеке, где находится содержимое регистра источника
        ADD        #2, R1
        MOV        R2, -(SP)       ; адресацию источника в стек
        ADD        PC, (SP)       ; и сформируем там адрес перехода
        ADD        #EPCBS2-., (SP)   ; а при этом у нас R5 свободен
        ADD        @(SP)+, PC       ; зачем надо было стек использовать, непонятно
EPCBS2:    .WORD    ADDR01-EPCBS2   ; 0 Rx
        .WORD    ADDR01-EPCBS2   ; 1 (Rx)
        .WORD    ADDR23-EPCBS2   ; 2 (Rx)+
        .WORD    ADDR23-EPCBS2   ; 3 @(Rx)+
        .WORD    ADDR45-EPCBS2   ; 4 -(Rx)
        .WORD    ADDR45-EPCBS2   ; 5 @-(Rx)
        .WORD    ADDR67-EPCBS2   ; 6 n(Rx)
        .WORD    ADDR67-EPCBS2   ; 7 @n(Rx)
; ─ автоинкрементная адресация ──────────────────────────────────────────────
ADDR23:    INC        (SP)           ; номер регистра источника ++ - признак автоинкрементной адресации
        MOV        (R1), R5       ; берём содержимое регистра источника
        ADD        #2, (R1)       ; инкрементируем
        BR        ARROP$
; ─ автодекрементная адресация ──────────────────────────────────────────────
ADDR45:    SUB        #2, (R1)       ; декрементируем
        MOV        (R1), R5       ; берём содержимое регистра источника
        BR        ARROP$
; ─ индексная адресация ─────────────────────────────────────────────────────
ADDR67:    MOV        @20(SP), R5       ; берём индекс по содержимому PC
        ADD        #2, 20(SP)       ; прибавляем содержимому PC два
        ADD        (R1), R5       ; прибавляем к индексу содержимое регистра источника
        BR        ARROP$
; ─ регистровая адресация ───────────────────────────────────────────────────
ADDR01:    MOV        R1, R5           ; берём регистр источник
ARROP$:    BIT        #2, R2           ; адресация относительная?
        BEQ        1$               ; нет
        MOV        (R5), R5       ; да - значит получим значение по адресу значения
1$:        MOV        R4, -(SP)       ; R+1 приёмника
        MOV        R3, -(SP)       ; R приёмника
        ADD        PC, R0
        ADD        #OFSTB2-., R0
        ADD        (R0), PC
OFSTB2:    .WORD    MUL$-OFSTB2       ; 70000
        .WORD    DIV$-OFSTB2       ; 71000
        .WORD    ASH$-OFSTB2       ; 72000
        .WORD    ASHC$-OFSTB2   ; 73000
        .WORD    XOR$-OFSTB2       ; 74000
; ───────────────────────────────────────────────────────────────────────────
; умножение R:R+1 = R * ss
MUL$:    MOV        (R3), R4       ; берём мл. часть
        BEQ        2$               ; если 0, то результат 0
        MOV        (R5), R5       ; берём источник
        BEQ        2$               ; если 0, то результат 0
        BPL        1$               ; если >= 0, то идём умножать
        NEG        R4               ; иначе R4 = -R4
        NEG        R5               ; R5 = -R5
        BPL        1$               ; если >= 0, то идём умножать
                               ; иначе в R5 число 100000
        MOV        R4, R3           ; R4 <-> R5
        MOV        R5, R4
        MOV        R3, R5
        BPL        1$               ; если >= 0, то идём умножать
        NEG        R5               ; иначе R5 = -R5
        BMI        4$               ; если < 0, то и в R4 тоже было число 100000
1$:        TST        R4               ; умножаем
        SXT        R3
        CALL    IMUL32           ; умножение R0:R1 = R3:R4 * R5
                               ; на выходе в R5 нуль
        TST        R1               ; посмотрим
        SXT        R2               ; какой знак у мл. части
        CMP        R0, R2           ; если знак распространён на ст. часть
        BEQ        3$               ; то всё нормально
        BIS        #1, R5           ; иначе бит C
3$:        JMP        EARX1$

2$:        CLR        R0               ; результат
        CLR        R1
        CLR        R5               ; флаги
        JMP        EARX1$           ; выходим

4$:        MOV        #40000, R0       ;результат умножения 100000 * 100000
        CLR        R1
        CLR        R5
        BR        3$
; ───────────────────────────────────────────────────────────────────────────
; деление R = R:R+1 / ss , R+1 = R:R+1 % ss
DIV$:    CLR        -(SP)           ; флаг знака результата
        MOV        (R3), R0       ; значение R приёмника
        MOV        (R4), R1       ; значение R+1 приёмника
        MOV        R0, -(SP)
        BPL        1$
        INC        2(SP)
        NEG        R1
        ADC        R0
        NEG        R0
        BMI        2$
1$:        MOV        (R5), R4
        BEQ        3$
        BPL        4$
        INC        2(SP)
        NEG        R4
        BMI        2$
4$:        CLR        R5
        CMP        R0, R4
        BGT        2$
        BLT        5$
        CMP        R1, R4
        BHIS    2$
5$:        CLR        R2
        MOV        #20, R3
6$:        ASR        R4
        ROR        R5
        SUB        R5, R1
        SBC        R0
        SUB        R4, R0
        BMI        7$
8$:        SEC
        ROL        R2
        SOB        R3, 6$
        BR        9$

10$:    ASR        R4
        ROR        R5
        ADD        R5, R1
        ADC        R0
        ADD        R4, R0
        BPL        8$
7$:        CLC
        ROL        R2
        SOB        R3, 10$
        ADD        R5, R1
9$:        TST        (SP)+
        BPL        11$
        NEG        R1
11$:    ASR        (SP)+
        BCC        12$
        NEG        R2
12$:    CLR        R5
        MOV        R2, R0
        BPL        13$
        BIS        #10, R5           ;N
13$:    BNE        14$
        BIS        #4, R5           ;Z
14$:    JMP        EARX2$

3$:        MOV        #3, R5           ; флаги VC
        BR        15$

2$:        MOV        #2, R5           ; переполнение V
15$:    ADD        #10, SP           ; результат не сохраняется
        JMP        EARX3$

; ███████████████ S U B R O U T I N E ███████████████████████████████████████
;получаем R и число битов для сдвигаем
;выход: R2 = 0
;        R0 = R
;        R5 = счётчик сдвигов
;        Z - в счётчике 0
;        С - сдвиг вправо
SRCASH:    CLR        R2
        MOV        (R3), R0       ; значение R приёмника
        MOV        (R5), R5       ; значение источника
        BIT        #40, R5           ; смотрим знак
        BEQ        1$               ; +
        BIS        #177700, R5       ; - , устанавливаем биты
        NEG        R5               ; и меняем знак
        RETURN

1$:        BIC        #177700, R5       ; очищаем биты
        RETURN
; End of function SRCASH

; ───────────────────────────────────────────────────────────────────────────
;арифметический сдвиг R = R << ss / R = R >> ss
ASH$:    MOV        R3, 2(SP)       ; R+1 заменяем на R
        CALL    SRCASH           ; подготовка
        BEQ        1$               ; 0, не надо ничего двигать
        BCS        2$               ; двигать вправо
3$:        ASL        R0               ; двигаем влево
        BVC        4$
        INC        R2               ; а тут отмечаем возникновение бита V
4$:        SOB        R5, 3$           ; на заданное количество бит
        BR        1$

2$:        ASR        R0               ; двигаем вправо, тут переполнения не бывает
        SOB        R5, 2$           ; на заданное количество бит
1$:        MOV        R0, R1           ; результат дублируем и для R+1
        BR        EARX4$
; ───────────────────────────────────────────────────────────────────────────
;арифметический сдвиг R:R+1 = R:R+1 << ss / R:R+1 = R:R+1 >> ss
ASHC$:    MOV        (R4), R1       ; значение R+1 приёмника
        CALL    SRCASH           ; подготовка
        BEQ        EARX4$           ; 0, не надо ничего двигать
        BCS        1$               ; двигать вправо
2$:        ASL        R1               ; двигаем влево
        ROL        R0
        BVC        3$
        INC        R2               ; а тут отмечаем возникновение бита V
3$:        SOB        R5, 2$           ; на заданное количество бит
        BR        EARX4$

1$:        ASR        R0               ; двигаем вправо, тут переполнения не бывает
        ROR        R1
        SOB        R5, 1$           ; на заданное количество бит
        BR        EARX4$
; ───────────────────────────────────────────────────────────────────────────
; операция исключающее или.
; dd = dd xor R
XOR$:    CMP        (SP)+, (SP)+   ;типа игнорируется? могли бы и заэмулировать. это не так и трудно
        BR        EARX3$
; ───────────────────────────────────────────────────────────────────────────
; вход только для ASH/ASHC
; вход R0:R1 - результат
;        R5 - флаги
;        R2 - признак возникновения переполнения V
EARX4$:    ADC        R5               ; ставим флаг C, если было
        TST        R2
        BEQ        EARX1$
        BIS        #2, R5           ; ставим флаг V
; вход R0:R1 - результат
;        R5 - флаги
EARX1$:    TST        R0               ; смотрим знак результата
        BPL        1$               ; >= 0
        BIS        #10, R5           ; < 0 - ставим флаг N
1$:        BNE        EARX2$           ; идём туда
        TST        R1
        BNE        EARX2$
        BIS        #4, R5           ; если R0:R1 == 0, ставим флаг Z
EARX2$:    MOV        R0, @(SP)+       ; ст часть в R
        MOV        R1, @(SP)+       ; мл часть в R+1
EARX3$:    CMP        (SP)+, #15       ; если регистр источник был SP и адресация была автоинкрементная
        BEQ        2$               ; то переход
        CALL    RSTRS$           ; установим признаки из R5 и восстановим регистры
        RTI                       ; и выходим
; ───────────────────────────────────────────────────────────────────────────
2$:        CALL    RSTRS$           ; установим признаки из R5 и восстановим регистры
       ; для автоинкрементной адресации со стеком, аргумент источника был в стеке, поэтому
        MOV        2(SP), 4(SP)   ; сдвинем PS/PC на место аргумента
        MOV        (SP)+, (SP)       ; сделаем освобождение стека от аргумента
        RTI                       ; и выходим

; ───────────────────────────────────────────────────────────────────────────
        mov        #2000, R3   ;забытый, никому не нужный код
        call    INIT
        movb    R0, UNIT(R3)
        jmp        BOOTN
; ───────────────────────────────────────────────────────────────────────────
        .byte    377   ;простой мусор
        .byte    377
        .byte    377
        .byte    377
        .byte    377
        .byte    25
; ───────────────────────────────────────────────────────────────────────────
;начало отладчика
DBGBGN:    MOV        #1000, SP   ;стек в начальное значение
        MOV        PC, R0
        ADD        #DBGBGN-., R0
        MOV        R0, @#4       ;вектор 4 на начало себя
        MOV        #25012, R0   ;'.'<12>
        EMT        16           ;выведем перевод строки
        SWAB    R0
        EMT        16           ;выведем приглашение - '.'
DB1$:    CLR        R2
        CLR        R1

2$:        CALL    REPKEY       ;принимаем код
        EMT        16           ;выведем его
        CMPB    R0, #30       ;это забой?
        BNE        1$           ;нет
        TST        R2           ;число вводили?
        BEQ        DB1$       ;нет
        ASR        R2           ;да - одну цифру уберем
        ASR        R2
        ASR        R2
        BR        7$           ;и на экране тоже, но потом зачем-то в R2 херим всё число. смысл забоя непонятен
; ───────────────────────────────────────────────────────────────────────────
1$:        CMPB    R0, #'0       ;это не цифры?
        BLO        3$           ;нет
        CMPB    R0, #'7       ;точно не цифры?
        BHI        3$           ;точно нет
        INC        R1           ;а если все-таки да
        ASL        R2           ;то добавим цифру к числу
        ASL        R2
        ASL        R2
        BIC        #177770, R0
        ADD        R0, R2
        BR        2$
; ───────────────────────────────────────────────────────────────────────────
3$:        CMP        R0, #100   ;а это не буква?
        BLO        4$           ;нет
        BIC        #240, R0   ;да - сделаем из неё большую латинскую букву
       ;ну и дальше проверки на всякие отладочные команды
4$:        CMPB    R0, #'A       ;это команда А?
        BNE        5$           ;нет
        TST        R1           ;в R2 что-то есть?
        BEQ        6$           ;нету
        MOV        R2, R3       ;есть - его сохраним в R3
        BR        DB1$
; ───────────────────────────────────────────────────────────────────────────
6$:        MOV        #'=, R0       ;выведем текущий адрес
        EMT        16
        MOV        R3, R2
        CALL    OUT8       ;выведем содержимое R2
        MOV        #12, R0
7$:        EMT        16
        BR        DB1$
; ───────────────────────────────────────────────────────────────────────────
5$:        CMPB    R0, #'I       ;это команда I?
        BNE        8$
        TST        R1           ;в R2 что-то есть?
        BEQ        9$           ;нету
        MOV        R2, (R3)   ;есть - поместим его по адресу
        BR        DB1$
; ───────────────────────────────────────────────────────────────────────────
8$:        CMPB    R0, #',       ;это команда запятая?
        BNE        10$
        TST        R1           ;в R2 что-то есть?
        BEQ        11$
        MOV        R2, (R3)   ;есть - поместим его по адресу
11$:    TST        (R3)+       ;и переходим к следующему
9$:        MOV        (R3), R2   ;возьмем содержимое по адресу
        CALL    OUT8       ;и выведем его
        BR        DB1$
; ───────────────────────────────────────────────────────────────────────────
10$:    CMPB    R0, #'-       ;это команда минус?
        BNE        12$
        TST        R1           ;в R2 что-то есть?
        BEQ        13$
        MOV        R2, (R3)   ;есть - поместим его по адресу
13$:    TST        -(R3)       ;и переходим к предыдущему
        BR        9$
; ───────────────────────────────────────────────────────────────────────────
12$:    CMPB    R0, #'G       ;это команда G?
        BNE        DB2$
        TST        R1           ;в R2 что-то есть?
        BEQ        DB2$
        CALL    (R2)       ;есть - значит это адрес перехода, сходим по адресу
        BR        DB1$

; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; приём кода с клавиатуры с автоповтором
REPKEY:    MOV        #232, R0   ;переключение режима индикации курсора
        TSTB    @#56       ;курсор погашен?
        BEQ        1$           ;да
        EMT        16           ;нет - погасим
1$:        MOV        #4000, R0   ;небольшая задержка
        SOB        R0, .
        MOV        #20000, R0
2$:        BIT        #100, @#177716   ;клавиша нажата?
        BNE        3$           ;нет
        TSTB    @#2           ;нажата, задержку делать?
        BNE        4$           ;нет
        SOB        R0, 2$       ;да - чуть задержимся
        INCB    @#2           ;и больше задержку делать не надо
4$:        MOV        @#104, R0   ;вернем код последнего нажатого символа
        RETURN

3$:        EMT        6           ;клавиша не нажата - ждем принятия кода
        CLRB    @#2           ;установим флаг, что надо будет сделать задержку
        RETURN
; End of function REPKEY

; ███████████████ S U B R O U T I N E ███████████████████████████████████████
;вывод числа из R2, с уничтожением содержимого
OUT8:    MOV        #6, R4
        CLR        R0
1$:        ASL        R2
        ROL        R0
        ADD        #'0, R0
        EMT        16
        CLR        R0
        ASL        R2
        ROL        R0
        ASL        R2
        ROL        R0
        SOB        R4, 1$
        MOVB    #40, R0
        EMT        16
        RETURN
; End of function OUT8

; ───────────────────────────────────────────────────────────────────────────
;продолжение отладчика
DB2$:    CMPB    R0, #'K       ;это команда K?
        BNE        1$
        JMP        @#100274   ;да - выход в монитор
; ───────────────────────────────────────────────────────────────────────────
1$:        CMPB    R0, #'B       ;это команда B?
        BNE        2$
        CALL    @#START       ;да - загрузимся с дисковода
        MOV        #'?, R0       ;не смогли загрузиться
        EMT        16           ;выведем
        CLR        R2
        BISB    @#ERRFDD, R2   ;код ошибки
        CALL    OUT8
        JMP        DBGBGN       ;и начнем все сначала
; ───────────────────────────────────────────────────────────────────────────
2$:        CMPB    R0, #'L       ;это команда L?
        BNE        3$
        MOV        PC, R1
        ADD        #AA-., R1   ;спросим адрес
        CLR        R2
        EMT        20
        CALL    @#100472   ; ввод восьмеричного числа с клавиатуры(коды меньше 60 и больше 67 не учитываются, число в R5)
        BR        5$
; ───────────────────────────────────────────────────────────────────────────
        .BYTE    0
        .BYTE    0
AA:        .ASCIZ    <12>"A= "
        .ASCIZ    <12>"L= "
        .EVEN
; ───────────────────────────────────────────────────────────────────────────
3$:        CMPB    #'S, R0           ;это команда S?
        BEQ        4$
        JMP        DB5$
; ───────────────────────────────────────────────────────────────────────────
4$:        MOV        PC, R1           ;да - спросим адрес
        SUB        #-AA+., R1
        CLR        R2
        EMT        20
        MOV        R1, -(SP)
        CALL    @#100472       ; ввод восьмеричного числа с клавиатуры(коды меньше 60 и больше 67 не учитываются, число в R5)
        MOV        R5, @#322
        MOV        (SP)+, R1       ;спросим длину
        CLR        R2
        EMT        20
        CALL    @#100472
        MOV        R5, @#324       ;заполняем блок параметров
        MOV        #2, @#320
        MOV        #326, R1
        BR        DB4$           ;и идем записывать
; ───────────────────────────────────────────────────────────────────────────
        BR        DB3$           ;бесполезная команда
; ───────────────────────────────────────────────────────────────────────────
5$:        CALL    @#100536       ; загрузка с магнитофона
DB3$:    JMP        DBGBGN
; ───────────────────────────────────────────────────────────────────────────
DBGTTL:    .ASCIZ "DEBUG MODE,H = HELP!"<12>
        .EVEN
; ───────────────────────────────────────────────────────────────────────────
;отладчик
DEBUGR:    MOV        PC, R1           ;выведем сообщение, что мы в отладчике
        SUB        #-DBGTTL+., R1
        CLR        R2
        EMT        20               ;внезапно только для БК10
        JMP        DBGBGN           ; ну и поёдем отлаживать
; ───────────────────────────────────────────────────────────────────────────
DB4$:    CALL    @#100552       ; операции с магнитофоном
        BR        DB3$
; ───────────────────────────────────────────────────────────────────────────
DBGHLP:    .ASCIZ    <12>"B A L S G , K"<12>
        .EVEN
; ───────────────────────────────────────────────────────────────────────────
DB5$:    CMPB    #'H, R0           ;это команда H?
        BEQ        DB6$           ;да - пойдем выведем справку
        JMP        DB1$           ;а если нет - начинай все сначала
; ───────────────────────────────────────────────────────────────────────────
        .WORD    0               ;впустую потраченное слово
; ───────────────────────────────────────────────────────────────────────────
JL5$:    CMPB    @#177717, #300   ;это БК11(М)?
        BNE        JL9$           ;нет, это БК10
        MOV        R0, -(SP)       ;сохраним номер привода, с которого надо загружаться
        MOV        #FDDTTL, R0       ;начало текста
        CMP        @#156616, #45440   ;это БК11?
        BEQ        JL8$           ;да - выведем текст по БК11цатишьи
        EMT        64               ;нет - это БК11М - выводим текст по БК11цатиМшьи
JL7$:    MOV        (SP)+, R0       ;восстановим номер привода
JL2$:    JMP        JL6$           ;пойдем загружаться с приводов

JL8$:    EMT        20               ;выводим текст по БК11цатишьи
JL11$:    BR        JL7$

JL9$:    MOV        R0, -(SP)       ;для БК10 текст выводится вот так
        MOV        #FDDTTL+1, R1   ;начало текста
        CLR        R2
        EMT        20               ;выведем текст по БК10тишьи
        BR        JL10$           ;и пойдем добавим перевод строки еще
; ───────────────────────────────────────────────────────────────────────────
        .BYTE    0
FDDTTL:    .ASCIZ    <15><12>"FDD/HDD BIOS 327 V12 (c) JD/DWG!"
        .EVEN
; ───────────────────────────────────────────────────────────────────────────
JL1$:    BIT        @#177712, #20   ; таймер уже работает?
        BNE        JL2$           ; да - пойдем дальше
        CMP        @#177706, #-1   ; значение инициализации таймера -1? (подразумевается, что оно выставляется при инициализации проца)
        BNE        JL3$           ; нет - сходим-ка туда

JL4$:    MOV        #160, @#177712   ; включаем таймер
        BR        JL5$           ; и пойдем выводить текст о себе

; П/п загрузки которая кроме загрузки делает разные другие действия
; а так же бессмысленно скачет туда-сюда с целью запутать исследователя.
; Либо авторы просто не знали про существование ассемблеров
BOOT:    MOV        #160000, R1       ; посчитаем контрольную сумму драйвера
        MOV        #BOOT-START-2, R2
        ASR        R2
        CLR        R3
1$:        ADD        (R1)+, R3
        ADC        R3
        SOB        R2, 1$
        CMP        R3, #145566       ;если вот такая
        BEQ        JL1$           ; - значит всё хорошо
        .WORD    177777           ;иначе - вот вам. получите враги народа
; ───────────────────────────────────────────────────────────────────────────
; непонятно зачем вклинившийся сюда кусок отладчика
DB6$:    MOV        #DBGHLP, R1       ; "\nB A L S G , K\n"
        CLR        R2
        EMT        20               ;выведем справку по командам отладчика
        JMP        DB1$
; ───────────────────────────────────────────────────────────────────────────
        .WORD    0               ;еще одно впустую потраченное слово
; ───────────────────────────────────────────────────────────────────────────
;попадая сюда, R0 == 0
JL6$:    CALL    BOOTC       ;пробуем загрузиться с привода 0
        MOV        #1, R0       ;потом попробуем с привода 1
        CALL    BOOTC
        MOV        #2, R0       ;потом - с привода 2
        JMP        BOOTC
; ───────────────────────────────────────────────────────────────────────────
        .WORD    0           ;просто лишнее слово
; ───────────────────────────────────────────────────────────────────────────
JL10$:    MOV        #12, R0       ;выведем
        EMT        16           ;перевод строки
        BR        JL11$
; ───────────────────────────────────────────────────────────────────────────
; запускаем прочитанный загрузчик
RUNLDR:    MOV        #1000, SP   ; Установим стек
        CALL    @#1000       ; Запускаем загрузчик
        HALT               ; останов, если загрузчик вместо того, чтобы дальше работать, вернулся сюда

; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; кусок п/п SETPTR: - настройки указателя FLGPTR
SETPT1:    BIC        #177774, FLGPTR(R3)       ; Отбросим лишние биты
        ADD        R3, FLGPTR(R3)           ; Прибавим базовый адрес FLGTAB
        RETURN
; ───────────────────────────────────────────────────────────────────────────
JL3$:    CMP        @#177710, #-1       ; а значение таймера -1?
        BEQ        JL4$               ; да - пойдем включим таймер, а потом выведем текст
        CMP        @#177710, #60000   ; а может, значение такое
        BHI        JL4$               ; если больше, пойдем включать таймер, а потом выведем текст
        MOV        #160, @#177712       ;иначе всё равно включим таймер
        BR        JL2$               ;но совершим хитрый кульбит, в результате которого продолжим загрузку

        .END







--------------------
Живы будем - Не помрем !
Пользователь в онлайне!Карточка пользователяОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
SuperMax
сообщение 20.6.2022, 21:40
Сообщение #4


Администратор
*****

Группа: Root Admin
Сообщений: 6 282
Регистрация: 7.1.2006
Из: Красноярск
Пользователь №: 1



тоже но файлом

Прикрепленный файл  326v12.asm ( 110.89 килобайт ) Кол-во скачиваний: 206



--------------------
Живы будем - Не помрем !
Пользователь в онлайне!Карточка пользователяОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения

Ответить в эту темуОткрыть новую тему
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 



Текстовая версия Сейчас: 28.3.2024, 18:47