;Сборщик загрузчиков игр

       ORG 24000

       LD IX,SRED0     ;сохраним первоначальную среду
       CALL SAVESRED

;определим тип системы - TASiS или iS-DOS
       LD C,#12
       RST 16
       EXX
       LD A,(HL)  ;для определения проверим длину курсора
       CP 4       ;если она 4 или 6, то система iS-DOS
       JP Z,SYSIS
       CP 6
       JP Z,SYSIS

       LD A,80       ;Для TASiS устанавливаем количество символов с строке
       LD (LENSTR),A

SYSIS  LD C,#10      ;определим адрес кэша
       RST 16
       EXX
       LD BC,5
       ADD HL,BC
       LD E,(HL)
       INC HL
       LD D,(HL)
       LD (CACHE),DE

       LD C,#45      ;сохраняем среду с открытым файлом программы
       RST 16
       EXX
       LD BC,-9
       ADD HL,BC
       LD DE,SRED3
       LD BC,4
       LDIR

BEG0   LD C,#43
       RST 16
       RET C

       JP Z,BEG1

       LD HL,0
FIL    EQU $-1
FIL2   EQU $-2
       LD A,H
       AND L
       LD A,0
       SCF
       RET Z

;Все файлы указаны

       LD HL,(BUF2ADR)

       LD A,"S"        ;занесем в 0-й байт банка ПЗУ идентификатор S
FBYTE  EQU $-1
       LD (HL),A
       INC HL
       LD (ROMADR),HL

       LD HL,EKRAN     ;было $BUFER. Начало загруженного файла с названиями игр
       LD (TEKSTR),HL
       DEC HL
AN0    INC HL
AN00   LD A,(HL)
       CP #0D     ;Если перевод строки
       JR Z,AN0
       CP #03     ;Признак конца файла
       JP Z,AN1

;Обнаружена новая строка с текстом
       CP ";"
       JP Z,AN2  ;Если комментарий

;Строка без комментария. Первое значение - имя игры
       PUSH HL
       LD HL,NAME   ;почистим буфер для имени игры
       LD D,H
       LD E,L
       INC DE
       LD (HL)," "
       LD BC,26-1  ;чистим сразу 2 буфера
       LDIR
       POP HL

       LD DE,NAME2+1
       LD B,12      ;максимум 12 символов имени берём
AN4    LD A,(HL)
       CP ","
       JR Z,AN3     ;конец имени
       LD C,A
       LD A,B
       OR A
       JR Z,AN41    ;если перебрали все 12 символов, остальные игнорируем
       LD A,C
       LD (DE),A
       DEC B
       INC DE
AN41   INC HL
       JR AN4

AN3    PUSH HL      ;конвертируем имя файла в формат Эльф
       LD HL,NAME2
       LD DE,NAME
       LD BC,13
       CALL $CONVERT
       POP HL
       INC HL      ;пропускаем пробелы
       LD A,(HL)
       CP " "
       JR Z,AN3

       CALL PRINT  ;печать имени игры сверху экрана


;HL указывает на путь к файлу с загрузчиком
       PUSH HL  ;обнаружим конец строки
AN7    INC HL
       LD A,(HL)
       CP #0D
       JR NZ,AN7
       INC HL
       LD (TEKSTR),HL    ;следующий символ за концом строки
       POP HL

       LD C,#42
       RST 16
       RET C
       JR Z,AN5
AN6    LD A,81
       SCF
       RET

AN5    OR A
       JR NZ,AN6

       EXX         ;откроем файл игры
       LD C,#25
       RST 16
       RET C

       EXX          ;сохраним описатель
       LD DE,OPIS3
       LD BC,32
       LDIR

       LD IX,SRED1    ;сохраним среду с игрой
       CALL SAVESRED

       LD A,(ADR3+2)   ;сколько байт влезет до конца текущего банка ПЗУ
       LD HL,(ADR3)
       CALL SETPORT
       EX DE,HL
       LD HL,#4000
       XOR A
       SBC HL,DE
       LD (OST),HL

       LD IX,(BUFFIL)
       XOR A
       LD HL,#02F4    ;первый блок загрузчика начинается после описания
       LD DE,#0100    ;грузим в память
       LD C,#29
       RST 16
       RET C

       LD L,(IX+11)    ;до конца банка ПЗУ должно влезть - загрузчик,
       LD H,(IX+12)
       LD DE,#02F4     ;описание игры
       ADD HL,DE
       LD DE,3         ;и 3 байта команды JP xxxx
       ADD HL,DE
       EX DE,HL
       LD HL,0
