ZX Review
#7-8-9-10
08 ноября 1997 |
|
TR-DOS для начинающих - Окончание.
┌──────────────────────────────┐ │ │ │ TR-DOS ДЛЯ НАЧИНАЮЩИХ │ │ │ └──────────────────────────────┘ Music by ZET (c) В.Сироткин ОКОНЧАНИЕ. Начало см. в ZX РЕВЮ 1996 NN 1-2, 4-5, 6, 7-8; ZX РЕВЮ 1997 NN 1-2, 3-4, 5-6. ВОССТАНОВЛЕНИЕ СБОЙНЫХ ДИСКОВ Сбой в дисках бывает 3-х типов: 1. Логический - изменение или исчезновение данных в секторах. 2. Системный - разрушение или изменение системных разметочных меток. 3. Физический - в результате механических повреждений. Первый тип сбоя бывает до- вольно часто в результате порчи или стирания части каталога дис- ка, восьмого системного сектора или секторов, где записана прог- рамма. Также может быть умышлен- ное изменение области каталога при защищенном диске. Если нарушен каталог, то ру- шится вся информация о том, где какой файл лежит на диске. Вос- становить каталог и программы можно, если запастись терпением и листком бумаги, а также прог- раммой типа ДИСК ДОКТОР, кото- рая позволяет редактировать ин- формацию в секторах. Вам надо будет находить на секторах файлы БЕЙСИКА каждой программы (а в большинстве своем программы обязательно имеют БЕЙ- СИК-файл). Вписывать в сектор каталога его данные - на каком секторе, на какой дорожке он ле- жит и какова его длина. Из БЕЙ- СИК-части узнавать, какие файлы, куда и какой длины загружаются. И тут два варианта: 1. Если все файлы программы записаны непрерывно, и вам ста- нут известны все данные загрузки последующих файлов, то вам по- везло! Останется лишь арифмети- ка - сложение длин файлов, номе- ров секторов и дорожек и запись всего этого в виде заголовков в каталог. 2. Второй вариант - это когда файлы разбросаны по диску, пере- межаясь с файлами из других программ, или когда не известны ни адрес загрузки в ОЗУ, ни дли- на. Тогда вам можно только посо- чувствовать. Попытаться восста- новить программы в этом случае можно, но это только методом ты- ка (искать экранные файлы, тек- сты сообщений программы и т.д. и т.п.) Если у вас оказался сбойный восьмой сектор, то тут проще... Копируете все программы с этого диска на другой, а этот диск мо- жете переразметить. Если же наступает полный крах сектора (а это случается, если изменяется байт по смещению #Е7 от начала сектора), и диск не читается ни системой, ни копи- ровщиками, то тогда загружаете сектор через функцию ТРДОС в па- мять, и восстановив этот прокля- тый байт и байт "тип диска" по смещению #E3, переписываете сек- тор из памяти на место, а потом поступаете так же, как описано выше. Избавиться от головной боли при случайном разрушении 0 до- рожки вам поможет следующая про- граммка. У этой программы две точки старта : START_S - СОХРАНЕНИЕ ноль до- рожки диска на 164 дорожку (164 дорожка размечается автоматичес- ки при сохранении) START_L - ВОССТАНОВЛЕНИЕ ин- формации со 164 дорожки на НУЛЕ- ВУЮ дорожку (с предварительным форматированием 0 дорожки). Сначала вы обрабатываете свой диск СОХРАНЕНИЕМ, а в случае сбоя по нулевой дорожке или слу- чайного стирания каталога запус- каете ВОССТАНОВЛЕНИЕ - и все то, что было на момент сохранения диска, восстановится со 164 до- рожки (82 цилиндра). Дорожка, где сохраняется ин- формация, недоступна системе и программно недоступна ни копи- ровщикам, ни "ДИСК ДОКТОРам". Так что не беспокойтесь, что копия системы будет когда-нибудь затерта. Единственное, что мо- жет произойти, так это конфликт с аналогичной системной програм- мой, которая использует тот же номер дорожки. Если же у вас диск изначально размечен на 86 цилиндров (на 172 дорожки), то изменив константу в листинге программы со 164 на 174, вы бу- дете сохранять ноль-дорожку на 88-ом цилиндре (правда, такая "дальняя" дорожка уже считается ненадежной. 140. ;программа "спасение - восстановление" системной ;дорожки диска ; в угловых скобках адреса для версии ТРДОС 5.03 ; буфер для считываемой информации с диска начинается ; с 40000 ; желательно перед запуском программы дать ; CLEAR 39999 ORG 50000 ; вы можете выбрать другой адрес ; работы START_S JP SAVING ; на спасение START_L JP RESTOR ; на восстановление ;-- вызов ДОС-подпрограмм DOS PUSH IX JP #3D2F ;-- TR0_UP LD C,02 ; функция ДОС - переход ; на 0 дорожку LD A,0 CALL #3D13 LD A,#3C ; готовность диска 'A', ; верхняя сторона LD IX,#2EC2 < #2F0C > CALL DOS ; исполнить RET ; -- чтение секторов с дорожки READ_S LD E,0 ; LD B,16 LD HL,40000 LD C,05 ; функция ДОС - считать ; 16 секторов в CALL #3D13 ; адрес ОЗУ с 40000 RET TR82 LD C,164 ; физическое перемещение ; головок LD IX,#2EFB < #2F45 > 3; на цилиндр 82 3; (164 дорожка) CALL DOS ; исполнить RET ;-- форматирование дорожки FORM LD A,82 LD (#5CD8),A ; там не должен быть ноль! LD IX,#1FC1 < #1FFD > CALL DOS ; отформатировать дорожку, ; на которой стоим RET ; номер запишем из ; регистра 'E' ;-- запись секторов SAV_S LD C,06 ; функция 'записать сектора ; информацией из ОЗУ' LD B,16 LD HL,40000 LD E,0 CALL #3D13 RET ;-- ПОДПРОГРАММА СОХРАНЕНИЯ SAVING CALL TR0_UP ; перейти на 0 дорожку LD D,0 CALL READ_S ; прочитать все сектора ; 0 дорожки CALL TR82 3; перейти на 82 цилиндр LD E,82 ; номер цилиндра для формата CALL FORM 3; отформатировать 164 дорожку LD D,164 ; записать на отформатирован- ; ную дорожку CALL SAV_S ; копию 0 дорожки из памяти EI ; на всякий случай разрешим ; прерывания RET ; выход ;-- ПОДПРОГРАММА ВОССТАНОВЛЕНИЯ ;( на 164 дорожке должна быть копия 0 дорожки этого ; диска) RESTOR CALL TR0_UP ; перейти на 0 дорожку, как на ; начало отсчета CALL TR82 3; перейти на 82 цилиндр LD D,164 ; прочитаем все сектора из ; резерва CALL READ_S ; в буфер CALL TR0_UP ; перейдем на 0 дорожку LD E,0 ; и отформатируем ее CALL FORM LD D,0 ; запишем на нее все сектора ; из буфера CALL SAV_S EI RET ; выход 2 * * * Если же у вас произошел сбой в секторах программы, то попро- буйте переписать эту программу на другий диск и запустить ее. Может, та часть сектора попа- ла не на рабочие коды программы, а на данные, спрайты или байты изображения. Если же это не так, то можно (конечно, покопавшись в программе) установить, что этот кусок программы делал, и обойти его. Но по-моему, легче всего про- сто поискать эту программу у приятелей. Второй и третий вид сбоев - сходны между собой тем, что на- рушается системная разметка дис- ка: байты синхронизации, кон- трольных кодов, область индек- сной метки и т.д. Системный сбой формата слу- чается по многим причинам: тут и сбой питания во время работы с диском, и неисправность контрол- лера или дисковода и многое дру- гое (иногда диск, читающийся на одном дисководе, отказывается работать на другом дисководе та- кого же типа). Такое нарушение диска можно попытаться восстановить. Если же сбой физический (это и царапины, и осыпание слоя на диске), то восстановить эти мес- та на диске уже невозможно. Но, в любом случае, копируете сбойный диск на другой (можно командой ТРДОС 'COPY'), игнори- руя сообщения системы 'SECTOR nn ERROR', а затем пробуете восста- новить те места на диске, кото- рые давали сбой. Написано уже много хороших программ восстановления дисков: это и 'DCU', и 'ADS', и 'FUCK'. Программа восстановления обы- чно состоит из трех моментов: - Посекторное чтение опреде- ленное количество раз всей сбой- ной дорожки в ОЗУ, а потом еще раз, и еще, и еще: до тех пор, пока вся дорожка не прочитается правильно (или пользователь про- граммы не остановит процесс). - Переразметка (форматирова- ние) дорожки, если сбой происхо- дит в области системных меток. - Посекторная запись считан- ной информации (полной или не- полной) из ОЗУ на дорожку с пос- ледующей проверкой на считывае- мость. Если вам захочется, вы може- те написать свою программу вос- становления, но ничего сущес- твенно лучшего, чем уже есть на данный момент из программ-вос- становителей, по-моему, уже не придумать. И в заключение давайте пого- ворим о том, как считывать или записывать диски других форма- тов от других машин. Перво-наперво необходимо точ- но знать, что это за диск, от какой машины. Как эта машина размечает диски, какой длины сектора и сколько их на дорожке. Например, IBM-диск стандартно размечен на сектора в 512 байт, а число секторов на дорожке 9, (18 у дисков высокой плотности, их даже не пытайтесь считывать на ваших дисководах). У CP-M и IS-DOS дисков размер сектора равен 1024 и количество их 5. Чтобы прочитать сектора дис- ков другого формата, особой изо- бретательности не надо: опреде- ляете буфер подходящих размеров в ОЗУ и через функцию ТРДОС "считывание секторов" - читаете содержимое в память. Естественно, запускать IBM- файлы на СИНКЛЕРЕ вы не сможете, но переписать и использовать текстовые файлы - пожалуйста. Или наоборот, переписывать тек- сты, "набитые" на СПЕККИ, в фор- мат IBM и там их редактировать. Самое трудное - это разоб- раться в файловой структуре этих дисков. Как открывать каталоги и подкаталоги IBM и IS-DOS дисков, как проследить по диску файл, который фрагментирован, да и за- головки файлов в этих системах не похожи на ТРДОСовские. Для тех, кто мечтает заняться таким направлением программиро- вания, я советую набрать книг по IBM-совместимым компьютерам и внимательно изучить файловую ор- ганизацию этих машин. ПРИЛОЖЕНИЕ К ГЛАВЕ 5 Всем тем, кто впоследствии будет программировать порты кон- троллера (подавать команды в порт #1F и в порт #FF) необхо- димо помнить, что не всякая пря- мая команда контроллеру ВГ93 бу- дет исполняться полностью с дис- ками, работающими в ТРДОС. Дело в том, что формат дисков ТРДОС является упрощенным, а всю прос- тоту формата компенсирует прог- раммное обеспечение ПЗУ ТРДОС. Рекомендуемые коды для подачи в порт #1F: Порт Команд (этими кодами оперирует ТРДОС). Запись формата - #F4 Поиск цилиндра - #1B или #18 Восстановление - #08 или #0B Прерывание - #D0 или #D8 Чтение адреса - #C0 Чтение сектора - #80 секторов - #90 Запись сектора - #A0 секторов - #B0 Шаг - #38 Шаг вперед - #58 Шаг назад - #78 Примеры управляющих кодов для порта #FF. Диск 'A', двойная плотность, две стороны. Готовность, верхняя сторона - #3C Готовность, нижняя сторона - #2C Сброс, верхняя сторона - #38 Для тех, у кого возникнет большое желание самому дизассем- блировать свое ПЗУ с ТРДОС, ниже приводится карта приблизительно- го распределения пространства ПЗУ ТРДОС (адреса в десятичном исчислении). 140. от 0 до 101 - инициализация системы от 102 до 105 - переход на адрес 10838, где помещены подпрограммы 'МАГИК ФАЙЛ' от 864 до 939 - название и версия ТРДОС от 2048 до 4095 - коды #FF (свободно) от 4099 до 4119 - текст "ИНТЕРФЕЙС 1" от 4261 до 4432 - текст системной информа- ции для LIST от 4445 до 4519 - подпрограмма печати от 8121 до 8131 - таблицы данных от 10086 до 10299 - тексты сообщений от 10380 до 10455 - таблица адресов для вызова подпрограмм функций ТРДОС по ре- гистру 'C' от 10673 до 10804 - тексты сообщений от 10838 до 12038 - подпрограммы - 'МАГИ- ЧЕСКИЙ ФАЙЛ' от 12275 до 12337 - таблицы данных от 12541 до 12786 - ключевые слова команд ТРДОС от 12797 до 15360 - код #FF (свободно) от 15610 до конца - точки входов в ТРДОС и основные подпрограммы 2 Кроме того, в ПЗУ ТРДОС ис- пользуются команды процессора RST для вызова некоторых преры- вающих процедур, а именно: КОМАНДА RST #20 - вызов под- программы из ПЗУ SOS (после ко- манды RST #20 всегда следуют два байта адреса вызываемой подпрог- раммы SOS). КОМАНДА RST #18 - напечатать на экране сообщение из адреса M(HL), в конце сообщения байт 0 или >#7F КОМАНДА RST #10 - печатать символ из регистра 'A' Листинги-Таблицы некоторых подпрограмм ПЗУ ТРДОС Значком '=>' помечены те ад- реса входов в подпрограммы, ко- торые упоминались в главе. За основу взяты адреса ТРДОС 5.01, в угловых скобках (<хххх>) будут указаны адреса для ТРДОС 5.03. 140. ЗАПИСЬ В ПОРТ #FF (переключение сторон диска) #1FAF LD A,(#5D16) #1FB2 OR #3C ;ВЕРХ,ГОТОВНОСТЬ #1FB4 LD (#5D16),A => #1FB7 < #1FF3 > OUT (#FF),A #1FB9 RET #1FBA LD A,(#5D16) #1FBD AND #6F ;НИЗ,ГОТОВНОСТЬ #1FBF JR #1FB4 ________________________ ЗАПИСЬ В ПОРТ #FF #2EC0 OR #3C ; верхняя ; сторона, готов => #2EC2 < #2F0C > OUT (#FF),A ; послать байт #2EC4 RET ________________________ ЗАПИСЬ В ПОРТ по (C) => #2A09 < #2A53 > OUT (C),A #2A0B RET ________________________ СЧИТАТЬ НОМЕР ЦИЛИНДРА С ДИСКА И/ИЛИ ЗАПИСЬ В ПОРТ #3F => #1DFA < #1E36 > CALL "N_TRACK"; считать с диска ; номер Цилиндра под ; головками #1DFD LD A,H ; номер из 'H' ; переместить => #1DFE < #1E3A > OUT (#3F),A ; записать в ; р.ДОРОЖКИ #1E00 RET ________________________ ЗАПИСЬ в порт ДОРОЖКИ, порт #3F (с последующей задержкой) => #3E8B < #3E95 > OUT (#3F),A ; записать в порт #3E8D LD A,(#5CCD) ; дисковод ГОТОВ? #3E90 OR A #3E91 RET Z ; да - выйти #3E92 XOR A ; не готов, так ; подождем #3E93 LD (#5CCD),A #3E96 LD B,#03 ; цикл ожидания #3E98 LD A,#FF ; число задержки #3E9A CALL #3DF5 ; п.программа ; ожидания #3E9D DJNZ #3E98 #3E9F RET ; выйти _________________________ ЗАПИСЬ в порт КОМАНД, порт #1F; (a также инициали- зация сист.переменных и/или подача команды "пре- рывание") #2F46 < #2F90 > LD HL,#FFFF ; инициализируем LD (#5CFA),HL ; системные перемен- ; ные LD (#5CFC),HL LD (#5CC8),HL LD (#5CCA),HL XOR A LD (#5D17),A LD (#5D19),A LD (#5D18),A LD (#5D0F),A LD (#5D1F),A LD A,#FF OUT (#FF),A LD (#5C3A),A LD (#5D16),A LD (#5D0C),A LD A,#C9 LD (#5CC2),A #2F77 < #2FC1 > LD A,#D0 ; команда ; 'прерывание' => #2F79 < #2FC3 > OUT (#1F),A ; запись команды RET ___________________________ ОПРОС порта #1F (порт состояния) с возможностью перехвата результата ВТОРЫМ прерыванием по HALT => #2D3D < #2D87 > IN A,(#1F) ; читать состояние #2D3F AND #7F ; выделить биты ; ошибок #2D41 RET Z ; ошибок нет #2D42 DEC D ; 'D'-1 #2D43 PUSH HL ; в стек #2D44 PUSH DE ; в стек #2D45 JR NZ,#2D31 ; если 'D'<>0 - ; переход #2D47 HALT ; Ждать прихода ; импульса ; прерывания __________________________ ОПРОС порта #1F (состояние) с выводом на экран сообщений (в ПЗУ ТРДОС эта часть вызывается после исполнения команд "чтение-запись сектора") => #3F28 < #3F32 > EI ; рарешить прерывания IN A,(#1F) ; прочитать состояние LD B,A ; сохранить для работы AND #7F ; выделить ошибки RET Z ; ошибки нет - выйти LD HL,#298E AND #40 ; диск заклеен ?? JR NZ,#3F41 ; да - перейти LD A,B AND #04 ; потеря данных ?? JR Z,#3F96 ; да - перейти DEC D ; 'D'-1 JR NZ,#3F0B ; перейти выше ; если 'D'<>0 LD HL,#2998 #3F41 LD A,#D0 ; прервать операцию OUT (#1F),A LD A,B AND #01 ; запрос данных ?? JP NZ,#3EDD ; да - перейти __________________________ ПОИСК ДОРОЖКИ. ПОИСК ЦИЛИНДРА. ЗАПИСЬ КОММАНД 1-го ТИПА. ВОСТАНОВЛЕНИЕ И Т.Д. ;--------- поиск ДОРОЖКИ ----- => #2EF0 < #2F3A > LD A,#3C ;верхняя сторона, ;готовность #2EFA OUT (#FF),A #2EF4 LD A,(#5C00) ; если ДОРОЖКА ; то A=0 #2EF7 AND #08 ; это будет номер ; ЦИЛИНДРА ; или ДОРОЖКИ ?? #2EF JR NZ,#2F05 ; переход если номер ; ЦИЛИНДРА #2EFB LD A,C ; номер ДОРОЖКИ #2EFC OR A #2EFD RRA ; переведем в номер ; ЦИЛИНДРА #2EFE LD C,A ; и сторону диска #2EFF JR NC,#2F05 ; переход, если ; четный ЦИЛИНДР #2F01 LD A,#2C ; это нечетный ЦИ- ; ЛИНДР - НИЗ ;----------- поиск ЦИЛИНДРА -------- => #2F03 < #2F4D > OUT (#FF),A ; выбрать сторону ; диска #2F05 LD A,C ; номер ЦИЛИНДРА ; на поиск #2F06 OUT (#7F),A ; в регистр данных #2F08 CALL #3DF3 ; п.программа ; задержки #2F0B LD A,#1B ; поиск с опущенной ; головкой ;-- исполнить КОМАНДУ 1-го типа (диск крутится, ;-- головки прижаты к диску. ---- => #2F0D < #2F57 > OUT (#1F),A ; на исполнение ; КОМАНДУ #2F0F IN A,(#FF) ; готовность. #2F11 AND #80 ; команда ; выполнена? #2F13 JR Z,#2F0F ; нет - ждем #2F15 PUSH BC ; сохраним #2F16 CALL #3DF3 ; п.программа ; задержки #2F19 POP BC ; извлечем #2F1A RET ; вернуться ;---------- подать команду ВОСТАНОВЛЕНИЕ ---- => #2F1B < #2F65 > LD A,#0B ; выход на 0 ; дорожку #2F1D JR #2F0D ; исполнить ______________________________________________ ЗАПИСЬ МАССИВА в ПОРТ (C). (сюда обращается подпрограмма 'запись сектора') ; - предварительный опрос ГОТОВНОСТИ и/или СТРОБА данных - #3FB0 < #3FBA > LD B,#04 ; цикл ожидания #3FB2 < #3FBC > IN A,(#FF) ; опросить на готов- ; ность #3FB4 AND #C0 ; есть Готовность ; или Строб? #3FB6 JR NZ,#3FC7; есть - переход на ; запись #3FB8 INC DE ; нет, тогда главный ; цикл ожидания #3FB9 LD A,E ; в 'E' и 'D' число ; повтора #3FBA OR D #3FBB JR NZ,#3FB2 ; циклу конец ? #3FBD DJNZ #3FB2 ; ожиданию конец ? #3FBF RET ; выйти, операция ; не пошла! ; - запись массива в порт (C) - => #3FC0 < #3FCA > IN A,(#FF) ; опросить на ; готовность #3FC2 AND #C0 ; есть Готовность ; или Строб ? #3FC4 JR Z,#3FC0 ; нет - ждать #3FC6 RET M ;ВЫПОЛНЕНО ВСЕ - ВЫЙТИ #3FC7 OUTI ; есть строб - ; послать байт ; в порт из M(HL) #3FC9 JR #3FC0 ;вернуться за ;следующим байтом ____________________________ ЧТЕНИЕ МАССИВА ИЗ ПОРТА (C) (сюда обращается подпрограмма 'ЧТЕНИЕ сектора') ; - предварительный опрос ГОТОВНОСТИ и/или СТРОБА данных - #3FCB < #3FD5 > LD B,#04 ; цикл ожидания 140. #3FCD < #3FD7 > IN A,(#FF) ; опросить на готов- ; ность #3FCF AND #C0 ; ГОТОВНОСТЬ? СТРОБ? #3FD1 JR NZ,#3FE2 ; да - переход #3FD3 INC DE ; ждем определенное #3FD4 LD A,E ; время #3FD5 OR D #3FD6 JR NZ,#3FCD ; время ожидания ; вышло? #3FD8 DJNZ #3FCD ; цикл кончился? #3FDA RET ; команда не пошла, ; выйти ; - чтение массива из порта (C) - => #3FDB < #3FE5 > IN A,(#FF) ; опросить ; на готовность #3FDD AND #C0 ; СТРОБ? ; ГОТОВНОСТЬ? #3FDF JR Z,#3FDB ; нет - ждать #3FE1 RET M ; ВЫПОЛНЕНО ВСЕ ; - выйти #3FE2 INI ; считать байт ; из порта ; в M(HL) #3FE4 JR #3FDB ; вернуться ; за следующим ; байтом __________________________ Подпрограмма ЧТЕНИЕ-ЗАПИСЬ СЕКТОРА (первая) => #3F00 < #3F0A > LD A,#A0 ; занести код ; 'ЗАПИСЬ' #3F02 JR #3F06 ; переход на ; продолжение => #3F04 < #3F0E > LD A,#80 ; занести код 'ЧТЕНИЕ' #3F06 LD (#5CFE),A ; СОХРАНИТЬ #3F09 LD D,#0A ; число попыток #3F0B PUSH DE ; спрятать #3F0C DI ; запретим ; прерывания #3F0D LD A,(#5CFF) ; ЛОГИЧЕСКИЙ ; НОМЕР СЕКТОРА #3F10 INC A ; переведем в ; физический #3F11 OUT (#5F),A ; занесем в ; РЕГ.СЕКТОРА #3F13 LD HL,(#5D00); адрес буфера #3F16 LD C,#7F ; порт ДАННЫХ #3F18 LD A,(#5CFE) ; достать КОМАНДУ #3F1B OUT (#1F),A ; подадим в порт #3F1D CP #A0 ; это ЗАПИСЬ? #3F1F PUSH AF ; спрячем флаг ; операции #3F20 CALL Z,#3FB0 ; ЗАПИСЬ - тогда ; запишем #3F23 POP AF ; достанем флаг ; операции #3F24 CALL NZ,#3FCB ; А это ЧТЕНИЕ ; - прочтем и так далее... ____________________________________ Подпрограмма СЧИТЫВАНИЕ СЕКТОРА (вторая). => #2ED1 < #2F1B > LD A,E ; логический ; НОМЕР СЕКТОРА #2ED2 INC A ; переведем в ; физический #2ED3 OUT (#5F),A ; занесем в порт ; СЕКТОРА #2ED5 PUSH HL ; адрес БУФЕРА - ; сохраним #2ED6 LD D,#14 ; число попыток - #2ED8 PUSH DE ; сохраним #2ED9 DI ; #2EDA LD C,#7F ; порт данных #2EDC LD A,#80 ; команда ; ЧТЕНИЕ СЕКТОРА #2EDE OUT (#1F),A ; подадим команду #2EE0 CALL #3FDB ; считаем СЕКТОР #2EE3 POP DE ; вернем число ; попыток #2EE4 POP HL ; адрес БУФЕРА #2EE5 IN A,(#1F) ; все нормально? #2EE7 AND #7F ; ошибок нет? #2EE9 RET Z ; выход, если нет ; ошибок #2EEA DEC D ; число попыток ; сократим #2EEB PUSH HL ; опять спрячем #2EEC PUSH DE #2EED JR NZ,#2ED9 ; попытки не кон- ; чились... ; читаем еще раз #2EEF HALT ; Все. ; Попытки кончились ____________________________________ Подпрограмма ЗАПИСИ СЕКТОРА (вторая) => #2D29 < #2D73 > LD A,E ; логический ; НОМЕР СЕКТОРА #2D2A INC A ; переведем в ; физический #2D2B OUT (#5F),A ; занесем в порт ; СЕКТОРА #2D2D PUSH HL ; адрес БУФЕРА - ; сохраним #2D2E LD D,#14 ; число попыток #2D30 PUSH DE ; сохраним #2D31 DI ; #2D32 LD C,#7F ; порт данных #2D34 LD A,#A0 ; команда ; ЗАПИСЬ СЕКТОРА #2D36 OUT (#1F),A ; подадим команду #2D38 CALL #3FC0 ; пишем СЕКТОР #2D3B POP DE ; вернем число по- ; пыток #2D3C POP HL ; адрес БУФЕРА #2D3D IN A,(#1F) ; все нормально? #2D3F AND #7F ; ошибок нет? #2D41 RET Z ; выход - если ; ошибок нет #2D42 DEC D ; чило попыток ; сократим #2D43 PUSH HL ; опять спрячем #2D44 PUSH DE #2D45 JR NZ,#2D31 ; попытки не ; кончились... ; будем писать еще #2D47 HALT ; Все. Попытки ; кончились ___________________________________ Форматирование одной дорожки =>#1FC1 < #1FFD > DI ;запретим прерывания #1FC2 LD A,#F4 ;команда ЗАПИСЬ ; ВСЕЙ ДОРОЖКИ #1FC4 OUT (#1F),A ; дадим команду #1FC6 LD HL,#1F7D ; адрес данных, ; где расположены ; номера секторов ; -- начало записи заданного формата -- =>#1FC9 < #2005 > LD C,#7F ; порт данных #1FCB LD B,#0A ; число записываемых ; байтов #1FCD LD D,4E ; байт для записи #1FCF CALL 2075 ; записать байты на ; дорожку ... и так далее, пока не запишем весь массив ... __________________________________ Циклическая ЗАПИСЬ в порт (C) байтов количеством из 'B'. (используется подпрограммой ФОРМАТИРОВАНИЕ) =>#2075 < #20B1 > IN A,(#FF) ; читаем готовность #2077 AND #C0 ; КОНЕЦ?, ; СТРОБ БАЙТА? #2079 JR Z,#2075 ; нет - ждем #207B RET M ; да, команда ; исполнена - выход #207C OUT (C),D ; если строб, то ; байт в порт #207E DJNZ #2075 ; все байты? ; нет - вернемся #2080 RET ; выйдем, если все _____________________________ КРАТКАЯ ТАБЛИЦА СООТВЕТСТВИЯ АДРЕСОВ ПОДПРОГРАММ ┌────────────┬────────────┬───────────────────────────┐ │ ТРДОС 5.01 │ ТРДОС 5.03 │ НАЗНАЧЕНИЕ │ ├────────────┼────────────┼───────────────────────────┤ │ #1DFE │ #1E3A │ OUT (#3F),а │ │ #1FB7 │ #1FF3 │ OUT (#FF),а │ │ #1DFA │ #1E36 │ определить цилиндр │ │ │ │ под головками │ │ #1FC1 │ #1FFD │ форматирование │ │ #1FC9 │ #2005 │ форматирование │ │ #2EC2 │ #2F0C │ OUT (#FF),а │ │ #2A09 │ #2A53 │ OUT (C),а │ │ #2D3D │ #2D87 │ IN a,(#1F), and #7F │ │ #2F1B │ #2F65 │ восстановление │ │ #2F03 │ #2F4D │ поиск ЦИЛИНДРА │ │ #2EF0 │ #2F3A │ поиск ДОРОЖКИ │ │ #2ED1 │ #2F1B │ чтение сектора │ │ #2F0D │ #2F57 │ подача команд 1-го типа │ │ #2075 │ #20B1 │ циклическая запись │ │ │ │ OUT(C),D │ │ #28A5 │ #2FEB │ LDIR, RET │ │ #2EFB │ #2F45 │ поиск ДОРОЖКИ │ │ #2F46 │ #2F90 │ инициализировать SYS │ │ │ │ TRDOS │ │ #2D29 │ #2D73 │ запись сектора │ │ #3ED5 │ #3EDF │ OUT (#1F),а │ │ #3E8B │ #3E95 │ OUT (#3F),а │ │ #3FDB │ #3FE5 │ чтение блока ( INI ) │ │ #3FC0 │ #3FCA │ запись блока (OUTI ) │ │ #3F28 │ #3F32 │ IN А,(#1F) + сообщения │ │ #3DAB │ #3DB5 │ IN A,(#1F); AND 02 │ │ #3E30 │ #3E3A │ IN A,(#1F); AND 04 │ │ #3E59 │ #3E63 │ поиск дорожки │ │ #3F00 │ #3F0A │ запись сектора │ │ #3F04 │ #3F0E │ чтение сектора │ │ #3DF3 │ #3DFE │ задержка │ │ #3E96 │ #3EA0 │ задержка │ │ #3FB0 │ #3FBA │ запись блока (OUTI ) │ │ #3FCB │ #3FD5 │ чтение блока ( INI ) │ └────────────┴────────────┴───────────────────────────┘ 2 * * * ГЛАВА 6 'МАГИЧЕСКИЕ' ФАЙЛЫ, или прерывание NMI В фирменных моделях платы ТРДОС (БЕТА-ДИСКа) предусмотрена специальная кнопка, т.н. 'MAGIC BUTTON', предназначенная (по за- думке автора) для копирования тех магнитофонных программ, ко- торые невозможно было адаптиро- вать к диску обычными методами ТРДОС, т.е. программ, занимающих все пространство ОЗУ компьютера, затирающих системную область ОЗУ или имеющих мощно защищенный загрузчик (программа вводится с магнитофона, запускается, и при нажатии в любой момент этой кнопки вся область ОЗУ компьюте- ра единым файлом сбрасывается на диск. После этого прерванная программа снова начинает работу как ни в чем не бывало. На диске же образовывается файл с именем "@" и типом <C>, запускать кото- рый можно командой ТРДОС GOTO "filename" CODE. Программа заг- ружается и запускается с того самого места, где она тормозну- лась при нажатии МАГИКА). Что же такое эта МАГИК-КНОП- КА? У процессора Z-80 есть специ- альный вход, т.н. 'НЕМАСКИРУЕМОЕ ПРЕРЫВАНИЕ, или NMI', при пода- че на который логического НУЛЯ процессор бросает свою работу и переходит на адрес #0066, как на подпрограмму. В отличие от первого и вто- рого прерываний, прерывание NMI невозможно запретить, и процес- сор в любом случае при возникно- вении сигнала NMI будет испол- нять подпрограмму по адресу #0066. Вот на этот самый вход и задействована та самая 'магичес- кая кнопка' ТРДОС. При нажатии на нее на вход NMI процессора подается НОЛЬ. В этот же самый момент этот же им- пульс переключает банки РПЗУ и включает в адресное простран- ство ПЗУ ТРДОС. Схемотехника выборки МАГИЧЕС- КОЙ КНОПКИ построена таким обра- зом, что формирование импульса NMI происходит в диапазоне рабо- чих адресов процессора от #4000 до #FFFF (это было сделано спе- циально, чтобы работу подпрог- рамм ПЗУ, как SOS, так и ТРДОС, нельзя было прервать). Многое уже писалось об этой кнопке... Очень многие ругают ее почем зря, называют обидными прозвища- ми типа "обезьяна" и др... Но, если все же учесть, что часть хороших программ, которые дош- ли до нас из-за бугра, вскрыты именно таким методом, то, может, не надо ее так ругать, а стоит отдать ей должное? Да, недостатков у этого спо- соба адаптации программ много. Это и то, что в стековую область программы заносится огромный массив данных, и то, что наруша- ются некоторые ячейки ОЗУ в сис- темной области ТРДОС и портится экран, и т.д., и т.п. Но вспомним, что когда был выпущен контроллер ТРДОС, еще не было таких программ, которые до последнего байта занимали бы всю область ОЗУ компьютера. Это сей- час программы для СИНКЛЕРА пи- шут на мощных 16-и или 32-х раз- рядных машинах, а тогда... Если современную программу сбрасывать на диск КНОПКОЙ, то в половине случаев она безнадежно портится, а если в программе стоит защита от МАГИКА, то и диск иногда приходится заново форматировать. Но все же КНОПКА иногда помо- гает, и даже здорово помогает! Это и вскрытие сильно защищен- ных магнитофонных загрузчиков, и анализ сложных программ во время их работы, и многое другое. Да и вообще, не в кнопке де- ло, а в програмном обеспечении, облсуживающем эту кнопку. Как было сказано, при нажатии кноп- ки процессор переходит на адрес #0066 ПЗУ ТРДОС. В этом месте стоит команда процессора 'JP ад- рес'. Для ТРДОС 5.01 это адрес #2A0C, а для 5.03 и др - #2A56. Концепция подпрограммы МАГИКА проста: 1. Сохранить значения всех ре- гистров процессора. 2. Сбросить в файл с именем '@' область ОЗУ с #4000 до #FFFF. 3. Восстановить значения всех регистров и вернуться в прог- рамму. Ниже дан листинг начального куска подпрограммы 'MAGIC SAVE'. 140. ; начало для ТРДОС 5.01 = #2A0C, для 5.03 = #2A56 PUSH AF ; сохраним основной набор ; регистров PUSH BC PUSH DE PUSH HL PUSH IX ; а также индексные регистры PUSH IY EXX ; сохраним второй набор ; регистров PUSH BC PUSH DE PUSH HL EX AF,AF' PUSH AF LD A,I ; регистр прерываний PUSH AF LD A,R ; регистр обновления PUSH AF LD HL,#0000 ADD HL,SP ; сохраним последним в стеке ; 'указатель стека', ; а последнее значение указа- ; теля стека ; потом выставим в заголовок ; файла, как PUSH HL ; СТАРТОВЫЙ АДРЕС LD A,#3C ; далее идет инициализация ; контроллера OUT (#FF),A ............ 2 Дальше программа сохраняет часть области экрана в 9, 10, 11 и 12-ом (!) секторах НУЛЕВОЙ до- рожки (так вот куда требуются пустующие сектора на системной дорожке) и переписывает на экран служебную информацию (оттуда и полосы на экране во время записи МАГИКА). Сохраненная экранная информа- ция затем переписывается в МАГИК файл. Таким образом, реально эк- ран программы не портится. После записи файла подпрог- рамма возвращает управление прерванной программе, предвари- тельно вернув из стека все зна- чения регистров микропроцессора и экранные куски. На диске же остается файл с именем '@', тип 'CODE' и с объе- мом, равным #C0 (192) сектора. Стартовый адрес этого файла указывает на адрес дна СТЕКА программы, а длина программы в байтах может быть любой, и в этом случае не играет никакой роли. Имя файлу потом можно бу- дет дать любое, но с одной ого- воркой. Если сбрасываемая программа работала во ВТОРОМ прерывании процессора, то имя программы должно начинаться с символа '$'. По этому символу во время за- пуска магик-файла ТРДОС распоз- нает, какое именно прерывание установить в загружаемой прог- рамме. Запуск МАГИК-файла произво- дится из ТРДОС командой GOTO "filename" CODE Кстати, командa 'GOTO' не различает принадлежность запус- каемого файла к 'МАГИК' типу. Вы можете дать команду 'GOTO' и обычному файлу и посмотреть, что получится... Так что если у вас файлов 'МАГИК' много, то, навер- ное, стоит завести для них от- дельный диск, чтобы не происхо- дило недоразумений (программы 'БУТЕРы' распознают МАГИК файл в каталоге по величине #C0, <объем занимаемых секторов>, и только такие файлы запускают, как МА- ГИК). Запуск МАГИК-файла происходит в следующем порядке: сначала за- гружаются 27 секторов экрана, а затем все остальное, используя ОЗУ экрана для загрузки. После того, как весь файл считан, подпрограмма в ПЗУ бе- рет из заголовка файла число 'СТАРТОВЫЙ АДРЕС', вводит его в регистр 'SP' и командами POP на- чинает заполнять все регистры данными из стека в том порядке, в каком они сохранялись при соз- дании МАГИК файла. В этот же самый момент анали- зируется имя файла на символ '$', и если он присутствует на 1-ом месте имени, подпрограмма выставляет IM2. И в завершение всего, коман- дой 'RET' производит запуск. Определенный интерес пред- ставляет способ, которым подпро- грамма ТРДОС определяет, РАЗРЕ- ШЕНЫ или ЗАПРЕЩЕНЫ были прерыва- ния на момент остановки програм- мы. Делается это так: ; определение разрешены или запрещены прерывания POP AF ; вернем значение регистра ; прерываний, ; а в регистре флагов значение ; триггера IFF2 процессора LD I,A DI ; для начала запретим прерывания JP PO, addr ; проверим триггер IFF2 и если ; IFF2=1 (ФЛАГ ЧЕТНОСТИ), ; то дать команду ПРЕРЫВАНИЯ ; РАЗРЕШИТЬ. ; А если IFF2=0 (НЕЧЕТНОСТЬ), то ; ПРЕРЫВАНИЯ ЗАПРЕТИТЬ. . . . . . . (кто не имеет представления о том, что такое триггер IFF2 и IFF1 микропроцессора, тот может прочитать об этом в книге А.ЛАРЧЕНКО и Н.РОДИОНОВА "ZX SPECTRUM для программистов и пользователей"). Можно было бы пойти дальше и, анализируя содержимое регистра "I" микропроцессора, определять, какое именно прерывание было в программе на момент нажатия МАГИКА (изначально регистр 'I' равен #3F, и если это не так, то в 90% случаев на этот момент в программе установлено прерыва- ние ДВА). Но этот способ не дает 100% достоверности, и конечное реше- ние о типе прерывания остается за нажимателем МАГИК-КНОПКИ. Большинство современных игро- вых программ используют прерыва- ние ДВА, и если после запуска 'свежеиспеченного' МАГИК-файла (без символа '$' в имени) что-то идет не так, или вовсе не идет - значит, ставьте впереди имени файла значок '$' и запускайте снова. Если и после этого программа на захочет работать, значит ваша МАГИК-кнопка запортила стек этой программы или же ячейки ОЗУ с адреса #5C00 и далее. Попытай- тесь сбросить программу в дру- гой момент времени ее работы или тогда, когда программа находится в меню. В процессе своей работы прог- рамма МАГИК безвозвратно портит несколько ячеек ОЗУ в области системных переменных ТРДОС, нап- ример ячейки с адресом #5C00, #5C01 и т.д. Так что защита от МАГИК-сброса в программе может строиться именно на опросе зна- чений этих ячеек. Существует уже множество про- грамм-утилит, которые предназна- чены облегчить работу с МАГИК- файлами. Это и пакет программ "@-CRACKER", который позволяет не только просматривать МАГИК- файл, но и выводить значения всех сохраненных регистров и со- держимое стека на экран, редак- тировать МАГИК-файл, а также де- лить его на 3 файла с автомати- ческой записью на диск БЕЙСИК- загрузчика, который загружает и запускает разделенные части. Это и программа "MFC v1.4", которая компрессирует МАГИК-файл и запи- сывает его единым блоком с БЕЙ- СИК-загрузчиком на диск. И мно- гое, многое другое. Можно долго и нудно спорить и говорить о вреде МАГИК кнопки. Атор этой книги склоняется к то- му, что в большинстве случаев МАГИК - это вред. Вред не только программе, но и самому пользова- телю, который нажимает эту кноп- ку... Но, как говорится:"Если нель- зя, а очень хочется - то можно". Можно было бы на этом месте и закрыть эту тему, но у некото- рых читателей возникнет вопрос: "А можно ли сделать так, чтобы МАГИК не портил программы?" Мож- но. Для этого вам придется пе- репрограммировать ПЗУ ТРДОС дру- гой подпрограммой, которая дол- жна учитывать все недостатки су- ществующей. А именно: - В родном стеке сбрасываемой программы должно сохраняться од- но-два значения - это регистры 'SP' и 'PC'. - Рабочий стек для сохране- ния всех остальных регистров должен быть переопределен на эк- ран (в ущерб картинке), или же (что предпочтительнее) в ТЕНЕВОМ ОЗУ. - Не должны затрагиваться ни- какие ячейки ОЗУ, кроме как на экране или в теневом ОЗУ. Хотя это тоже не выход! Можно пойти другим путем и запрограммировать ПЗУ SOS для сохранения МАГИКА на магнитофон тремя-четырьмя кусками (для этой цели подойдет и ТЕНЕВОЕ ОЗУ, у кого оно есть). Единственное, что необходимо сделать для этого - обрезать проводник, идущий от схемы МАГИК КНОПКИ к узлу, переключающему микросхемы ПЗУ, чтобы при нажа- тии на кнопку у вас осталась ак- тивной ПЗУ SOS. И, конечно, на- писать программу-загрузчик, ко- торый загружал бы потом эти кус- ки и запускал программу (кстати, имено вот таким 'магнитофонным МАГИКОМ' и вскрывались изначаль- но сильно защищеные 'фирменные' программы на магнитофонных лен- тах. В некоторых современных (на- шенских) моделях контроллера Ма- гик-кнопка подвязана на вызов из дополнительного ПЗУ программы 'монитор-отладчик', который поз- воляет оперативно что-то изме- нять в остановленной программе и записывать ее на диск. Вот уж воистину: "Голь на выдумки хит- ра!". А на некоторых моделях кон- троллера Магик-кнопка вообще от- сутствует. Ну что же, тоже "муд- рое" решение. Не нравится она некоторым разработчикам, и все тут. * * *
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября