┌──────────────────────────────┐
│ │
│ 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. И, конечно, на-
писать программу-загрузчик, ко-
торый загружал бы потом эти кус-
ки и запускал программу (кстати,
имено вот таким 'магнитофонным
МАГИКОМ' и вскрывались изначаль-
но сильно защищеные 'фирменные'
программы на магнитофонных лен-
тах.
В некоторых современных (на-
шенских) моделях контроллера Ма-
гик-кнопка подвязана на вызов из
дополнительного ПЗУ программы
'монитор-отладчик', который поз-
воляет оперативно что-то изме-
нять в остановленной программе и
записывать ее на диск. Вот уж
воистину: "Голь на выдумки хит-
ра!".
А на некоторых моделях кон-
троллера Магик-кнопка вообще от-
сутствует. Ну что же, тоже "муд-
рое" решение. Не нравится она
некоторым разработчикам, и все
тут.
* * *