OST    EQU $-2
       XOR A
       SBC HL,DE
       JR NC,AN51

;Загрузчик не влезет до конца банка ПЗУ
       LD DE,#0100      ;заполняем буфер длиной до конца банка ПЗУ кодом 255
       ADD IX,DE
       PUSH IX
       POP HL
       PUSH HL
       LD (NEWBUF),HL
       LD D,H
       LD E,L
       INC DE
       LD BC,(OST)
       DEC BC
       LD (HL),#FF
       LDIR
       LD A,#00      ;в конец добавляем код 0 - начало нового банка
       LD (DE),A

       POP HL
       LD BC,(OST)  ;длину дополнительного блока с 255 увеличиваем на 1,
       INC BC       ;так как добавлен код 00
       LD (OST),BC
       CALL CALCCS  ;считаем контрольную сумму блока

       LD IX,SRED2    ;среда с выходным файлом
       CALL LOADSRED

       LD DE,(OST)    ;увеличиваем размер файла на длину доп. блока
       LD C,#31
       RST 16
       RET C

       LD IX,0       ;пишем коды 255 и 0 в конце из буфера в конец
NEWBUF EQU $-2       ;выходного файла
       LD A,(ADR3+2)
       LD HL,(ADR3)
       LD C,#2A
       RST 16
       RET C

       LD IX,SRED1    ;среда с открытой игрой
       CALL LOADSRED

       LD A,(ADR3+2)  ;считаем новый адрес начала игры
       LD HL,(ADR3)
       LD DE,(OST)
       ADD HL,DE
       JR NC,$+3
       INC A
       LD (ADR3),HL
       LD (ADR3+2),A

       LD IX,(BUFFIL)

AN51   LD DE,(OPIS3+26)  ;кс файла с игрой
       XOR A
       LD HL,0
       SBC HL,DE         ;сумма всех байтов файла с игрой
       XOR A
       LD E,(IX+4)
       LD D,0
       SBC HL,DE
       LD E,(IX+5)
       SBC HL,DE
       LD E,(IX+6)
       SBC HL,DE
       PUSH HL

       LD A,(ADR3+2)   ;заносим адрес начала игры в ПЗУ в загрузчик по
       LD HL,(ADR3)    ;смещению +4

       LD BC,(SMESH)   ;Добавляем к адресу начала игры смещение на случай
       ADD HL,BC       ;компиляции образа под прошивку в ПЗУ Эльф
       ADC A,0

       LD (IX+4),L     ;заносим результат в загрузчик добавляемой игры
       LD (IX+5),H
       LD (IX+6),A

       POP HL
       LD E,(IX+4)
       ADD HL,DE
       LD E,(IX+5)
       ADD HL,DE
       LD E,(IX+6)
       ADD HL,DE
       EX DE,HL      ;DE-сумма всех байт файла с игрой (после изменения)
       XOR A
       SBC HL,HL
       SBC HL,DE     ;HL-новая контрольная сумма файла с игрой
       PUSH HL

       LD C,#35      ;Заносим новую контрольную сумму в описатель файла с игрой
       RST 16
       EXX
       LD DE,26
       ADD HL,DE
       POP DE
       LD (HL),E
       INC HL
       LD (HL),D

       LD C,#28     ;Сохраняем описатель файла с игрой
       RST 16
       RET C

       XOR A            ;сохраняем изменённый блок загрузчика игры
       LD HL,#02F4
       LD DE,#0100
       LD C,#2A
       RST 16
       RET C



