(C)2001...2002 Alex Makeev            Редакция 24 марта 2002 г.

                 Формат файла UDI ( Ultra Disk Image )
                             Версия 1.0
                       !Окончательный вариант!


ВНИМАНИЕ! Заголовок отличается от первоначальных вариантов!
          Больше изменений не будет (кроме введения сжатия...)
          Можно смело писать плугины и конвертеры...
          Кстати в UDI можно хранить и образы High Density дисков (aka PC;)


   Зачем нужен еще один формат образа дискеты ZX Spectrum? Все очень
просто - даже пресловутый FDI на самом деле не такой уж и FDI! :-)
В файлах FDI кроме дампа секторов диска хранятся только адресные метки
(причем в достаточно корявом виде - с покуроченной CRC). При использовании 
Spectrum программ, которые активно используют команды чтения адресной метки и 
чтения дорожки невозможно абсолютно корректно эмулировать эти команды из-за 
недостатка информации о диске, даже если использовать FDI.

   Формат Ultra Disk Image ( UDI ) - очень простой и в то-же время наиболее
полный формат для хранения образов дискет ZX Spectrum (хотя достаточно 
объемный, типичный размер - 1,074 Мб, но сжимается UDI не намного хуже 
чем FDI, в некоторых случаях даже намного лучше). 
Формат файлов UDI предполагает хранение АБСОЛЮТНО ПОЛНЫХ образов дорожек 
дискеты ZX Spectrum.
   В дальнейшем для UDI планируется ввести поддержку формата дорожек с
"плавающими" байтами и дискет с FM записью (на данный момент поддерживается 
только MFM запись).

   Следует отметить что информации, предоставляемой в файлах UDI абсолютно
достаточно для эмуляции любых особенностей контроллеров дисководов!
   Этот формат предназначен в основном для использования в LOW-LEVEL 
эмуляторах контроллеров дисководов.



итак...
--------------------------------------------------------------------------------
                           Формат файла UDI:

Offset          Length  Comment
----------      ------  ----------------------------------------------------
0x00000000      0x0004  Идентификатор "UDI!", если идентификатор
                           записан маленькими буквами ("udi!"), то 
                           применено сжатие данных, алгоритм сжатия
                           пока не определен, но вероятно будет аналогичен 
                           TELEDISK'у
                           Упаковываются данные, начиная с образа первой 
                           дорожки, т.е. сразу после основного 
                           (и дополнительных) заголовка
0x00000004      0x0004  Размер файла после распаковки без учета CRC 
                           (если файл не упакован, то просто размер файла - 4)
0x00000008      0x0001  Версия формата, для UDI 1.0 содержит #00
0x00000009      0x0001  Максимально доступный цилиндр (0x00...0xFF),
                           итого макс. число цилиндров = 256
0x0000000A      0x0001  Максимальный номер поверхности диска:
                           0x01 - DoubleSided, 0x00 - SingleSided
                           (0x02..0xFF -reserved!)
0x0000000B      0x0001  В этой версии не используется поэтому всегда 0x00
0x0000000C      0x0004  EXTHDL - Длина дополнительного заголовка 
                           (всегда 0, в противном случае структура данных
                           может быть другая...)


Далее следуют образы каждой из дорожек, в порядке размещения на диске
(Trk00, Side00; Trk00, Side01; Trk01, Side00; Trk01, Side01; ...):

0x00000010      0xXXXX  Образ дорожки см. ниже...
0xXXXXXXXX      0xXXXX  Образ следующей дорожки
0xXXXXXXXX      0xXXXX  Образ следующей дорожки
...
...
0xXXXXXXXX      0x0004  CRC файла (CRC32, алгоритм см. приложение 2)


Образ дорожки:

Offset          Length     Comment
----------      ------  ----------------------------------------------------
0x00000000      0x0001  Определяет формат дорожки:
                              0x00 - MFM only  (например TR-DOS-ный формат)
                              другие значения форматов пока запрещены!
                              (т.к. еще не известно сколько доп. инфы
                               нужно хранить)


***Для формата дорожки 0x00 (MFM only):


