;целевой ассемблер: BK Turbo8 Cross Assembler

;Доработанный тест контроллеров АльтПро с ДОЗУ 64-512КБ. Версия 4.76F
;Изменения и нововведения в v4.1:
;* Тест памяти определяет только её количество, и корректность байтового доступа.
;* Тест режимов работает и на БК-0010(01), и на БК-0011М, вывод результатов теста режимов сделан более
;  человекопонятным.
;* Определяется тип контроллера по признаку в слове 0167776.
;Изменения и нововведения в v4.3:
;* Изменён тест определения количества памяти.
;* Добавлен тест проверки на битые ячейки памяти.
;Изменения и нововведения в v4.41:
;* Тест режимов перенесён вперёд, перед тестом памяти.
;* Добавлен свой знакогенератор, чтобы не зависеть от мониторов БК10 и БК11.
;* Добавлено определение версии прошивки 555РТ5.
;* v4.41 - попытка исправить ошибки скроллинга.
;Изменения и нововведения в v4.51:
;* Добавлен тест переключения страниц в проблемных режимах.
;* При заполнении экрана информацией выводится сообщение "нажмите любую клавишу" и программа
;  ожидает нажатия любой клавиши, кроме СТОП и управляющих естественно.
;* v4.51 - Иногда, в нештатных случаях могли возникнуть ситуации, когда регистр 177130 на БК-0010
;  накладывался на ПЗУ бейсика и это приводило к неправильной работе теста. Теперь это исправлено,
;  возникающее прерывание по вектору 4 при записи в 177130 теперь игнорируется.
;Изменения и нововведения в v4.72F:
;* Добавлены тесты конструктивных особенностей: доступ к регистрам HDD, тест буфера ОЗУ для HDD,
;  реакция на команду RESET, реакция на биты 2 (код 4) и 3 (код 10)
;* v4.71 - уточнение реакции на биты 2 и 3.
;* v4.72 - ещё одно уточнение реакции на биты 2 и 3.
;Изменения и нововведения в v4.73F:
;* Тест памяти на ошибки немного усложнён.
;Изменения и нововведения в v4.74F:
;* Тест памяти на ошибки изменён. Добавлено длинное тестирование случайными числами, 
;  с целью проверки стабильности, длительность длинного тестирования можно задать свою,
;  а так же совсем отменить. 
;Изменения и нововведения в v4.75F:
;* номера сегментов теперь 0..7, а не 10..17
;* сообщения об ошибках теста режима уточнены
;* тест блокировки битом 2 регистров 177130, 177132 усложнён
;* тест подключения ПЗУ бейсика на БК 10 битом 3 уточнён
;* тест теперь полностью самостоятелен. и не нуждается ни в какой ОС и никаком мониторе.
;  Версия v4.74F всё же требовала в начале монитор БК10.
;* изменён вывод контрольной суммы ПЗУ, теперь вместо слова KDJN выводится обычное 16-ричное
;  число A39D
;* исходник переписан под кросс ассемблер
;Изменения и нововведения в v4.76F:
;* В проверке теста режимов в выводе на экран различаются первая и вторая части сегмента 7
;* В тесте подсчёта кол-ва ОЗУ и ошибок страниц переделан вывод текста на экран.
;Изменения и нововведения в v4.77F:
;* Отображаем на экране реплика СМК или нет.
;* Исправлена ошибка для теста режимов реплики СМК и оригинала


SYNCW   = 55000 ; значение синхронизации. Контрольное слово, которое записывается в ячейку
                ; памяти, и ожидается, что при чтении будет именно оно.

OFSF8   = 400   ; смещение в шрифте

; системные ячейки знакогенератора
SCRCRD  = 160   ; Абсолютный адрес курсора в ОЗУ экрана
SCRY    = 156   ; Y координата, для рулонного сдвига
SCRFNT  = 166   ; адрес начала шрифта
SCRLNC  = 164   ; счётчик строк

StdMode = 400   ; ячейка, где хранится код стандартного режима и признак БК10/11
RAMBGN  = 402   ; ячейка, где хранится адрес начала ОЗУ для БК10/11
SCR_INI = 404   ; ячейка больше не используется
V4BUF   = 406   ; ячейка, где хранится оригинальное значение вектора 4
CurrentMode = 410   ; буфер хранения текущего режима работы контроллера
LNGTST  = 412   ; ячейка, где хранится длительность длинного тестирования

;-------переменные--
TZADDR  = 420   ; приходится вводить переменную, т.к. хитрый тест режимов проверяет 07 сегмент дважды
TZMODE  = 422
TRCODE  = 424
VALUE1  = 426   ; временная многофункциональная переменная
AltProDev = 430 ; флаг детектирования контроллера АльтПро 0 - норма, >0 - не обнаружен <0 - неверное ПЗУ
SMKHDD  = 431   ; флаг наличия регистров HDD
ERCOD   = 432
ERT31   = 434

DECBUF  = 600   ; буфер ввода десятичного числа

Begin:          mov     #100, @#177660      ; запрещаем прерывания от клавиатуры
                mtps    #340
                mov     #4, R4
                mov     (R4), @#V4BUF       ; сохраним текущий вектор 4, потом заменим его
                                            ; своими данными
                mov     #PZP1, (R4)+        ; тест 10/11
                mfps    (R4)                ; чтобы не терять приоритет
                mov     #177716, R5
                mov     #StdMode, R2
                mov     #60, (R2)           ; код рабочего режима БК10
                mov     #42400, @#177662    ; белая палитра, тут на 10-ке случается прер. по вектору 4
                mov     #100140, (R2)       ; признак и код рабочего режима БК11
                mov     #16000, (R5)        ; страницы ANDOS
PZP1:           clr     R1
                mov     (PC), R0            ; почувствовать клавиатуру на 6 МГц: > 40000 SOB
                mov     #177130, R3