;обработка файла игры

       LD HL,NAME      ;перенос имени файла (13 байт)
       LD DE,(ROMADR)
       LD BC,13
       LDIR

       LD HL,(ADR3)  ;из адреса игры на картридже вычисляем
       LD A,(ADR3+2) ;номер банка ПЗУ
       LD BC,#02F4   ;добавляем смещение для описания игры
       ADD HL,BC
       JR NC,$+3
       INC A
       CALL SETPORT  ;A-номер банка ПЗУ,HL-адрес внутри банка ПЗУ
       LD (DE),A     ;+13 от начала заголовка игры, заносим банк

       INC DE
       LD A,L
       LD (DE),A     ;+14 - заносим адрес игры внутри банка ПЗУ
       INC DE
       LD A,H
       LD (DE),A     ;+15
       INC DE
       EX DE,HL

       LD IX,(BUFFIL) ;адрес загрузчика берётся из 0-го блока игры
       LD A,(IX+2)
       LD (HL),A      ;заносим адрес в описатель игры
       INC HL
       LD A,(IX+3)
       LD (HL),A
       INC HL

       LD A,(IX+7+4)  ;длина загрузчика по смещению +11
       LD (HL),A      ;заносим в +17
       INC HL
       LD A,(IX+7+5)
       LD (HL),A
       INC HL

       LD (ROMADR),HL

       CALL LDBLK      ;перенесём файл с игрой в конец выходного файла
       RET C

       LD HL,(TEKSTR)  ;восстанавливаем позицию в файле-источнике
       JP AN00         ;анализ следующей строки


;запись сформированного банка ПЗУ по окончании анализа файла
AN1
       LD IX,SRED2      ;среда с выходным файлом ПЗУ
       CALL LOADSRED


       LD HL,(ROMADR)
       LD (HL),#FF
       INC HL
       LD DE,(BUF2ADR)
       PUSH DE
       XOR A
       SBC HL,DE
       EX DE,HL         ;DE - сколько байт писать с заголовками игр
       LD (AN11),DE

       LD HL,(BUF2ADR)  ;считаем контрольную сумму сформированного
       LD B,D           ;заголовка игр
       LD C,E
       CALL CALCCS

       POP IX      ;сохраняем сформированный банк ПЗУ в выходной файл
       XOR A
       LD HL,0
       LD C,#2A
       RST 16
       RET C

       LD HL,$HRUST
       LD DE,(AN11)
       XOR A
       SBC HL,DE
       LD B,H
       LD C,L
       LD (AN12),BC   ;сколько байт с FF надо дописать
       DEC BC

       LD HL,(BUF2ADR)   ;заполняем буфер длиной до начала игр значениями 255
       PUSH HL
       LD D,H
       LD E,L
       INC DE
       LD (HL),#FF
       LDIR

       LD HL,(BUF2ADR) ;подсчёт КС записываемого куска
       LD BC,(AN12)
       CALL CALCCS

       POP IX         ;пишем длину до начала игр в выходной файл
       LD DE,0        ;сколько байт надо дописать
AN12   EQU $-2
       XOR A
       LD HL,0        ;с адреса после окончания описателей игр
AN11   EQU $-2
       LD C,#2A
       RST 16
       RET C


