Исходники ПЗУ: КНГМД 326ая прошивка ПЗУ |
Здравствуйте, гость ( Вход | Регистрация )
Исходники ПЗУ: КНГМД 326ая прошивка ПЗУ |
SuperMax |
20.6.2022, 17:53
Сообщение
#1
|
Администратор Группа: Root Admin Сообщений: 6 295 Регистрация: 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 295 Регистрация: 7.1.2006 Из: Красноярск Пользователь №: 1 |
-------------------- Живы будем - Не помрем !
|
SuperMax |
20.6.2022, 21:39
Сообщение
#3
|
Администратор Группа: Root Admin Сообщений: 6 295 Регистрация: 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 295 Регистрация: 7.1.2006 Из: Красноярск Пользователь №: 1 |
-------------------- Живы будем - Не помрем !
|
Текстовая версия | Сейчас: 26.9.2024, 19:01 |