04$:            mov     R4, (R3)            ; R4 == строб 6
                movb    (PC), (R5)          ; звук (#200)
                mov     (R2), (R3)          ; стандартный режим
                mov     R1, (R3)            ; строб 0
                movb    (PC), (R5)          ; звук (#300)
                mov     #Begin, SP
                sob     R0, 04$

; инициализация
Tests:          mov     #DISTRP, @#34
                mfps    @#36
                trap    0                   ; инициализация экрана
                trap    40                  ; включение стандартного режима с учётом типа БК
                call    SetMemTestLen

                mov     #100, @#177660      ; запрещаем прерывания от клавиатуры
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrTitle
                call    DETECT
                tstb    @#AltProDev
                beq     MemTest1            ; если после детекта найден контроллер АльтПро
                bmi     MemTest1            ; если прошивка РТ5 не правильная, тоже тесты проведём, но мы предупреждали.
                jmp     StopTests           ; иначе тестов памяти делать не будем.
; тесты памяти

; обработка halt для этапа MemTest1
TT4MemTest1:    bis     R3, PageErrors(R5)
; обработка halt для теста режимов
TT4All:         add     #4, (SP)
                rti

; этап1
; 1. пробуем все 32 кода страниц независимо от кол-ва памяти, для каждой страницы заполняем массив PageErrors
MemTest1:       trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrPrepare
                clr     R5                  ; индекс в массиве PageErrors и RamCodTable
                mov     #TT4MemTest1, @#4
                mov     #123456, R4
                br      0TR3$

0TR2$:          tst     (R5)+
0TR3$:          clr     PageErrors(R5)
                mov     @#RAMBGN, R2
                mov     RamCodTable(R5), R1 ; берём очередной код
                beq     0MemTest2$          ; 0 - конец.
                mov     #'., R0
                trap    16                  ; вывод символа на экран. Вход: R0 - код символа
                mov     R1, R0              ; устанавливаем нужную страницу
                trap    2                   ; включение режима с учётом типа БК, вход: R0 - код режима
                mov     R0, R1              ; сохраним исправленный код с учётом типа БК
                ; проверим, а не подключали ли мы эту страницу ранее
                mov     #1, R3              ; это признак, когда случился halt, 1 - не было чтения
                mov     R2, R0
                ; проверим, а не подключали ли ранее
                cmp     (R0)+, R4           ; если нет чтения, тут будет halt ---+
                beq     1$                  ;                                    |
                nop                         ;                                    |
                inc     R3                  ; 2 - не было записи <- сюда --------+
                mov     R4, (R2)+           ; если нет записи, тут будет halt ---+
                br      2$                  ;                                    |
                nop                         ;                                    |
                br      0TR2$               ; <- сюда ---------------------------+
                ; записать в первое слово смогли, теперь проверим остальные
2$:             mov     #17777, R0          ; всю страницу заполним кодом страницы
3$:             mov     R1, (R2)+           ; тут будет halt ----+
                sob     R0, 3$              ;                    |
                br      4$                  ;                    |
                br      0TR2$               ; <- сюда -----------+

4$:             ; сюда попадаем если не было halta ни при чтении, ни при записи во всей странице.
                ; проведём байт тест
                mov     R4, R2
                mov     R2, (R2)            ; допустим, произошёл halt --+
                nop                         ;                            |
                br      8$                  ;                            |
                br      9$                  ; < - сюда ------------------+

8$:             movb    R2, 1(R2)           ; допустим, произошёл halt --+
                nop                         ;                            |
                br      10$                 ;                            |
                br      9$                  ; < - сюда ------------------+

10$:            cmp     #27056, (R2)        ; а здесь halt перейдёт туда ------------+
                beq     0TR2$               ; байт тест удачно пройден               |
                nop                         ; байт тест провален                     |
9$:             bis     #10, PageErrors(R5) ; признак ошибки байт теста < - сюда ----+
                br      0TR2$

1$:             bis     #100000, PageErrors(R5)  ; признак, что страницу уже подключали
                br      0TR2$

0MemTest2$:
                ; этап2
                call    MemTest2            ; 2. подсчитываем доступное кол-во ОЗУ

; промежуточные дополнительные тесты
                call    TestHDDRegs         ; тест доступности регистров HDD по чтению/записи
                call    TestHDDRAM          ; тест ОЗУ, выделенного под буфер HDD
                call    TestBit2            ; тест влияния бита 2
                call    TestBit3            ; тест влияния бита 3
                call    TestReset           ; тест влияния команды RESET

; Тут какой-то непонятный феномен. Если TestReset выполняется перед TestBit2, то
; на реальной БК и СМК перестаёт выдавать корректные результаты тест режимов.
; а в эмуляторе всё работает. В чём косяк, где ошибка в эмуляторе пока не выяснено.
; тест режимов
TREZ:           clr     @#VALUE1
                call    MEMTS4              ; заполняем память синхрокодом
                mov     #7, ZN
                trap    40                  ; включение стандартного режима с учётом типа БК
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TRZINF
                clr     @#ERCOD
                cmpb    @#167777, #374
                blo     1$                  ; если А16, то не проверять HDD ОЗУ
                cmpb    @#167776, #300
                bhis    1$                  ; если А64+, то тоже не проверять HDD ОЗУ
                mov     #240, SMKCON        ; для контроллеров SMK там NOP
1$:             mov     #AltProModes, R5
                mov     TZCODS, R4
                mov     #SYNCW, R2
                mov     #TT4All, @#4
                mov     #277, -(SP)         ; 8 реж. * 8 банков

Z1:             mov     @#StdMode, R0
                bpl     10$
                ; для БК11М, надо включать стандартный режим,
                trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                mov     #100000, R1         ; чтобы
                mov     #20000, R0          ; чистить верхнее ОЗУ, чтобы гарантированно отличить его от 
12$:            clr     (R1)+               ; ДОЗУ
                sob     R0, 12$             ; это нужно делать каждый раз при смене режима
10$:            movb    (R5), R1            ; выводим код режима.
                trap    24                  ; вывод восьмеричного 4-х значного числа из R1, без подавления ведущих нулей
                mov     #':, R0
                trap    16                  ; вывод символа на экран. Вход: R0 - код символа
                clr     @#VALUE1
                mov     #100172, R3         ; начальный адрес для проверки
Z2:             mov     R3, @#TZADDR
                mov     #1003, ZC           ; BNE 3$ = норм.!!!
                movb    (R5), R0            ; очередной режим
                bne     7$                  ; привязка к коду режима !!!
                tst     @#StdMode
                bmi     7$                  ; если БК11 - не надо никаких привязок
                cmp     R3, #120000
                bhis    7$                  ; ПЗУ мон.БК10 может не отключаться:
                mov     #240, ZC            ; ПЗУ есть = нет: != == halt
7$:             mov     R0, @#TZMODE        ; режим для вывода на экран
                trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                cmp     R3, #177172
                beq     2$
                incb    (SP)
                beq     ZE
2$:             clr     R0                  ; тут накапливается код результата теста
                cmp     R2, (R3)            ; тестируем, есть ли доступ по чтению
ZC:             bne     3$
                beq     4$
                cmp     (R0)+, (R0)+        ; <-halt сюда для cmp
4$:             cmp     (R0)+, (R0)+
                ; здесь R0 == 0, 4, 010 при !=, =, halt
3$:             mov     R3, (R3)            ; тестируем, есть ли доступ по записи
                cmp     R2, (R3)            ; тестируем, работает ли запись как надо
                beq     6$                  ; если запись прошла, но по чтению все равно изначальный вариант
                nop                         ; <-halt сюда для mov
                mov     R2, (R3)            ; <-halt сюда для cmp
                cmp     R2, (R3)
                br      5$
                br      1$                  ; <-halt сюда для mov
5$:             bne     6$                  ; <-halt сюда для cmp - !=
                inc     R0                  ; write
6$:             inc     R0                  ; nowr 
1$:             cmp     R0, #11             ; для HALT-ОЗУ: R0=11->10
                bne     7$                  ; -
                cmpb    (SP), #327          ; это у нас сегмент 177000 в режиме 120?
                bne     7$                  ; нет
                dec     R0                  ; да, для старой версии прошивки подменяем код с ОЗУзч на ПУСТО
7$:             cmpb    (SP), #366          ; а тут смотрим - это сегмент 160000 в режиме 100?
                bne     SMKCON              ; нет
                cmp     R0, #4              ; да, а схема старая?
                bne     SMKCON              ; нет, новая
                tst     (R0)+               ; для старой подменяем код ОЗУзз на ОЗУ
SMKCON:         br      0$
                cmp     R3, #170172
                bne     0$
                cmpb    (SP), #307          ; в режиме 160 в сегменте 170000 везде ПЗУ
                beq     0$                  ; так что нет нужды проверять его дважды.
                sub     #1000, R3           ; вот поэтому то у нас и проверяется 2 раза сегмент 17
                mov     #6, R1              ; в сегменте 170000 в диапазоне 170000-176777 - всегда ОЗУ
                br      3$                  ; должно быть

0$:             movb    (R4)+, R1
3$:             cmpb    R0, R1
                beq     2$
                movb    R0, @#TRCODE        ; то, что есть - в мл.байт
                movb    R1, @#TRCODE+1      ; то, что должно быть - в ст.байт
                call    TRERR
                inc     @#VALUE1
                inc     @#ERCOD
2$:             add     #10000, R3
                bmi     Z2
                inc     R5
                tst     @#VALUE1
                bne     8$
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TROK
8$:             trap    12                  ; перевод строки. выход: R0 - код 12
                dec     (PC)+
ZN:             .word   7                   ; всего 8 режимов
                bpl     Z1
ZE:             tst     @#ERCOD
                beq     11$
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   ERINFO
11$:
; тест режимов 2
; проведём тесты переключения между режимами (20 и 100) и (20 и 0)
; по типу синхротеста.
TREZ2:          trap    40                  ; включение стандартного режима с учётом типа БК
                cmpb    @#167777, #374
                blo     MEMTS3              ; если А16, то пропустить тест
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TRSWPG
                mov     #TRST31, @#4
                mov     #SWREZ, R4
0$:             mov     R4, -(SP)
                call    MEMTS4              ; заполняем синхротест
                mov     (SP)+, R4
                movb    (R4)+, R0           ; берём первый режим
                tstb    (R4)
                bmi     MEMTS3
                mov     R0, R1              ; включаем
                trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                trap    24                  ; вывод восьмеричного 4-х значного числа из R1, без подавления ведущих нулей
                mov     #"->, R0
                trap    16                  ; вывод символа на экран. Вход: R0 - код символа
                swab    R0
                trap    16                  ; вывод символа на экран. Вход: R0 - код символа
                movb    (R4), R0            ; берём режим, на который переключаемся
                mov     R0, @#TZMODE
                mov     R0, R1              ; включаем
                trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                trap    24                  ; вывод восьмеричного 4-х значного числа из R1, без подавления ведущих нулей
                trap    12                  ; перевод строки. выход: R0 - код 12
                tst     R1
                bne     1$
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TRSKIP
                br      0$

1$:             mov     @#RAMBGN, R2
                mov     #20000, R5
                call    SYNCTS              ; синхротест
                trap    12                  ; перевод строки. выход: R0 - код 12
                br      0$
; этап 3
; 3. тестируем на сбойность доступное кол-во ОЗУ
; с подробным выводом каждого сбоя в таком виде:
; код - маска адрес:сбойные биты
MEMTS3:         call    MEMTS4
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TZERRS
                mov     #MEMTST, R4
                call    MEMSSS
                call    MEMTS4
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TZEST2
                mov     #MEMTSU, R4
                call    MEMSSS
                sob     R3, .
                sob     R3, .
                sob     R3, .
                sob     R3, .
; проверка контрольной суммы.
CRCCHK:         trap    40                  ; включение стандартного режима с учётом типа БК
                mov     #4, R4
                mov     #StopTests, (R4)
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   CRCINF
                trap    6                   ; ввод кода с клавиатуры. выход: R0 - код
                trap    20                  ; вывод следующего asciz
                call    CRC                 ; считаем crc
                mov     R0, R5              ; и преобразуем его в hex-текст
2$:             mov     #4, R1
                clr     R2
1$:             rol     R0
                rol     R2
                sob     R1, 1$
                add     #'0, R2
                cmp     R2, #'0 + 10.
                blo     6$
                add     #'A - '0 - 10., R2
6$:             movb    R2, (R3)+
                sob     R4, 2$
                cmp     -(R3), -(R3)        ; и выведем его на экран
                trap    20                  ; вывод строки символов. Вход: R3 - адрес строки
3$:             mov     #10., R4
4$:             call    CRC
                cmp     R5, R0
                bne     5$
                sob     R4, 4$
                trap    20                  ; вывод строки символов. Вход: R3 - адрес строки
                tst     -(R3)
                br      3$

5$:             clr     R0
                call    ERRR0
                sob     R0, .
                br      3$


; --------------------------------------------
; этап2

; 2. подсчитываем доступное кол-во ОЗУ
;   для каждой модели имеется набор ожидаемых кодов страниц.
;   выводим на экран ошибки только из этого набора
MemTest2:       trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrDOZU
                clr     R5                  ; индекс в массиве PageErrors и RamCodTable
                clr     R1                  ; счётчик доп. ОЗУ
                clr     R4                  ; флаг наличия ошибок
0NEXT$:         mov     RamCodTable(R5), R0 ; берём очередной код
                beq     0END$               ; если коды кончились - выход
                trap    22                  ; вывод на экран десятичного числа с подавлением ведущих нулей. вход:  R1 - число
                mov     #5, R2              ; курсор просто влево.
                trap    14                  ; двигаем курсор на заданное количество раз влево, вход: R2 - количество раз
                mov     PageErrors(R5), R0  ; код ошибки
                bis     R0, R4              ; набираем статистику ошибок
                tst     R0                  ; если страница была подключена ранее
                bmi     1$                  ; то страницу не считаем.
                add     #16., R1            ; увеличим счётчик кб
1$:             tst     (R5)+               ; перемещаемся дальше по таблице
                cmp     R5, EndRamCod       ; для заданной модели контроллера таблица кончилась?
                blo     0NEXT$              ; если нет - продолжим
                ; выведем конечное кол-во ОЗУ
0END$:          trap    22                  ; вывод на экран десятичного числа с подавлением ведущих нулей. вход:  R1 - число
                trap    12                  ; перевод строки.
                tst     R4                  ; ошибки страниц были?
                bne     1Tst2St2$           ; да - будем выводить.
                return

; TODO: улучшить понятность вывода на экран.
; тут надо  вместо кодов подключения выводить что-то типа
; первая половина стр N, вторая половина стр N, 

; обработка halt для этапа MemTest2
TT4MemTest2:    bit     (SP)+, (SP)+        ; корректируем стек
                clr     R1                  ; признак случившегося trap to 4
                br      1HLT$
1Tst2St2$:      trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrPgErr
                mov     #TT4MemTest2, @#4
                clr     R5                  ; индекс в массиве PageErrors и RamCodTable
1NEXT$:         mov     RamCodTable(R5), R1 ; берём очередной код
                beq     1END$               ; если коды кончились - выход
                mov     PageErrors(R5), R4  ; проблемы с этой страницей были?
                beq     3$                  ; нет.
                ; !!! тут надо вывести номер страницы, если у неё были проблемы.
                trap    24                  ; вывод восьмеричного 4-х значного числа из R1, без подавления ведущих нулей
                mov     #':, R0
                trap    16
                tst     R4
                bpl     1$
                ; эту страницу уже подключали
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrPageAlrUse
                mov     R1, R0
                trap    2                   ; включение режима с учётом типа БК, вход: R0 - код режима
                mov     @#RAMBGN, R1
                mov     2(R1), R1           ; код страницы, с которой уже подключали.
                                            ; тут и только тут может случиться tpap to 4
                                            ; если он случался на прошлом этапе
1HLT$:          trap    24                  ; вывод восьмеричного 4-х значного числа из R1, без подавления ведущих нулей
                br      2NEXT$

1$:             bit     #1, R4
                beq     2$
                ; не было чтения
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrRead
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrHalt
2$:             bit     #2, R4
                beq     7$
                ; не было записи
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrWrite
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrHalt
7$:             bit     #10, R4
                beq     2NEXT$
                ; не пройден байт-тест
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrByteFail

2NEXT$:         trap    12                  ; перевод строки
3$:             tst     (R5)+               ; перемещаемся дальше по таблице
                cmp     R5, EndRamCod       ; для заданной модели контроллера таблица кончилась?
                blo     1NEXT$              ; если нет - продолжим
1END$:          return

; тест доступности регистров HDD
TestHDDRegs:    trap    40                  ; включение стандартного режима с учётом типа БК
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrTHDInfo1
                tstb    @#SMKHDD
                bne     0OK$
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrTHDDError
                return

0OK$:           mov     #TT4All, @#4
                mov     #HDDRegsTable, R5   ; таблица регистров HDD
                mov     #377, R4
04$:            mov     (R5)+, R1           ; берём регистр
                beq     0EX$                ; закончились - выход
                trap    10                  ; вывод восьмеричного числа из R1, с подавлением ведущих нулей
                mov     #": , R0
                trap    16                  ; вывод символа на экран. Вход: R0 - код символа
                swab    R0
                trap    16                  ; вывод символа на экран. Вход: R0 - код символа
                mov     #StrHDDRegNoWrt, R3
                mov     R4, (R1)            ; если нет записи, тут будет halt ---+
                br      00$                 ; запись есть                        |
                nop                         ;                                   |
                br      01$                 ; записи нет              <-- сюда --+

00$:            tst     (R3)+
01$:            trap    20                  ; вывод строки символов. Вход: R3 - адрес строки
                mov     #StrHDDRegNoRead, R3
                cmp     (R1), R4            ; если нет чтения, тут будет halt ---+
                br      02$                 ; чтение есть                        |
                nop                         ;                                   |
                br      03$                 ; чтения нет              <-- сюда --+

02$:            tst     (R3)+
03$:            trap    20                  ; вывод строки символов. Вход: R3 - адрес строки
                br      04$

0EX$:           return


; тест ОЗУ, выделенного под буфер HDD
TestHDDRAM:     trap    40                  ; включение стандартного режима с учётом типа БК
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrTHDInfo2
                tstb    @#SMKHDD
                bne     0OK$
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrTHDDError
                return
; подготовим контрольный массив
0OK$:           mov     #30000, R5          ; адрес начала массива
                mov     #3400, R4           ; размер массива в словах
                mov     R5, R1
                mov     R4, R2
                mov     #123456, R0
                mov     #65432, R3
2$:             mov     R0, (R1)+
                xor     R0, R3
                rol     R3
                ror     R0
                adc     R3
                bcc     1$
                swab    R0
1$:             rol     R3
                ror     R0
                adc     R3
                bcc     0$
                swab    R3
0$:             add     R3, R0
                sob     R2, 2$
; посчитаем его CRC
; и заодно скопируем в буфер ОЗУ HDD
                mov     #TT4TestHDDRAM, @#4
                mov     R5, R1
                mov     R4, R2
                mov     #170000, R3
                clr     R0
3$:             mov     (R1), (R3)+
                add     (R1)+, R0
                adc     R0
                sob     R2, 3$
                mov     R0, R5
                mov     #160, R0
                trap    4               ; включение режима без учёта типа БК, вход: R0 - код режима
                sob     R2, .           ; пауза
                trap    40              ; включение стандартного режима с учётом типа БК
                mov     #170000, R1
                mov     R4, R2
                clr     R0
4$:             add     (R1)+, R0
                adc     R0
                sob     R2, 4$
                mov     #StrTHROK, R3
                cmp     R0, R5
                beq     5$
                mov     #StrTHRError, R3
                br      5$

TT4TestHDDRAM:  bit     (SP)+, (SP)+
                mov     #StrTHRAMNone, R3
5$:             trap    20              ; вывод строки символов. Вход: R3 - адрес строки
                return

; ----------------------------------------------------------------------------
; тест влияния бита 2
; код 4 блокирует регистры по чтению.
TestBit2:       trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrTstBit2Info
                call    MEMFIL              ; заполним память синхрокодом.
                mov     #TT4TstBit2, @#4
                mov     #AltProModes+1, R5  ; таблица режимов контроллера
                                            ; режим 160 не будем проверять
4$:             movb    (R5)+, R1           ; проверим во всех режимах
                bmi     0$                  ; режимы кончились
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrMode
                trap    24                  ; вывод восьмеричного 4-х значного числа из R1, без подавления ведущих нулей
                mov     #':, R0
                trap    16
                trap    12
                mov     R1, R0
                clr     R4                  ; тут будет формироваться результат теста
                trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                mov     #2, R3
                mov     #177130, R1
                mov     #4, (R1)            ; блокируем регистры по чтению
1$:             mov     (R1)+, R2           ; читаем 177130, если не получится, halt ---+
                br      0next$              ; Что-то прочлось                           |
                br      0Ok$                ;                               <-- сюда --+

0next$:         cmp     R2, #SYNCW          ; если прочёлся синхрокод 
                beq     0Ok$                ; то тоже нормально
                incb    R4
0Ok$:           swab    R4
                sob     R3, 1$              ; дальше прочитаем 177132
                ; теперь в R4 в мл байте - результат чтения 177130, в старшем - 177132
                ; если 0 - то всё в порядке, если !0 - то не в порядке.
                mov     #2, R2
                mov     #177130, R1
3$:             trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrRegister
                trap    26
                mov     #StrBit2TstRes1, R3 ; это неудача
                tstb    R4
                bne     2$
                mov     #StrBit2TstRes2, R3 ; это удача
2$:             trap    20
                swab    R4
                add     #2, R1
                sob     R2, 3$
                br      4$
0$:             return

TT4TstBit2:     add     #2, (SP)
                rti
; В режимах 60, 120, 140, 40, 100, 0 - должен делаться trap to 4
; потому что там ничего нету, и если регистры заблокировать - читаться ничего не должно
; в режиме 20 - должен читаться синхрокод из 3го сегмента. т.к. он накладывается на регистры

; ----------------------------------------------------------------------------
TT4TstBit3:     inc     @#VALUE1
                rti
; тест влияния бита 3
; код 10 подключает ПЗУ бейсика на БК10.
TestBit3:       trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrTstBit3Info
                tst     @#StdMode           ; это БК11
                bpl     0OK$                ; нет - делаем тест
                ; да - тест не нужен
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrBit3TstNone
                return

0OK$:           call    MEMFIL
                mov     #VALUE1, R3
                clr     (R3)
                mov     #TT4TstBit3, @#4
                mov     #SYNCW, R4
                mov     #120, R0
                trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                mov     #10, @#177130       ; подключаем бейсик, при этом ПЗУ накладывается на ОЗУ,
                                            ; и чтение-запись туда будет возможно, но читаться должно не то,
                                            ; что записывается
                mov     #120010, R5
                cmp     (R5), R4            ; читается что? синхрокод?
                beq     0$                  ; да, значит наложения нет
                inc     (R3)                ; нет - значит наложение есть
0$:             clr     (R5)                ; очищаем
                tst     (R5)                ; очистилось?
                beq     00$                 ; да - там чисто ОЗУ
                inc     (R3)                ; нет - значит наложение есть
00$:            add     #40000, R5          ; меняем адрес
                cmp     (R5), R4            ; читается что? синхрокод?
                beq     1$                  ; да, значит наложения нет
                inc     (R3)                ; нет - значит наложение есть
1$:             clr     (R5)
                tst     (R5)                ; очистилось?
                beq     10$                 ; да - там чисто ОЗУ
                inc     (R3)                ; нет - значит наложение есть
10$:            ; теперь второй вариант.
                ; в режиме 140 по адресам 120000-160000 ничего нет.
                ; и если бейсик подключается, там должно работать чтение
                mov     #TT4All, @#4
                mov     #140, R0
                trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                mov     #10, @#177130
                mov     #120020, R5
                tst     (R5)
                inc     (R3)                ; чтение произошло
                nop                         ; значит бейсик подключается
                add     #20000, R5          ; если чтения нет, halt сюда
                tst     (R5)
                inc     (R3)
                nop
                cmp     EndRamCod, #C128-RamCodTable
                blo     01$                 ; реакция в норме, должно накладываться
                ; не должно.
                tst     (R3)                ; наложение есть?
                beq     02$                 ; нету
                ; хреново, наложение происходит, но не должно
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrBitError
                br      05$

02$:            ; отлично, нету и не должно быть.
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrBitOK
                br      04$

01$:            tst     (R3)                ; наложение есть?
                beq     03$                 ; нету
                ; есть, так и скажем
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrBitOK
05$:            ; Ок. всё в норме.
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrBit3TstRes1+3
                return

03$:            ; хреново, не работает бит 10
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrBitError
04$:            trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrBit3TstRes1
                return


; тест влияния команды RESET
TestReset:      trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrTstResetInfo
; 1. Заполним каждую страницу своим уникальным кодом.
                call    MEMFIL              ; ну, почти всю страницу, одного слова в одном месте достаточно
; 2. Включаем стандартный режим
                tst     @#StdMode
                bmi     011$
                mov     #120, R0
                trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                br      010$

011$:           mov     #140, R0
                trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                mov     #16000, @#177716
                mov     #100000, R1
                mov     #20000, R0
10$:            clr     (R1)+
                sob     R0, 10$
010$:
; 3. Запоминаем, что было
                call    RDCRD
; 4. Делаем ресет
                reset
; 5. Смотрим, что стало
                call    RDRES
; Вывод результатов
                mov     #ADDRSS, R5
                mov     #DTAB, R4
                clr     @#VALUE1
12$:            mov     (R5)+, R1
                beq     11$
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrAddress
                trap    26                  ; вывод восьмеричного числа из R1, без подавления ведущих нулей
                cmp     DTAA-DTAB(R4), (R4)+
                bne     13$
                cmp     DTAA-DTAB(R4), (R4)+
                bne     14$
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TANRM
                br      12$

14$:            mov     -2(R4), R1
                br      15$

13$:            mov     (R4), R1
15$:            inc     @#VALUE1
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TAERR
                trap    10                  ; вывод восьмеричного числа из R1, с подавлением ведущих нулей
                trap    12                  ; перевод строки. выход: R0 - код 12
                br      12$

11$:            mov     #TRRSOK, R3
                tst     @#VALUE1
                beq     16$
                mov     #TRRSER, R3
16$:            trap    20                  ; вывод строки символов. Вход: R3 - адрес строки
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TRRSTL
                return

RDRES:          mov     #DTAA, R2
                br      0RD$

RDCRD:          mov     #DTAB, R2
0RD$:           mov     #ADDRSS, R1
1$:             mov     (R1)+, R0
                beq     0$
                mov     (R0)+, (R2)+
                mov     (R0)+, (R2)+
                br      1$
0$:             return

MEMFIL:         clr     R5
                mov     #SYNCW, R4
                mov     #TRST30, @#4        ; игнорируем все возможные trap to 4
11$:            mov     @#RAMBGN, R2
                mov     RamCodTable(R5), R0 ; берём очередной код
                beq     10$
                tst     PageErrors(R5)      ; если на странице были ошибки
                bne     12$                 ; то её пропустим
                trap    2                   ; включение режима с учётом типа БК, вход: R0 - код режима
                mov     #123456, (R2)+      ; признак, что страницу обработали
                mov     R0, (R2)+           ; код подключения страницы
                mov     #17776, R1          ; заполняем все 4 сегмента 
13$:            mov     R4, (R2)+           ; синхрокодом
                sob     R1, 13$
12$:            tst     (R5)+
                cmp     R5, EndRamCod
                blo     11$
10$:            return



; --подпрограммы----------------------------------------------------------------

MEMSSS:         mov     #TRST31, @#4
                clr     R1
32NEXT:         mov     RamCodTable(R1), R0 ; берём очередной код
                beq     31END               ; если коды кончились - выход
                tst     PageErrors(R1)      ; эту страницу уже подключали
                bmi     31NEXT              ; да - её не тестируем
                mov     @#RAMBGN, R2
                mov     #20000, R5
                trap    2                   ; включение режима с учётом типа БК, вход: R0 - код режима
                mov     R0, @#TZMODE        ; сохраняем режим, т.к. для вывода на экран нужно включать стандартный режим
4$:             call    IsKeyPress          ; если кнопка нажата, то может она ещё с прошлого раза нажата.
                beq     4$                  ; подождём, пока отпустят.
                call    SYNCTS              ; синхротест
                call    MEMTSS
31NEXT:         tst     (R1)+               ; перемещаемся дальше по таблице
                cmp     R1, EndRamCod       ; для заданной модели контроллера таблица кончилась?
                blo     32NEXT              ; если нет - продолжим
31END:          return

; синхротест
SYNCTS:         call    MTINF2
                mov     R1, -(SP)
                mov     R5, R1
                mov     R2, R3
                mov     #SYNCW, R0          ; синхрокод
                mov     R0, @#ERT31
2$:             call    IsKeyPress
                beq     0SKIP
                clr     @#VALUE1
                cmp     R0, (R3)
                beq     1$
                tst     @#VALUE1            ; если случился halt
                bne     1$                  ; то не надо, уже вывели сообщение об ошибке
                call    EROUT2              ; выведем сообщение, что ошибка синхротеста
1$:             inc     R3
                inc     R3
                sob     R1, 2$
0SKIP:          call    IsKeyPress          ; если кнопка нажата, то может она ещё с прошлого раза нажата.
                beq     0SKIP               ; подождём, пока отпустят.
                mov     (SP)+, R1
                return
        
; если случился halt при тестировании
TRST31:         call    EROUT1
TRST30:         rti                 ; продолжим тесты, как будто ничего не было

MEMTSS:         mov     #2, R3
                clr     R0
1$:             com     R0  ; -1
                call    (R4)
                com     R0  ; 0
                call    (R4)
                sob     R3, 1$
                mov     #16., R3
                inc     R0  ; 1
2$:             call    (R4)
                asl     R0
                sob     R3, 2$
                tst     (R3)+ ; 2
3$:             clr     R0
                call    (R4)
                com     R0  ; -1
                call    (R4)
                sob     R3, 3$
                mov     #16., R3
                dec     R0  ; -2
4$:             call    (R4)
                sec
                rol     R0
                sob     R3, 4$
                tst     (R3)+ ; 2, R0 = -1
5$:             call    (R4)
                com     R0
                call    (R4)
                com     R0
                sob     R3, 5$
                mov     #16., R3 ; R0 = -1
6$:             call    (R4)
                clc
                ror     R0
                sob     R3, 6$
                mov     #16., R3 ; R0 = 0
7$:             call    (R4)
                sec
                ror     R0
                sob     R3, 7$
                tst     (R3)+ ; 2, R0 = -1
8$:             call    (R4)
                com     R0
                call    (R4)
                com     R0
                sob     R3, 8$
; добавляем длительное тестирование
                mov     @#LNGTST, R3
                beq     10$
9$:             mov     #-1, R0
                call    RANDOM
                call    (R4)
                sob     R3, 9$
10$:            return

MEMTST:         mov     R3, -(SP)
                mov     R4, -(SP)
                trap    32  ; вывод информации о текущем режиме тестирования
                mov     R5, R4
                mov     R2, R3
1$:             call    IsKeyPress
                beq     MSKIP
                clr     @#VALUE1
                clr     @#ERT31
                mov     R0, (R3)
                inc     @#ERT31
                cmp     R0, (R3)
                beq     0$
                ; случилась ошибка. надо вывести на экран
                tst     @#VALUE1
                bne     0$
                call    ERROUT
0$:             inc     R3
                inc     R3
                sob     R4, 1$
                br      0MOUT

MEMTSU:         mov     R3, -(SP)
                mov     R4, -(SP)
                trap    32  ; вывод информации о текущем режиме тестирования
                mov     R5, R4
                mov     R2, R3
                clr     @#ERT31
1$:             call    IsKeyPress
                beq     MSKIP
                mov     R0, (R3)
                inc     R3
                inc     R3
                sob     R4, 1$
                mov     R5, R4
                mov     R2, R3
                inc     @#ERT31
2$:             call    IsKeyPress
                beq     MSKIP
                clr     @#VALUE1
                cmp     R0, (R3)
                beq     0$
                ; случилась ошибка. надо вывести на экран
                tst     @#VALUE1
                bne     0$
                call    ERROUT
0$:             inc     R3
                inc     R3
                sob     R4, 2$
0MOUT:          mov     (SP)+, R4
                mov     (SP)+, R3
                return

MSKIP:          mov     (SP)+, R4
                mov     (SP)+, R3
                tst     (SP)+
                return

ERRR0:          mov     R3, -(SP)
                mov     R1, -(SP)
                mov     R0, -(SP)
                trap    42              ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TERR
                mov     SP, R3
                trap    20              ; вывод строки символов. Вход: R3 - адрес строки
                mov     (SP)+, R0
                mov     (SP)+, R1
                mov     (SP)+, R3
                return

; новый вид вывода сообщений об ошибках
; такого вида Segment-Code(Code) - в скобках то, что должно быть
TRERR:          ; портит R0, R1
                mov     @#TZADDR, R1    ; адрес, из которого получаем номер сегмента по 10000 байт
                swab    R1
                asr     R1
                asr     R1
                ror     -(SP)           ; если вторая часть 7 сегмента, то тут будет бит С
                asr     R1
                asr     R1
                bic     #177770, R1     ; сегмент
                mov     #40, R0
                trap    16              ; вывод символа на экран. Вход: R0 - код символа
                trap    10              ; вывод восьмеричного числа из R1, с подавлением ведущих нулей
                mov     #"h-, R0
                rol     (SP)+           ; если вторая часть 7 сегмента
                bcc     1$
                trap    16              ; то отметим это.
1$:             swab    R0
                trap    16              ; вывод символа на экран. Вход: R0 - код символа
                mov     @#TRCODE, R1    ; код, то что есть
                mov     R1, -(SP)
                clrb    (SP)            ; ст.байт - то, что должно быть
                bic     (SP), R1        ; мл байт - то, что есть
                trap    10              ; вывод восьмеричного числа из R1, с подавлением ведущих нулей
                mov     #"(), R0
                trap    16              ; вывод символа на экран. Вход: R0 - код символа
                mov     (SP)+, R1       ; код, то что должно быть
                swab    R1
                trap    10              ; вывод восьмеричного числа из R1, с подавлением ведущих нулей
                swab    R0
                trap    16              ; вывод символа на экран. Вход: R0 - код символа
                return

; подготовительный этап перед 3м этапом
; идея в том, чтобы заполнить все страницы памяти определенным кодом,
; чтобы отловить ошибку следующего вида: пишем в одну ячейку памяти,
; а меняются данные в какой-то другой ячейке в другой странице.
MEMTS4:         clr     R5
                mov     #SYNCW, R4
                mov     #TRST30, @#4
11$:            mov     @#RAMBGN, R2
                mov     RamCodTable(R5), R0 ; берём очередной код
                beq     10$
                tst     PageErrors(R5)      ; если на странице были ошибки
                bne     12$                 ; то её пропустим
                trap    2                   ; включение режима с учётом типа БК, вход: R0 - код режима
                mov     #20000, R1
13$:            mov     R4, (R2)+
                sob     R1, 13$
12$:            tst     (R5)+
                cmp     R5, EndRamCod
                blo     11$
10$:            return

; trap 34 - вывод кода текущего режима и текущей маски
MTMIN2:         trap    24      ; вывод восьмеричного 4-х значного числа из R1, без подавления ведущих нулей
                trap    42      ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TAERR
                mov     R5, R1  ; выведем маску
                trap    30      ; вывод числа в бинарном виде, вход - R1 число
                return

; trap 36 - вывод кода текущего режима и слова "синхро"
MTMIN3:         trap    24              ; вывод восьмеричного 4-х значного числа из R1, без подавления ведущих нулей
                trap    42              ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TZSYN1
                return

; trap 32 - вывод инфы о текущем режиме тестирования
MTINFO:         jsr     R5, PUSHA
                mov     R0, R5
                mov     @#TZMODE, R1
                trap    34      ; вывод кода текущего режима и текущей маски
                br      3EROUE

; вывод инфы о синхропоследовательности
MTINF2:         jsr     R5, PUSHA
                mov     @#TZMODE, R1
                trap    36  ; вывод кода текущего режима и слова "синхро"
3EROUE:         mov     #15, R0
                trap    16  ; вывод символа на экран. Вход: R0 - код символа
                return

; вывод сообщения от ошибке синхропоследовательности
; на входе
; r3 - адрес, где случилась ошибка
EROUT2:         jsr     R5, PUSHA
                mov     @#TZMODE, R1
                mov     R3, -(SP)       ; адрес с ошибкой
                trap    36              ; вывод кода текущего режима и слова "синхро"
                mov     (SP), R1        ; выведем адрес, где случилась ошибка
                trap    26              ; вывод восьмеричного числа из R1, без подавления ведущих нулей
                mov     #':, R0
                trap    16              ; вывод символа на экран. Вход: R0 - код символа
                mov     @(SP)+, R1      ; выведем неправильное значение
                trap    26              ; вывод восьмеричного числа из R1, без подавления ведущих нулей
                trap    42              ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TZSYNF
                br      EROUEN
; на входе
; r0 - маска, с которой случилась ошибка
; r3 - адрес, где случилась ошибка
ERROUT:         jsr     R5, PUSHA
                mov     R0, R5          ; что должно быть
                mov     @#TZMODE, R1
                mov     (R3), -(SP)     ; что есть
                mov     R3, -(SP)       ; адрес с ошибкой
                trap    34              ; вывод кода текущего режима и текущей маски
                mov     #" :, R0        ; выведем ' '
                trap    16              ; вывод символа на экран. Вход: R0 - код символа
                mov     (SP)+, R1       ; выведем адрес, где случилась ошибка
                trap    26              ; вывод восьмеричного числа из R1, без подавления ведущих нулей
                swab    R0              ; выведем ':'
                trap    16              ; вывод символа на экран. Вход: R0 - код символа
                mov     (SP)+, R1       ; выведем то, что прочлось
                trap    30              ; вывод числа в бинарном виде, вход - R1 число
                br      EROUEN

; обработка ошибки по halt.
; r3 - адрес, где случилась ошибка
EROUT1:         inc     @#VALUE1        ; признак halt 
                jsr     R5, PUSHA
                mov     R0, R5          ; что должно быть
                mov     @#TZMODE, R1
2$:             mov     R3, -(SP)       ; адрес с ошибкой
                trap    34              ; вывод кода текущего режима и текущей маски
                mov     #" :, R0        ; выведем ' '
                trap    16              ; вывод символа на экран. Вход: R0 - код символа
                mov     (SP)+, R1       ; выведем адрес, где случилась ошибка
                trap    26              ; вывод восьмеричного числа из R1, без подавления ведущих нулей
                swab    R0              ; выведем ':'
                trap    16              ; вывод символа на экран. Вход: R0 - код символа
                mov     #StrWrite, R3
                tst     @#ERT31
                beq     0$
                mov     #StrRead, R3
0$:             trap    20              ; вывод строки символов. Вход: R3 - адрес строки
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrHalt
EROUEN:         trap    12              ; перевод строки. выход: R0 - код 12
EROUE2:         return


CRC:            mov     #160000, R1
                mov     #4000, R2
                clr     R0
0$:             add     (R1)+, R0
                adc     R0
                sob     R2, 0$
                return

; выход из теста CRC по кнопке стоп
StopTests:      mov     @#V4BUF, @#4
                mov     #Begin, SP
                trap    40                  ; включение стандартного режима с учётом типа БК
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrEndTest
                ; ждём нажатия клавиши
                trap    6                   ; ввод кода с клавиатуры. выход: R0 - код
                halt                        ; выходим

; БК11М - выход в клавиатурный монитор
ZAGR:           call    @#150170
                emt     0
                emt     1
                halt

; rnd генератор.
; вход: R0 - макс.значение
; выход: R0 - результат
RANDOM:         mov     R1, -(SP)
                mov     R2, -(SP)
                call    FRN
                mov     R0, R1
                clr     R2
                mov     RAN, R0
                sec
3A:             bic     R2, R0
                ror     R2
                cmp     R0, R1
                bhi     3A
                mov     (SP)+, R2
                mov     (SP)+, R1
                return
FRN:            swab    (PC)+
RAN:            .word   0
                incb    RAN
                rolb    RAN+1
MM:             add     #0, RAN
                add     #3337, MM+2
                return

; вызов так: jsr R5, pusha, сохраняем все регистры
; но в R5 нельзя передать параметр, чтобы было можно, есть более сложный метод
PUSHA:          mov     R4, -(SP)
                mov     R3, -(SP)
                mov     R2, -(SP)
                mov     R1, -(SP)
                mov     R0, -(SP)
                ; mov    R5, -(SP)           ; это - чтобы и в R5 можно было
                ; mov    14(SP), R5          ; передавать параметры
                ; call   @(SP)+
                call    (R5)
                mov     (SP)+, R0
                mov     (SP)+, R1
                mov     (SP)+, R2
                mov     (SP)+, R3
                mov     (SP)+, R4
                mov     (SP)+, R5
                return

; ------------------------------------------------------------------------------
; диспетчер трап
; сохранение регистров на совести подпрограмм
DISTRP:         mov     (SP), -(SP)         ; адрес возврата из трап
                sub     #2, (SP)            ; получим адрес команды трап
                mov     @(SP)+, -(SP)       ; достанем саму команду
                bic     #177401, (SP)       ; номера трапов только чётные, так мы экономим 1 слово
                add     #TRPTBL, (SP)       ; адрес адреса п/п
                mov     @(SP)+, -(SP)       ; получим адрес п/п
                call    @(SP)+              ; выполняем 
                rti
TRPTBL:         .word   Init                ; 0
                .word   SetPage             ; 2
                .word   VKL                 ; 4
                .word   EMT6                ; 6
                .word   OctNumOut           ; 10
                .word   OutCR               ; 12
                .word   CursorToLeft        ; 14
                .word   PutChar             ; 16
                .word   JIRN                ; 20
                .word   DecNumOut           ; 22
                .word   OctNumOut$4         ; 24
                .word   OctNumOut$6         ; 26
                .word   BinNumOut           ; 30
                .word   MTINFO              ; 32
                .word   MTMIN2              ; 34
                .word   MTMIN3              ; 36
                .word   VKLSTD              ; 40
                .word   OutStrI             ; 42

; trap 0
Init:           mov     #StdMode, R1
                mov     (R1)+, R0           ; параметр для trap 4
                bpl     2$
                mov     #100000, (R1)+      ; адрес начала ОЗУ - 11M
                tst     (R1)+               ; SCR_Ini
                mov     #ZAGR, (R1)         ; для выхода в MON 11 -> V4BUF
                mov     #16000, @#114       ; как в ANDOS
                br      1$

2$:             mov     #120000, (R1)+      ; адрес начала ОЗУ - 10
                tst     (R1)+               ; SCR_Ini
                mov     #100274, (R1)       ; для выхода в MON 10 -> V4BUF
1$:             trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                ; инициализация экрана
ScreenInit:     mov     #40000, R1
                mov     R1, R0
                mov     R1, @#SCRCRD
                clr     @#SCRY              ; Y координата, для рулонного сдвига
                clr     @#SCRLNC            ; счётчик строк
                mov     #1330, @#177664
3$:             clrb    (R1)+
                sob     R0, 3$
                mov     #FONT8, R0          ; собственный знакогенератор
                sub     #OFSF8, R0
                mov     R0, @#SCRFNT
                return


; trap 2 - подключение страниц и включение режима с учётом типа БК
; вход: R0 - код режима
SetPage:        tst     @#StdMode           ; БК11?
                bpl     VKL                 ; нет
                bic     #40, R0             ; да
; trap 4 - включение режима без учёта типа БК
; вход: R0 - код режима
VKL:            mov     R0, @#CurrentMode
VKL0:           mov     @#4, VV4BUF
                mov     #TRST30, @#4        ; прер по вектору 4 просто будем игнорировать.
                mov     R0, @#177716
                mov     #6, @#177130
                mov     R0, @#177130
                mov     #0, @#177130
                clr     @#177716
                mov     VV4BUF, @#4
                return
VV4BUF:         .word   0   ; буфер сохранения вектора 4

; trap 6 - ввод скан кода клавиши с клавиатуры
; выход: R0 - скан код
EMT6:           call    IsKeyPress          ; клавиша нажата?
                bne     EMT6                ; нет, ждём нажатия
1$:             call    IsKeyPress          ; клавиша нажата?
                beq     1$                  ; да, ждём пока отпустят
                movb    @#177662, R0        ; код нажатой клавиши
                return

IsKeyPress:     bit     #100, @#177716
                return

; trap 10 - вывод восьмеричного числа с подавлением ведущих нулей
; вход: R1 - число
OctNumOut:      jsr     R5, PUSHA
                mov     #6, R4              ; максимальное кол-во цифр в числе
                clr     R5                  ; счётчик цифр
0$:             mov     R1, R0
                bic     #177770, R0         ; получим очередную цифру
                add     #'0, R0
                mov     R0, -(SP)           ; в стек её
                inc     R5
                ror     R1                  ; пододвинем следующую, ADD бит С обнуляет, так что можно
                asr     R1
                asr     R1                  ; цифры остались?
                beq     1$                  ; кончились - выход, если число отрицательное, то мы отработает все 6 цифр.
                sob     R4, 0$
1$:             mov     (SP)+, R0
                trap    16                  ; вывод символа на экран. Вход: R0 - код символа
                sob     R5, 1$
                return

; trap 26 - вывод восьмеричного числа, без подавления ведущих нулей
; вход: R1 - число
OctNumOut$6:    jsr     R5, PUSHA
                mov     #6, R4              ; максимальное кол-во цифр в числе
                br      0DGO$
; trap 24 - вывод восьмеричного 4-х значного числа, без подавления ведущих нулей
; вход: R1 - число
OctNumOut$4:    jsr     R5, PUSHA
                mov     #4, R4              ; максимальное кол-во цифр в числе
0DGO$:          mov     R4, R5              ; счётчик цифр
0$:             mov     R1, R0
                bic     #177770, R0         ; получим очередную цифру
                add     #'0, R0
                mov     R0, -(SP)           ; в стек её
                ror     R1                  ; пододвинем следующую, ADD бит С обнуляет, так что можно
                asr     R1
                asr     R1                  ; цифры остались?
                sob     R4, 0$
1$:             mov     (SP)+, R0
                trap    16                  ; вывод символа на экран. Вход: R0 - код символа
                sob     R5, 1$
                return

; trap 14 - двигаем курсор на заданное количество раз влево,
; R2 - количество раз
CursorToLeft:   mov     #10, R0
7$:             trap    16                  ; вывод символа на экран. Вход: R0 - код символа
                sob     R2, 7$
                return

; trap 12 - перевод строки, портит R0
OutCR:          mov     #12, R0
; trap 16 - вывод символа на экран
; вход: R0 - код символа
PutChar:        jsr     R5, PUSHA
                call    VKLSTP              ; включаем стандартный режим без сохранения его в переменной "текущий режим"
                bic     #177400, R0         ; чистим старший байт
                bitb    #140, R0            ; символ?
                bne     01$                 ; да, переходим
                ; обрабатываем спецсимволы
                mov     @#SCRCRD, R3        ; координаты экрана
                cmp     #15, R0             ; LF?
                bne     23$                 ; нет
                bic     #77, R3             ; возвращаем курсор в начало строки
                br      31$                 ; проверка на сдвиг экрана

23$:            cmp     #12, R0             ; CR?
                bne     21$                 ; нет
                bic     #77, R3             ; возвращаем курсор в начало строки
                br      22$

21$:            cmp     #10, R0             ; курсор влево?
                bne     06$                 ; нет
                bit     #77, R3             ; мы где?
                beq     20$                 ; в начале строки, некуда влево уже
                dec     @#SCRCRD            ; где-то в строке, двигаемся влево.
                br      20$                 ; и выходим

06$:            cmp     #30, R0             ; забой
                bne     20$                 ; нет - остальные игнорируем
                bit     #77, R3             ; мы где?
                beq     20$                 ; в начале строки, некуда уже двигаться
                dec     @#SCRCRD            ; где-то в строке, двигаемся влево.
                mov     #10, R2             ; очищаем поле под курсором
                mov     @#SCRCRD, R1
07$:            clrb    (R1)
                add     #100, R1
                bpl     08$
                sub     #40000, R1
08$:            sob     R2, 07$
                br      20$                 ; и выходим

01$:            tstb    R0                  ; что за символ?
                bpl     02$                 ; латинский
                sub     #40, R0             ; русский - корректируем
02$:            asl     R0                  ; умножаем на 8
                ; mov    R0, R2
                asl     R0
                asl     R0
                ; add    R2, R0
                add     @#SCRFNT, R0        ; получаем адрес в шрифте
                mov     #10, R2             ; выводим
                mov     @#SCRCRD, R1
                mov     R1, R3              ; будущий адрес курсора
03$:            movb    (R0)+, (R1)
                add     #100, R1
                bpl     04$
                sub     #40000, R1
04$:            sob     R2, 03$
                ; двигаем адрес вывода
                mov     R3, R1
                mov     #177700, R0
                bic     R0, R1
                com     R0
                cmp     R1, R0              ; дошли до конца строки?
                bhis    10$                 ; да, надо делать перевод строки
                inc     @#SCRCRD            ; нет, просто на следующую позицию вправо
                br      20$

10$:            bic     R0, R3
22$:            inc     @#SCRLNC            ; увеличим счётчик строк
                add     #1000, R3           ; переходим на новую строку (высота символов 8 точек)
                bpl     11$                 ; за экран не вылезли?
                sub     #40000, R3          ; вылезли - корректируем. это новая координата
11$:            mov     R3, R2              ; если делать рулонный сдвиг, то прежде надо будет очистить от старого текста
                cmp     @#SCRY, #37         ; Если мы в самом низу
                bhis    13$                 ; то увеличивать координату больше не надо
                inc     @#SCRY              ; иначе увеличим
                br      31$                 ; проверка на сдвиг экрана

13$:            ; делаем рулонный сдвиг
                mov     @#177664, R0        ; берём значение рулонного регистра
                bic     #177400, R0         ; очищаем старший байт
                mov     #10, R1             ; высота символов 8 точек
15$:            mov     #32., R4            ; в строке 32 слова
14$:            clr     (R2)+
                sob     R4, 14$
                tst     R2                  ; за пределы экрана не вылезли?
                bpl     16$                 ; нет
                sub     #40000, R2          ; да, корректируем
16$:            incb    R0                  ; увеличиваем значение рулонного сдвига
                bis     #1000, R0           ; режим полного экрана
                mov     R0, @#177664        ; заносим значение в регистр.
                ; incb @#177664 не работает как надо, потому что обращение к этому регистру
                ; только словное. байтовое не работает.
                ; а inc @#177664 рано или поздно начинает влиять на бит режима РП
                sob     R1, 15$

31$:            mov     R3, @#SCRCRD        ; сохраняем координаты курсора
                cmp     @#SCRLNC, #37       ; экран заполнился строками?
                blt     20$                 ; нет ещё, всё нормально
                mov     #-1, @#SCRLNC       ; да - инициализируем счётчик
                mov     #StrPressAnyKey, R3 ; 
                call    JIRN                ; выведем сообщение, "нажмите любую клавишу"
                call    EMT6                ; подождём нажатия клавиши
                call    OutCR               ; перевод строки
20$:
; возвращаем режим, который был подключён до вывода символа
RETVKL:         mov     R0, -(SP)
                mov     @#CurrentMode, R0
                br      00VKL
; включаем стандартный режим без сохранения его в переменной "текущий режим"
VKLSTP:         mov     R0, -(SP)
                mov     @#StdMode, R0
00VKL:          call    VKL0
                mov     (SP)+, R0
                return

; trap 42 - вывод строки символов
; вход: адрес строки в слове за командой
OutStrI:        mov     2(SP), R3           ; адрес возврата из trap
                add     (PC), 2(SP)         ; корректируем адрес
                mov     (R3)+, R3           ; получаем адрес строки

; trap 20 - вывод строки символов.
; вход: R3 - адрес строки
JIRN:           mov     R2, -(SP)
                mov     R5, -(SP)
3$:             movb    (R3)+, R0           ; Портит R0
                beq     1$                  ; 0 - конец строки
                cmpb    R0, #220            ; 200-220 - повтор 1-20, 100 раз
                bgt     4$                  ; если 1..177 или 221..377 переход
                blt     6$                  ; если 200..217 переход
                movb    #277, R0            ; полная строка !!!
6$:             movb    R0, R2              ; счётчик символов
                ; вариант с рекурсией тут мы можем повторять повторения
;                clr     -(SP)
;                movb    (R3)+, (SP)        ; код символа, который будем повторять
;                mov     R3, R5             ; адрес в строке запомним
; 5$:             mov     SP, R3             ; строка из одного кода
;                call    JIRN               ; выведем
;                decb    R2                 ; столько раз, сколько надо
;                bmi     5$
;                mov     R5, R3             ; восстановим адрес в строке
;                tst     (SP)+
;                br      3$
                ; вариант без рекурсии
                movb    (R3)+, R0           ; символ, который надо повторять
5$:             call    PutChar
                decb    R2                  ; столько раз, сколько надо
                bmi     5$
                br      3$

4$:             call    PutChar
                br      3$

1$:             mov     (SP)+, R5
                mov     (SP)+, R2
                return

; trap 22 - вывод десятичного числа с подавлением ведущих нулей
; вход:  R1 - число
DecNumOut:      jsr     R5, PUSHA
                clr     R5
                mov     #CONST, R2
6$:             clr     R0
                mov     (R2)+, R4
                beq     2$
1$:             sub     R4, R1
                bcs     0$
                inc     R0
                br      1$

0$:             add     R4, R1
                bis     R0, R5
                bne     4$
                cmp     #1, R4
                beq     4$
                mov     #-20, R0            ; вместо ведущих нулей будем рисовать пробелы.
4$:             add     #'0, R0
                trap    16                  ; вывод символа на экран. Вход: R0 - код символа
                br      6$

2$:             return


; trap 30 - вывод числа в бинарном виде
; вход - R1 число
BinNumOut:      jsr     R5, PUSHA
                mov     #16., R2
0$:             mov     #30, R0
                asl     R1
                rol     R0
                trap    16                  ; вывод символа на экран. Вход: R0 - код символа
                sob     R2, 0$
                return

; trap 40 - включение стандартного режима с учётом типа БК
VKLSTD:         mov     R0, -(SP)
                mov     @#StdMode, R0
                trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                mov     (SP)+, R0
                return


; -------константы--------------------------
ADDRSS:         .word   100000,120000,140000,160000,0
HDDRegsTable:   .word   177740,177742,177744,177746,177750,177752,177754,177756,177741,177743,0
CONST:          .word   10000.,1000.,100.,10.,1,0

TZCODS:         .word   CODS11 ; адрес таблицы кодов ошибок теста режимов

; коды ошибок теста режимов для оригинального SMK. по 8 байт на режим
CODS:           .byte   00,00,06,06,06,06,00,00 ; 160
                .byte   00,00,06,06,06,06,00,10 ; 60
                .byte   06,06,06,06,06,06,06,10 ; 120
                .byte   06,06,06,06,06,06,06,04 ; 20
                .byte   00,00,10,10,10,10,00,10 ; 140
                .byte   00,00,10,10,06,06,06,10 ; 40
                .byte   04,06,06,06,06,06,06,11 ; 100
                .byte   10,10,10,10,06,06,06,11 ; 0

CODS11:         .byte   10,10,06,06,01,01,00,00 ; 160
                .byte   10,10,06,06,06,06,00,10 ; 60
                .byte   06,06,06,06,01,01,06,10 ; 120
                .byte   06,06,06,06,06,06,06,04 ; 20
                .byte   02,02,02,02,00,00,00,10 ; 140
                .byte   02,02,02,02,06,06,06,10 ; 40
                .byte   05,06,06,06,01,01,06,11 ; 100
                .byte   02,02,02,02,06,06,06,11 ; 0
; коды ошибок теста режимов для реплики SMK. по 8 байт на режим
CODSR11:        .byte   10,10,06,06,06,06,00,00 ; 160
                .byte   10,10,06,06,06,06,00,10 ; 60
                .byte   06,06,06,06,06,06,06,10 ; 120
                .byte   06,06,06,06,06,06,06,04 ; 20
                .byte   02,02,02,02,00,00,00,10 ; 140
                .byte   02,02,02,02,06,06,06,10 ; 40
                .byte   05,06,06,06,06,06,06,11 ; 100
                .byte   02,02,02,02,06,06,06,11 ; 0
; для А16
COAD16:         .byte   00,00,06,06,06,06,00,00 ; 160
                .byte   00,00,06,06,06,06,00,10 ; 60
                .byte   06,06,06,06,10,10,00,10 ; 120
                .byte   04,06,10,10,10,10,10,10 ; 20
                .byte   00,00,10,10,10,10,00,10 ; 140
                .byte   00,00,10,10,06,06,06,10 ; 40
                .byte   04,06,06,06,10,10,00,10 ; 100
                .byte   10,10,10,10,06,06,06,11 ; 0

COAD16_11:      .byte   10,10,06,06,01,01,00,00 ; 160
                .byte   10,10,06,06,06,06,00,10 ; 60
                .byte   06,06,06,06,00,00,00,10 ; 120
                .byte   04,06,10,10,10,10,10,10 ; 20
                .byte   02,02,02,02,00,00,00,10 ; 140
                .byte   02,02,02,02,06,06,06,10 ; 40
                .byte   05,06,06,06,00,00,00,10 ; 100
                .byte   02,02,02,02,06,06,06,11 ; 0

; таблица режимов контроллера
AltProModes:    .byte   160,60,120,20,140,40,100,0,377

SWREZ:          .byte   120,20,120,100,20,100,0,20,0,377
                .even

; адрес конца таблицы кодов для подключения страниц памяти
EndRamCod:      .word   C512-RamCodTable
; коды для подключения страниц памяти
RamCodTable:    .word   160   ; 0     (код 0)
C016:           .word   60
C032:           .word   2160  ; +32Кб (код 2000)
                .word   2060
C064:           .word   164   ; +64Кб (код 4)
                .word   64
                .word   2164  ; +96Кб (код 2004)(64+32)
                .word   2064
C128:           .word   170   ; +128Кб (код 10)
                .word   70
                .word   2170  ; +160Кб (код 2010)(128+32)
                .word   2070
                .word   174   ; +192Кб (код 14)(128+64)
                .word   74
                .word   2174  ; +224Кб (код 2014)(128+64+32)
                .word   2074
; это для 512Кб (вторая половина)
C256:           .word   161   ; +256Кб (код 1)
                .word   61
                .word   2161  ; +288Кб (код 2001)(256+32)
                .word   2061
                .word   165   ; +320Кб (код 5)(256+64)
                .word   65
                .word   2165  ; +352Кб (код 2005)(256+64+32)
                .word   2065
                .word   171   ; +384Кб (код 11)(256+128)
                .word   71
                .word   2171  ; +416Кб (код 2011)(256+128+32)
                .word   2071
                .word   175   ; +448Кб (код 15)(256+128+64)
                .word   75
                .word   2175  ; +480Кб (код 2015)(256+128+64+32)
                .word   2075
C512:           .word   0
; таблица адресов конца таблицы кодов для подключения страниц памяти
TZCTB:          .word   C016-RamCodTable
                .word   C016-RamCodTable
                .word   C016-RamCodTable
                .word   C016-RamCodTable
                .word   C064-RamCodTable
                .word   C128-RamCodTable
                .word   C256-RamCodTable
                .word   C512-RamCodTable
                .word   C064-RamCodTable
                .word   C128-RamCodTable
                .word   C256-RamCodTable
                .word   C512-RamCodTable
; таблица имён контроллеров
NameTable:      .word   NameA16
                .word   NameA16H
                .word   NameA16M
                .word   NameAUNK
                .word   NameA64M
                .word   NameA128M
                .word   NameA256M
                .word   NameA512M
                .word   NameS64
                .word   NameS128
                .word   NameS256
                .word   NameS512

; имена контроллеров
NameA16:        .asciz  "A16"
NameA16H:       .asciz  "A16HDD"
NameA16M:       .asciz  "A16M"
NameAUNK:       .asciz  "Несуществующий"
NameA64M:       .asciz  "A64M"
NameA128M:      .asciz  "A128M"
NameA256M:      .asciz  "A256M"
NameA512M:      .asciz  "A512M"
NameS64:        .asciz  "SMK64"
NameS128:       .asciz  "SMK128"
NameS256:       .asciz  "SMK256"
NameS512:       .asciz  "SMK512"
S512Repl:       .asciz  "(ПЛИС репл.)"
StrNoAltPro:    .asciz  "Не обнаружен контроллер АльтПро"<12>
StrFound:       .asciz  "Обнаружен контроллер "
StrVersion:     .asciz  " верс. прошивки ПЗУ: "
StrVersionRT:   .asciz  "Версия прошивки 555РТ5: "
RTOK:           .asciz  "новая"<12>
RTBAD:          .ascii  "старая, не рекомендуется к использованию"<12>
                .ascii  "из-за неправильных режимов работы, тест будет показывать ошибки"<12>
                .asciz  "синхронизации на БК11М"<12>
RTERR:          .asciz  "повреждена."<12>

StrTitle:       .ascii  <220>/"/
                .ascii  <210>/ Тест контроллера "АльтПро" с ДОЗУ 64-512 Кб/<12>
                .ascii  <220>/"/
                .asciz  <211>" (c) АльтПро 1997, gid 2012-2021, v4.76F"<12>

StrPrepare:     .asciz  "Подготовка"
TERR:           .asciz  <7><7>" Error "
StrDOZU:        .asciz  <12>"ДОЗУ, Кбайт:"
StrPgErr:       .asciz  "Ошибки страниц:"<12>
StrPageAlrUse:  .asciz  "эту страницу уже подключали с кодом "
TZ2ERC:         .asciz  <12><213>" "
TZERRS:         .ascii  <12>"Тест памяти на ошибки..."
TZEST1:         .asciz  <12>"Этап 1"<12>
TZEST2:         .asciz  <12>"Этап 2"<12>
StrWrite:       .asciz  " write-"
StrRead:        .asciz  " read-"
StrHalt:        .asciz  "halt"
StrByteFail:    .asciz  " byte-test fail"

TZSYN1:         .asciz  " - синхро           "
TZSYNF:         .asciz  ":ошибка"
TRZINF:         .asciz  <12>"Тест режимов..."<12>
TRSWPG:         .asciz  <12>"Тест переключения страниц..."<12>
TROK:           .asciz  " OK"
TRSKIP:         .asciz  "пропуск."<12>
ERINFO:         .ascii  "Код ошибки: Сегмент-Код(Код). Сегмент -"<12>
                .ascii  "сегмент памяти по 10000 байтов, Код - код ошибки, в скобках"<12>
                .ascii  "ожидаемый код. Расшифровка:"<12>
                .ascii  "0-ПЗУ, 1-ОЗУ на ПЗУ БК, 2-ОЗУ БК, 4-ОЗУзз,"<12>
                .asciz  "5-ОЗУзз на ОЗУ БК, 6-ОЗУ, 10-пусто, 11-ОЗУзч"<12>

CRCINF:         .ascii  <12><202>"* Для запуска непрерывного теста контрольной суммы ПЗУ"<12>
                .ascii  <203>" нажмите любую клавишу. Правильное значение уточните"<12>
                .asciz  <203>" по документации. Прервать тест - СТОП."<12>

                .asciz   <12>"   Код К.С.= "
                .asciz  "1234 "
                .asciz  "."

StrTHDInfo1:    .asciz  <12>"Тест доступности регистров HDD..."<12>
StrTHDInfo2:    .asciz  <12>"Тест буфера ОЗУ HDD..."<12>
StrTHROK:       .asciz  "ОЗУ в норме."<12>
StrTHRError:    .asciz  "Внимание! ОЗУ повредилось!"<12>
StrTHRAMNone:   .asciz  "Внимание! ОЗУ недоступно!"<12>
StrTHDDError:   .asciz  "Это не СМК, пропускаем тест."<12>
StrHDDRegNoWrt: .asciz  "недоступен по записи, "
StrHDDRegNoRead:.asciz  "недоступен по чтению"<12>
StrTstBit2Info: .asciz  <12>"Тест влияния бита 2..."<12>
StrMode:        .asciz  "Режим "
StrRegister:    .asciz  "Регистр "
StrBit2TstRes1: .asciz  " - не блокируется!"<12>
StrBit2TstRes2: .asciz  " - блокируется."<12>

StrBitError:    .asciz  "ОШИБКА! "
StrBitOK:       .asciz  "Норма. "
StrTstBit3Info: .asciz  <12>"Тест влияния бита 3..."<12>
StrBit3TstRes1: .asciz  "не подключается ПЗУ Бейсика."<12>
StrBit3TstNone: .asciz  "На БК11(М) бит 3 влияния не имеет."<12>
StrTstResetInfo:.asciz  <12>"Тест влияния RESET..."<12>
StrAddress:     .asciz  "Адрес: "
TANRM:          .asciz  " - без изменений"<12>
TAERR:          .asciz  " - "
TRRSOK:         .asciz  "Норма. RESET не"
TRRSER:         .asciz  "ОШИБКА. RESET"
TRRSTL:         .asciz  " влияет на режимы."<12>

StrEndTest:     .asciz  <12><202>"* Тестирование окончено !"
StrPressAnyKey: .asciz  <216>" *** Нажмите любую клавишу. ***"
                .even


; тут будут храниться флаги ошибок для каждой страницы
; возможные результаты:
;   0 - всё отлично
; иначе маски:
;   1 - нет записи (halt)
;   2 - нет чтения (halt)
;   10 - провал байт-теста
;   100000 - страницу уже подключали
PageErrors:     .blkw   32.

DTAB:           .blkw   8.
DTAA:           .blkw   8.

; ------------------------------------------------------------------------------
; часть кода, нужная только один раз при инициализации

DETECT:         tst     @#StdMode           ; чтобы тест нельзя было запустить
                bpl     20$                 ; повторно
                mov     #140000, R0         ; сделаем переход на 
                br      21$                 ; выход в монитор

20$:            mov     #100000, R0         ; потому что, тест режимов самомодифицирующийся,
21$:            mov     #137, @#Begin       ; и после его прохода код не восстанавливается в
                mov     R0, @#Begin+2       ; исходное состояние

                ; определяем тип контроллера и кол-во памяти по значению в 167776
                clrb    @#AltProDev         ; флаг детектирования контроллера
                clrb    @#SMKHDD            ; флаг наличия регистров HDD
                mov     @#167776, R5        ; в мл. байте версия прошивки
                mov     R5, R4
                clrb    R4                  ; очищаем младший байт
                bic     R4, R5              ; очищаем старший байт
                swab    R4                  ; в мл. байте код количества памяти
                cmp     R4, #370            ; это вообще АльтПро?
                bhis    1$                  ; да
0$:             trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrNoAltPro
                incb    @#AltProDev         ; отметим, что контроллер не найден
                return

1$:             bic     #177770, R4         ; определим тип контроллера
                ; коды в ячейке 167777, определяющие тип контроллера
                ; R4=0 : 370 - A16
                ; R4=1 : 371 - A16+контроллера винта с дозу 4кб
                ; R4=2 : 372 - A16M
                ; R4=3 : 373 - не исп-ся
                ; R4=4 : 374 - SMK64 или A64M
                ; R4=5 : 375 - SMK128 или A128M
                ; R4=6 : 376 - SMK256 или A256M
                ; R4=7 : 377 - SMK512 или A512M
                mov     #4, R3
                cmp     R4, R3              ; для а16 нечего делать
                blo     3$                  ; а если smk или a64m, надо определить, что это
                cmpb    R5, #300            ; это A64-A512?
                bhi     3$                  ; да
                comb    @#SMKHDD            ; нет - отметим, что есть регистры HDD
                add     R3, R4              ; и это СМК
3$:             asl     R4                  ; *2
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrFound
                mov     TZCTB(R4), EndRamCod ; зададим адрес конца таблицы кодов для подключения страниц памяти
                mov     NameTable(R4), R3   ; выведем имя контроллера
                trap    20                  ; вывод строки символов. Вход: R3 - адрес строки
                mov     R5, R1              ; версию поместим сюда

                ; сейчас проверим, это ПЛИС реплика или оригинал?
                mov     #TRST30, @#4        ; прерывание по вектору 4 просто будем игнорировать.
                mov     #7, @#177130        ; вместо кода 6 используем код 7
                                            ; при этом на оригиналах и новоделах СМК-64 всё будет работать как обычно
                                            ; а на ПЛИС реплике - нет, режим не установится.
                                            ; эта особенность найдена при детальном изучении прошивки ПЛИС.
                                            ; там строб установки режима = 0110 = 0х6 (4 бита)
                mov     #160, @#177130      ; включаем стартовый режим
                mov     #0, @#177130
                mov     #160000, R0
                mov     #170000, R3         ; так нужно, чтобы выход из trap to 4 не попадал в середину многословной команды.
                clr     R5
                cmp     (R0), (R3)          ; если значения по этим адресам равны
                beq     0SMK64              ; то режим включился и это оригинал
                inc     R5                  ; нет - режим не включился, это ПЛИС реплика
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   S512Repl
0SMK64:         ; теперь в R5 код контроллера: 0 - не реплика, 1 - реплика
                ; и в R4 код контроллера, <10 - A16(M), >=10 - CMK64-512 A64-512

                ; выведем версию ПЗУ, в нечеловекообразном виде
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrVersion
                trap    10                  ; вывод восьмеричного числа из R1, с подавлением ведущих нулей
                trap    12                  ; перевод строки. выход: R0 - код 12
                ; вывели всё. теперь надо переходить к тестам

                ; сейчас проверим, какая прошивка РТ5, будем просто использовать кусок теста режимов.
                cmp     R4, #10             ; если это не СМК
                blo     15$                 ; то прошивку проверять не надо

                tst     R5                  ; это реплика?
                bne     17$                 ; да
; оригинальный СМК/A64+
                mov     #CODS, R0           ; таблица кодов для СМКхх на БК10
                tst     @#StdMode           ; это БК10?
                bpl     18$                 ; да
                mov     #CODS11, R0         ; таблица кодов для СМК-512 на БК11
                br      18$
; реплика СМК
17$:            mov     #CODS, R0           ; таблица кодов для реплики СМКхх на БК10
                tst     @#StdMode           ; это БК10?
                bpl     18$                 ; да
                mov     #CODSR11, R0        ; таблица кодов для реплики СМК-512 на БК11
                br      18$

; контроллер А16(М)
15$:            mov     #COAD16, R0         ; таблица кодов для А16 на БК10
                tst     @#StdMode
                bpl     16$
                mov     #COAD16_11, R0      ; таблица кодов для А16 на БК11
16$:            mov     R0, TZCODS          ; зададим таблицу
                return

18$:            mov     R0, TZCODS          ; зададим таблицу
                mov     #TT4All, @#4
                mov     #SYNCW, R2          ; проверочное слово
                clr     R5                  ; тут накапливается признак.
                mov     #100, R0            ; код режима
                mov     #160172, R3         ; адрес для проверки
                call    DetectOldRT
                cmp     #4, R0
                bne     10$
                inc     R5
10$:            mov     #120, R0
                mov     #177172, R3
                call    DetectOldRT
                cmp     #11, R0
                bne     11$
                inc     R5
11$:            trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   StrVersionRT
                tst     R5                  ; что получилось?
                bne     12$                 ; что-то отловили
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   RTOK
                return

12$:            comb    @#AltProDev         ; отметим, что прошивка неправильная
                cmp     #2, R5
                bne     13$
                trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   RTBAD
                return

13$:            trap    42                  ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   RTERR
                return


DetectOldRT:    mov     R0, -(SP)
                mov     #20, R0             ; включаем режим 20, чтобы вписать куда нужно проверочное слово
                trap    4                   ; чтобы алгоритм из теста режимов срабатывал стандартно
                mov     R2, -40000(R3)
                mov     (SP)+, R0           ; устанавливаем нужный режим
                trap    4                   ; включение режима без учёта типа БК, вход: R0 - код режима
                clr     R0                  ; тут накапливается код результата теста
                cmp     R2, (R3)            ; тестируем, есть ли доступ по чтению
                bne     3$
                beq     4$
                cmp     (R0)+, (R0)+        ; <-halt сюда для cmp
4$:             cmp     (R0)+, (R0)+
                ; зесь R0 == 0, 4, 010 при !=, =, halt
3$:             mov     R3, (R3)            ; тестируем, есть ли доступ по записи
                cmp     R2, (R3)            ; тестируем, работает ли запись как надо
                beq     6$                  ; если запись прошла, но по чтению все равно изначальный вариант
                nop                         ; <-halt сюда для mov
                mov     R2, (R3)            ; <-halt сюда для cmp
                cmp     R2, (R3)
                br      5$
                br      1$                  ; <-halt сюда для mov
5$:             bne     6$                  ; <-halt сюда для cmp - !=
                inc     R0                  ; write
6$:             inc     R0                  ; nowr
1$:             return


SetMemTestLen:  clr     @#177660        ; разрешим прерывания от клавиатуры
                trap    42              ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TZLNTS
                mov     #32., R1        ; начальное значение по умолчанию 
                mov     R1, @#LNGTST
                call    DECOU$
                trap    42              ; вывод строки символов. Вход: адрес строки в слове за командой
                .word   TZLNTSE
                call    DECIN           ; ввод десятичного числа
                bcs     1$
                mov     R1, @#LNGTST
1$:             trap    12
                return

; выход:  R1 - полученное число.
; переполнение не проверяется, так что сколько влезет в 16 бит, столько и будет
; если бит С - то выходной результат недостоверен и должен игнорироваться
DECIN:          clr     R1              ; счётчик вводимых цифр
                mov     #DECBUF, R2     ; буфер, куда сохранять цифры
2$:             trap    6               ; ввод кода с клавиатуры. выход: R0 - код
                cmpb    #3, R0          ; если нажали КТ - то отмена
                beq     1CANS
                cmpb    #12, R0         ; конец ввода
                beq     10$
                cmpb    #30, R0         ; забой
                bne     1$
                tst     R1              ; что-то вводили?
                beq     2$              ; нет, игнорируем
                trap    16
                dec     R1              ; да, отменим последнюю цифру
                dec     R2
                br      2$

1$:             cmpb    R0, #'0         ; если не цифры
                blo     2$
                cmpb    R0, #'9
                bhi     2$              ; то тоже игнорируем
                cmp     R1, #5          ; больше 5 цифр не вводить
                bge     2$
                trap    16
                sub     #'0, R0         ; получим число
                movb    R0, (R2)+       ; и сохраним его
                inc     R1              ; увеличим счётчик введённые чисел
                br      2$

10$:            tst     R1              ; если нажали enter до ввода числа,
                beq     3$              ; то это означает просто согласие со значением по умолчанию
                ; а иначе интерпретируем введённое число
                mov     #DECBUF, R2
                clr     R3              ; тут накапливается результат
4$:             asl     R3
                mov     R3, R4
                asl     R3
                asl     R3
                add     R4, R3
                movb    (R2)+, R0
                add     R0, R3
                sob     R1, 4$
                mov     R3, R1
                br      5$

1CANS:          tst     R1              ; если нажали esc, когда вводили число
                bne     3$              ; то это означает, просто отмену и согласие со значением по умолчанию
5$:             tst     (PC)+           ; а если нажали до ввода числа - значит отказ от теста
3$:             sec
                return
; вывод десятичного числа с подавлением ведущих нулей
; вход:  R1 - число
DECOU$:         jsr     R5, PUSHA
                clr     R5
                mov     #CONST, R2
6$:             clr     R0
                mov     (R2)+, R4
                beq     2$
1$:             sub     R4, R1
                bcs     0$
                inc     R0
                br      1$

0$:             add     R4, R1
                bis     R0, R5
                bne     4$
                cmp     #1, R4
                bne     6$
4$:             add     #'0, R0
                trap    16
                br      6$

2$:             return

TZLNTS:         .asciz  "Задайте длительность длинного теста (0 - без теста) ["
TZLNTSE:        .asciz  "]:"
                .even

                .END

; Коды теста режимов
; 0 - ПЗУ (чтение есть, не равно; записи нет)
; 1 - ОЗУ поверх ПЗУ (чтение есть, не равно; запись есть, результат не меняется)
; 2 - чужое ОЗУ (чтение есть, не равно; запись есть, результат меняется)
; 4 - ОЗУ с защитой от записи (чтение есть, равно; записи нет)
; 5 - ОЗУ с защитой от записи поверх ОЗУ, (чтение есть, равно; запись есть, результат не меняется, выдаётся RPLY)
; 6 - ОЗУ (чтение есть, равно; запись есть, равно)
; 10 - пусто (чтения нет; записи нет)
; 11 - ОЗУ с защитой от чтения (чтения нет; запись есть, результат не определён)


