Абзац
:: Поиск
:: ПоддерЖка ПрОекта
Webmoney:
  • Z610389805629
  • R427996570517
  • E023541002978
  • :: №25 (09.09.2005) ПрОсмотрОв: 5706

    Автор: Влад Сотников.

    Рубрика: Читатель читателю.

    Номер: №25 (09.09.2005).



    Особенности программирования CD-ROM на Спектруме

    1. Введение


    В газете «ZX News» № 54 мной была опубликована статья об особенностях программирования винчестера на Спектруме (обновленная версия была напечатана в газете «Абзац» № 21, 2004 г.). Также мной было в 2002 году написано продолжение, статья о программировании CD-ROM. Однако из-за того, что эта статья была опубликована лишь в Интернете (электронный вариант газеты «ZX News» № 55 так и не вышел на Спектруме), она не получила широкого распространения среди тех, кому она была бы действительно интересна, т.е. пользователям ZX Spectrum.

    Публикуемый здесь вариант - исправленная и дополненная версия того, что было опубликовано на сайте газеты «ZX News» в Интернете.

    Появление CD-ROM на Спектруме не было случайным - предпосылкой было создание IDE-контроллеров. Это и SMUC на Scorpion’е, и HDD-контроллер © Nemo. И хотя основной целью создания этих устройств было подключение винчестера, тем не менее «побочным» результатом стала возможность работы с CD-ROM. Мной совместно с Павлом Васильевым (POL) была написана программа, позволяющая читать данные с компакт дисков. Это CD_Walk, которую вы можете найти на специально созданном для программы Кириллом Фроловым сайте: http://cdwalk.narod.ru. Программа поддерживает оба контроллера (SMUC и NEMO). Так что все написанное здесь, служит единственной цели - облегчить людям написание подобных программ, но никак не может претендовать на документальное описание устройства. Так что могут встретиться погрешности и неточности. Тем не менее, информация, приведенная здесь, должна помочь людям, решившим сделать поддержку CD-ROM’а в своих программах.

    В отличие от моей предыдущей статьи, рассчитанной на начинающих пользователей, здесь я решил не объяснять лишний раз элементарных вещей и понятий, чтобы ограничить текст в объеме. Я предполагаю, что читатель уже знаком с моей предыдущей статьей (газета «Абзац» № 21 или «ZX News» № 54) и владеет базовыми навыками программирования на ассемблере и программирования винчестера. Назначение регистров и многие подпрограммы, используемые мной здесь, вы можете найти в моей статье о программировании винчестера.


    2. Немного о cd-rom’е


    По своим особенностям CD-ROM сильно отличается от винчестера. Во-первых, CD-ROM можно отнести к разряду Read-only устройств (пишущие CD-ROM мной здесь не рассматриваются в связи с ограниченным объемом информации об этих приводах. Возможно следующая версия CD_Walk, поддерживающая запись компакт-дисков, послужит основой для написания следующей статьи, посвященной данной тематике). CD-ROM является сейчас одним из популярных внешних носителей информации, в основном благодаря дешевизне компакт-дисков и удобству использования его в качестве архива.

    CD-ROM является внешним носителем информации. Он состоит из CD-проигрывателя, куда вставляются компакт-диски (объем дисков колеблется от 640 до 700 мегабайт и выше), а также еще одной важной части - трей. Это платформа, на которую кладутся компакт-диски. Она является подвижной частью устройства, которой можно управлять как вручную, так и программно.

    Как и винчестер, CD-ROM может быть как Master, так и Slave устройством. Однако принцип подачи команд несколько отличается от того, который использовался с винчестером, и был описан мной в предыдущей статье. Для программирования винчестера использовался набор регистров (или портов), каждый из которых выполнял какую-либо определенную роль (регистр команд, регистр состояния, регистр данных), и команды подавались через регистр команд, причем набор этих команд был ограничен. Совсем иначе дело обстоит с CD-ROM. Команда подается через пакет данных, состоящий обычно из 12 байт. Этот стандарт получил название ATAPI (ATA Packet Interface - Пакетный протокол ATA). В Регистр Команд подается команда «запись данных», и затем через Регистры Данных CD-ROM’у передается пакет из 12 байт. Причина этих сложностей состоит в том, что набор команд и регистров ATA не подходит для некоторых командных структур CD-ROM. Поэтому устройства ATAPI поддерживают только минимальный набор традиционных команд ATA.


    3. Форматы компакт-дисков


    3.1. «Красная книга»


    Изначально компакт-диски были созданы фирмами Philips и Sony для воспроизведения звуковой информации. Сейчас это обычные аудио-диски, которые можно воспроизвести на любом CD-проигрывателе. Формат данных определен как «Красная книга» и выглядит следующим образом: на диске находится некоторое количество звуковых дорожек (треков). Трек - это, как правило, одна песня. Дорожка, в свою очередь, делится на сектора, которые являются 1/75 секунды по длине и содержат 2352 байта данных в звуковой форме.


    3.2. «Желтая книга»


    Позже эти же компании-производители представили другой стандарт дисков, известный как «Желтая книга». В нем была предоставлена возможность сохранения на диске информации, не являющейся audio. Был пересмотрен формат сектора: теперь 2352 байта звукового сектора воспринимались следующим образом:


    12 байт синхронизации;

    4 байта информации о головке;

    2048 байт данных пользователя;

    288 байт исправления ошибки.


    Это основной стандарт. Существуют еще стандарты «Зеленая книга», «Оранжевая книга», но все они являются вариацией этих двух основных стандартов. Кроме того, существует стандарт ISO-9660, который изначально предназначен для хранения данных и имеет собственную файловую структуру. В нем не предусмотрено хранение аудио-информации. При этом нужно иметь в виду, что современные CD-ROM’ы самостоятельно определяют стандарт, в котором записан диск, и работают либо с аудио, либо с данными. Во втором случае нам нужно считывать 2048 байт данных. Это и есть длина сектора компакт-диска и минимальная длина считываемых данных.


    3.3. ISO-9660


    Стандарт ISO-9660 определяет структуру хранения файлов на диске. Она будет подробно описана далее в главе 12 - «Структура файловой системы диска». На самом деле, это довольно простая для понимания файловая структура. Диск делится на сектора по 2048 байт. В 16 секторе находится информация о диске и местоположении корневого каталога. Далее следуют все каталоги компакт-диска, и затем идут файлы. Причем информация в файлах располагается последовательно, сектор за сектором. Эта структура очень напоминает структуру дисков TR-DOS.


    4. Подпрограммы для контроллера


    Еще раз приведу порты SMUC и контроллера (c) NEMO, которые соответствуют регистрам IDE-устройства. Так же следует напомнить, что порты SMUC вызываются из-под TR-DOS.

    Название регистра                   Контроллер  Контроллер 
                                        SMUC        (с) NEMO       
    Регистр команд/состояния            #FFBE       #F0    
    Регистр накопителя/головки          #FEBE       #D0    
    Регистр цилиндра (старшая часть)    #FDBE       #B0    
    Регистр цилиндра (младшая часть)    #FCBE       #90    
    Регистр номера сектора              #FBBE       #70    
    Регистр счетчика секторов           #FABE       #50    
    Регистр ошибки/доп. возможностей    #F9BE       #30    
    Регистр данных (младшая часть)      #F8BE       #10    
    Регистр данных (старшая часть)      #D8BE       #11

    4.1 Подпрограммы для контроллера SMUC


    Здесь приведены подпрограммы для работы с контроллером SMUC. В принципе, эти подпрограммы соответствуют тем, что были приведены в статье про винчестер, здесь они лишь более систематизированы.

    ;Записать значение в порт.
    ;IN: [BC] - номер порта
    ;    [A] - значение
    OUT_A    LD IX,#3FF0
        PUSH IX
        JP #3D2F
    
    ;Считать значение из порта.
    ;IN:  [BC] - номер порта
    ;OUT: [A]  - значение
    IN_A    LD IX,#3FF3
        PUSH IX
        JP #3D2F
    
    ;Ожидание освобождения устройства.
    NO_BSY    LD BC,#FFBE
        CALL IN_A
        RLCA : RET NC
        JR NO_BSY
    
    ;Ожидание готовности передачи данных.
    WAIT_DRQ    LD BC,#FFBE
        CALL IN_A
        BIT 3,A
        RET NZ
        JR WAIT_DRQ
    ;Смотрим, не произошла ли ошибка.
    NO_ERROR    LD BC,#FFBE
        CALL IN_A
        RRCA
        RET
    
    ;Выбор устройства.
    ;IN: A=#00 - Master.
    ;    A=#B0 - Slave
    SEL_DRIVE    LD BC,#FEBE
        CALL OUT_A
        RET
    
    ;Запись числа в Регистр Цилиндра.
    HL_TO_LEN    LD BC,#FCBE
        LD A,L
        CALL OUT_A
        LD BC,#FDBE
        LD A,H
        CALL OUT_A
        RET
    
    ;Чтение числа из Регистра Цилиндра.
    LEN_TO_HL    LD BC,#FCBE
        CALL IN_A
        LD L,A
        LD BC,#FDBE
        CALL IN_A
        LD H,A
        RET

    4.2 Подпрограммы для контроллера (c) NEMO


    Для тех, кто пользуется контроллером винчестера (c) NEMO, также приведены отдельные подпрограммы. Этот контроллер удобен тем, что для его работы не нужно отдельное ПрофПЗУ, как для контроллера SMUC на Scorpion. Контроллер (c) Nemo достаточно вставить в системный разъем любого Spectrum-совместимого компьютера. Кроме того, для обращения к нему не нужно каждый раз вызывать ПЗУ TR-DOS - порты здесь открытые, что, в свою очередь, увеличивает скорость работы с CD-ROM’ом. И последнее - схема контроллера настолько проста, что его вполне можно собрать самостоятельно.

    ;Записать значение в порт.
    ;IN:  [BC] - номер порта
    ;     [A]  - значение
    OUT_A    OUT (C),A
        RET
    
    ;Считать значение из порта.
    ;IN:  [BC] - номер порта
    ;OUT: [A]  - значение
    IN_A    IN (C),A
        RET
    
    ;Ожидание освобождения устройства.
    NO_BSY    LD BC,#F0
        CALL IN_A
        RLCA 
        RET NC
        JR NO_BSY
    
    ;Ожидание готовности передачи данных.
    WAIT_DRQ    LD BC,#F0
        CALL IN_A
        BIT 3,A
        RET NZ
        JR WAIT_DRQ
    
    ;Смотрим, не произошла ли ошибка.
    NO_ERROR    LD BC,#F0
        CALL IN_A
        RRCA
        RET
    
    ;Выбор устройства.
    ;IN: A=#00 - Master.
    ;    A=#B0 - Slave
    SEL_DRIVE    LD BC,#D0
        CALL OUT_A
        RET
    
    ;Запись числа в Регистр Цилиндра.
    HL_TO_LEN    LD BC,#90
        LD A,L
        CALL OUT_A
        LD BC,#B0
        LD A,H
        CALL OUT_A
        RET
    
    ;Чтение числа из Регистра Цилиндра.
    LEN_TO_HL    LD BC,#90
        CALL IN_A
        LD L,A
        LD BC,#B0
        CALL IN_A
        LD H,A
        RET

    Далее по тексту (для подпрограмм определения наличия CD-ROM’а и чтения данных) пользователям HDD-контроллера (c) NEMO нужно заменить регистры (порты) контроллера SMUC соответствующими портами контроллера (c) NEMO.


    5. Ata-команды


    Это вспомогательные команды, которые передаются в CD-ROM через Регистр Команд, а не через пакет. Таких команд всего 4:

    1. #A0 - команда передачи ATAPI пакета. Подробнее ее использование будет рассмотрено ниже.

    2. #08 - Программный сброс. Выполняется полная инициализация CD-ROM’а.

    3. #A1 - Идентификация CD-ROM’а. Аналогична команде #EC для винчестера.

    4. #EC - Воспринимается как ошибка, но в Регистре Цилиндра устанавливается значение #14EB - признак ATAPI устройства.


    6. Определение наличия cd-rom’а


    Чтобы определить наличие CD-ROM’а, необходимо выполнить следующие действия:

    1. Выбрать устройство Slave/Master.

    2. Посмотреть отсутствие сигнала BSY. Если занято, значит, устройства нет. (Обратите внимание, чтобы перед этим CD-ROM не выполнял никаких ваших команд, иначе флаг BSY также может быть установлен).

    3. Подать команду общего сброса. Хотя можно обойтись и без этого.

    4. В Регистр Цилиндра записать число, отличающееся от #14EB. Для простоты можно записать 0 (ноль).

    5. В Регистр Команд подать ATA команду #EC и подождать пару прерываний.

    6. Прочитать Регистр Цилиндра. В нем должно находиться число #14EB. Если это так, значит, подключен CD-ROM. В противном случае это может быть винчестер. При этом нужно учитывать, что в Регистре Ошибок CD-ROM сообщит об ошибке. Это нормально.

    Здесь я приведу подпрограмму, которая определяет наличие CD-ROM’а. Хочу заметить, что CD-ROM на Cпектруме - это как правило Slave устройство, находящееся рядом с винчестером, и проверять его наличие я рекомендую в таком порядке: вначале Slave, затем Master.

    ;IN: A=#00 - Master.
    ;    A=#B0 - Slave
    CD_INI    CALL SEL_DRIVE
        LD BC,#FFBE ;#F0 для Nemo
        CALL IN_A
        INC A
        JP Z,NO_CDROM
        LD HL,0
        CALL HL_TO_LEN
        LD BC,#FFBE ;#F0 для Nemo
        LD A,#EC
        CALL OUT_A
        CALL NO_BSY
        CALL LEN_TO_HL
        LD BC,#EB14
        OR A
        SBC HL,BC
        JP NZ,NO_CDROM
        RET
    NO_CDROM ...

    Теперь мы убедились, что у нас подключено ATAPI устройство. Однако для полной уверенности не лишним будет проверить, точно ли это CD-ROM. Для этого нужно посмотреть 1-й байт в идентификационной таблице CD-ROM’а (передаваемой по команде #A1).

    Чтобы определить, какой диск вставлен в CD-ROM (диск с данными или аудио-диск), необходимо выполнить подпрограмму проверки, приведенную в конце главы 9.11


    7. Идентификационная таблица cd-rom’а


    Идентификационная таблица - это один сектор данных, в котором находится информация о конкретном CD-ROM’е. Сектор вызывается ATA командой #A1. После передачи команды нам необходимо принять 2048 байт от CD-ROM’а. Обратите внимание! Данные в этой таблице, как и в аналогичной таблице винчестера, перевернуты! Сначала идет старший байт, затем младший. Вам необходимо поменять каждые два рядом стоящих байта местами. Ниже приведен пример такой подпрограммы:

    ;IN: [HL] - адрес для приема данных.
    ;    [BC] - количество байт.
    TRANS_IN    PUSH BC
        CALL NO_BSY
        CALL WAIT_DRQ
        POP BC
        OR A
        RR B
        RR C
        JR NC,$+3
        INC BC
    TRANS_IN1    PUSH BC
        LD BC,#F8BE ;#10 для Nemo
        CALL IN_A
        LD (HL),A
        INC HL
        LD BC,#D8BE ;#11 для Nemo
        CALL IN_A
        LD (HL),A
        INC HL
        POP BC
        DEC BC
        LD A,B
        OR C
        JR NZ,TRANS_IN1
        RET
    Итак, чтобы считать идентификационную таблицу, нам нужно выполнить следующую подпрограмму:
    
    CD_INITAB    LD A,#A1
        LD BC,#FFBE ;#F0 для Nemo
        CALL OUT_A
        LD HL,MY_BUFF
        LD BC,#0200
        CALL TRANS_IN
        RET

    И у нас в памяти находится идентификационная таблица. В ней находится следующая информация:

    00, bit 0 - Длина пакета:

           0 - 12 байт,

           1 - 16 байт.

    01, bit 0-4 - Тип устройства: 5 (%00000101) -CD-ROM.

    20-39 - Серийный номер.

    40-45 - Что-то от производителя

    46-53 - Версия прошивки

    54-93 - Название модели

    94-95 - Что-то от производителя

    Остальные параметры для нас не так существенны. Таким образом, чтобы убедиться, что у нас действительно подключен CD-ROM, а не другое ATAPI устройство, нам нужно считать в аккумулятор байт из таблицы со смещением 1, выполнить команду AND #1F и посмотреть, не равен ли он 5. Хотя вероятность подключения к Спектруму ATAPI-устройства, не являющегося CD-ROM’ом, весьма мала, но, тем не менее, советую эту проверку проводить.


    8. Передача atapi-пакета


    Это ни что иное, как непосредственное программирование CD-ROM. Команды, которые он воспринимает, передаются ему в пакете, состоящем из 12 байт. Первый байт пакета является кодом команды, а остальные 11 байт - параметрами команды. Для начала я приведу подпрограмму, которая передает 12-байтный пакет в CD-ROM. Она выполняет следующие действия: записывает в Регистр Команд ATA команду #A0 (передача ATAPI пакета) и передает через регистры данных 12 байт являющихся ATAPI пакетом.

    Внимание! При передаче пакета нужно всегда указывать устройство, с которым мы работаем (Master/Slave).

    ;Передача ATAPI пакета.
    ;IN: [HL] - адрес пакета.
    SEND_ATAPI    PUSH HL
        LD A,master/slave #00/#B0
        CALL SEL_DRIVE
        CALL NO_BSY
        LD HL,#0800
        CALL HL_TO_LEN
        LD BC,#FFBE ;#F0 для Nemo
        LD A,#A0
        CALL OUT_A
        POP HL
        LD BC,12
    
    ;передача данных
    ;IN: [HL] - адрес данных.
    ;    [BC] - количество байт.
    TRANSFER_OUT
        PUSH BC
        CALL NO_BSY
        CALL WAIT_DRQ
        POP BC
        OR A
        RR B
        RR C
        JR NC,$+3
        INC BC
    TRANS_OUT1    PUSH BC
        INC HL
        LD A,(HL)
        LD BC,#D8BE ;#11 для Nemo
        CALL OUT_A
        DEC HL
        LD A,(HL)
        LD BC,#F8BE ;#10 для Nemo
        CALL OUT_A
        INC HL
        INC HL
        POP BC
        DEC BC
        LD A,B
        OR C
        JR NZ,TRANS_OUT1
        RET

    И пара слов о том, как должен выглядеть этот командный пакет. В своем описании я буду представлять его в таком виде:

    #00 - «Пустышка».
        DB 0
        DS 11

    Первый байт - это код команды. Остальные - параметры. Неиспользуемые байты я описываю командой ассемблера DS X (последовательность X нулей). Хотя неиспользуемые данные не анализируются, для совместимости их лучше устанавливать в 0.

    Итак, сам пакет можно оформить таким образом:

    AP_00    DB 0
        DS 11

    И вызываться он будет так:

        LD HL,AP_00
        CALL SEND_ATAPI
        ...

    9. Описание команд cd-rom’а


    Общие команды.


    9.1. «Пустышка»


    Эта команда была приведена мной в качестве примера в предыдущей главе. Пакет состоит из 12 нулей. Эта команда не выполняет никаких действий. Однако она крайне необходима - дело в том, что в силу непонятных причин CD-ROM отказывается выполнять многие команды и сообщает об ошибке. В частности, это происходит непосредственно за сменой носителя (Master -> Slave или наоборот). Поэтому настоятельно рекомендую вам перед каждой командой вызывать «пустышку». Именно так я добился работоспособности своей программы CD_Walk на Спектруме. Иными словами, выполнение команды, описанной пакетом AP_?? должно выглядеть так:

        LD HL,AP_00
        CALL SEND_ATAPI
        LD HL,AP_??
        CALL SEND_ATAPI
        ...

    9.2. Позиционирование

    ;#01 - Установить головку на начало диска.
        DB #01
        DS 11

    Эта команда управляющая, и в своей программе я не использовал ее ни разу.

    ;#2B - Позиционирование в формате MSF.
        DB #2B
        DS 2
        DB минуты
        DB секунды
        DB доли секунды
        DS 6

    MSF (Minute/Second/Frame) - это один из способов позиционирования на диске. Оно определяется в минутах/секундах/долях секунды, которые прошли бы при чтении с начала диска со скоростью 1. Формат удобен при работе с аудио-дисками.


    9.3. Управление треем

    ;#1B - Управление треем.
        DB #1B
        DS 3
        DB Function
        DS 7
    Function:
        0 - Войти в режим Sleep.
        1 - Остановить проигрывание/чтение.
        2 - Выдвинуть трей.
        3 - Задвинуть трей.

    Как вы видите, функции этой команды не ограничиваются одним управлением треем. Режим Sleep - это режим пониженного энергопотребления, диск останавливается или замедляет свое вращение до прихода команды чтения данных. Функцию с кодом 1 удобно использовать для остановки проигрывания мелодии. Управление треем осуществляется только в том случае, если он не блокирован.

    ;#1E - Блокировка трея.
        DB #1E
        DS 3
        DB Function
        DS 7
    Function:
        0 - разблокировать трей.
        1 - заблокировать трей.

    Команда блокирует действие команды #1B.

    Итак, если трей не заблокирован (можно заблаговременно его разблокировать), с помощью этой подпрограммы мы можем его выдвинуть:

    TRAY_OUT    LD A,2
        LD (AP_1B+4),A
        LD HL,AP_1B
        CALL SEND_ATAPI
        RET

    А эта подпрограмма задвинет его обратно:

    TRAY_IN    LD A,3
        LD (AP_1B+4),A
        LD HL,AP_1B
        CALL SEND_ATAPI
        RET
    AP_1B    DB #1B,0,0,0,0,0
        db 0,0,0,0,0,0

    Информационные команды.


    9.4. Чтение параметров изготовителя (Inquiry)


    Здесь содержатся практически те же данные, что и в идентификационной таблице, вызываемой ATA-командой #A0.

    ;#12 - Чтение строки параметров изготовителя.
        DB #12
        DS 3
        DB длина строки.
        DS 7

    Длина строки обычно 36. Возвращаются следующие данные:

    +0 - тип устройства (CD = 5)

    +1 - bit 7: поддерживаются сменные носители

    +2 - версии ISO, ECMA и ANSI.

    +3 - 0, для совместимости со SCSI-2

    +4 - длина оставшегося блока

    +5 - резервные

    +7 - 0, для совместимости со SCSI-2

    +8 - строка изготовителя (там бывает “ATAPI”)

    +16 - название продукции

    +32 - версия изделия


    9.5. Получение общих параметров


    Эта команда мной не изучена, поэтому привожу ее из описания без изменений и комментариев. Вам предстоит либо изучить ее действие самим, либо пропустить, поскольку она сообщает специфические сведения о CD-ROM’е и для Спектрума решающего значения не имеет.

    ;#5A - Получить общие параметры.
        DB #5A
        DB 0
        DB Page - определяет требуемые параметры, состоит из двух битовых полей:
    
    bits 1…5 - номер требуемой страницы параметров:
    %00000001 - параметры исправления ошибок
    %00001011 - общие параметры
    %00001110 - аудио-управление
    %00101010 - параметры устройства (только читается)
    %00111111 - все странички
    
    bits 6…7 -    биты типа требуемой страницы:
    %00000000 - текущие значения
    %01000000 - измененные значения
    %10000000 - значения по умолчанию
    %11000000 - сохраненные значения
        DS 4
        DW Length; длина таблицы
        DS 3

    Команда информационная, выдает соответствующую страничку параметров.


    Общий заголовок:

    00-01 - Длина всего блока (без первого слова)

    02 - Состояние привода

    03-07 - ?


    Заголовок каждой страницы:

    08 - Номер страницы из запроса

    09 - Длина страницы


    Страница #01 - исправление ошибок

    10 - Параметр исправления ошибок

    11 - Счетчик повторов чтения


    Страница #0D - общие параметры

    10 - ?

    11 - Множитель таймера неактивности

    12-13 - Число S единиц в M единице для формата MSF (60)

    14-15 - Число F единиц в S единице для формата MSF (75)


    Страница #0E - аудио параметры

    10 - Параметр не исп., но изменяется

    11-12 - ?

    13 - =0 LBA всегда равен номеру сектора, старший бит указывает правильность следующего поля

    14-15 - Число логических блоков в секунду для проигрывания. (как правило, не используется)

    16 - мл. тетрада - биты выходного порта канала 0

    17 - громкость канала 0

    18 - мл. тетрада - биты выходного порта канала 1

    19 - громкость канала 1

    20 - мл. тетрада - биты выходного порта канала 2

    21 - громкость канала 2

    22 - мл. тетрада - биты выходного порта канала 3

    23 - громкость канала 3


    Страница #2A - параметры устройства (только чтение)

        ; биты присутствия/отсутствия функций


    12 - bit 0 - проигрывание аудио

        bit 1 - композитный аудио/видео поток

        bit 2 - Digital out to port 1

        bit 3 - Digital out to port 2

        bit 4 - чтение секторов Mode 2 Form 1

        bit 5 - - - // - - - - Mode 2 Form 2

        bit 6 - Чтение многосессионных дисков

        bit 7 - ?


    13 - bit 0 - Чтение «Красной Книги» через команду Read-CD

        bit 1 - Чтение «Красной Книги»»with accurate stream»

        bit 2 - Чтение субканала

        bit 3 - Поддержка деинтерливинга данных субканала

        bit 4 - Поддержка «C2 error pointers»

        bit 5 - Поддержка чтения ISRC

        bit 6 - Поддержка чтения UPC

        bit 7 - ?


    14 - bit 0 - блокировка носителя

        bit 1 - чтение статуса блокировки

        bit 2 - Disk prevent jumper present

        bit 3 - команда выброса носителя

        bit 4 - ?

        bit 5…7 - Тип загрузчика:

        0 - Caddy

        1 - Tray

        2 - Pop-Up

        3 - Reserved

        4 - Ченджер с индивидуально меняемыми дисками

        5 - Картридж

        6 - Reserved

        7 - Reserved


    15 - bit 0 - Раздельная регулировка каналов

        bit 1 - Раздельный коммутатор каналов

        bit 2- Информация о наличии диска

       

    16-17 - Максимальная скорость обмена в килобайтах

    18 - ?

    19 - Число градаций регулировки громкости

    20-21 - Размер буфера в килобайтах

    22-23 - Текущая скорость обмена

    ; - - - - иногда может отсутствовать - - - - - - -

    24 - ?

    25 - bit 0 - Digital out по фронту/спаду сигнала BCKF

        bit 1 - LRCK индицирует левый/правый канал

        bit 2 - данные в формате LSB/MSB

        bit 3 - ?

        bit 4 \ BCKs: 0 - 32

        bit 5 | 1 - 16

        bit 6 /    2 - 24

        3 - 24 (I^2S)

        bit 7 - ?


    Длина каждой из страниц может быть разной. Здесь описаны только те поля, которые более-менее стандартны. Если запрашиваются все странички (биты 0...5), то в выходном блоке будет присутствовать один общий заголовок и последовательно расположенные странички со своими заголовками.


    9.6. Установка общих параметров


    Действие команды аналогично предыдущей, с той лишь разницей, что она не возвращает значения, а записывает их. Коды и формат страниц вы можете посмотреть из описания предыдущей команды.

    ;#55 - Установка общих параметров.
        DB #55
        DB ?; бит 1 - сохранять 
        ;в NVRAM (?)
        DB Page; требуемая 
        ;страница параметров
        DS 4
        DW Length; длина таблицы
        DS 3*

    9.7. Код ошибки операции

    ;#03 - Чтение состояния привода.
        DB #03
        DS 3
        DB #12; длина таблицы 
        ;ошибок
        DS 7

    Затем нужно считать 18 байт данных, где второй байт будет кодом ошибки операции. CD-ROM возвращает следующие ошибки:

    0 - бессмысленные данные

    1 - повторная ошибка

    2 - нет готовности

    3 - ошибка среды

    4 - ошибка оборудования

    5 - неверный запрос

    6 - обслуживание устройства

    7 - защита данных

    11 - команда прервана

    14 - неверное сравнение

    К сожалению, я не могу привести здесь полное описание значения каждой ошибки, так как подробно ими не занимался. Хотя обработка ошибок при программировании CD-ROM наиболее важна, чем при программировании винчестера. Дело в том, что при работе с компакт-диском CD-ROM довольно часто возвращает ошибку. Но это не всегда значит, что произошла ошибка в прямом смысле этого слова. Например, это может свидетельствовать о неготовности CD-ROM’а передавать данные из-за недостаточной скорости вращения компакт-диска (то есть, попросту говоря, диск еще не раскрутился).

    Я приведу пример из моего непосредственного опыта написания копировщика для CD-ROM. Если какое-то долгое время не происходит обращения к диску, то CD-ROM переходит в режим пониженного энергопотребления. Начинает медленнее вращаться. И при обращении к диску, например, при попытке считать данные, он снимает флаг BSY, однако скорости вращения диска еще недостаточно для выполнения операции. CD-ROM будет возвращать ошибку «2 - нет готовности» до тех пор, пока скорость вращения диска не позволит считать данные и передать их компьютеру.

    Действия при чтении данных (сектора) должны иметь следующую последовательность:

    1. Передаем пакет с командой чтения данных (описан ниже).

    2. Ожидаем снятия флага занятости BSY.

    3. Смотрим 0-й бит Регистра состояния (нет ли ошибки)

    4. Если нет ошибки, продолжаем чтение данных.

    5. Передаем пакет «03». Читаем 18 байт. Смотрим код ошибки.

    6. Если код равен 0 - «бессмысленные данные», то необходимо продолжить чтение. В противном случае переходим в состояние ошибки.

    Для более подробной информации смотрите главу 10 - «Пример чтения данных на Спектруме».


    9.8. Определение размера диска

    ;#25 - Размер диска в секторах.
        DB #25
        DS 11

    Затем необходимо считать 8 байт. Первые четыре байта - количество секторов на текущем диске, и следующие - размер сектора (как правило, не зависит от диска и равен 2352). Напомню, что размер диска также можно узнать из TOC-сектора диска (глава 12.1).


    9.9. Информация об аудио-дисках


    Следующая команда позволяет получить информацию, относящуюся к audio-дискам. Работа этой команды мной не исследована, поэтому привожу ее описание практически без комментариев. Может быть, вам удастся извлечь отсюда полезную информацию.

    ;#42 - смешанная информация (чтение субканала)
        DB #42
        DB ScMsf -    bit 1 - тип выдачи
            адресов 0 - номер 
            сектора, 1 - MSF
        DB FullInfo -    вариант запроса 
            (полный/краткий - 
            6-й бит)
        DB Func -    подфункция (только 
            для полного запроса)
        DS 3
        DW Length -    Длина таблицы
        DS 3
    Команда выдает блок следующей информации:
    +01 DB - состояние проигрывания аудио:
        0 - неизвестно или не поддерживается
        1 - Играет аудио
        2 - Аудио стоит
        3 - Аудио остановилось на конце
        4 - Открыта дверь или ошибка запуска
        5 - Прочее
    +02 DW длина следующих за заголовком данных (0 - нет)
    
    Внимание! +04 и далее присутствует при наличии бита 40h в FullInfo и зависят от Func.
    
    Func не равен 2 или 3:
    +04 DB 01 (формат данных субканала = 1)
    +05 DB Ctrl/Addr
    +06 DB Номер трека.
    +07 DB Point or Index
    +08 DB 0
    +09 DS 3 - MSF/SECTOR на диске
    +12 DB 0
    +13 DS 3 - MSF/SECTOR на дорожке
    
    - Подфункция 2 - (Получить UPC код)
    +04 DB 2 (формат данных субканала = 2)
    +05 DS 3
    +08 DB #80 - флажок наличия UPC (если нет, то UPC отсутствует)
    +09 DS 12 - здесь хранится UPC код (6 цифр в BCD коде)
    +23 DS 3 - Положение чего-то на диске в формате MSF
    
    - Подфункция 3 - (получить ISRC код)
    +04 DB 03h (формат данных субканала = 2)
    +05 DB Ctrl/Addr
    +06 DB Номер трека- не всегда используется.
    +07 DB ?
    +08 DB #80 - флажок присутствия (аналогично функции 2)
    +09 DB далее запись ISRC

    9.10. Информация о секторе


    Эта команда создает некий компромисс между двумя типами адресации информации на компакт-диске: аудио-адресацией (MFS) и секторной адресацией. На входе команды задаются минуты/секунды/фреймы, а на выходе формируется информация о секторе, находящемся в этом месте - его номере и формате.

    ;#44 - информация о реальных метках положения (Read HEADER).
        DB #44
        DB SL -     бит 2 - что 
            записывать в выходной 
            буфер (исходный номер 
            сектора или считанный)
        DB 0
        DS M,S,F -    Номер сектора
        DB 0
        DW Len -    длина выдаваемой 
            информации
        DS 3

    Команда возвращает таблицу из 8 байт:


    +00 Тип формата сектора (data mode)

    +01 0,0,0,0

    +05 Адрес сектора (M,F,S).

    Информация возвращается только в том случае, если CD смог считать заданный сектор и определить его тип.


    9.11. Информация о дорожках


    Эта команда также мною не исследована, поэтому привожу ее без комментариев и пояснений. Я эту команду использовал единственно для выяснения, какой компакт-диск находится в CD-ROM’е аудио или информационный. Подпрограмма, позволяющая это делать, будет приведена в конце описания команды.

    ;#43 - информация о дорожках (READ TOC).
        DB #43
        DB ScMsf -    bit 1: 
            тип выдачи адресов 
            (0-номер сектора,
            1-MSF)
        DB Format -    информация, 
            которую мы хотим 
            получить.
        DS 3
        DB BegTrk -     начальная дорожка/
            сессия (от 1,0 
            заменяется на 1)
        DW Length -    Длина таблицы 
            (в секторах)
        DB Func -    варианты выдачи 
            информации (0/#40/#80)
        DS 2

    Описание байта Format:

        0 - выдаются данные для всех сессий.

        1 - выдается номер первой завершенной сессии, последней завершенной сессии и начальный адрес последней сессии (в этом случае BegTrk должно быть 0).

        2 - начиная с номера сессии, заданной в BegTrk, выдается информация обо всех последующих сессиях.

        3 - выдаются данные PMA (учитывающееся пространства диска для записи сессий).

        4 - выдаются данные ATIP (абсолютное время канавки для незаписанных CD-болванок. BegTrk должно быть 0, а MSF - 1).

        5 - выдаются данные CD-TEXT


    Команда информационная, выдает таблицу дорожек. Максимальная длина таблицы = 8*#64+4 байт или #64 (100) дорожек.


        Func = #00 - получить обычную таблицу дорожек

        = #40 - получить таблицу сессий

        = #80 - получить обычную таблицу в расширенном формате


    Общий формат таблицы:

        DW Len    - длина последующих полей в байтах

        DB BegTrk - первая дорожка

        DB EndTrk - последняя дорожка


    Описание дорожек может быть трех форматов:


    1) 5 байт на дорожку (внутренний формат, наружу из CD не выдается):

        DB Ctrl/Addr - тип дорожки и флаги

        DB Index    - индекс дорожки (номер)

        DB Start (3 байта) - адрес начала дорожки


    2) 8 байт на дорожку (Func=0/#40):

        DB ?

        DB Ctrl/Addr - тип дорожки и флаги

        DB TrackNumber - номер дорожки

        DB ?

        DB Start (4 байта) - адрес начала дорожки


    3) 11 байт на дорожку (Func = #80):

        DB Res1

        DB Ctrl/Addr - тип дорожки

        DB Res2

        DB Index    - индекс дорожки

        DB Res3

        DB Res4

        DB Res5

        DB Start (4 байта) - адрес начала дорожки


    Возвращаемые переменные имеют следующие значения:


    Ctrl/Addr - тип дорожки

    Ctrl (младшая тетрада, отдельные биты):

    01 - есть pre-emphasis

    02 - разрешено копирование

    04 - дорожка данных

    08 - 4 канала (а не 2)


    Addr (старшая тетрада, коды):

    0 - нет субканала

    1 - в субканале закодирована позиция

    2 - в субканале закодирован UPC

    3 - в субканале закодирован ISRC

    прочее - зарезервировано


    Самые распространенные коды:


        14h - ROM

        10h - audio


    Index - кодируется в BCD и для обычной дорожки находится в интервале 01-99. Коды #A0 и выше имеют специальное значение, они не соответствуют физическим дорожкам на диске, а носят служебный характер - информируют о числе дорожек, начале диска, конце диска и т.п.

    Start - в зависимости от запроса, может быть либо номером сектора, либо адресом сектора в формате MSF.

    С помощью следующей подпрограммы можно узнать, с каким диском мы имеем дело: с данными либо с аудио-диском. Если установлен флаг нуля (Z), то у нас аудио-диск, и пытаться искать на нем файловую систему бесполезно.

    TEST_AUDIO    LD HL,AP_00
        CALL SEND_ATAPI
        LD HL,AP_43_AUDIO
        CALL SEND_ATAPI
        LD HL,AUDIO_BUF
        LD BC,#0006
        CALL TRANSFER_IN
        LD A,(AUDIO_BUF+5)
        CP #10
        RET
    
    AP_43_AUDIO    DB #43,0,0,0,0,0
        db 1,0,6,#80,0,0
    
    AUDIO_BUF    DS 6

    Команды управления аудио-дисками.


    Поскольку изначально CD-ROM’ы использовались для воспроизведения звука, и лишь позже их приспособили для хранения информации, то поэтому среди команд управления CD-ROM’ом присутствует большое количество команд, работающих непосредственно с audio-форматом дисков. Это так называемые звуковые дорожки, или треки. Как правило, каждый CD-ROM может работать с audio-треками. Так, на передней панели CD-ROM’а существует аудио-выход, куда можно подключить наушники или усилитель, и кнопка для последовательного переключения треков. Звук можно снимать также в цифровом виде и считывать его компьютером (на IBM PC для этого существуют так называемые аудиограбберы - программы, считывающие звуковые дорожки и преобразующие их в *.wav или *.mp3 файлы), но на Спектруме, к сожалению, этого сделать пока нельзя. Поэтому программно можно ограничиться только переключением проигрывания выбранного трека, но звук при этом должен сниматься на усилитель либо наушники только с передней панели CD-ROM’а или с аналогичного audio-выхода задней панели.


    9.12. Проигрывание в блоках


    Эта команда задает начало проигрывания и длину проигрывания в блоках. Причем количество проигрываемых блоков 16-разрядное (максимум - 65535).

    ;#45 - проигрывать audio в блоках.
        DB #45
        DB 0
        DD StartBlock - блок начала 
            проигрывания 
            (#FFFFFFFF - с тек. 
            положения). 
            «DD» означает, что 
            задается 4 байта 
            («DB»-1, «DW»-2).
        DB 0
        DW Length    - число блоков
        DS 3
    
    ;#A5 - проигрывать audio в блоках.

    От предыдущей эта команда отличается только тем, что количество проигрываемых блоков задается 32-разрядным числом (соответственно, с помощью нее можно задать проигрывание довольно большого отрезка диска).

        DB #A5
        DB 0 
        DD StartBlock - блок начала 
            проигрывания 
            (-1 - с тек. 
            положения).
        DD Length -    количество блоков.
        DS 2

    9.13. Проигрывание audio в MSF


    Эта команда задает проигрывание в формате MSF. Такой способ позволяет задать очень точное (до долей секунды) место начала проигрывания и время проигрывания. Таблицу расположения дорожек в этом формате можно получить с помощью команды «#43 - информация о дорожках» (глава 9.11).

    ;#47 - проигрывать audio в MSF.
        DB #47
        DS 2
        DB M,S,F -    начало отрезка
            (FF:FF:FF - текущая 
            позиция)
        DB M,S,F -    конец отрезка
        DS 3
    
    9.14. Остановить/продолжить проигрывание
    Эта команда служит для остановки/продолжения проигрывания музыки.
    ;#4B - Start/stop audio.
        DB #4B
        DS 7
        DB Func
        DS 3

    Func=0 - остановить проигрывание.

    Func=1 - продолжить проигрывание.


    9.15. Остановка проигрывания


    Эта команда очень простая, и служит единственной цели - остановке проигрывания звуковой дорожки. К тому же она не требует дополнительных параметров.

    ;#4E - остановить проигрывание.
        DB #4e
        DS 11

    Команды чтения данных


    Существует две команды чтения данных. Одна из них позволяет читать данные в конкретных секторах, а другая в параметрах MSF (описанных выше). Если чтение в MSF актуально для audio-дисков, когда мы хотим ровно считать звуковую дорожку для преобразования ее, например, в файл (*.wav или *.mp3, минимальный размер такого файла - несколько мегабайт, для Спектрума неактуально). Хотя можно написать программу, проигрывающую с audio-диска короткие области для последующего преобразования их в сэмплы для General Sound. Тогда читать данные удобно как раз в MSF. Чтение же в секторах как раз удобно для чтения файлов (поскольку все параметры файлов указываются именно в секторах). Ниже я приведу описание двух вариантов чтения и пример для чтения секторов на Спектруме.


    9.16. Чтение данных в MFS

    ;#B9 - Чтение данных в MSF.
        DS 3
        DB #B9 
        DB Fmt     может быть = 
            #00 годится любой 
            формат
            #08 обычный CD-диск 
            (Желтая книга)
            #10\ разновидности
            #14/ Зеленой книги.
        DB 0 
        DB M,S,F    начало чтения
        DB M,S,F    конец чтения
        DB Flg    флаги читаемой 
            части сектора:
        bit 0 - не используется
        bit 1 \ поле ошибки
        bit 2 / (неактуально) 
        bit 3 - EDC/ECC (для нас также 
            не актуально)
        bit 4 - передавать данные 
            пользователя.
        bit 5 \ Код загаловка 
                (%00 - не передавать,
                %01 - заголовок
        bit 6 / %10 - подзаголовок, 
                %11 - и то, и другое)
        bit 7 - добавить данные 
                синхронизации блока
        DB 0    всегда д.б.=0, 
                иначе ошибка
        DB 0

    Если в этой команде адрес начала чтения совпадает с адресом конца чтения, то происходит позиционирование на указанную позицию и тестируется чтение. Данные не передаются.


    9.17. Чтение данных в секторах

    ;#BE - Чтение данных в секторах.
        DB #BE 
        DB Fmt -    формат чтения 
            (как в #B9).
        DB Sec -    начало чтения - 
            4 байта. 
            (исп. только 24 бита)
        DB 0 
        DW ScNum -    Число секторов
        DB Flg -    флаги читаемого 
            куска сектора 
            (как в #B9)
        DB 0 -    всегда д.б.=0, 
            иначе ошибка.
        DB 0

    Команда полностью аналогична команде #B9 - «Чтение данных в MFS», за исключением задания адресов области чтения в секторах.


    10. Пример чтения данных на Спектруме


    Ниже я приведу пример подпрограммы чтения секторов на Спектруме. Перед ее вызовом необходимо выставить значения в пакете AP_BE (чтение данных в секторах). Пример такого пакета вы видите перед собой.

    SECTOR - сектор для чтения.

    SECTORS - количество секторов для чтения (к сожалению, по непонятным причинам, при попытке считать более одного сектора в принимаемых данных возникают ошибки. Поэтому советую вам читать по одному сектору и эту переменную не менять).

    AP_BE    DB #BE,#00
    SECTOR    DB #00,#00,#00,#1F
        DB 0
    SECTORS    DB #00,#01
        DB #10
        DB 0,0
    
    И собственно подпрограмма чтения:
    
    ;IN: [HL] - адрес для чтения.
    LOAD_SECTOR    PUSH HL
        CALL NO_BSY
        LD HL,AP_00
        CALL SEND_ATAPI
        LD HL,AP_BE
        CALL SEND_ATAPI
        CALL NO_BSY
        CALL NO_ERROR
        JP C,ERROR
        CALL WAIT_DRQ
        POP HL
        LD B,8
    LOAD_SECTOR1    PUSH BC
        CALL READ_S
        POP BC
        DJNZ LOAD_SECTOR1
        RET
    
    READ_S    LD B,0
    READ_1    PUSH BC
        LD BC,#F8BE ;#10 для Nemo
        CALL IN_A
        LD (HL),A
        INC HL
        LD BC,#D8BE ;#11 для Nemo
        CALL IN_A
        LD (HL),A
        INC HL
        POP BC
        DJNZ READ_1
        RET

    В момент чтения может произойти ошибка. Если она будет иметь код 0 - «бессмысленные данные», то дело, вероятно, в том, что диск еще недостаточно успел раскрутиться. В таком случае нужно продолжать чтение. В случае же остальных ошибок нужно производить исправляющие действия (менять диск, сообщать об ошибке) - в общем, на усмотрение программиста. Соответствующая процедура приведена ниже:

    ERROR    LD HL,AP_00
        CALL SEND_ATAPI
        LD HL,AP_03
        CALL SEND_ATAPI
        LD HL,BUF_ERROR
        LD BC,#0012
        CALL TRANSFER_IN
        LD A,(BUF_ERROR+2)
        OR A
        JP Z,LOAD_SECTOR
        ... - сообщение 
        об ошибке и т.д.
    BUF_ERROR    DS 18

    Для работы процедуры обработки ошибок ERROR необходим вызов пакета определения ошибки (глава 9.7). Вот он:

    AP_03    DB #03
        DS #03
        DB #12
        DS #07

    Иногда возникает такая ситуация: после очередного чтения проходит некоторое время, и CD-ROM автоматически переходит в режим пониженного энергопотребления. Диск начинает вращаться медленнее. И при попытке очередного чтения начинается инициализация CD-ROM’а, длящаяся 10-15 секунд. Это очень неудобно при работе. Я решил для себя эту проблему следующим образом: после чтения данных, когда некоторое время обращения к CD-ROM’у не будет и он может остановиться, я выставляю головку CD-ROM’а на начало диска (произвожу «холостое» чтение из сектора 0). При этом команда «01 - Позиционирование» мне по каким-то причинам не подошла. Привожу работоспособную процедуру из моей программы CD_Walk:

    RECALIBRATE    LD HL,0
        LD (SECTOR),HL
        LD (SECTOR+2),HL
        LD (SECTORS),HL
        LD HL,AP_00
        CALL SEND_ATAPI
        LD HL,AP_BE
        CALL SEND_ATAPI
        LD HL,#0100
        LD (SECTORS),HL
        RET

    11. Пример работы с аудио-дисками


    Если вы определили диск, вставленный в ваш CD-ROM как аудио-диск (гл. 9.11), то мы с помощью подпрограмм, описанных в главах 9.12 - 9.15 можем управлять проигрыванием расположенных на нем мелодий (в виде звуковых дорожек или треков). Еще раз напомню, что звук в этом случае необходимо снимать с передней панели CD-ROM или со специального разъема на его задней панели.


    11.1 Считывание таблицы треков. Анализ таблицы


    Следующая подпрограмма позволит нам считать таблицу треков на аудио-диске.

    READ_AUDIO    LD HL,AP_TAB_AUDIO
        CALL SEND_ATAPI
        LD HL,BUF_AUDTAB
        LD BC,#0100
        CALL TRANSFER_IN
        RET
    
    AP_TAB_AUDIO    DB #43,2,0,0,0,0,1,1,0,0,0
    BUF_AUDTAB    DS #0100

    CD-ROM возвращает таблицу, данные в которой удобно интерпретировать следующим образом: вначале идет 6 байт информации (первые 4 байта - общее время проигрывания диска?). Затем идет последовательность 8-байтных описателей, которые имеют следующий формат:

        +0 - номер трека.
        +1 - как правило, 0.
        +2 - часы?
        +3 - минуты
        +4 - секунды
        +5 - фреймы (доли секунды)

    Нас интересует номер трека, и его местонахождение на диске, находящееся в 3,4 и 5 байтах описателя. Причем оно указано во временных единицах. Чтобы выяснить время проигрывания трека, нам необходимо из времени следующего трека вычесть время текущего. Самый последний трек в таблице обозначается байтом #AA вместо номера. Итак, давайте посчитаем, сколько у нас треков на диске:

    ;OUT: [A] - количество треков.
    COUNT_TRACKS
        CALL READ_AUDIO
        LD HL,BUF_AUDTAB-2
        XOR A
        LD B,A 
        LD DE,8
    COUNT_TRACK1
        INC B
        ADD HL,DE
        LD A,(HL)
        CP #AA
        JR NZ,COUNT_TRACK1
        LD A,B
        RET

    11.2 Запуск проигрывания трека


    Чтобы запустить проигрывание звукового трека, нам необходимо указать CD-ROM’у, с какого места по какое ему требуется играть. Для этого нужно указать начало нахождения этого трека на диске (3,4,5 байты описателя) и его конец - те же байты следующего описателя. Если конец проигрывания не указывать - то будут проигрываться все последующие треки до конца диска.

    PLAY_TRACK    LD HL, BUF_AUDTAB-2
        LD DE,8
    PLAY_TRACK1    ADD HL,DE
        CP (HL)
        JR NZ,PLAY_T1 ;находим 
            ;нужный 
            ;описатель
        LD BC,3
        LD DE,3
        ADD HL,DE
        LD DE,AP_PLAY+3 ;начало 
            ;проигрывания
        LDIR
        LD DE,5
        ADD HL,DE
        LD BC,3
        LD DE,AP_PLAY+6 ;окончание 
            ;проигрывания
        LDIR
        LD HL,AP_PLAY
        SEND_ATAPI
        RET
    AP_PLAY    DB #47,0,0,0,0,0
        db 0,0,0,0,0,0

    11.3 Остановка и продолжение проигрывания

    Эти команды не представляют никакой трудности. Для остановки (паузы) проигрывания трека необходимо выполнить следующую подпрограмму:

    STOP_PLAY    XOR A
        LD (AP_4B+8),A
        LD HL,AP_4B
        CALL SEND_ATAPI
        RET

    Для продолжения проигрывания делаем следующее:

    CONT_PLAY    LD A,1
        LD (AP_4B+8),A
        LD HL,AP_4B
        CALL SEND_ATAPI
        RET
    AP_4B    DB #4B,0,0,0,0,0
        db 0,0,0,0,0,0

    12. Структура файловой системы диска


    В главе 3.3 я уже говорил о файловой структуре диска, имеющей название ISO-9660. Этот стандарт получил широкое распространение, и сейчас практически невозможно встретить диски, не являющиеся ISO-9660. Поэтому можно смело ориентироваться на эту файловую структуру, и не бояться, что с какими-нибудь дисками возникнет несовместимость.


    12.1. TOC (Оглавление диска)


    Что из себя представляет эта файловая структура? Как на диске располагаются файлы? Вкратце это выглядит следующим образом: в начале диска, в 16-м секторе, находится так называемая TOC (Table of Contents, оглавление). Информация в этом секторе располагается следующим образом:


    0 - тип диска:

    0 - boot disk

    1 - основной диск (как правило,

    установлен этот байт)

    2 - дополнительный диск

    1-5 - идентификатор ISO-9660. При этом он всегда выглядит как «CD001».

    6 - версия файловой структуры (как правило, «1»).

    40-71 - имя диска (т.н. «метка тома»).

    80-87 - размер диска.

    156-189 - информация о корневом каталоге. При этом строка описания имеет именно такой вид, как и описатель любого файла. Здесь есть информация о местоположении каталога, его длине, времени его создания. Формат описателя подробно рассмотрен в следующей главе. Тем не менее, чтобы узнать, где находится корневой каталог, смотрите байты 162-165 - здесь в 4-байтном виде хранится начальный сектор корневого каталога диска.

    813-829 - дата создания

    Что касается появившихся в последнее время, благодаря пишущим CD-ROM’ам, так называемых мультисессионных дисков (на которые запись была произведена не один раз), то с ними ситуация не так проста, как кажется на первый взгляд. При первой сессии (записи) в 16 дорожку записывается TOC, и никак там перезаписаться она не может. Все последующие сессии располагаются где-то в другом месте, причем неясно, имеют ли они собственную TOC. Узнать, сколько сессий было на диске, можно через команду #43, задав переменную func = #40. Обратно вернется 12-байтная таблица, в которой 3-й и 6-й байты будут указывать на количество сессий. Так что при работе с CD-ROM на Спектруме настоятельно рекомендую избегать мультисессионных дисков. Тем не менее, в дальнейшем я надеюсь эту проблему решить.


    12.2. Каталог. Описание файлов


    Корневой каталог - это ни что иное, как один из каталогов на диске. Формат всех каталогов одинаков: последовательно располагается информация о файлах/каталогах, находящихся в описываемом каталоге. Все описатели файлов имеют неодинаковую длину, из-за разной длины имен файлов. Здесь мною приведена схема такого описателя:

    0 \ Размер описателя

    1 / файла/каталога.


    2 \

    3 - Положение файла

    4 - на диске.

    5 /


    6 \

    7 - Положение файла

    8 - на диске (перевернутое).

    9 /


    10 \

    11 - Размер файла.

    12 - в байтах

    13 /


    14 \

    15 - Размер файла в байтах

    16 - (перевернутый)

    17 /


    18 - год

    19 - месяц

    20 - число

    21 - час

    22 - минуты

    23 - секунды

    24 - смещение по Гринвичу


    25 - атрибуты.


    26 - размер файлового элемента


    27 - чередование секторов (interleave)

    28 \ порядковый номер

    29 / тома.


    30 \ порядковый номер

    31 / тома (перевернутый).


    32 - длина имени файла (file_len)

    33… - имя файла


    32+file_len - байт выравнивания (0)

    32+filelen+1 - стандартом не определено.


    А теперь подробнее.


    1. Размер описателя файла - это количество байт, сколько занимает данный описатель. Чтобы узнать начало следующего описателя, нужно к текущему адресу прибавить размер описателя.

    2. Положение файла на диске - это номер сектора, с которого начинается файл. Это число приводится в прямом и перевернутом виде. Читайте, как вам удобно. Далее файл располагается по секторам последовательно, здесь структура ISO 9660 очень похожа на TR-DOS.

    3. Размер файла. Приводится в байтах. Для каталога он кратен длине сектора - 2048 (может быть 2048, 4096 и т.д.).

    4. Дата создания. На смещение по Гринвичу, думаю, внимания обращать не стоит.

    5. Здесь описываются довольно специфические и бесполезные для нас атрибуты. Однако только благодаря этому байту мы можем узнать, с чем имеем дело: с файлом или с подразделом. Если байт равен нулю, то мы находимся в описателе файла. Если он равен 2 (установлен 1-й бит), то, значит, это подраздел.

    6. Размер файлового элемента. Связан с режимом чередования секторов. Но т.к. чередование практически не используется, то этот байт теряет значение и равен 0.

    7. Чередование секторов. Практически всегда равно 0, то есть отсутствует, и сектора располагаются последовательно, один за другим.

    8. Порядковый номер тома. Количество томов, как правило, всегда равно 1, т.е. здесь мы найдем единицу.

    9. Длина имени файла. Включает в себя и собственно имя, и точку, и расширение. Так что, например, длина «autoexec.bat» будет равна 12. Кроме того, надо иметь в виду, что в конце имени файла (не подраздела) может находиться последовательность из двух байт: #3B #31. Они также включаются в байт длины имени файла. Если описатель описывает подраздел, то после имени перед следующим описателем находится еще дополнительная информация.

    В начале каждого каталога обязательно находится запись с информацией о текущем подразделе, а за ней - запись с информацией о родительском подразделе. Так, в описателе подраздела INFO (…\DIR\DOCS\INFO) в начале будет описание подраздела INFO, а за ним - описание подраздела DOCS. Предполагалось, что это позволит быстро осуществить переход в предыдущий подраздел. Соответственно, в начале корневого каталога будет два одинаковых описателя, указывающих на сам корневой каталог.

    Наибольшую трудность при этом вызывает определение количества файлов в каталоге и определение конца каталога. Нам, конечно, известно количество секторов, отведенных под описание каталога. Однако где в последнем секторе находится последний файл, нам неизвестно. Поэтому, чтобы определить количество файлов, нужно двигаться по описателям до тех пор, пока длина очередного описателя не будет равна 0. На машинах с большим объемом памяти предполагается, что все описатели будут считаны в память, однако, когда файлов в одном каталоге больше 700-1000, на Спектруме сделать это становится затруднительным. Поэтому после перехода в очередной каталог нужно проделать определенные операции: посчитать количество файлов (и директорий), создать в памяти таблицу расположения описателей в каталоге (при необходимости) и т.д.


    13. Заключение


    Автор выражает большую благодарность Константину Норватову, человеку, одним из первых изучившему протокол ATAPI и предоставившему мне его описание. Также хочу поблагодарить Павла Васильева, помогавшего мне при создании программы и подготовке этого материала, и Мишу Жарова, без которого не были бы написаны программа и данная статья.

    В заключение я хочу еще раз уточнить, что статья является лишь практическим руководством по работе с CD-ROM на Спектруме. Поэтому я привел только ту информацию, которая соответствует цели написания данной статьи. Также вполне вероятны небольшие неточности. Если вам нужна более подробная информация по CD-ROM, рекомендую обратиться к замечательной книге Владимира Кулакова «Программирование дисковых подсистем» (СПб., «Питер», 2002).

    © 2004-2013 Perspective group