0x00000001      0x0002  tlen - Длина дорожки в байтах (типичная длина
                           дорожки 6250 байт)
                           ВНИМАНИЕ! Для MFM DoubleDensity (ВГ93) крайне
                           не рекомендуется задавать длину
                           дорожки, сильно отличающуюся от 6250 байт!!!
0x00000003      tlen    Побайтовый образ дорожки - включая пробелы,
                           синхропробелы, синхроимпульсы (маркеры MFM), 
                           адресные маркеры, заголовки, массивы данных, etc.
                           Другими словами здесь записаны те байты,
                           которые будут выданы ВГ93 по команде "чтение дорожки"

0x0003+tlen     сtlen   Битовый массив, описывающий тип CLK для каждого
                           байта образа дорожки (см. приложение 1);
                           Один бит соответствует одному байту образа дорожки:
                              0 - записано с обычным CLK (обычные данные)
                              1 - записано с маркерным CLK (метки #A1 и #C2)
                           Например имеем последовательность байт:
                              { 0xA1,0xA1,0x00,0xA1,0xFE,0x00,0x00,0x01 }
                              где 0xA1 - MFM маркеры
                           тогда байт битового массива будет равен 0x0B.

                           Для типичной длины дорожки 6250 байт:
                           ctlen = tlen/8 + ((tlen-(tlen/8)*8)? 1:0) = 782 байт
                           Лишние биты - незначащие, их рекомендуется
                           заполнять нулями.

                           Программы, создающие/записывающие UDI файлы обязаны
                           обеспечивать присутствие реальных CRC кодов для 
                           массивов данных и адресных массивов по алгоритму 
                           CRC с полиномом F = X^16 + X^12 + X^5 + 1

                           Симуляцию ошибочного CRC синтетическим способом,
                           при конвертировании из файлов FDI, рекомендуется
                           производить с помощью выражения C = RC^0xFFFF,
                           где C - crc которую нужно записать, RC - crc
                           синтетическая, корректно вычисленная по 
                           алгоритму CRC...   это чтоб накладок не выходило,
                           запишешь bad CRC равный нулю или еще чему-нибудь,
                           глядишь, а он и впрямь окажется равным нулю -
                           получается реально bad'овый CRC будет определятся
                           как безошибочный 


***для других форматов дорожки (не 0x00):

#0001+tlen      4       MTIL - Длина блока, описывающего дорожку

#0005+tlen      MTIL     Блок описывающий формат дорожки

--------------------------------------------------------------------------------


Почему типичная длина дорожки 6250 байт?
Изучив процедуру форматирования у TR-DOS и утилиты FUT я выяснил, что
реальная длина (она естественно зависит от аппаратуры) должна лежать в 
диапазоне 6208...6464 байт, для других длин произойдет ошибка. Однако, 
просчитав timing, учитывая что на один бит информации уходит 4мкс - получаем 
время 32мкс на байт; время одного полного оборота диска известно - 200000 мкс; 
далее просто считаем длину дорожки: 200000 / 32 = 6250 байт.


   Вниманию разработчикам эмуляторов: большая просьба - своих корректив в
формат UDI без согласования с автором не вносить.

-------------------------------------------------------------------------------

                            ПРИЛОЖЕНИЕ 1

                Описание стандартного низкоуровневого 
                формата дорожек в режиме записи MFM
                     (C)2001...2002 Alex Makeev


Структура дорожки:
                                                  ..С...
  4E  4E .... 4E  00  00 .... 00  C2  C2  C2  FC  ..Е...  4E  4E .... 4E 
 └──────────────┘└──────────────┘└──────────────┘ ..К... └──────────────┘
      GAP4A        Синхропробел        IAM        ..Т...       GAP4B     
      (80шт)          (12шт)                      ..О...  (до конца дор.)
                                                  ..Р...
                                                  ..Ы...

Структура сектора:

                                                                                                                      F8                                         
  4E  4E .... 4E  00  00 .... 00  A1  A1  A1  FE  cc  hh  rr  nn  k1  k2  4E  4E .... 4E  00  00 .... 00  A1  A1  A1  FB  xx  xx .... xx  k1  k2  4E  4E .... 4E 
 └──────────────┘└──────────────┘└──────────────┘└──────────────┘└──────┘└──────────────┘└──────────────┘└──────────────┘└──────────────┘└──────┘└──────────────┘
       GAP1        Синхропробел        IDAM         ID сектора      CRC         GAP2       Синхропробел       DATA AM         данные        CRC         GAP3     
      (50шт)          (12шт)                        (заголовок)  заголовка     (22шт)         (12шт)                          сектора      данных      (разл.)   


Байты 0xA1 и 0xC2 в IAM, IDAM и DATA AM являются маркерными и записываются 
особым образом. Именно эти байты отмечаются в битовом массиве файла UDI.
Байты 0xA1 и 0xC2 в массивах данных маркерными не являются (если они таковыми
не записаны умышленно) и в битовом массиве файла UDI не отмечаются...


GAPx - пробел
IAM - адресный маркер дорожки
IDAM - адресный маркер заголовка
DATA AM - адресный маркер данных сектора
Синхропробел - последовательность нулевых байт, необходимых для
               подстройки частоты и фазы синхрогенератора контроллера
               дисковода

Длина пробелов и синхропробелов может быть различной, но не менее 1 байта.
Количество маркерных байт 0xC2 в IAM или 0xA1 в IDAM и DATA AM может быть 
различным, но не менне 1 байта.
Для некоторых контроллеров (КР1818ВГ93) адресный маркер дорожки может
отсутствовать. Другие контроллеры (PC-совместимые) обычно отказываются
читать диски без адресного маркера дорожки.
Короткий синхропробел приводит к уменьшению надежности чтения данных
(вследствие плохой подстройки частоты и фазы синхрогенератора контроллера).
Минимальная длина синхропробела, при которой обеспечивается подстройка
синхрогенератора контроллера - 8 бит (т.е. 1 байт).
Есть подозрение что синхропробел длиной менее 3 байт ВГ'шкой читаться не
будет (исходя из длины внутренней линии задержки = 32бит) однако это лишь 
недоказанное теоретическое предположение.
Пробелы (GAPx) могут содержать отличные от 0x4E байты, что часто используется
для защиты от копирования.


ID сектора состоит из:

cc = C  -> Цилиндр
hh = H  -> Головка
rr = R  -> Номер сектора
nn   N  -> Код длины сектора 
k1      -> Старший байт CRC16 для IDAM и ID сектора включительно
k2      -> Младший байт CRC16 для IDAM и ID сектора включительно


ID сектора могут содержать произвольные значения и служат для поиска 
нужного сектора контроллером дисковода.


Код длины сектора (определяет длину блока данных без CRC):

Код     Длина в байтах
----    --------------
0x00    128
0x01    256
0x02    512
0x03    1024
0x04    2048
0x05    4096
0x06    8192
0x07    16384

коды длины сектора больше 3 используются в HighDensity формате.


CRC данных вычисляется для DATA AM и данных сектора включительно

В DATA AM после маркеных байт 0xA1 может содержаться значение 0xF8 или 0xFB:
0xF8 - "удаленные" данные
0xFB - "нормальные" данные

Удаленные и нормальные данные отличаются только способом доступа к ним -
для каждого типа данных используется своя команда контроллера дисковода.


Более подробную информацию можно получить обратившись к стандарту
IBM System 34. 


-------------------------------------------------------------------------------

                            ПРИЛОЖЕНИЕ 2

                Алгоритм вычисления CRC32 для файла UDI


Начальное значение CRC = 0xFFFFFFFF  (-1l).

Функция обновления CRC32 для одного байта Symbol:

long CalcCRC32(long CRC, unsigned char Symbol)
{
   long temp;
   CRC ^= -1l ^ Symbol;
   for(int k = 8; k--;) 
      { temp = -(CRC & 1), CRC >>= 1, CRC ^= 0xEDB88320ul & temp; }
   CRC ^= -1l;
   return CRC;
}

Эту функцию нужно вызвать для каждого байта из файла UDI (исключая последние
4 байта CRC). 

Первый аргумент функции - текущая CRC, второй аргумент - байт данных,
результат - новая CRC.


-------------------------------------------------------------------------------

                            ПРИЛОЖЕНИЕ 3

                Параметры стандартного формата TR-DOS
                       (cracked from TR-DOS)


При форматировании дисков TR-DOS (дисковая система ZX Spectrum) использует
следующие особенности:


IAM (адресный маркер дорожки) отсутствует
Длина синхропробела = 12 байт
Число MFM-маркеров 0xA1 в IDAM и DATA AM = 3 

Длина GAP4A = 0 байт
Длина GAP1 = 10 байт
Длина GAP2 = 22 байт
Длина GAP3 = 60 байт
Длина GAP4B = до конца дорожки

Содержимое заголовков секторов:
Отсчет номера цилиндра C начинается с 0.
Байт H (номер головки) всегда равен 0x00.
Отсчет номера сектора R начинается с 1.
Байт N (код длины сектора) равен 0x01 (т.е. сектор 256 байт).

16 секторов на дорожке с интерлейвом 8 (т.е. порядок следования
секторов на дорожке следующий 1,9,2,10,3,11,4,12,5,13,6,14,7,15,8,16).

-------------------------------------------------------------------------------

                            ПРИЛОЖЕНИЕ 4

                Обзор способов защиты от копирования с
                использованием нестандартных форматов
                дискет
                (Позаимствовано из документации к FDA)


                   Способы создания ключевых меток на дискетах.

      1.  Использование   инженерные  цилиндров.   Стандартный  5.25"   40  -
   дорожечный дисковод может читать и записывать 42 цилиндра, 80 - дорожечный
   - 84  цилиндра, однако, DOS  использует соответственно  только 40  и 80 из
   них. Дисководы 3.5"  поддерживают 82 цилиндра, но  DOS использует лишь 80.
   Не используемые  DOS цилиндры  называются инженерными.  Эти цилиндры могут
   иметь произвольный нестандартный формат, например, иметь всего один сектор
   с любой  вмещающейся в  длину  дорожки длиной  и каким  угодно заголовком.
   Использование инженерных цилиндров  очень удобно,  однако, есть опасность,
   что найдутся дисководы, их не поддерживающие.
      2. Особые  секторы. При  обращении к  дискете, DOS,  вызывая прерывание
   BIOS 13H, читает или записывает всю  дорожку одной командой FDC. При этом,
   как уже  было сказано,  все  секторы на  дорожке должны  иметь стандартные
   заголовки и расположены в порядке возрастания номеров. Если же между двумя
   нормальными  секторами вклинится  сектор  с  нестандартным  заголовком, он
   будет проигнорирован  командой чтения.  Такой особый  сектор можно создать
   при форматировании дорожки и использовать в качестве ключевой метки.
      3. Запись  ключевой информации  в  промежутки. Этим  способом создаются
   одни  из   самых  скрытых   и  труднообнаружимых   ключевых  меток.  Путем
   комбинированного применения  команд  короткого  форматирования  и короткой
   записи,   можно  поместить   ключевую   информацию   в   любой  промежуток
   (GAP1...GAP4). Напимер, чтобы  поместить ключевую информацию  в GAP3 между
   первым и вторым секторами, требуется отформатировать дорожку на нормальное
   число секторов  с  длиной  2 и  нормальным  GPL, но  параметр  N заголовка
   первого сектора установить при форматировании  не 2, а 3. Затем произвести
   короткую  запись  в  первый  сектор  так,  чтобы  только-только  не задеть
   заголовок  второго сектора  (если  вовремя  не  прервать  операцию записи,
   второй сектор  будет  затерт  удлинившейся зоной  данных  первого). Запись
   необходимо прервать,  не  доходя  одного  - двух  байтов  до  IDAM второго
   сектора.  Затем,  путем  короткого  форматирования,  необходимо  подменить
   заголовок первого сектора на нормальный.  В результате GAP3 между первым и
   вторым секторами  будет  содержать  не код  4E,  а  записанную информацию.
   Необходимо    отметить,     что    успешное     осуществление    описанной
   последовательности  операций   требует   высокой   точности   таймера.  Из
   существующих  программных средств  только  Floppy  Disk  Analyser способен
   создать описанную  ключевую метку.  Для  проверки наличия  ключевой метки,
   защищенная этой меткой  программа должна использовать  команду FDC "чтение
   дорожки". При помощи повторного  короткого форматирования, можно создавать
   межсекторные  промежутки любой  длины.  Например,  если  после нормального
   форматирования,  произвести  короткое   форматирование  этой  же  дорожки,
   "заказав"  только  один  сектор  и  прервав  операцию  внутри  GAP3  между
   предпоследним и  последним  сектором,  в результате  на  дорожке останутся
   только два  сектора, причем  один в  начале дорожки,  а другой  - в конце.
   Такая  операция  называется  "трущим  форматированием",  поскольку  второе
   короткое форматирование создает  один сектор (как  "заказано"), а затирает
   все, кроме последнего.
      4.  Секторы,  переходящие   через  начало  дорожки.   Если  параметр  N
   последнего по порядку сектора на дорожке таков, что длина, соответствующая
   этому параметру, превышает  сумму физической длины  сектора плюс GAP4B, то
   этот сектор  нельзя нормально  записать,  поскольку его  удлинившаяся зона
   данных перейдет  за конец дорожки  и затрет  IAM, один  или даже несколько
   первых секторов. Однако, считать такой  сектор можно, причем будет считана
   не только зона данных этого  сектора, но и участок дорожки, продолжающийся
   далеко вперед,  за пределы физической  длины сектора,  и переходящий через
   конец дорожки. Тем  не менее, считанная информация  будет верной только на
   участке от начала  зоны данных  сектора до конца  дорожки, поскольку далее
   произойдет сбой  синхронизации чтения.  Это объясняется  тем, что интервал
   между битами  синхронизации  на  границе дорожки  испытывает  скачок из-за
   неравенства полной длины окружности  дорожки целому числу интервалов между
   битами  синхронизации.  По  этой  причине,  все  биты  синхронизации после
   границы дорожки  будут  иметь некоторый  постоянный  сдвиг по  отношению к
   экстраполяции их  дограничного расположения  через границу.  Путем анализа
   информации,  считанной  при  сбитой  синхронизации,  можно  точно выявлять
   только  "ступеньки",  т.е.   точки,  ограничивающие  области,  заполненные
   одинаковым кодом.  Например,  если  имеется строка  aaaaabbbc,  то  при ее
   чтении со сбитой синхронизацией,  коды произвольно изменятся, но положение
   мест переходов  от a  к b  и  от b  к c  останется прежним,  или сдвинется
   максимум на  один байт. Физическое  положение таких  "ступенек" зависит от
   индивидуальных  параметров  дисковода,  на  котором  производилась запись,
   поэтому  переходящие  секторы  могут   служить  ключевой  меткой,  которую
   невозможно скопировать.  Хотя ключевые  метки такого  типа и  не поддаются
   копированию, они,  однако, имеют  крайне неприятный  недостаток, а именно,
   невоспроизводимость   результатов    записи   метки    из-за   случайного,
   вероятностного характера  стыковки  конца дорожки  с  ее началом.  Даже на
   одном и том  же дисководе  будут каждый раз  получаться разные результаты.
   При  чтении  ключевой  метки,  где  синхронизация  случайно  оказалась "не
   достаточно  сильно  сбита",  возможно  самовосстановление  синхронизации в
   произвольном месте,  и,  следовательно, образование  ложной  ступеньки. По
   этой причине, не все ключевые  метки будут надежно опознаваться защищенной
   программой, и  неизбежны  накладки, особенно,  при  массовом тиражировании
   защищенных дискет. Из известных систем защиты дискет от копирования, такие
   ключевые метки используют CopyLock, Cerberus, и некоторые другие.
      5. Секторы с ошибкой CRC. Это, пожалуй, самый известный способ создания
   ключевой метки.  Можно,  как уже  отмечено,  имитировать ошибку  CRC путем
   "отсечки"  второго  байта  CRC  при  записи  с  прерыванием  опрерации  до
   завершения. Однако,  такой  способ  требует наличия  хорошего  дисковода и
   высокой  точности  таймера  управляющей   FDC  программы,  что  не  всегда
   приемлемо. Существует  другой  способ  имитации ошибки  CRC  путем подмены
   заголовка  сектора. Для  этого  необходимо  отформатировать  дорожку таким
   образом, чтобы "ошибочный"  сектор имел в заголовке  параметр N на единицу
   больше  требуемого, например,  3  вместо  2-х.  Затем  произвести короткую
   запись в этот  сектор, чтобы  не затереть заголовок  следующего по порядку
   сектора, и, наконец, произвести  повторное короткое форматирование дорожки
   с нормальными  заголовками  секторов и  прерыванием  в середине  поля GAP2
   требуемого сектора.  Этот  способ  более надежен,  поскольку  требования к
   точности  намного   ниже.   Отличная,   труднокопируемая   ключевая  метка
   получается,  если  создать  два  последовательно  расположенных  сектора с
   одинаковыми заголовками и ошибкой CRC в каждом. При этом доступ ко второму
   по порядку ключевому сектору будет заблокирован первым.
      6. "Пустые"  секторы. Если сектор  имеет заголовок,  но DATA  AM и зона
   данных  отсутствуют, такой  сектор  называется  "пустым".  "Пустой" сектор
   можно   создать    следующим   образом.    Сначала   произвести   "трущее"
   форматирование на  один короткий  сектор, затем  короткое форматирование с
   прерыванием операции в поле GAP2 требуемого сектора.

                   Сравнительные характеристики ключевых меток.

      Основными  параметрами,   характеризующими   качество   ключевой  метки
   являются:
      - совместимость, т.е. способность  ключевой метки уверенно опознаваться
   всеми компьютерами заданного типа, например, PC/AT;
      -  устойчивость  против   несанкционированного  копирования  различными
   программными и аппаратными средствами;
      - стабильность  ключевых меток при  естественном старении  дискет и при
   изменении параметров окружающей среды.
      1. Совместимость.  Наилучшей  совместимостью  обладают  ключевые метки,
   наличие  которых  можно  проверить  при  помощи  стандартных  функций BIOS
   (особые  секторы),  средней  -  метки,  для  проверки  которых  необходимо
   обращаться к  FDC,  но только  с целью  записи  или чтения  одного сектора
   ("пустые" секторы),  и, наконец, наихудшей  - метки,  для проверки которых
   необходимо обращаться к дополнительным функциям FDC, не используемым BIOS,
   например,  чтение  дорожки,  сканирование   (запись  информации  в  GAPS).
   Неудовлетворительной  совместимостью,  независимо   от  способа  проверки,
   отличаются метки,  основанные на  сбоях синхронизации,  например, секторы,
   переходящие через начало дорожки.  Все метки, созданные вышеперечисленными
   способами,  могут  быть  проверены  как  средствами  BIOS,  так  и  прямым
   обращением к FDC.
      2. Устойчивость  против  несанкционированного копирования.  Проще всего
   копируются особые  секторы и  различные  нестандартные форматы,  труднее -
   секторы с ошибкой CRC и проверкой  на подрезание, еще труднее - информация
   в промежутках (GAPS). Секторы, переходящие  через начало дорожки, могут не
   копироваться вовсе, если проверяется сбой синхронизации, но такие метки не
   надежны.
      3. Стабильность. Надежность  чтения ключевой метки  не должна быть ниже
   надежности чтения  остальной информации,  записанной стандартным способом.
   Этому требованию  в полной мере  удовлетворяют особые  и "пустые" секторы,
   ошибки  CRC. Чуть  менее  надежны,  но  вполне  удовлетворительны ключевые
   метки, основанные  на  записи информации  в  GAPS, и,  наконец, совершенно
   неудовлетворительную  надежность   имеют   метки,   основанные   на  сбоях
   синхронизации.  То  же   относится  и  к   устойчивости  против  старения,
   повышенной  температуры и  влажности,  внешних  магнитных  полей (телефон,
   видеомонитор, бытовые радиоприборы).

-------------------------------------------------------------------------------


На сайте http://zxmak.chat.ru/ можно найти утилиту TRX2X,
предназначенную для конвертирования образа диска из одного формата
(любого) в другой (любой), которая поддерживает форматы TRD, SCL, FDI,
UDI, TD0 (поддерживается также формат hobeta, но только для чтения).
Утилита TRX2X предназначена для функционирования только в 32-разрядной 
ОС Windows, так как требует большой объем ОЗУ для работы...
Здесь же можно найти эмулятор Спектрума ZXMAK, поддерживающий формат UDI.


                                              ┌───────────────────────────────
                                              │ Alex Makeev
                                              │ e-mail: zxmak@mail.ru
                                              │ WWW:    http://zxmak.chat.ru/
                                              │
