Код:
КАК ДЕЛАТЬ ПРОГРАММЫ С АВТОМАТИЧЕСКОЙ ЗАГРУЗКОЙ
===============================================
Все видели, как красиво загружаются с магнитофона игровые программы
ZX-SPECTRUM. Программы для "СПЕЦИАЛИСТА" могут загружаться также эффек-
тно, тем более, что в "СПЕЦИАЛИСТЕ" загрузка осуществляется сразу по
сбросу, т.е нет необходимости набора команды с клавиатуры: запустил маг-
нитофон нажал на кнопку и любуйся "эффектами загрузки". Весьма эффектна
загрузка заставки прямо в экран, бегущий счетчик, отсчитывающий время
загрузки, двигающиеся спрайты и блоки, вывод текста-описания игры во
время ее загрузки с ленты и другие подобные эффекты. Кроме задачи "укра-
шения" процесса загрузки, блочная автоматическая загрузка позволяет ре-
шить задачу защиты от копирования коммерческих программ, т.к при блоч-
ной загрузке появляется возможность изменить формат записи на ленту, тем
самым затрудняя задачу взлома защиты кракеру (нельзя путать 2 разных
термина - кракер и хакер; в то время как хакер, это высококвалифициро-
ванный программист-любитель, не занимающийся пиратством, кракер - прог-
раммист-вредитель "ломающий" защиты с целью "прославиться" и "зарабо-
тать" на пиратстве, т.е понятие кракер равноценно понятию вор).
Данная статья предназначена для начинающих программистов для
"СПЕЦИАЛИСТА" и предполагает то, что читатель уже знает все стандартные
подпрограммы BIOS "СПЕЦИАЛИСТА". Кроме того необходимо заметить, что эта
статья относится только к "настоящему СПЕЦИАЛИСТу", т.е к "СПЕЦИАЛИСТу"
в самой стандартной версии, а именно аппаратура соответствует 48к-бай-
тной версии (МК,1987,N2), BIOS - загрузчик Волкова (MK, 1987,N5) или лю-
бой другой полностью совместимый BIOS (напр: ленинградский МОНИТОР лю-
бой версии). Версии аппаратуры и программ кооп."SP-580", Афанасьева,
"КОЛЕД" и других, совместимы не 100% и имеют другие "стандартные" под-
программы.
Для начала вспомним, что происходит при работе загрузчика сразу пос-
ле нажатия на кнопку "сброс" волковский загрузчик сразу "вылетает" на
адрес C444. Здесь осуществляется инициализация системных переменных BIOS
(и МОНИТОРА в версии Л-89). Для этого вызывается стандартная (и так "го-
рячо" всеми любимая) подпрограмма пересылки блока: C42D- переброска бло-
ка (HL)...(DE) -> (BC). Далее п/п-ма C438 (PRINT) выводит на экран код
"СТР" (очистка экрана) и сообщение: "PROGRAMM?" (в ленинградском монито-
ре выводится надпись "ЛЕНИНГРАД-1989") и вот здесь начинается самое ин-
тересное. Запускается п/п-мма C3F9. Смысл ее работы: сначала на ленте
ищется синхробайт "Е6". Пока он не найден или нет сигнала, эта п/п-ма
"крутится" на одном месте. Как только синхробайт пойман, то вводятся 4
последующих байта. Два первых определяют с какого адреса загружать вво-
димый блок в ОЗУ (адрес начала блока), 2 следующих - адрес конца блока в
ОЗУ. После этого п/п-ма C3F9 вводит блок и заносит его в ОЗУ по задан-
ным адресам. Ввод заканчивается при заполнении последней ячейки. Адрес
начала блока заносится в ячейку 8FE3. И на этом работа п/п-мы C3F9 за-
канчивается. Далее загрузчик с помощью команды PCHL передает управление
введенной программе (по адресу начала блока). Никакого контроля на пра-
вильность ввода не осуществляется. Таким образом блок грузящийся "по
сбросу" имеет вид: цепочка нулевых-байт (пилотон), синхробайт Е6,
нач.адрес блока (мл.байт, старший байт), конечный адрес блока
(мл.б,ст.б) и сам блок. В таком формате работал монитор Волкова (мони-
тор-1985, 8D00). Этот МОНИТОР уже не используется на "СПЕЦИАЛИСТАХ" и
все пользователи с сентября 1988 года используют только "орловский
МОНИТОР" (обычно в комплекте со зверковским загрузчиком МК,89/4) или го-
раздо более совершенный ленинградский монитор (В.Ивинских). Эти монито-
ры имеют директивы R/W работающие в таком-же формате, за исключением то-
го, что сразу-же за блоком следует контр.сумма: сразу-же, а не как в "у-
родском" формате РК-86, где "К.С" идет только после дополнительной це-
почки нулей и еще одного синхробайта Е6 (кроме того в РК-86 "перепутаны"
адреса блока, т.е у них сначала идёт старший, потом младший байты адре-
са). Кроме директив R/W МОНИТОР имеет директивы I/O - формат с именем
файла (имя до 17 символов, запрашивается). Запись имеет следующий вид:
пилотон (256 0-вых байт), синхробайт E6, 3 байта D9, имя файла, длинный
пилотон (768 0-вых байт), синхробайт Е6,нач.адр, кон.адр, файл, кон-
тр.сумма. Т.е по сути добавлен только "заголовок" со своим пилотоном.
Формат RAMDOS-COMMANDERа полностью совместим с таким форматом, т.к
доп.параметры файла (CSUM, SCODE, WBYTE, ADRAM) передаются вслед за име-
нем файла. Это теория. Как же делаются многоблочные автоматически загру-
жающиеся программы? Идея заключается в том, что сначала загружается ма-
ленькая программка, для "раскрутки". Она может грузиться по сбросу или
перехватывать управление при работе директив ввода - R/I/Y/Z. После заг-
рузки этой программки, ей передается управление, а дальше она уже де-
лает, что хочет.
Первый пример. Пусть по сбросу загружается следующая программа:
ORG 0
LXI H,TXT1 ; HL-адрес текста
CALL 0C438H ; выводим текст (C818)
CALL 0C3F9H ; вводим новый блок
LHLD 8FE3H ; и передаем
PCHL ; ему управление
TXT1: DB 1FH,'ПРИВЕТ !'
DB 0DH,0AH,0
Эта программа очистит экран, напишет "ПРИВЕТ !" и будет вводить но-
вый блок, а потом его запустит на исполнение. Пусть второй блок будет
такой:
ORG 1000H
LXI H,TXT2
CALL 0C438H ; вывод TXT2
JMP 0C800H ; выход в монитор
TXT2: DB 'КОНЕЦ ВВОДА',0
После загрузки этого второго блока будет выдано сообщение TXT2 и
"выйдем" в монитор. Такой ввод возможен только в разные адреса, ведь
после ввода второго блока еще продолжает работать первый блок. Однако в
BIOS имеется п/программа C453, которая вводит и автоматически запускает
на исполнение введенный блок. Если использовать эту подпрограмму, то
второй блок можно грузить прямо на место расположения первого (если пер-
вый блок уже не нужен). Это всё для блоков загружаемых по "указанным"
адресам. Но BIOS "СПЕЦИАЛИСТА" позволяет загружать блоки и по адресам,
задаваемых программой. Тогда на ленте должны отсутствовать начальный и
конечный адреса загрузки блока. Итак C422 - п/п-ма, которая загружает
блок по "произвольным" адресам. Ей надо указать, куда загружать блок в
регистрах HL,DE. Вот пример. 1-й блок:
LXI H,TXT1
CALL 0C438H ; вывод сообщения
LXI H,1000H ; указываем нач. И
LXI D,17FFH ; конечный адреса
CALL 0C422H ; вводим 2 к-байт
JMP 1000H ; и запускаем
Таким образом BIOS "СПЕЦИАЛИСТА" предоставляет 4 стандартные подпрог-
раммы ввода блока. Они описаны во всей литературе по "СПЕЦИАЛИСТу" и
должны безусловно поддерживаться на всех его клонах:
C3F9 - ввод блока с поиском синхробайта, адреса
начала и конца блока указаны на ленте
C422 - ввод блока с поиском синхробайта, адреса
начала и конца блока заданы в HL и DE
C414 - то же самое, но без поиска синхробайта,
позволяет иметь синхробайт не равный E6
C453 - ввод блока с поиском синхробайта и авто-
матическим запуском блока на исполнение
Как видите, благодаря наличию этих удобных П/П-м и процедуры загруз-
ки по сбросу делать автоматически загружаемые программы для
"СПЕЦИАЛИСТА" совсем не сложно. Однако теперь теперь перед программис-
том возникает задача - а как же записать на ленту блоки один за другим,
да еще в некоторых не указывать адреса загрузки, а в других указывать.
Также встает задача последующего копирования блочных программ. Обе эти
задачи были блестяще решены еще в 1988 г В.Ивинских. Записывать блоки на
ленту можно используя ранние версии ленинградского МОНИТОРА (до 2.7), в
которых возможности директив работы с лентой существенно расширены (мож-
но вводить/выводить блоки в указанных выше форматах).
Тем не менее специально для создания и копирования многоблочных прог-
рамм В.Ивинских в конце 1988 г разработал две программы: КОМПОНОВЩИК и
КОПИРОВЩИК. Эти программы предназначены для работы с блоками в одном
стандартном двухфазном формате записи на ленту. Поэтому многие пользова-
тели столкнувшись с тем, что КОПИРОВЩИК не позволяет им копировать защи-
щенные форматом записи блочные программы "СПЕЦИАЛИСТА" напрасно ругали
программу КОПИРОВЩИК (SP-COPY). Рассмотрим назначение программы
КОМПОНОВЩИК. Эта программа позволяет загрузить в ОЗУ компьютера с ленты
заранее подготовленные блоки, причем все они должны быть в стандартном
формате монитора (с именем по директиве "О"). При вводе КОМПОНОВЩИК за-
поминает параметры введенных блоков: адреса, длины пилотонов, имена,
константы ввода. Далее можно, установив требуемые параметры вывода,
вновь вывести эти блоки на ленту и получить готовую многоблочную прог-
рамму. Отличительная особенность КОМПОНОВЩИКА - автоматическое определе-
ние константы чтения (для владельцев ленинградского МОНИТОРА это не осо-
бенность, ибо в нем настройка на скорость осуществляется при работе всех
директив ввода, в том числе и ZX!). После запуска КОМПОНОВЩИКА внизу эк-
рана появляется главное меню программы. Выбранный режим отображается пу-
тем "инверсии". В начале надо запустить режим "LOAD" (нажатием <ВК>) и
ввести все заранее подготовленные блоки. Вводимые блоки укладываются в
ОЗУ один за другим (до 8000H), а на экране в виде таблицы отображается
информация о введенных блоках. Когда введены все блоки, выходят в меню
нажатием <СТР>. Режим "EDIT" позволяет корректировать длину цепочки ну-
левых байтов перед блоком при записи на ленту: миним.длина соответ-
ствует 01, максим. - 09 и выбирается нажатием на соотвующую цифровую
клавишу. Каждая единица дает 85 нулевых байтов (поэтому 03 - стандар-
тная длина 256). Далее нажатием <+> и <-> можно определить выводить ад-
реса начала и конца блока или нет. Клавишами управления курсором влево и
вправо можно задать константу записи (25-99). В режиме "DELETE" можно
удалить самый последний введенный блок, нажав на <ПС> (а не <ВК>!), и
так можно удалить все блоки (тут надо осторожнее). Режим "SAVE". Тут все
просто - <ВК> и на ленту пошли блоки один за другим в заданных форматах
и с нужными скоростями. "EXIT" - это выход в МОНИТОР по адресу C800.
Теперь о копировщике "SP-COPY". В.Ивинских сделал его множество вер-
сий. Наибольшее распространение получили версии 1.3/4 и версия 2.0
(MSХ). Эти версии загружаются по сбросу, причем работают прямо из экран-
ной области (как "жаловались" многие пользователи - работает хорошо, но
возникает "грязь" у правого края экрана !). Т.е сама программа разме-
щаясь в экране (4К) не занимает места в ОЗУ для программ, оставляя для
буфера ввода все 36К ровно. Эта программа абсолютно не использует ника-
ких П/П-мм в ПЗУ и даже стек переносит в экранную область. Скопировать
SP-COPY можно "им самим", но не нужно пытаться что-либо менять в прог-
рамме, впрочем вряд ли это у вас получится. Режимов работы всего 3 и всё
очень просто. Режим выбирается "стрелками вверх-вниз" и запускается по
<ВК>. Отмена режима - <СТР>. Последний введенный блок можно удалить в
любом режиме, нажав <НР>/<СТР> (одновременно). Скорость вывода общая для
всех блоков - и устанавливается "стрелками вправо-влево". Скорость вво-
да определяется автоматически и запоминается; "автоматически" вычисляет-
ся и устанавливается соответствующая константа вывода. Режим "EXIT" -
выход в монитор.
А теперь рассмотрим какие блоки применялись в некоторых блочных прог-
раммах "СПЕЦИАЛИСТА", сделанных в Ленинграде, на примере простейшего
блочного загрузчика игры с заставкой. Игра загружается по сбросу (это
наиболее удобно). Первым загружается и сразу запускается маленький стар-
товый блок (100 байт). Он очищает экран, выводит надпись "НЕ ВЫКЛЮЧАЙТЕ
МАГНИТОФОН..." (или по английски - "DO NOT STOP YOUR TAPE NOW..."). Да-
лее определяется константа чтения (так как пользователь может не иметь
ленинградского МОНИТОРА, где это делается по сбросу) и управление пере-
дается программе C453 - загрузка следующего блока с его автоматическим
запуском. Пока всё просто. То есть первый блок на ленте имеет вид:
Нач.адрес
Кон.адрес
Вывод надписи
Опред-е конст.чт.
JMP 0C453H
Контр.сумма
В этом блоке контр.сумма не используется, но в последующих блоках она
имеет значение. Следующий блок - загрузчик всего остального. Его струк-
тура:
Нач.адрес
Кон.адрес
Вывод текста "GAME IS LOADING"
Загрузка программы вывода заставки (бл.3)
Загрузка картинки-заставки (бл.4)
CALL программы вывода картинки
Загрузка блоков игры (бл.5)
JMP игра
Контр.сумма
Таким образом 2-й блок по загрузке и запуску не отличается от первого
- так же загружается и автоматически запускается (хоть так как констан-
та чтения теперь не важна, этот блок можно для повышения надежности гру-
зить со скоростью вдвое медленнее). Вся дальнейшая загрузка осущес-
твляется под управлением этой программы - загрузчика (блока 2). За-
метьте ! - последующие 3 блока уже не имеют начального и конечного адре-
сов. Программа-загрузчик знает их заранее. Этот загрузчик уже не ис-
пользует П/П-мы BIOS "СПЕЦИАЛИСТА", а имеет свою собственную, более со-
вершенную программу ввода с магнитофона, - она осуществляет текущий кон-
троль качества ввода, подстраивается под скорость записи, проверяет кон-
тр.суммы и может делать различные "чудеса", типа бегущего счетчика, по-
лос по бордюру, двигающихся блоков и т.п. Впрочем эти эффекты вовсе не
являются чудесами, а являются обычным делом для владельцев ленинградско-
го монитора (где бегущий счетчик адреса и поддержка бордюра входят пря-
мо в стандартные п/п-мы ввода/ вывода байта). Текущий контроль ввода
сразу-же позволяет определить "останов" магнитофона или провал в записи
(попробуйте остановить ленту - сразу же "запищит" и замигает надпись
"TAPE LOADING ERROR !"). Игру полезно грузить маленькими блоками с кон-
тр.суммами каждого. Во-первых это позволяет сразу же обнаружить сбой, а
во-вторых большое количество блочков загружаемых по разным адресам
(напр-р: задом наперед) не затрудняя копирование копировщиком, сильно
затрудняет работу кракерам, любящим "влезать" в чужие программы. Естес-
твенно стартовый адрес игры не должен быть очевидным и при работе игра
должна проверять "флаги", выставленные загрузчиком, для сообщения "об
отсутствии пиратства". Немного фантазии и "изменять" вашу программу уже
мало кто захочет, ибо время потраченное на взлом сравнится с трудоемкос-
тью создания новой программы. Естественно если ваша программа защищает-
ся от копирования, а не только от изменения, то загрузчик должен изме-
нить и формат записи и конечно от копирования защищать программы нужно
значительно "умнее",так как программу защищаемую от копирования, "кра-
кают гнусные пираты", с целью получения наживы, а не любители для лично-
го удовольствия.
Чтобы сделать описанную выше блочную загрузку игры можно воспользо-
ваться компоновщиком, а если скорость ввода не меняется то можно обой-
тись ленинградским монитором и копировщиком. Все блоки готовятся зара-
нее и записываются на ленту причем первые 2 блока обязательно из тех-же
адресов, где они будут работать! Остальные - всё равно. Эти блоки запи-
сывают на ленту, причем для блоков 1 и 2 нужно выводить адреса загрузки,
а для блоков 3,4 и 5 не надо, и даже нельзя. Иначе весь блок будет счи-
тан со сдвижкой на 4 байта! кроме того между блоком 4 и блоком 5 необхо-
дима пауза побольше - т.е длинный пилотон перед блоком 5. Это необходи-
мо, чтобы успела отработать программа копирования в экран цветной зас-
тавки. Тут уж без компоновщика, одним копировщиком не обойтись кстати
копировщик при копировании всегда "считает" и запоминает длину пилотона,
поэтому если вы будете нажимать <ВК> позже начала пилотона, то пилотон
на копии будет короче, чем на оригинале. Чтобы облегчить вам разработку
собственных блочных загрузчиков, рассмотрим простую 4-х блочную програм-
мку. Проделайте всё сами на компьютере. С помощью редактора и ассемблера
подготовьте на ленте 4 файла (уже в машинных кодах разумеется).
БЛОК 1: ORG 0
LXI H,TXT1
CALL 0C438H
JMP 0C453H
TXT1: DB 1FH,'ЗАГРУЖЕН БЛОК 1',0
БЛОК 2: ORG 0
LXI H,TXT2
CALL 0C438H
LXI H,100H
LXI D,KON3-1 ; конечный адрес блока 3
MVI A,0FFH ; подставьте после трансляции
CALL 0C416H ; программы блока 3
JMP 100H
TXT2: DB 13,10,'ЗАГРУЖЕН БЛОК 2',0
БЛОК 3: ORG 100H
LXI H,TXT3
CALL 0C438H
CALL 0C3F9H
LXI H,TXT4:
LHLD 8FE3H
CALL 0CC6CH ; вывод HL в HEX-виде
PCHL
TXT3: DB 13,10,'ЗАГРУЖЕН БЛОК 3',0
TXT4: DB 13,10,'ЗАГРУЖЕН БЛОК 4 С АДРЕСА: ',0
KON3: ; это адрес конца блока 3
БЛОК 4: ORG 200H
LXI H,TXT5
CALL 0C438H
JMP OC800H ; выход в монитор
TXT5: DB 13,10,'БЛОК 4 ОТРАБОТАЛ !',0
Тут применены все виды загрузки. При компоновке для блоков 1,2 и 4
надо указывать их адреса загрузки (т.е "+" в таблице компоновщика), для
блока 3 - нет. Но в блоке 2 должны быть заданы его начальный и конечный
адреса. Думаю проделать этот простейший пример сможет каждый. Применив
немного фантазии и свои несложные програмки вы можете значительно "укра-
сить" процесс загрузки имеющихся у вас игр (например: сделайте процесс
загрузки с двойным дублированием блоков или с выводом сообщения после
ввода очередного блока: "до конца загрузки осталось XX мин. XX сек.").
Советуем также разобрать стартовые блочки-загрузчики, примененные,
напр-р в копировщике или других наших блочных программах. Изучив их заг-
рузчики, вы сможете "выдрать" надежные п/программы чтения, а из игр вы
можете взять подпрограмму ввода заставки прямо в экран (по
синклеровски). А изучение загрузчиков защищенных от копирования прог-
рамм позволит вам и самим защищать свои программы, что позволит вам да-
же продавать ваши программы, не опасаясь пиратов. К сожалению нарисо-
вать граф.редактором картинку-заставку - невозможно (если вы не худож-
ник). Поэтому выходом здесь может быть использование заставок или спрай-
тов из программ ZX-SPECTRUM. Для этого служит программа В.Ивинских
"ZX-PICTURE". Она позволяет считывать с ленты программы в формате
"СИНКЛЕРА" и использовать графику его программ. Несколько замечаний. Для
"СПЕЦИАЛИСТА" существует несколько версий BIOS и МОНИТОРОВ (конечно ни
один из этих МОНИТОРОВ нельзя даже сравнивать по качеству с ленинград-
ским). Все эти программы большей частью совместимы с BIOS Волкова по
системным п/программам в ПЗУ, но служебные ячейки в ОЗУ обычно ис-
пользуют по-разному. Например в ленинградском МОНИТОРЕ векторизованы все
стандартные п/программы, что означает, что любая из них может быть заме-
нена п/программой пользователя (напр: можно загрузить магн.драйвер, ко-
торый заменив стандартные п/п-мы ввода/вывода байта на МГ, изменит фор-
мат работы с магнитофоном на MSX (2-х частотн.с побайтовой синхр-ей) или
напр-р "синклеровский"), а также в ОЗУ хранятся адреса важных п/п-м са-
мого монитора (CCP), служебные ячейки RAMDOS и т.д. Именно благодаря та-
кому "расширению" количества служебных ячеек BIOS, ленинградский мони-
тор и стал таким "гибким" и удобным. Поэтому, чтобы обеспечить совмести-
мость со всеми используемыми системными программами не стоит использо-
вать для загрузчиков ОЗУ по адресам служебных ячеек (256 байт ниже экра-
на), делать блочные программы использующие "нестандартные" входные точ-
ки разных BIOS-ов, а также "перехватывающие" управление за счет "служеб-
ных" ячеек. Конечно эффектно, когда программа "вышибает" управление у
монитора и Вы при попытке загрузить обычный файл директивой "I", вдруг
видите на экране разные неожиданные "чудеса". Однако это приведет к неу-
добству других пользователей, ведь для "СПЕЦИАЛИСТА" столько-же монито-
ров, сколько крупных городов в стране. Поэтому для "трюков" следует ис-
пользовать лишь стандартные ячейки. Некоторые из этих стандартных ячеек
приведены ниже:
8FE3/E4 - при работе п/п-мы C3F9 сюда заносится
адрес начала введенной в ОЗУ программы
8FE7/E8 - адрес начала знакогенератора сдвинутый
вправо на 3 разряда
8FEC - признак регистра РУС/ЛАТ (8А ИЛИ 3А)
8FEF/F0 - код нажатой клавиши по верхн. Регистру
8FF1/F2 - частота/длительность звука при работе
станд.подпрограммы вывода звука - C170
8FF6/F7 - ячейка временного хранения стека (SP)
8FFA/FB - "маска" при выводе на экран (XRA)
8FFC - вертикальная координата курсора (0...255)
8FFD - горизонтальн.координата курсора (0...191)
8FFE - константа записи. Зависит от такта про-
цессора. Для 2 МГЦ=28H, 2,5=34H, 4,0=5FH
8FFF - константа ввода. При такте 2МГЦ = 3CH.
Для 2,5 МГЦ = 4CH, для 4 МГЦ = 80H. Для
ленинградского монитора при работе п/п-м
с поиском с/б это значение не играет роли
т.к сюда заносится автоматически опреде-
ленная константа ввода, но при работе п/п
ввода байта, эта ячейка ОЗУ также важна.
И еще один совет. В последнее время многие "специалисты" повышают
такт процессора до 2,5-3,5 МГЦ для КР580, и до 4,0-4,5 МГЦ при замене
процессора на "ZILOG-80". При разработке блочных загрузчиков это необхо-
димо учитывать, ибо, если например ваш загрузчик контролирует время до
начала очередного блока (естественно, чтобы "помучить кракера"), а т.к
считать время можно только програмно, то при загрузке на машине с двой-
ным тактом, программа подождав вдвое меньшее время будет вынуждена "у-
ничтожить" всё ОЗУ, полагая что "кракер" пытается "ломать вашу защиту".
Проще всего узнать скорость машины можно "посмотрев" константу записи,
которая также инициализируется по сбросу.
Этот текст был написан в 1989. Сейчас он был лишь немного доработан.
Следует также заметить, что все, что здесь описано, было разработано
В.Ивинских еще в 1988 году. Тем не менее эти материалы могут помочь на-
чинающим сделать первые шаги в программировании, кого-то подтолкнут к
собственным разработкам (возможно и для "ОРИОНА") поэтому этот текст и
был предложен для планируемого журнала для любителей ОРИОНА В.Леонтьева
из Ижевска.
barsik, С-Петербург, апрель 1993