;Загрузка распаковщика и четырёх модулей

       LD HL,(BUFFIL)  ;чистим место в памяти под все модули
       LD D,H
       LD E,L
       INC DE
       LD BC,$LENMOD-1
       LD (HL),0
       LDIR

       LD IX,SRED3    ;среда с открытой программой. В папке с программой
       CALL LOADSRED  ;должны располагаться файлы модулей

       LD HL,DEHR    ;открываем файл с распаковщиком
       LD C,#25
       RST 16
       RET C

       EXX            ;описатель распаковщика
       LD DE,OPIS3
       LD BC,32
       LDIR

       LD IX,(BUFFIL)  ;загружаем распаковщик
       LD DE,(OPIS3+14)
       XOR A
       LD HL,0
       LD C,#29
       RST 16
       RET C


       LD HL,CH128    ;открываем файл с модулем проверки на 128К
       LD C,#25
       RST 16
       RET C

       EXX            ;описатель модуля
       LD DE,OPIS3
       LD BC,32
       LDIR

       LD IX,(BUFFIL)  ;загружаем модуль
       LD DE,$LENDEP  ;Относительно начала буфера адрес будет +#0100
       ADD IX,DE
       LD DE,(OPIS3+14)
       XOR A
       LD HL,0
       LD C,#29
       RST 16
       RET C

       LD HL,CHNOV    ;открываем файл с модулем проверки на новодел
       LD C,#25
       RST 16
       RET C

       EXX            ;описатель модуля
       LD DE,OPIS3
       LD BC,32
       LDIR

       LD IX,(BUFFIL)  ;загружаем модуль
       LD DE,$LENDEP+$LEN128  ;Относительно начала буфера адрес будет +#0200
       ADD IX,DE
       LD DE,(OPIS3+14)
       XOR A
       LD HL,0
       LD C,#29
       RST 16
       RET C

       LD HL,MENU    ;открываем файл с модулем меню
       LD C,#25
       RST 16
       RET C

       EXX            ;описатель модуля
       LD DE,OPIS3
       LD BC,32
       LDIR

       LD IX,(BUFFIL)  ;загружаем модуль

     ;Относительно начала буфера адрес будет +#0300
       LD DE,$LENDEP+$LEN128+$LENNOV
       ADD IX,DE
       LD DE,(OPIS3+14) ;длина не более #0200 байт
       XOR A
       LD HL,0
       LD C,#29
       RST 16
       RET C


       LD HL,FUNC    ;открываем файл с модулем функций
       LD C,#25
       RST 16
       RET C

       EXX            ;описатель модуля
       LD DE,OPIS3
       LD BC,32
       LDIR

       LD IX,(BUFFIL)  ;загружаем модуль
     ;Относительно начала буфера адрес будет +#0500
       LD DE,$LENDEP+$LEN128+$LENNOV+$LENMENU
       ADD IX,DE
       LD DE,(OPIS3+14) ;длина не более #0100 байт
       XOR A
       LD HL,0
       LD C,#29
       RST 16
       RET C

       LD HL,(BUFFIL)     ;считаем КС распаковщика и всех модулей
       LD BC,$LENMOD      ;длина всех файлов - #0600 байт
       CALL CALCCS

       LD IX,SRED2       ;среда с открытым выходным файлом
       CALL LOADSRED

       LD IX,(BUFFIL)    ;пишем все модули внутрь выходного файла
       XOR A
       LD HL,$HRUST
       LD DE,$LENMOD     ;длина четырёх модулей подряд
       LD C,#2A
       RST 16
       RET C

       LD DE,(KS)  ;окончательный подсчёт контрольной суммы всех модулей
       XOR A
       SBC HL,HL
       SBC HL,DE
       PUSH HL

       LD C,#35    ;сохраним КС выходного файла в описатель файла
       RST 16
       EXX
       LD DE,26
       ADD HL,DE
       POP DE
       LD (HL),E
       INC HL
       LD (HL),D

       LD C,#28    ;сохраним изменённый описатель файла
       RST 16
       RET C

       LD C,#45     ;восстановим первоначальную среду
       RST 16
       EXX
       LD HL,SRED0
       LD BC,4
       LDIR

       JP QUIT

;Обнаружен комментарий (строка начинается с символа ;)
;Пропускаем всю строку
AN2    INC HL
       LD A,(HL)
       CP #0D
       JR NZ,AN2
       JP AN0




QUIT   LD C,2
       RST 16
       RET C

       XOR A
       LD A,#F4
       RET


;Указан ключ
BEG2   RES 5,A
       CP "R"      ;Режим сборки в ПЗУ
       JR Z,BEG22

       CP "O"      ;Указание выходного файла
       JR Z,BEG21

       JP BEG0

;Включение режима сборки в ПЗУ Эльф
BEG22
       LD HL,#8000
       LD (SMESH),HL
       XOR A        ;убираем установку 7-го бита в номере порта
       LD (SETP0),A
       LD A,2       ;добавляем к номерам банков ПЗУ число 2
       LD (SETP1),A
       LD A,#FF     ;первый байт банка не "S", а #FF
       LD (FBYTE),A
       JP BEG0

;Ключ /O - указание выходного файла
BEG21  EXX          ;HL указывает на "/"
       INC HL       ;указывает на ключ "О"
       INC HL       ;HL указывает на первый символ имени файла
       LD DE,OPIS2  ;преобразуем имя выходного файла в 11 байт описателя DE
       LD C,#46
       RST 16
       RET C

       LD C,#45   ;перенос даты из системы в описатель
       RST 16
       EXX
       DEC HL
       DEC HL
       LD D,(HL)
       DEC HL
       LD E,(HL)
       LD (OPIS2+30),DE

       LD C,#24       ;удаляем файл, если он был
       LD HL,OPIS2
       RST 16
       RET C

       LD HL,OPIS2   ;создаём выходной файл с длиной до начала игр
       LD C,#23      ;длина уже задана в описателе
       RST 16
       RET C

       LD IX,SRED2
       CALL SAVESRED

       OR #FF
       LD (FIL2),A

       LD C,2
       RST 16
       RET C

       JP BEG0

