СЕКРЕТЫ TRDOS
Алексеев А.Г.
Итак, Вы обзавелись БЕТА-ДИСК интерфейсом, а также чистыми дискетами. Если есть у кого переписывать готовые программы на дискетах - Вы на некоторое время будете избавлены от прочих забот, наслаждаясь тем, как лихо проходит загрузка игр. Вы даже поначалу не будете обращать внимание на то, что где-то подпорчена заставка (нет двух нижних строк), а где-то на экран загружается какая-то цветная дрянь. Правда, после этого игра стартует нормально, но выглядит это как-то кустарно. Кроме того, наверняка есть у Вас игры на магнитной ленте, которые Вы относите к самим "игручим", а их дисковых версий как-то не оказалось у Ваших друзей. В общем, постоянные "житейские" заботы будут каждый день подталкивать Вас на более глубокое изучение TR-DOS. Поэтому я поделюсь тем опытом, который накопился у меня с момента подключения БЕТА-диска.
Вам предлагается обобщенный материал, собранный из разрозненных источников, а также уникальные данные, полученные в результате экспериментальной работы.
Начальные сведения по дисковой операционной системе TR-DOS достаточно подробно изложены в многочисленных описаниях, распространяемых в достаточном количестве на компьютерных рынках страны. Поэтому в этой статье я буду подразумевать, что владельцы БЕТА-ДИСК интерфейсов уже знакомы с этими материалами.
Первое, что усваивает каждый пользователь TR-DOS, это то, что вместо, например:
LOAD "" CODE
в Бейсик-строке теперь надо ставить:
RANDOMIZE USR 15619 : REM : LOAD "name" CODE
а вход в систему TR-DOS из Бейсика производится командой:
RANDOMIZE USR 15616
Прежде всего, давайте выясним что это за адреса? 15616 и 15619 это же ведь адреса ПЗУ, того самого, которое было до подключения TR-DOS. Не вступаем ли мы в конфликт с машинный кодом основного ПЗУ Спектрума? Оказывается нет. С адреса 15616 в ПЗУ Спектрума расположен символьный набор, начиная с пробела, то есть, в нормальном режиме работы "Спектрума" никогда не происходит выполнение машинного кода в этих адресах. В случае БЕТА-ДИСК интерфейса, при попадании на этот адрес срабатывает селектор адреса, который подключает теневое ПЗУ и дальнейшая работа происходит в нем. В теневом ПЗУ с системой TR-DOS по этим адресам располагаются команды, передающие управление в соответствующие точки ПЗУ TR-DOS.
Рассмотрим теперь более детально, как же устроена TR-DOS.
КАРТА ПАМЯТИ ОЗУ.
Те сведения, которые изложены в "фирменных" руководствах по TR-DOS, можно охарактеризовать как TR-DOS снаружи. Ну, например, в "фирменном" описании сказано, что для работы TR-DOS выделяется дополнительно 112 байт ОЗУ. И еще говорится о том, что в процессе работы TR-DOS динамически выделяется 256 байт, причем происходит это незаметно для пользователя. И все про это. Попробуем раскрыть поподробнее эти фразы, взглянув на TR-DOS изнутри.
Для начала посмотрим, где эти 112 байт ОЗУ выделяются. До инициализации БЕТА-ДИСК интерфейса карта памяти ОЗУ имела следующий вид (только то, что представляет интерес):
Буфер принтера |
23296 |
Системные |
23552 |
переменные |
|
Бейсик-программа 23755 <-- PROG
----------------------------------------------<--RAMTOP
Свободно
65535 <-- PRAMT
При подаче команды RANDOMIZE USR 15616 происходит инициализация БЕТА-ДИСК интерфейса. При этом перестраивается карта памяти. Дополнительные 112 байт ОЗУ выделяется перед областью Бейсик-системы. Системная переменная PROG становится равной 23755+112=23867. Бейсик-программа со всеми Бейсик-переменными и маркером конца передвигается на 112 байт ближе к RAMTOP. А область, отведенная под Бейсик-систему становится, таким образом, меньше на 112 байт:
Экранная память |
16384 |
Буфер принтера |
23296 |
Системные |
23552 |
переменные |
|
Системные |
|
переменные TR-DOS |
|
Бейсик-программа 23867 <-- PROG
----------------------- <--RAMTOP
Свободно
65535 <-- PRAMT
Кроме того, непосредственно в тот момент, когда происходит чтение или запись сектора данных, Бейсик-программа отодвигается еще дальше к RAMTOP. Эту переброску осуществляет TR-DOS и происходит она для пользователя незаметно (однако это может доставить массу проблем при адаптации магнитофонных программ под диск). Бейсик-программа со всеми своими переменными отодвигается еще на 257 байт. Это место освобождается непосредственно для операции чтения-записи сектора данных на диск: 256 байт информации плюс один байт - контрольная сумма сектора. Карта памяти в этот момент имеет следующий вид:
Буфер принтера 232 9 6
Системные 2 3 552
переменные
Системные переменные TR-DOS
2 57-байтное пространство
Бейсик-программа 24124 <-- PROG
-----------------------<--RAMTOP
Свободно
65535 <-- PRAMT
По завершении операции чтения-записи Бейсик-программа возвращается на свое прежнее место - в адрес 23867.
Такое изменение адресов не то что происходит незаметно, но, как уже говорилось, может создать массу проблем для адаптации магнитофонных версий программ под диск. Большинство пользователей Спектрумов начинали с магнитофонных вариантов и БЕТА-диском оснащали свои уже готовые компьютеры. Поэтому, конечно, одной из первых потребностей, с которой Вы сталкиваетесь, (и с которой столкнулся я), является адаптация своих собственных программ под БЕТА-диск. Переделка фирменных игровых программ -это тема для отдельного разговора, однако на рынке существует огромное множество дисковых версий игр. Дешевле пойти и купить то, что надо. Но свои собственные программы Вам придется переделывать самим. Проблемы могут быть вызваны, например, нехваткой памяти в связи с выделением дополнительных 112 байт ОЗУ. Если значение RAMTOP небольшое, порядка 25000, то под Бейсик-программу остается совсем мало места. И программа, которая нормально работает в магнитофонном варианте, может отказаться работать в дисковом. Значение RAMTOP изменить бывает проблематично, поэтому приходится прибегать к другим приемам по экономии памяти. Многие из этих приемов достаточно подробно разбирались на страницах ZX-РЕВЮ. Это, в частности, замена цифровых значений на VAL "..." и другие приемы. Может оказаться так, что в принципе Бейсик-программа работает, но если в программе встречаются команды TR-DOS с префиксом:
RANDOMIZE USR 15619: REM :
то вместо выполнения их, на экране появляется сообщение об ошибке: "Out of memory". Это значит, что свободного места не хватает при попытке выделить 257-байтное пространство для операции чтения-записи сектора.
Если способы экономии памяти исчерпаны, то возможно придется серьезно подумать над изменением структуры программы в целях увеличения значения RAMTOP. Кроме этого, следует упомянуть еще об одной проблеме. Во многих программах применяется нулевая строка для размещения в ней блоков машинных кодов за оператором REM. Об этом подробно рассказывалось в ZX-РЕВЮ N 9-10 за 1992 год, см. стр.193. Там говорилось, что если строка с REM это начальная строка программы, то свободное место за REM начинается с адреса PROG+5. В случае TR-DOS, это будет 23867+5=23872. Однако, если Вы попробуете загрузить с диска блок кодов по этому адресу при помощи команды TR-DOS:
LOAD "name" CODE 23872
то у Вас ничего не получится. Дело вот в чем. В тот момент когда происходит загрузка (выполнение процедуры чтения сектора данных), Бейсик-програма и оператор REM вместе с ней уже имеют другой адрес - на 257 больший, чем тот, который был. Поэтому загрузку кодов с диска в нулевую строку надо выполнять следующим образом:
LOAD "name" CODE (23872+257)
Тогда блок кодов попадет точно в адрес 23872.
Вышесказанное относится к загрузке блока кодов и адреса между PROG и RAMTOP. То же относится и к записи блока кодов из этого интервала адресов на диск.
СИСТЕМНЫЕ ПЕРЕМЕННЫЕ TR-DOS.
Продолжая взгляд на TR-DOS изнутри, рассмотрим некоторые из системных переменных, составляющих дополнительные 112 байт ОЗУ. Еще раз упомяну: предполагается, что читатель знаком с описанием TR-DOS в начальном объеме. Сначала кратко.
23752 |
#5СС8 |
23753 |
#5СС9 |
23754 |
#5ССА |
23755 |
#5ССВ |
23773 |
(#5CDD |
23781 |
(#5СЕ5) |
23782 |
(#5СЕ6) |
23784 |
(#5СЕ8) |
23786 |
#5СЕА |
23787 |
#5СЕВ |
23788 |
(#5CEC |
23798 |
(#5CF6) |
23800 |
(#5CF8) |
23801 |
(#5CF9) |
23802 |
#5CFА |
23803 |
(#5CFB) |
23804 |
(#5CFC) |
23805 |
(#5CFD) |
23823 |
(#5D0F) |
23830 |
#5D16 |
23833 |
(#5D19) |
23838 |
#5D1E |
1 байт - режим работы диска "А" 1 байт - режим работы диска "В"
■ 1 байт - режим работы диска "С"
- 1 байт - режим работы диска "D"
- 8 байт - имя файла в кодах ASCII
1 байт - тип файла
2 байта - параметр START 2 байта - длина файла
1 байт - объем файла в секторах
■ 1 байт - номер первого сектора файла
■ 1 байт - номер первого трека файла
1 байт - дисковод для временной операции 1 байт - дисковод при операции с 2 файлами 1 байт - признак операции READ/VERIFY 1 байт - время перемещения головки дисковода "А" 1 байт - время перемещения головки дисковода "В" 1 байт - время перемещения головки дисковода "С" 1 байт - время перемещения головки дисковода "D" 1 байт - код ошибки TR-DOS 1 байт - копия системного регистра 1 байт - номер дисковода 1 байт - номер файла, если он найден.
Теперь подробнее
С адреса 23752 по 23755 расположены 4 числа, по одному на каждый из возможных четырех подключенных дисководов A, B, C и D. 7-й бит этого числа определяет количество дорожек дисковода: 0 - 40-дорожечный дисковод, 1 - 80-дорожечный дисковод. 1-й бит этого числа равен 1, если дисковод двусторонний. 0-й бит этого числа равен 0, если выполняется команда по использованию 80-дорожечного дисковода, как 40-дорожечного.
Начиная с адреса 23773, 8 байт занимает имя файла в кодах ASCII. При инициализации интерфейса в эти ячейки заносится имя "boot". Так осуществляется подготовка к считыванию с диска программы-загрузчика.
Следующий байт после имени файла, ячейка 23781, определяет его тип. Это один из
четырех кодов ASCII - "В", "C", "D" или '#".
Следующие два байта, с адреса 23782, это параметр "START". Если тип файла - "С", то это начальный адрес размещения кодов в памяти Спектрума. Если же тип файла "В", то двухбайтное число в этих ячейках является системной информацией, связанной с автостартом Бейсик-программы.
Два байта с адреса 23784 обозначают длину файла в байтах. Один байт по адресу 23786 определяет длину файла в секторах (по 256 байт). Разумеется, должно иметь место выражение:
PEEK 23786 = PEEK 23785 + (PEEK 23784<>0)
Очевидно, что если младший байт длины файла имеет хоть какое-то значение, отличное от нуля, то должен быть выделен сектор для размещения файла.
Когда происходит поиск файла на дискете по заданному имени и типу, считывается содержимое нулевой дорожки. В том случае, если такой файл найден, его номер заносится в ячейку 23838. А в ячейки 23787 и 23788 заносятся соответственно начальные сектор и дорожка файла согласно его расположению на диске. Таким образом, теперь имеется вся необходимая информация для загрузки файла в память.
Если Вы выполняете, например, команду: А> LOAD "В:name"
то номер дисковода, указанного Вами в качестве временного (в данном случае это "В"), заносится в ячейку 23798. Для дисковода "А" это 0, "В" - 1, "C" - 2, "D" - 3.
Ячейка 23801 содержит признак операции LOAD/VERIFY. Значение 0 соответствует чтению, а 255 - сравнению файла. Вы можете проделать интересный эксперимент: сделайте POKE 23801,255, а затем подайте команду TR-DOS, например, LOAD "name" CODE. Однако вместо загрузки будет выполнена верификация.
Интересна информация, находящаяся в ячейках 23802...23805. Здесь (по одному байту на каждый дисковод) расположен код, определяющий время перемещения головки дисководов А..^. Число, стоящее там после инициализации - 8. Оно соответствует наибольшей скорости перемещения головки. Если чтение сектора прошло неудачно, то это число увеличивается на единицу, то есть становится 9 - это соответствует меньшей скорости перемещения головки. Она отводится на нулевую дорожку, после этого повторяется чтение. Если опять неудача, то опять уменьшение скорости (PEEK 23802=10) и повторяется чтение и так до PEEK 23802=11. Это наименьшая скорость перемещения головки. Вы можете искусственно увеличить ее после неудачного чтения, подав команду (для дисковода "А", например): POKE 23802,8. (Кстати тот же эффект даст POKE 23802,12.)
Вышесказанное про скорость перемещения головки относится к TR-DOS версии 5.01. В более поздних версиях, например, 5.04s, установлена только быстрая скорость перемещения головки и она не зависит от содержимого ячеек 23802...23805. Хотя при инициализации дисковода туда по-прежнему заносится 8. Это число является признаком того, что инициализация произведена (до инициализации каждого из дисководов A... D в этих ячейках содержится значение 255).
В ячейке 23814 задается число байт, по которым в каталоге диска ищется файл. Начальное значение этого параметра - 9 (8 байт - имя файла плюс 1 байт - его тип).
Ячейка 23823 содержит код ошибки TR-DOS. На коде ошибки необходимо остановиться поподробнее. Наберите и выполните следующую Бейсик-программу:
10 RANDOMIZE USR 15619 : REM : LOAD "abcde" CODE 20 PRINT PEEK 23823
В том случае, если файл "abcde" отсутствует на диске, то сообщения об ошибке не последует: программа остановится с сообщением 0 OK. 20:1. О наличии ошибки свидетельствует только единица на экране. По таблице кодов ошибок (смотри в описании TR-DOS) это соответствует ситуации "нет файла". Код ошибки из Бейсик-программы можно подучить еще и другим способом. Ранее в "ZX-РЕВЮ" мы уже говорили о том, что вместо
RANDOMIZE USR ... вполне можно использовать LET S=USR ... Все это относится точно также и к адресу 15619. Измените нашу программу:
10 LET err = USR 15619 : RЕМ : LOAD "abcde" CODE
20 PRINT err
Результат работы этой программы будет точно такой же, как и первой. Можете использовать значение err в Бейсик-программе по своему усмотрению, например:
20 IF err<>0 THEN PRINT "ERROR"
Продолжаем разговор о системных переменных TR-DOS.
Ячейка 23830 это копия системного регистра. Если посмотреть на схему контроллера дисковода, то это тот регистр, который собран на микросхеме 555ТМ9. Интересная особенность, но у меня пока что нет никаких данных о том, как практически это можно использовать.
Ячейка 23833 определяет номер накопителя А..^ (A-0, B-1, C-2, D-3). Можете проделать небольшой эксперимент. Войдите в TR-DOS. Вы увидите приглашение: А>. Теперь выполните: *"b". Приглашение сменится на: B>. Теперь перейдите из TR-DOS в Бейсик, выполнив RETURN, затем сделайте POKE 23833,2 и войдите опять в TR-DOS. Вместо приглашения: B> Вы увидите: C>, так как искусственно поменяли дисковод, изменив содержимое системной ячейки 23833.
Перечислены основные, но далеко не все системные переменные TR-DOS. Если кто-нибудь из читателей обладает более полной информацией, напишите об этом.
Теперь рассмотрим подробнее вопрос о том, как информация хранится на дискете.
ФОРМАТ ЗАПИСИ НА ДИСК.
Данные на дискету записываются в виде секторов, имеющих объем 256 байт. Вдвое меньший, по сравнению с IBM PC объем одного сектора позволяет несколько сэкономить потери из-за недоиспользования места, так как длина файла не кратна объему одного сектора. При большом числе коротких файлов это дает определенный выигрыш.
Предположим, что имеется двусторонний 80-дорожечный дисковод (во всяком случае, таких, наверное, большинство). Если Вы отформатируете дискету, то при завершении форматирования увидите, что на дискете имеется 2544 свободных сектора. Но 80 дорожек умножить на 16 секторов получится 2560 секторов. Где остальные? Дело в том, что нулевая дорожка дискеты 16 секторов - является системной. А файлы могут располагаться начиная с 1-й дорожки по 159 (так как запись двусторонняя).
Информация на нулевую дорожку записывается в строго определенном формате. Эти 16 секторов поделены на две части. В первой части - сектора с 0 по 7 - хранятся заголовки файлов. При этом на один заголовок отводится 16 байт информации. Всего на восьми секторах может быть размещено 128 заголовков файлов. То есть:
8 секторов * 256 байт = 2048 байт
то же самое, что:
128 файлов * 16 байт = 2048 байт.
Из максимального числа файлов, кстати, происходит название: "БЕТА-ДИСК 128".
Для тех, кто программирует в машинных кодах может оказаться полезным еще и такой взгляд. Порядковый номер заголовка имеет следующее свойство: старший полубайт этого числа (старшие 4 бита) соответствует номеру сектора, в котором записан заголовок файла, а младший полубайт (младшие 4 бита) соответствует номеру заголовка в секторе.
О том, как в память компьютера считать нулевую дорожку - позже. А сейчас о формате заголовка файла. Он в точности совпадает с 16 ячейками системных переменных с 23773 по 23788. Из 16 байт, отведенных на один заголовок, первые восемь занимает имя файла в ASCII. Следующий байт - тип файла (тоже в ASCII) - В, С, D или #. Следующие два байта -параметр START, далее 2 байта - длина файла, следующий байт - объем файла в секторах и далее 1 байт - номер начального сектора файла и 1 байт - номер начального трека (дорожки) файла на дискете.
Кроме сказанного, надо добавить следующее. При удалении файла первый символ имени (первый байт заголовка) заменяется на код 01. В таком виде файл считается удаленным, однако, если Вы не делали команду MOVE, то удаленный файл всегда можно восстановить, изменив первый символ его имени в заголовке либо при помощи программ типа "DISK-DOCTOR", либо при помощи всевозможных программ-оболочек типа "MOA-SERVICE". Однако, если удаляется последний файл каталога, то первый символ имени заменяется не на 1, а на 0. По значению 0 определяется конец каталога. Заголовки вновь записываемых файлов будут располагаться в каталоге, начиная с этого места.
Кроме секторов 0...7, в которых располагаются заголовки файлов, есть еще один сектор, восьмой, в котором содержится общая информация по диску. Эта информация расположена не с начала сектора, а ближе к его концу. Если начать нумерацию байтов сектора с 0, то вот содержание байтов, несущих информацию по диску.
Байты 225 и 226 хранят начало свободного места на диске, доступного для записи файлов - сектор и трек соответственно. Сразу же после форматирования дискеты эти байты имеют значения 0 и 1 соответственно (как говорилось выше, запись файлов на дискету начинается с дорожки номер 1).
Байт 227 определяет тип разметки диска. Значения этого байта могут быть следующими.
22 (#16) - 80 дорожек, 2 стороны;
23 (#17) - 40 дорожек, 2 стороны;
24 (#18) - 80 дорожек, 1 сторона;
25 (#19) - 40 дорожек, 1 сторона.
Байт 228 определяет общее количество файлов, записанных на диск. Это число включает в себя и удаленные файлы, так как физически они все равно присутствуют на диске. То есть это все файлы от начала каталога до начала свободного места.
Байты 229 и 230 (младший и старший) определяют количество свободных секторов на диске. Сразу же после форматирования дискеты командой TR-DOS: FORMAT "name", они равны соответственно 240 и 9. То есть 240+9*256=2544. Если для форматирования воспользоваться программой "DCU" Н. Родионова, можно отформатировать диск на максимальное число дорожек, для большинства дискет практически до 83-84 дорожек. При этом байты 229 и 230 сразу же после форматирования могут иметь другие значения, например 2640 или 2672. На первый взгляд может показаться, что на такую дискету удастся записать больше файлов. Но это только на первый взгляд. Попробуйте отформатировать дискету таким образом, а потом записать на нее файл объемом, например, 1 сектор. После записи Вы увидите, что на дискете осталось 2543 свободных сектора (2544-1 = 2543). То есть TR-DOS пересчитывает число свободных секторов при записи файла исходя не из того, что записано в байтах 229 и 230 системного сектора, а из того, что на диске может быть только 80 или 40 дорожек по 16 секторов.
Единственным преимуществом форматировании на максимальное число дорожек пока что видится возможность использования места за 80-й дорожкой для каких-то своих целей, например, там может располагаться пароль, защищающий дискету от копирования. Практически такой способ защиты очень распространен, но это - тема для отдельного разговора.
Если дискета форматировалась при помощи программы "DCU", то байты 223 и 224 содержат максимальное число форматированных секторов, доступных для записи файлов. Сразу же после форматирования дискеты значения этих байтов совпадают со значением байтов 229 и 230. Но значения последних изменяются по мере записи файлов на дискету, а значения байтов 223 и 224 остаются неизменными и используются при работе программы "DCU".
Если дискета форматировалась командой TR-DOS: FORMAT "name", то содержимое байтов 223 и 224 равно 0. Ненулевое значение этих байтов является признаком того, что
дискета форматирована при помощи программы "DCU".
Байт 231 всегда хранит код 16 (#10). Он определяет число секторов на одной дорожке и никогда не меняет своего значения. Это число обозначает принадлежность диска к операционной системе TR-DOS.
Байт 244 содержит число удаленных файлов - то есть тех, первый символ имени которых в каталоге диска имеет значение 01.
Байты с 245 по 252 хранят имя диска в кодах ASCII (всего - 8 байт).
Сектора с 9 по 15 не несут никакой информации, связанной с обычным функционированием файловой системы диска.
Вот это все, что касается нулевой дорожки. К сказанному можно добавить, что искажение системной информации диска и каталога диска широко используется для зашиты от копирования, и разговор об этом будет уже в этой статье, но чуть позже. А сейчас мы подошли, пожалуй, к самой главной теме.