Драйвер RAM Disk'а для ZX Spectrum 128 1. Вместо вступления Было это очень давно... Или, если быть точным - на дворе стоял 1995-й год. Как раз в то время мы, как и все начинающие Спектрумовские команды, работали сразу над многими проектами, а планировали сделать еще больше. Часть из этих проектов естественно относилась к таким жанрам как game и demo (в том числе в планах были небезызвестные Megaball и Paradise Lost). И, что тоже вполне очевидно для начинающей команды - у нас были проблемы с софтом. В частности нам очень не хватало программы для работы со спрайтами - ее попросту не было. Тогда-то и появилась идея SpriteLand'а. По началу это был просто набор процедурок не имеющий не только общего интерфейса, но даже не собранный в кучу. Каждая из них просто запускалась из Zeus'а, отрабатывала, а затем результаты вручную выгружались через BASIC. Впоследствии (когда подобное "удобство работы" нам осточертело) был написан первый вариант интерфейса (на BASIC'е) и были предприняты попытки собрать все это в кучу. Дальше - больше. Нам уже стало ясно, что из "утилитки для внутреннего пользования" эта программа постепенно вырастает в нечто вполне конкурентоспособное... Версия 1.0 появилась в октябре 1995-го, затем, буквально в течение месяца появились версии вплоть до 1.19. Причем версию 1.11 даже удалось продать Логросу за "бешеные деньги" - 100 рублей! :) Видимо, поэтому версия 1.11 стала наиболее распространенной, несмотря на некоторое количество багов. На версии 1.19, как ни странно все заглохло... Причем заглохло капитально - аж на 2 года :) И это несмотря на то, что там сидела парочка отвратительных багов, а некоторые необходимые функции просто отсутствовали. Реанимация проекта SpriteLand как ни странно произошла благодаря появлению проекта Scenergy, первый номер которого Вы в данный момент наблюдаете на экране своего монитора. Была выпущена существенно доработанная версия 1.25, однако дальше меня она так и не ушла. Все дело в том, что я планировал опубликовать ее в приложении к нулевому номеру Scenergy, но в силу ряда причин он так и не вышел. Теперь, в первом номере Scenergy Вы получаете сразу два подарка: новую версию SpriteLand'а в приложении, а также, в качестве бонуса, эту статью. :) "Про что это он?" - спросите Вы, - "при чем здесь жизнеописание SpriteLand'а, когда статья-то про RAM Disk?". Отвечу: Дело в том, что в ходе разработки SpriteLand'а были созданы 2 весьма полезные вещи: это драйвер RAM Disk'а и библиотека интерфейса. Пришло время, и теперь я хочу опубликовать их исходники для пользы всей Спектрумовской сцены. Ведь всегда гораздо проще и приятнее пользоваться для разработки своих программ готовыми, отлаженными и хорошо документированными исходниками, нежели пытаться в сотый раз изобрести велосипед. Именно поэтому на страницах Scenergy я хочу начать публикацию различных исходных текстов. Надеюсь, что опытные кодеры поддержат меня в этом начинании - ведь от этого всем будет только польза! Недаром же на всех других платформах пишутся кучи статей с описаниями алгоритмов, публикуются кучи исходников - это очень способствует развитию платформы. Так надо перенимать эту добрую традицию! 2. Несколько общих слов Итак, что мы имеем на сегодня? В данной статье Вы найдете полное описание драйвера RAM Disk'а, а в приложении - сам исходник в формате TASM v3.0. Все (c) на данный исходник и его описание принадлежат мне - Flying/DR. А посему я, как владелец авторских прав, разрешаю его свободное использование для любых целей. Разрешаю также исправление исходника с целью его доработки или переделки под ваши нужды. Единственное условие - сохранение копирайтов. Данный драйвер создавался специально для SpriteLand'а. Дата последней редакции: 25.10.1995 (древность какая :) ). При создании использовались TASM v3.0 (c) RST7/CBS и STS v2.6 (c) Stalker, за что им огромное спасибо! Хочу сразу заметить, что я не дорабатывал драйвер специально для публикации - он именно в том виде, в котором он стоит в SpriteLand'е. Отчасти это объясняется моей ленью досконально разбираться с исходником написанным более 3-х лет назад, а отчасти тем, что я не хочу лезть в полностью рабочую программу. О 100%-ной безглючности данного драйвера я могу говорить на основании того, что вот уже 3 года он работает в SpriteLand'е и за все это время ни одного глюка в нем не замечено. Опять же по причине моей лени в тексте исходника осталось немного смутное описание функций драйвера на немного корявом английском (т.к. TASM не поддерживает русских символов и слава Богу! :) ) 3. Характеристики драйвера Общее назначение: данная программа представляет собой драйвер RAM Disk'а для ZX Spectrum 128. Технические характеристики драйвера: - максимальное количество файлов на RAM Disk'е: 256 - размер файла: 1..65535 байт. - максимальный объем диска: 64кб (подробнее об этом ниже) - поддерживаются операции: - чтение - запись - удаление - переименование - оптимизация пространства RAM Disk'a - принцип организации: a-la TR-DOS, но память не поделена на сектора, минимальный блок - 1 байт. - принцип работы: a-la TR-DOS. Т.е. через точку входа с передачей номера функции и параметров в регистрах. - требования к памяти: - сам драйвер : 1588 байт - буфер для операций: 256 байт - каталог RAM Disk'а: 256*6=1536 байт - вся остальная страничная память может использоваться под RAM disk. Каталог может находиться в страничной памяти, сам драйвер и буфер должны находиться ниже #C000. Все операции с данными на RAM Disk'е производятся через буфер. Это позволяет снять все ограничения на адреса расположения данных для чтения/записи. Размер буфера можно варьировать при компиляции, однако, следует помнить, что слишком маленький размер буфера приведет к общему замедлению работы процедур RAM Disk'а. Надо заметить, что в отличие от TR-DOS файлы на RAM Disk'е не имеют имени - только номер, который, по сути, и является именем файла и используется при всех дисковых операциях. 4. Функции драйвера Вся работа с драйвером RAM Disk'а производится через единую точку входа. Номер вызываемой функции и необходимые параметры передаются через регистры. Общий формат вызова функций драйвера: LD A,<номер функции> CALL RAMDRV На выходе для всех функций содержимое регистров отражает текущее состояние RAM Disk'а: - Флаг CY указывает на то, успешно ли завершилась работа драйвера. CY=0 - все OK CY=1 - произошла ошибка. При этом в A будет находиться код ошибки (см. ниже) - Регистр B содержит количество использованных дескрипторов. В общем случае оно не равно количеству файлов на RAM Disk'е т.к. удаленные файлы тоже занимают дескрипторы до того как будет произведена оптимизация пространства RAM Disk'а. - Регистр C содержит количество свободных страниц памяти. - Регистр HL содержит количество свободной памяти в текущей используемой странице. Т.о. по состоянию регистров C и HL можно оценить общее количество свободной памяти на RAM Disk'е. Список функций драйвера: #00 - Инициализация драйвера RAM Disk'а. Производится очистка каталога и инициализация всех внутренних переменных. Эту функцию необходимо вызвать перед началом работы с RAM Disk'ом. Параметры: Нет #01 - Чтение файла с RAM Disk'а в память. Чтение производится под любой адрес в памяти, но только в основную память компьютера! Читать / писать в страничную память драйвер не умеет! Параметры: HL - Адрес буфера в памяти куда будет производиться чтение. DE - Размер считываемого блока. Если DE=0 то размер блока будет взят из дескриптора файла в каталоге. B - Номер считываемого файла. Возможные ошибки: #03 - 'Object is non exist'. Файл с таким номером на RAM Disk'е отсутствует. #02 - Запись файла на RAM Disk. Запись производится с любого адреса в памяти, но только из основной памяти компьютера! Читать/писать в страничную память драйвер не умеет! Параметры: HL - Адрес буфера в памяти, который будет записан на RAM Disk. DE - Размер записываемого блока. B - Номер записываемого файла. Возможные ошибки: #01 - 'No free ram disk space' Не хватает свободного места для записи файла на RAM Disk. Стоит попробовать освободить место, сделав оптимизацию пространства RAM Disk'а. #02 - 'Catalogue overflow'.Все дескрипторы в каталоге RAM Disk'а заняты. Стоит попробовать освободить дескрипторы занятые удаленными файлами, сделав оптимизацию пространства RAM Disk'а. #05 - 'Object is already exist'. Файл с таким номером уже есть на RAM Disk'е #03 - Удаление файла с RAM Disk'а. Параметры: B - Номер удаляемого файла. Возможные ошибки: #03 - 'Object is non exist'. Файл с таким номером на RAM Disk'е отсутствует. #04 - Переименование файла. Параметры: B - Старый номер файла. C - Новый номер файла. Возможные ошибки: #05 - 'Object is already exist'. Файл с таким номером уже есть на RAM Disk'е #05 - Оптимизация пространства RAM Disk'а Данная функция аналогична операции MOVE в TR-DOS. Как правило, вызывать ее следует в случае получения ошибок 'No free ram disk space' или 'Catalogue overflow' при попытке записи файла т.к. это, возможно, освободит дисковое пространство и дескрипторы, занятые удаленными файлами. Например, в SpriteLand'е вызов этой функции встроен в процедуру обработки ошибок драйвера RAM Disk'а и после получения соответствующей ошибки сначала производится попытка дефрагментировать пространство RAM Disk'а, затем снова предпринимается попытка записи файла и только в случае повторной неудачи выдается сообщение об ошибке. Параметры: Нет. Возможные ошибки: Нет. #06 - Получение информации о текущем состоянии RAM Disk'а. Вообще-то эта функция является чисто формальной т.к. возвращаемые ею данные и так возвращаются при каждом обращении к RAM Disk'у. Но иногда бывает полезно узнать о текущем состоянии RAM Disk'а ничего при этом не делая. Параметры: Нет. Возможные ошибки: Нет. #07 - Получение информации о файле. Параметры: B - Номер файла. Возвращаемые значения: B - Номер файла. С - Номер страницы, на которой расположено начало файла. Если C=#FF, то данный файл не существует на диске. HL - Адрес, по которому расположен файл на RAM Disk'е. В принципе данные в регистрах C и HL позволяют добраться до данных в файле непосредственно на RAM Disk'е, однако делать это я не советую т.к. никто не может гарантировать того, что данный файл целиком расположен в одной странице памяти. DE - Длина файла. Возможные ошибки: Нет. 5. Сообщения об ошибках. Данные сообщения об ошибках возвращаются в регистре A при каждом вызове драйвера RAM Disk'а. Если код ошибки отличен от #00 - устанавливается флаг CY как признак ошибочного завершения. #00 - 'No errors'. Все OK. #01 - 'No free ram disk space' Не хватает свободного места для записи файла на RAM Disk. Стоит попробовать освободить место, сделав оптимизацию пространства RAM Disk'а. #02 - 'Catalogue overflow'. Все элементы в каталоге RAM Disk'а заняты. Стоит попробовать освободить дескрипторы, занятые удаленными файлами, сделав оптимизацию пространства RAM Disk'а. #03 - 'Object is non exist'. Файл с таким номером на RAM Disk'е отсутствует. #04 - 'Illegal function number'. Функция с таким номером отсутствует в драйвере. #05 - 'Object is already exist'. Файл с таким номером уже есть на RAM Disk'е 6. Структура каталога RAM Disk'а Структура каталога RAM Disk'а: +0 [byte] Номер файла. +1 [byte] Номер начальной страницы или #FF если данный дескриптор свободен. +2 [word] Адрес начала файла в памяти. +4 [word] Размер файла. Данные из (+1) и (+2) образуют полный указатель на начало файла в пространстве RAM Disk'а. Номер страницы - логический (#00..#FE). Физический номер страницы берется из таблицы RAMPAGE (см. ниже) 7. Описание внутренних переменных Собственно говоря, исходник достаточно хорошо комментирован (правда на английском сомнительного качества :) ), поэтому здесь я опишу только наиболее важные переменные и функции. EQUS: CATLEN EQU 6 Размер одного элемента каталога RAM Disk'а. На данный момент равен 6 байтам таким образом, весь каталог занимает: 6*256=#600=1536 байт. Приписка к этой переменной в исходнике гласит, что при изменении размера элемента каталога необходимо переписать умножение на CATLEN в процедуре GETPADR так что учтите! :) CAT EQU #C000 Местоположение каталога в памяти. Как я уже сказал - он может располагаться где угодно (даже на страницах, где он и сидит в SpriteLand'е). Более подробно см. описание переменной CATPAGE и процедуры SETCATP. BUFLEN EQU 256 Размер буфера для обмена данными между RAM Disk'ом и основной памятью. В исходном виде расположен в теле драйвера, однако может располагаться по любому адресу ниже #C000. MAXFUNC EQU 7 Количество функций поддерживаемых драйвером RAM Disk'а. Необходимо для проверки корректности номера функции. RAMPORT EQU #7FFD Номер порта переключения страниц. Изначально задумывалось сделать поддержку расширенной памяти (о чем ниже), но до конца эта идея так и не была реализована... Переменные PAGES DEFB 4 Количество страниц памяти используемых под RAM Disk. В принципе размер RAM disk'а не ограничен 64кб, однако, т.к. в SpriteLand'е (откуда я взял этот исходник) свободной памяти оставалось только 64кб - соответственно здесь и стоит цифра 4. Об увеличении размеров RAM disk'а - ниже. MAINRAM DEFB #10 Номер страницы включенной по умолчанию в качестве основной памяти компьютера. Немного поясню: драйвер вообще-то может работать (читать/писать) только с основной памятью компьютера, которая, как известно, состоит из 5-й, 2-й, и еще одной (любой) страницы включенной в статьи с описаниями алгоритмов, процедур, различных кодерских хитростей позволяющих повысить быстродействие программ... А в приложении мы будем видеть качественные исходные тексты, которые будут полезны не только начинающим кодерам. Размечтался... :) Посмотрим - может мои мечты сбудутся... адреса #C000-#FFFF. Так вот, номер этой страницы и необходимо задать в данной переменной. Номер страницы должен быть физический! Кстати, если менять здесь номер страни- цы - можно читать/писать и в остальные страницы памяти :) CATPAGE DEFB #11 Номер страницы, в которой находится каталог RAM Disk'а. Это осталось от SpriteLand'а, в котором каталог RAM Disk'а лежит в страничной памяти. Номер страницы должен быть физический! RAMPAGE DEFB #13,#14,#16,#17 В этой таблице перечисляются физические номера страниц отведенных под RAM Disk. Их количество задается в переменной PAGES. BUFFER DEFS BUFLEN Буфер для обмена данными. При желании можно переставить в другое место. FUNCT DEFW INIT DEFW READ DEFW WRITE DEFW ERASE DEFW RENAME DEFW MOVE DEFW SYSINFO DEFW OBJINFO Это таблица указателей на процедуры, реализующие соответствующие функции драйвера RAM Disk'а. Адрес процедуры выбирается по номеру функции. Процедуры я здесь описывать не буду - те, кому это понадобится, смогут разобраться с ними сами. Тем более что каждая процедура в исходнике содержит комментарий с кратким описанием и перечислением своих входных параметров. 8. Перспективы. Естественно, что первое, что хочется сделать с этим драйвером - заставить его работать с верхней памятью различных моделей компьютеров. Приступая к написанию этой статьи, я еще раз просмотрел исходник, и обнаружил, что препятствий к этому нет никаких! :) Как все-таки классно я писал программы 3 года назад! :) Видимо сказывалось обучение на 3-ем курсе ПОВТ'а в универе. Вообщем единственное, что мешает прямо сразу начать использовать этот драйвер с верхней памятью - отсутствие собственно переключалки страниц верхней памяти. Что же надо сделать чтобы все заработало? 1) Вставить процедуру переключения страниц верхней памяти вместо процедуры CHPAGE. На входе в эту процедуру передается логический номер страницы памяти RAM Disk'а. Эта процедура должна взять физический номер страницы из таблицы RAMPAGE и включить ее. Все регистры должны быть сохранены. 2) Необходимо переделать процедуры SETMRAM и SETCATP так, чтобы они включали соответственно страницы основной памяти и каталога RAM Disk'а. (Более подробно см. описания переменных MAINRAM и CATPAGE). Все! :) Таким образом, Вы получите полностью рабочий RAM Disk с максимальным объемом #FE*#4000=4161536 байт или почти 4Mb! Кроме того, было бы неплохо добавить еще функций в дополнение к имеющимся. Сделать это также несложно: 1) Написать новую функцию драйвера. Все процедуры по низкоуровневой работе с RAM Disk'ом находятся в начале драйвера. 2) Добавить указатель на нее в таблицу FUNCT. 3) Изменить число функций в MAXFUNC. И все - функция станет частью драйвера. 9. Послесловие Надеюсь, данный драйвер Вам пригодится. Его действительно удобно использовать при написании ряда программ (SpriteLand'а, например :) ). Также я надеюсь, что остальные кодеры поддержат мое начинание, и на страницах нашего журнала мы будем видеть хорошие