;Указан файл-параметр или ключ
BEG1   OR A
       JR NZ,BEG2    ;ключ

;указан файл-параметр
       EXX
       LD C,#25
       RST 16
       RET C

       EXX
       LD DE,OPIS
       LD BC,32
       LDIR

;Посчитаем адрес буфера для создания выходного файла
       LD DE,(OPIS+14)  ;длина входного файла со списком игр
       LD HL,EKRAN      ;было $BUFER, а грузим в экранную область (#4800)
       ADD HL,DE
       LD (BUF2ADR),HL

       LD HL,$BUFER    ;Буфер для копирования файлов игр будет
       LD (BUFFIL),HL  ;расположен сразу на концом программы

       LD DE,BUFLEN    ;в буфер должно поместиться 16К
       ADD HL,DE
       CALL CACHEMEM   ;влезет ли буфер под кэш?
       RET C

       LD DE,(OPIS+14)  ;Загружаем входной файл в буфер
       LD C,#29
       LD IX,EKRAN      ;было $BUFER
       XOR A
       LD HL,0
       RST 16
       RET C

       OR #FF      ;Признак, что входной файл указан и загружен
       LD (FIL),A
       JP BEG0


SAVESRED
       XOR A
       LD C,#36
       RST 16
       RET

LOADSRED
       XOR A
       LD C,#37
       RST 16
       RET

;Установка адреса порта в A и адреса в банке в HL в зависимости от адреса AHL
SETPORT
       PUSH HL
       PUSH AF
       LD A,H
       AND %11000000
       LD H,A
       POP AF
       SLA H
       RLA
       SLA H
       RLA
       OR %10000000
SETP0  EQU $-1        ;для режима сборки в ПЗУ Эльф не устанавливаем 7-й бит
       POP HL
       PUSH AF
       LD A,H
       AND %00111111
       LD H,A
       POP AF
       ADD A,0       ;для режима сборки в ПЗУ Эльф добавляем к банку число 2
SETP1  EQU $-1       ;так как банки с играми начинаются с банка №2
       LD (BANK),A
       LD (BADR),HL
       RET


;Подсчёт  контрольной суммы блока HL длиной BC байт. Возврат в HL и сохранение
;в KS.
CALCCS PUSH IX
       PUSH BC
       PUSH AF
       PUSH DE
       LD IX,(KS)
       LD D,0
1$     LD A,(HL)
       LD E,A
       ADD IX,DE
       INC HL
       DEC BC
       LD A,B
       OR C
       JR NZ,1$
       PUSH IX
       POP HL
       LD (KS),HL
       POP DE
       POP AF
       POP BC
       POP IX
       RET

;Проверка - влезет ли адрес HL под кэш.
;CF - не влезет, ошибка 130
CACHEMEM
       PUSH DE
       EX DE,HL
       LD HL,(CACHE)
       DEC HL
       OR A
       SBC HL,DE
       POP DE
       RET NC
       LD A,130
       RET


;Перенос файла с игрой в конец выходного файла.
;Учитываются 0-е байты в начале каждого банка ПЗУ
LDBLK
       XOR A
       SBC HL,HL
       LD (FADR),HL      ;текущая позиция в файле с игрой = 0
       LD (FADR+2),A
       LD HL,(OPIS3+14)  ;Длина игры
       LD A,(OPIS3+16)
       LD (FLEN),HL
       LD (FLEN+2),A

LDBLK2 XOR A
       LD (DOPLEN),A
       LD HL,(BUFFIL)
       LD (ADRBUF),HL

       LD HL,(ADR3)    ;считаем адрес банка ПЗУ и адрес внутри банка
       LD A,(ADR3+2)
       CALL SETPORT
       LD A,H          ;если начинаем с адреса 0 в банке ПЗУ
       OR L
       JR NZ,LDBLK0
       INC A           ;то добавляем дополнительный байт 0 к переносимой
       LD (DOPLEN),A   ;информации
       INC HL          ;начинаем банк с адреса 1
       LD (BADR),HL
       LD HL,(ADRBUF)
       LD (HL),0
       INC HL
       LD (ADRBUF),HL
LDBLK0                 ;сколько байт влезет до конца текущего банка ПЗУ?
       LD HL,#4000
       LD DE,(BADR)
       XOR A
       SBC HL,DE      ;HL - остаток до конца текущего банка ПЗУ
       LD (QUANT),HL

       LD A,(FLEN+2)  ;От доступного объёма в банке ПЗУ AHL вычитаем
       LD B,A         ;оставшуюся длину файла с игрой BDE
       LD DE,(FLEN)
       XOR A
       SBC HL,DE
       SBC A,B
       JR C,LDBLK1

;Остаток игры помещается до конца текущего банка ПЗУ
       LD DE,(FLEN)
       CALL MOVE       ;переносим поэтапно через буфер данные
       RET C

;       LD IX,SRED1      ;среда с игрой
;       CALL LOADSRED

;       LD IX,(ADRBUF)   ;загружаем остаток игры
;       LD HL,(FADR)
;       LD A,(FADR+2)
;       LD DE,(FLEN)
;       LD C,#29
;       RST 16
;       RET C

;       LD HL,(FLEN)      ;считаем КС остатка игры
;       LD DE,(DOPLEN)
;       LD D,0
;       ADD HL,DE
;       LD B,H
;       LD C,L
;       PUSH BC
;       LD HL,(BUFFIL)
;       CALL CALCCS

;       LD IX,SRED2    ;среда с файлом ПЗУ
;       CALL LOADSRED

;       POP DE        ;добавляем к выходному файлу остаток байт
;       LD C,#31
;       RST 16
;       RET C

;       LD A,(ADR3+2)  ;пишем остаток игры в файл с ПЗУ
;       LD HL,(ADR3)
;       LD IX,(BUFFIL)
;       LD C,#2A
;       RST 16
;       RET C

       LD HL,(FLEN)
       LD DE,(DOPLEN)
       LD D,0
       ADD HL,DE
       EX DE,HL
       LD A,(ADR3+2) ;посчитаем следующий адрес внутри ПЗУ
       LD HL,(ADR3)
       ADD HL,DE     ;DE посчитано ранее - это кол-во добавляемых к ПЗУ байт
       JR NC,$+3
       INC A
       LD (ADR3),HL
       LD (ADR3+2),A

       XOR A
       RET

;Остаток игры не влезет до конца текущего банка ПЗУ
LDBLK1

       LD DE,(QUANT)
       CALL MOVE
       RET C

;       LD IX,SRED1      ;среда с игрой
;       CALL LOADSRED

;       LD IX,(ADRBUF)   ;загружаем столько байт, сколько доступно до конца ПЗУ
;       LD HL,(FADR)
;       LD A,(FADR+2)
;       LD DE,(QUANT)
;       LD C,#29
;       RST 16
;       RET C

;       LD HL,(QUANT)      ;считаем КС загруженного куска файла
;       LD DE,(DOPLEN)
;       LD D,0
;       ADD HL,DE
;       LD B,H
;       LD C,L
;       PUSH BC
;       LD HL,(BUFFIL)
;       CALL CALCCS

;       LD IX,SRED2    ;среда с файлом ПЗУ
;       CALL LOADSRED

;       POP DE        ;добавляем к выходному файлу количество загруженных байт
;       LD C,#31
;       RST 16
;       RET C

;       LD A,(ADR3+2)  ;пишем остаток игры в файл с ПЗУ
;       LD HL,(ADR3)
;       LD IX,(BUFFIL)
;       LD C,#2A
;       RST 16
;       RET C

       LD HL,(QUANT)
       LD DE,(DOPLEN)
       LD D,0
       ADD HL,DE
       EX DE,HL
       LD A,(ADR3+2) ;посчитаем следующий адрес внутри ПЗУ
       LD HL,(ADR3)
       ADD HL,DE     ;DE посчитано ранее - это кол-во добавляемых к ПЗУ байт
       JR NC,$+3
       INC A
       LD (ADR3),HL
       LD (ADR3+2),A

       LD A,(FADR+2) ;посчитаем следующий адрес внутри игры
       LD HL,(FADR)
       LD DE,(QUANT) ;сколько байт было доступно до конца ПЗУ
       ADD HL,DE
       JR NC,$+3
       INC A
       LD (FADR),HL
       LD (FADR+2),A

       LD HL,(FLEN)    ;уменьшаем оставшуюся длину игры
       LD A,(FLEN+2)
       OR A
       SBC HL,DE
       JR NC,$+3
       DEC A
       LD (FLEN),HL
       LD (FLEN+2),A

       LD B,A     ;если всё считали, выходим
       LD A,H
       OR L
       OR B
       RET Z

       JP LDBLK2



;DE-количество байт для переноса
MOVE
       LD (MOVEC),DE
       LD HL,(FADR)
       LD (FADR2),HL
       LD A,(FADR+2)
       LD (FADR2+2),A
       LD HL,(ADR3)
       LD A,(ADR3+2)
       LD (ADR32),HL
       LD (ADR32+2),A
       LD A,(DOPLEN)
       LD (MOVED),A

MOVE0  XOR A          ;проверка влезет ли загружаемая длина в буфер
       LD HL,BUFLEN
       LD DE,(MOVEC)
       SBC HL,DE
       JR C,MOVE1

;остаток файла целиком влезет в буфер
       LD IX,SRED1    ;среда файла с игрой
       CALL LOADSRED

       LD IX,(ADRBUF)    ;грузим остаток файла
       LD HL,(FADR2)
       LD A,(FADR2+2)
       LD DE,(MOVEC)
       LD C,#29
       RST 16
       RET C

       LD HL,(MOVEC)      ;считаем КС остатка игры
       LD DE,(MOVED)      ;с учётом байта 0 в начала банка ПЗУ, если надо
       LD D,0
       ADD HL,DE
       LD B,H
       LD C,L
       PUSH BC
       LD HL,(BUFFIL)
       CALL CALCCS


       LD IX,SRED2   ;среда выходного файла
       CALL LOADSRED

       POP DE        ;увеличиваем выходной файл на считанное кол-во байт
       LD C,#31      ;+0-й байт начала банка ПЗУ, если надо
       RST 16
       RET C

       LD IX,(BUFFIL)   ;пишем остаток в выходной файл
       LD HL,(ADR32)    ;количество байт для записи - ранее посчитанное в DE
       LD A,(ADR32+2)
       LD C,#2A
       RST 16
       RET

;остаток файла не влезает в буфер
MOVE1  LD IX,SRED1    ;среда файла с игрой
       CALL LOADSRED

       LD IX,(ADRBUF)    ;грузим часть файла
       LD HL,(FADR2)
       LD A,(FADR2+2)
       LD DE,BUFLEN
       LD C,#29
       RST 16
       RET C

       LD HL,BUFLEN      ;считаем КС остатка игры с учётом 0-го байта 0 в
       LD DE,(MOVED)     ;начале банка ПЗУ, если надо
       LD D,0
       ADD HL,DE
       LD B,H
       LD C,L
       PUSH BC
       LD HL,(BUFFIL)
       CALL CALCCS


       LD IX,SRED2   ;среда выходного файла
       CALL LOADSRED

       POP DE        ;увеличиваем выходной файл на считанное количество байт
       LD C,#31      ;+0-й байт начала банка ПЗУ, если надо
       RST 16
       RET C

       LD IX,(BUFFIL)   ;пишем загруженное в выходной файл
       LD HL,(ADR32)    ;количество байт в DE ранее посчитано
       LD A,(ADR32+2)
       LD C,#2A
       RST 16
       RET C

       LD DE,BUFLEN
       LD HL,(FADR2)   ;увеличиваем адрес в файле-источнике
       LD A,(FADR2+2)
       ADD HL,DE
       JR NC,$+3
       INC A
       LD (FADR2),HL
       LD (FADR2+2),A


       LD HL,BUFLEN
       LD DE,(MOVED)
       LD D,0
       ADD HL,DE
       EX DE,HL
       LD A,(ADR32+2) ;посчитаем следующий адрес внутри ПЗУ
       LD HL,(ADR32)
       ADD HL,DE     ;DE посчитано ранее - это кол-во добавляемых к ПЗУ байт
       JR NC,$+3
       INC A
       LD (ADR32),HL
       LD (ADR32+2),A

       XOR A          ;если 0-й байт в начале банка ПЗУ уже был, больше
       LD (MOVED),A   ;его не используем, он нужен только один раз
       LD HL,(BUFFIL) ;адрес буфера для считывания возвращаем к оригиналу,
       LD (ADRBUF),HL ;без учёта 0-го байта в начале банка ПЗУ

       XOR A         ;уменьшаем количество оставшихся байт
       LD HL,(MOVEC)
       LD DE,BUFLEN
       SBC HL,DE
       LD (MOVEC),HL

       JP MOVE0

MOVEC  DEFW 0
MOVED  DEFB 0  ;копия DOPLEN
FADR2  DEFS 3  ;копия FADR
ADR32  DEFS 3  ;копия ADR32



ADRBUF DEFW 0
DOPLEN DEFB 0
BANK   DEFB 0
BADR   DEFS 3
QUANT  DEFW 0
FLEN   DEFS 3
FADR   DEFS 3


;Печать имени конвертируемой игры из NAME2 в 0-й строке экрана
PRINT  PUSH HL
       PUSH DE
       PUSH BC
       PUSH AF

       LD HL,0     ;Установка координат для печати
PRTCRD EQU $-2
       LD C,#0C
       RST 16

       LD A,(PRTCRD)  ;Если уже напечатали строку "Processing"
       OR A           ;переходим сразу к печати имени игры
       JR NZ,PRT2

       LD HL,PRTSTR   ;Если процедура была вызвана первый раз,
       LD C,#6C       ;печатаем строку "Processing"
       RST 16
       LD A,11        ;Устанавливаем новую координату печати
       LD (PRTCRD),A

PRT2   LD B,42  ;Количество символов в строке экрана (тут значение для iS-DOS)
LENSTR EQU $-1
       LD C,#0A
       LD HL,NAME2
PRT0   LD A,(HL)
       CP #0D
       JR Z,PRT1
       RST 16
       INC HL
       DJNZ PRT0
PRT1   LD A," "   ;Остаток строки допечатываем пробелами
       RST 16
       DJNZ PRT1

       POP AF
       POP BC
       POP DE
       POP HL
       RET

PRTSTR DEFM "Processing:"
       DEFB 13


SRED0  DEFS 4    ;изначальная среда вызова программы
SRED1  DEFS 4    ;среда файла с игрой
SRED2  DEFS 4    ;среда файла с ПЗУ
SRED3  DEFS 4    ;среда с открытым файлом программы
OPIS   DEFS 32   ;описатель входного файла
OPIS2  DEFS 11   ;описатель файла с ПЗУ
       DEFB %00000001
       DEFW 0
       DEFW $GAMES  ;3 байта длины файла
       DEFB 0
       DEFS 15
OPIS3  DEFS 32   ;описатель файла с игрой
NAME   DEFS 13   ;буфер для формирования имени игры
NAME2  DEFS 13   ;буфер для конвертирования имени игры
       DEFB 13
TEKSTR DEFW 0
KS     DEFW 0    ;контрольная сумма выходного файла
BUF2ADR DEFW 0   ;адрес буфера для создания банка ПЗУ
BUFFIL  DEFW 0   ;адрес буфера для копирования файлов
ROMADR  DEFW 0   ;текущий адрес в банке ПЗУ при формировании меню игр
ADR3    DEFW $GAMES ;текущий адрес в ПЗУ картриджа при формировании игр
        DEFB 0
DEHR    DEFM "dehrust cod"
CH128   DEFM "check128cod"
CHNOV   DEFM "checkAlfcod"
MENU    DEFM "menu    cod"
FUNC    DEFM "func    cod"
CACHE   DEFW 0   ;адрес кэша
SMESH   DEFW 0   ;смещение при расчёте положения игры на картридже. Нужно для
                 ;случая компиляции образа для прошивки непосредственно в ПЗУ
                 ;приставки. В этом случае тут будет значение #8000

BUFLEN  EQU 8192   ;Размер буфера для загрузки игр
EKRAN   EQU #4800  ;Адрес в экранной области для буфера загрузки входного
                   ;текстового файла
