Adventurer
#06
28 февраля 1997 |
|
Обмен опытом - Как сделать дисковую версию программы ?..
(C) RAY (C) Музыка PHANTOM LORD/ACCEPT CORP. ╔───────────────────────────────────────╗ │ ──── КАК СДЕЛАТЬ ДИСКОВУЮ ВЕРСИЮ ──── │ ╚───────────────────────────────────────╝ Вам, безусловно, знакома такая ситу- ация: при загрузке некоторой программы (неважно, игра или системка) выдается со- общение "Disked by ...", a затем, при по- пытке, скажем, загрузить что-то, вы ви- дите помаргивающий бордер. Какие слова будут сказаны в адрес того самого "диске- тизатора", надеюсь, вы сами догадаетесь. В общем, я считаю так : можно писать в загрузчике, что программа дискетирована только тогда, когда сделана ПОЛНАЯ ДИСКО- ВАЯ версия. Если же просто приляпан дис- ковый loader, то уж лучше ничего не пи- сать или отметить, что-де не полностью прога дискетирована. Правда последний ва- риант мало кого может устроить, поэтому я поделюсь с вами некоторой информацией о том, как сделать полную дисковую версию программы. Итак, у вас есть некий кодовый блок, в котором надо изменить загрузку/выгрузку каких-либо данных с ленты на диск. Снача- ла смотрим адрес загрузки блока. Обычно на единицу меньше этого адреса устанавли- вается стек. (ВНИМАНИЕ : убедитесь, что после запуска программа не изменяет свое- го положения в памяти, в частности, не перебрасывает ли себя ниже этого адреса!) Обычно минимальный адрес бывает 24500. Если у блока такой адрес или больший - все О.к., 90%, что проблем с переделкой под диск не возникнет. Если же нет - си- туация чуть более сложная и ее рассмотрим позже (в этой статье рассматривается дис- кетизация стандартными методами TR-DOS). Перед тем, как искать точки входа в ленточные процедуры загрузки/записи, по- лезно просмотреть всю память на предмет нахождения незанятого программой места. Как показала практика, в любой проге всегда найдется байт 150..200 свободного места (можно кусками, байт по 45). А это- го с лихвой хватит для наших целей. Если же нет - можно использовать место, кото- рое занимает BASIC-загрузчик. Теперь начинаем искать точки входа. Тут тоже может быть два варианта: 1) программа использует собственные про- цедуры загрузки/записи; 2) программа пользуется процедурами из ПЗУ. В первом случае искать точки входа труднее, но зато не нужно будет потом на- ходить свободное место в программе, т.к. новые подпрограммы как раз уместятся на месте старых. Во втором случае можно попытаться найти вызовы ПЗУ. Рекомендую сначала найти точку входа в SAVE, т.к. в ней легче определить пара- метры отгружаемого блока (начальный адрес /обычно в регистре IX/ и длину /рег. DE/). Приведу некоторые точки входа для ленточных подпрограмм в ПЗУ, вытащенные из разных программ: мнемоника байты для поиска ───────────────────────────────────────── SAVE: CALL 1218 CD C2 04 CALL 1222 CD C6 04 LOAD: CALL 1366 CD 56 05 CALL 2050 CD 02 08 CALL 1378 CD 62 05 CALL 1889 CD 61 07 ───────────────────────────────────────── Кроме этого встречаются и экзотические способы: CALL #0605 где SAVE или LOAD определяется по ячейке 23688 = 0 - SAVE 1 - LOAD Еще более интересный способ: SAVE: CALL 2416, где IX - первые 17 байт - заголовок, затем данные; длина задается так: LD DE, длина LD (IX+11),D LD (IX+12),E . Если же у вас подозрение, что в программе используются собственные проце- дуры работы с лентой, то можно сделать следующее. Т.к. обычно такие процедуры делаются на основе ПЗУ'шных, то ищите такую последовательность: код мнемоника ────────────────── 08 EX AF,AF' 13 INC DE DD 2B DEC IX F3 DI Это кусочек из процедуры, расположенной в ПЗУ по адресу 1222 (#04C6). Если вы нашли нечто подобное, значит это начало (почти) подпрограммы записи на ленту. Осталось только найти, где осуществляется ее вызов и определить параметры отгружаемого бло- ка. Если ничего из вышеприведенного не помогло - попробуйте поискать сообщения, которые программа выдает при работе с лентой. Обычно эти сообщения находятся рядом с соответствующими процедурами. Итак, все мы нашли. Замените адреса вызова найденных подпрограмм на приведен- ные ниже. Правда, есть еще один момент: может быть три варианта отгрузки (для загрузки - аналогично): 1) в один и тот же файл; 2) в одно и то же место на диске или "в себя"; 3) в разные файлы (наиболее предпочти- тельно). В первом случае имя файла фиксирова- но. Во втором оно вообще не нужно. А в третьем нужно его как-то вводить (такое обычно встречается в адвентюрных играх). Рассмотрим эти случаи... 1. В один Файл: ─────────────── SAVE CALL SET_NAME ; готовим сист. ; переменные LD C,10 ; ищем файл CALL 15635 LD A,C BIT 7,C JR NZ,SAV_BL ; его нет LD DE,(23878) ; нашли, rewrite LD BC,#nn06 LD HL,адрес CALL 15635 RET SAV_BL ; создаем новый LD HL,адрес LD DE,размер LD C,11 CALL 15635 RET где адрес - адрес начала отгружаемого блока; размер - его размер в байтах; nn = его размер в секторах. LOAD CALL SET_NAME ; готовим сист. ; переменные LD C,10 ; ищем файл CALL 15635 LD A,C BIT 7,C JR Z,LD_1 ; Сообщение "файл не найден" или... RET LD_1 ; грузим... LD A,C LD C,8 CALL 15635 XOR A LD (23801),A LD (23824),A LD C,14 CALL 15635 RET ; Подпрограмма установки сист.переменных SET_NAME LD HL,NAME ; перекидываем LD DE,23773 ; имя файла LD BC,8 LDIR LD A,"C" ; тип файла м.б. LD (23781),A ; любой, кроме ; "#","D","B" LD A,9 ; поиск файла LD (23814),A ; по 9 символам RET NAME DEFM "filename" 2. В одно и то же место ("в себя"): ─────────────────────────────────── SAVE LD HL,адрес LD DE,(T_S) LD BC,#nn06 CALL 15635 RET LOAD LD HL,адрес LD DE,(T_S) LD BC,#nn05 CALL 15635 RET T_S DEFW #SSTT ; дорожка и сектор, ; куда писать/читать 3. В разные файлы: ────────────────── Случай аналогичный 1, только процедуру SET_NAME надо заменить на INP_NAME. * Если вы дискетируете адвентюру, то лучше найти в программе процедуру ввода строки и использовать ее для ввода имени файла. Как это можно использовать - пока- зано ниже. В противном случае вам придет- ся написать ее самостоятельно. NAME EQU ; адрес, куда считывается ; строка INPUT EQU ; адрес процедуры считывания ; строки FROM EQU ; параметр "адрес" LEN EQU ; параметр "длина" (BYTES) INP_NAME LD HL,NAME ; очищаем имя LD DE,NAME+1 ; файла LD BC,7 LD (HL),#20 LDIR CALL INPUT ; см. * LD A,"C" ; тип файла м.б. LD (23781),A ; любой, кроме ; "#","D","B" LD A,9 ; поиск файла LD (23814),A ; по 9 символам LD HL,NAME LD B,8 CHECK LD A,(HL) CP NN ; признак конца JR NZ,NEXTS ; строки код NN LD A,#20 ; заменяем на LD (HL),A ; пробел NEXTS INC HL DJNZ CHECK LD HL,NAME LD DE,23773 LD BC,8 LDIR RET И в заключение хочу поделиться одной подпрограммкой, которая позволяет сменить дисковод: вызов: LD D,n ; n-номер диска CALL CNG_D ; 0-A, 1-B, 2-C .... CNG_D DI LD A,#C9 ; отключаем об- LD (#5CC2),A ; работку ошибок ; (см. ADV #5) LD (IY+0),#FF ; сбрасываем XOR A ; все коды LD (23824),A ; ошибок LD A,D ; устанавливаем LD (23833),A ; системные пе- LD (23798),A ; ременные TRDOS LD C,1 ; выбор CALL #3D13 ; дисковода LD C,#18 ; настройка на CALL #3D13 ; диск EI RET P.S. Если не делать настройку на диск, то при смене дисковода может получиться так, что он будет читать только нулевой трек. P.P.S. Приведенные в ADV #5 и этом номере процедуры не являются идеальными, хотя и вполне работоспособными. Если кто-то зна- ет как можно сделать лучше (или еще луч- ше - драйвер с прямым программирование ВГ и обработкой ошибок, например, так: стан- дартный вызов, а по завершению работы в регистре A код ошибки), то мы с удоволь- ствием опубликуем его достижения. Дерзай- те, виртуозы клавиатуры! На этом позволю себе закончить. Если что-то не понятно - пишите. ───────────────────────── Мы продолжаем цикл статей, посвящен- ных дисковым загрузчикам. Слово нашему корреспонденту. (C) Nicolas Viper "Чем ленивее человек, тем больше любой его поступок похож на подвиг." Народная мудрость Задержка великовата, ну а кому нынче легко ? Доставайте свои мозги из баночек с растворами, протрите, у кого запыли- лись, и вникайте. Прежде всего необходимо заметить, что утверждение, будто в проверке пра- вильности чтения (далее: ППЧ) ДОС нам по- мочь не может оказалось НЕВЕРНЫМ. Только, в свою очередь, мы должны помочь ему. Взгляните на листинг: ORG 40000 DI ;Инсталляция: LD HL,#FD00 ;-Пре LD A,H ; ры LD DE,#FD01 ; ва LD BC,256 ; ний LD (HL),#FE LDIR LD I,A IM 2 CALL MUSRUN ;-Музыки EI LD DE,#0100 ;-Откуда, LD HL,16384 ; куда и LD B,27 ; сколько будем CALL LOADER ; грузить JP MUSRUN ; Music off + RET *************** ГРУЗИМ ***************** LOADER LD IX,#2F65 ;Раскрутка CALL DOS L1 PUSH DE PUSH BC LD A,D OR A RRA LD C,A LD A,#3C JR NC,L2 LD A,#2C L2 LD IX,#2F4D ;Ставим череп на CALL DOS ;дорогу POP BC POP DE PUSH HL PUSH DE PUSH BC CALL LOA_COM POP BC POP DE POP HL ;Пересчет: INC H ;- адреса LD A,E ;- сек INC A ; то AND 15 ; ра LD E,A JR NZ,L5 ;- дороги INC D L5 DJNZ L1 ;Новый сектор DI ;Выход IM 1 EI RET Эта часть не поменялась со времен первого пришествия. А вот самое важное: LOA_COM LD C,#5F ;Пересчет номера LD A,E ;сектора, засыл- INC A ;ка в регистр LD IX,#2A53 ;сектора ВГ-шки CALL GODOS TRY1 PUSH HL ;На стек PUSH DE TRYMET XOR A ;Ошибок нет LD (ERRFLG+1),A ;(пока :) LD B,A ;B=0 LD C,#1F ;Команда LD A,#80 ;"чтение LD IX,#2A53 ; сектора" CALL DOS LD C,#7F ;Чтение сектора LD IX,#3FE5 CALL GODOS POP DE ;Взяли со стека POP HL ERRFLG LD A,0 ;Проверка на OR A ;ошибки во время JR NZ,TRY1 ;чтения. (под- LD D,1 ;робнее описано LD IX,#2F2F ;ниже) JP GODOS DOS HALT GODOS PUSH IX JP #3D2F IMCOM ;Словили преры- LD (STACK),SP ;вание PUSH IX PUSH HL ;Тут тоже в PUSH DE ;двух словах PUSH AF ;не опишешь :) PUSH BC ;Ищите подроб- CALL MUSIC ;ности ниже. LD HL,(STACK) LD E,(HL) INC HL LD D,(HL) LD A,D CP #40 JR NC,RETOS CP #3F JR NZ,PA_CNT POP BC PUSH BC LD A,B LD (ERRFLG+1),A PA_CNT LD HL,0-#2F3A OR A ADC HL,DE JR Z,RTBR LD A,#C3 POPALL LD (CHANGE),A POP BC POP AF POP DE POP HL POP IX EI CHANGE JP #3D2F RETOS LD A,#C9 JR POPALL RTBR LD SP,(STACK) POP AF EI JP TRYMET STACK DW 0 ORG #C000 INSERT "MUSIC" ORG #FEFE JP IMCOM MUSRUN EQU #C000 MUSIC EQU #C006 По адресу #2F2F в TR-DOS: #2F2F IN A,(#1F) AND #7F RET Z DEC D PUSH HL PUSH DE JR NZ,#2EXX ;Неважно куда HALT ;) Ловим! Кратенько: По поводу IMCOM : задача этой процедуры - проверить, когда пришло прерывание. Возможны варианты: - в ОЗУ. Тогда нам все по барабану - иг- раем музыку и вертаемся. - в ПЗУ (считаем, что это ДОС!!! По-идее, мы в СОС не попадаем). Тогда тоже ва- рианты: - Схватили с адреса #2F3A - это зна- чит, что мы словили HALT (см. выше), что, в свою очередь, говорит о том, что при чтении произошла одна из "стан- дартных" ошибок - потеря данных, не- совпадение контрольных сумм и т.п. - ...с адреса #3FXX (XX - любое значе- ние) - опять-таки, по идее, мы там мо- жем перехватить только процедуру чте- ния сектора. Это значит, что, увы, у нас неопределенное положение - надо закончить процедуру, но из-за задержки на проигрывание мелодии и т.п. мы упустили время и чтение придется пов- торить. При возникновении ошибки, мы кладем по адресу (ERRFLG + 1) НЕ ноль - это го- ворит, что необходимо перечитать сектор (см. с метки ERRFLG). Все остальное не так сложно и было расписано раньше. Пишите, если что не так, в редакцию или мыльте мне: nicky@univ.uniyar.ac.ru Хотя, судя по предыдущим публикаци- ям, вы, дорогие читатели, все равно не обратили на данную процедуру никакого внимания - глюков в ней было полно, а никто так и не написал: "...из-за этого Вашего #@$&$-го прога я себе дискету ис- портил, любимую!" (C) Котов А.В. (CAV Inc.)
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября