Re: Мост # 3 - специализированный компьютер для чтения дискет
Месяц была пауза, занимался kraftway, иногда возился со всякими мелочами, допиливал, подправлял, немного тестировал, всё офлайн. Т.е. плата моста в кладовке уже давно, вообще её не включаю - не трогаю. Почти не трогаю.
Тут были примеры дискет с Радио-РК86/Микроша, их немного посмотрел, также наснимал разных дисков для тестов. Снимал в eim3, просто по одному обороту на трек. Этот формат ещё не установился, нахожу проблемы, буду подправлять ещё.
Основное: отладка цепочки декодеров.
Сами декодеры были закончены где-то в январе ещё, сейчас только микрошу туда добавил.
Но вся сложность в обвесе декодеров.
У некоторых есть настройки - поправка на скорость дисковода, 300/360 rpm, интервальные окна, формат дорожки, максимальное число секторов....
Т.е. если формат известен, то всё просто: просто с одного декодера передаём в другой и на выходе получаем подробный отчёт.
Такая утилита у меня уже есть.
На входе читает старые файлы flux или eim3, для заданного формата записи перебирает всё, что можно настроить в декодерах и добивается корректного раскодирования полей данных. Может записать dsk, но лучше разрешать ей сохранять старый eim-формат, а потом уже его прогонять через rawedit и с него получать dsk.
{
У агата слабая контрольная сумма полей данных: иногда бывает так, что данные битые, а контролька совпала. Rawedit140 имет несколько буферов для каждого сектора + счётчик попыток. По итогу он проверяет, сколько раз встретился тот или иной вариант сектора и выбирает тот, который встречался явно чаще, чем другой. У цепочки декодеров моста3 и у Rawedit840 такого фичи нет. Они только фиксируют факт успешного декодирования двух разных вариантов сектора и считают это ошибкой.
Заметно чаще эта проблема вылезала на 140ке. Возможно, из-за большего числа перечтений во время игр с положением головки. Возможно из-за того, что 840ка, помимо контроля по CRC, также контролирует сектор на наличие сбоев MFM-синхронизации.
}
Но эта утилита не умеет определять формат и rpm.
{ rpm можно сохранять в eim3, но, например, во flux-формате rpm вроде бы не сохраняется... }
И это вызывало у меня некоторую прокастанацию.
В последнем декодере (level 4) есть выходной флаг, которым он отмечает - похожа ли дорога на заданный ему формат или нет. Т.е. чтобы определить формат, нужно просто вызвать все декодеры l4 и посмотреть, кто из них выставит этот флаг.
Но декодер выставит флаг только если действительно опознает формат.
Он может не опознать его если:
- сильное отклонение в скорости записи (300/360 rpm)
- 140ка воткнута в 840ку и на B-стороне имеет 140-формат (нужно реверсировать поток данных)
- и т.д.
=======
В итоге я всё таки сделал для начала массив цепочек декодирования:
цепочка: это полный список настроек для декодирования дорожки.
// Все настройки параметров и цепочки декодеров, с которыми можно что-то раскодировать
struct DECS_CHAIN {
enum ARCH_TYPE arch; // агат840, агат140, pc.... etc
enum RPM rpm; // 300/360
double adjust, t_time; // тонкая подстройка скорости, время таймслота
struct DECODER_L2_CONF dec_l2_conf; // pll_table, итоговый bitrate and e.t.c.
int reverse; // дорожка крутится в обратную сторону
} decs_chains[3000];
Да, чуть меньше 3000 комбинаций.
Но массив заполняется не тупым перебором, он строится таким образом, чтобы в первые элементы попали наиболее вероятные комбинации.
Он синтезируется примерно так:
static void add_suite_L1(const double adjust, enum RPM rpm, const enum PLL_SET pll_set) {
add_suite_L2_agat140(adjust, rpm, pll_set);
add_suite_L2_agat840(adjust, rpm, pll_set);
add_suite_L2_PC(adjust, rpm, pll_set);
add_suite_L2_micro(adjust, rpm, pll_set);
}
static void add_suite_L0(const unsigned int drive_type, const double adjust, const enum PLL_SET pll_set) {
add_suite_L1(adjust, rpm_300, pll_set);
if (drive_type == DC_DT_D840) add_suite_L1(adjust, rpm_360, pll_set);
}
static void decoders_suites_synthesis(const unsigned int drive_type) {
add_suite_L0(drive_type, 1.00, one_PLL);
add_suite_L0(drive_type, 0.97, one_PLL);
add_suite_L0(drive_type, 1.03, one_PLL);
const double adjust[] = { 1.00, 0.97, 0.98, 0.96, 1.03, 1.02, 1.04, 1.06, 1.05, 1.07, 1.09, 1.08, 1.10, 1.15, 1.20, 1.25, 1.30, 1.35 };
for (unsigned int i = 0; i < sizeof(adjust) / sizeof(adjust[0]); i++)
add_suite_L0(drive_type, adjust[i], all_PLL);
}
decoders_suites_synthesis() - от этой процедуры начинается работа.
В первых трёх строка синтезируются элементы самые вероятные, с минимальным подстройками.
Дальше добавляются возможности более широкой подстройки корректора скорости
(бывает полезно, если скорость диска была нестабильна при записи).
В процедуре void add_suite_L0 добавляется вероятность того, что привод 840ка может иметь
скорость 360. В _L1 добавляются различные форматы записи. В L2 формат PC делится на Standart и High density. В L3 добавляются разные таблицы автоподстройки фазы (разные для разных форматов записи), L4 добавляет возможность реверса записи и т.д.
Итого: получили массив вариантов настроек, отсортированный по снижению вероятности успеха.
=======
Теперь нужно правильно выбрать стратегию чтения.
Сперва я пытался найти универсальный подход для уже снятых образов и для физических дискет.
Потом понял, что это будет неверно:
==
1) Когда у нас есть много уже снятых данных (eim3, flux...), нет причин не прошерстить всё, что уже есть.
Скорость значения не имеет. Обычно это не один, а много образов, так что загрузить любую современную многоядерную машину нет проблем: зарядил на каждый образ по анализатору и все ядра проца по уши заняты. А я ушел ужинать. Или спать. Специальная утилитка, следящая за загрузкой ЦП, выключит комп, когда всё будет закончено (старый трюк).
В этом случае создаётся один большой пул результатов декодирования на каждую дорожку, затем из образа дёргаем отдельные блоки, смотрим номер физического трека, с которого сняты данные, прогоняем через декодеры и наблюдаем, как накапливаются результаты.
Заодно проверяем и те самые сектора с совпавшими CRC и не совпавшим содержимым.
Прога декодирования даёт развёрнутый отчёт (до нескольких десятков Мб), в котором есть и спектры, и причины неуспешности декодирования данных и ещё статистику эффективности различных настроек декодеров. По ней я понемногу уточняю синтезатор цепочек декодирования (!! сейчас этот синтезатор пока ещё не используется в проге !! Используется более простая версия перебора основных параметров (вложенными циклами)).
Проге можно сказать, чтобы она только добивалась успеха декодирования коротким путём или же прокрутила все возможные комбинации декодеров (полезно для сбора статистики на некоторых интересных дисках).
Прога хороша, но я бы хотел пересадить её на синтезатор цепочек и добиться полностью автоматического декодирования.
{
Игорь заполучил несколько новых коллекций, так что подопытные кошки и кролики имеются.
}
==
2) С дискетами всё по другому. Заранее неизвестен ни формат дискеты, ни записано ли на ней хоть что-то.
- Нежелательно крутить флопик, если мы долго крутим математику.
- Неуверенное чтение лучше сперва починить перечтением дорожки и только потом натравливать долгую математику. Если не получилось, тогда ретрейс головки и снова быстрая математика.
В итоге удалось пока только синтезировать наброски алгоритма чтения диска:
Здесь важно то, что нам нужно сделать минимальное количество чтений, по возможности сгруппированных по времени
чтобы между обработкой можно было выключать привод:
1) Сперва читаем весь диск быстро, без ретрейсов, за 1-2 оборота и останавливаем привод.
Можно сделать редкие ретрейсы, например, каждые 10 цилиндров.
2) Анализируем результат: для каждой дорожки пытаемся применять все быстрые цепочки [0.97 < adjust < 1.03].
Если о предыдущей дорожке нет информации (читаем дорожку 0) - используем все цепочки.
Если о предыдущей дорожке есть информация - используем её цепочку.
Если удалось прочитать хотя бы один сектор - пробуем все цепочки, соответствующие найденным arch, rpm, t_time и reverse.
Если не удалось прочитать текущую дорожку совсем
(нет ни одного успешного сектора) - пробуем все цепочки (Опционально, потребует много времени. Вероятно, настраивается пользователем).
4) Принимаем решение о формате диска: смешанный (pc360 поверх агат840, агат840 поверх агат140 и т.д, а также всевозможные недоформатированные диски (полдиска подряд - один формат, потом - другой)), агат140, PC, agat840.
Формат, имеющий большинство дорог агат140 объявляется именно агат140,
а не смешанный (так как дороги за 35й могут остаться от другого формата).
5) Если найден формат PC, пытаемся определить число секторов:
оцениваем максимальный номер сектора отдельно для большинства чётных и нечётных _цилиндров_.
(Например для случая: 1.2mb переписан сверзу 360kb).
7) Дочитываем все дорожки, на которых были ошибки чтения, независимо от формата записи. В зависимости от типа диска (шаг 4):
- Смешанный формат: читаем все дорожки, но не долго (используем только быстрые цепочки для контроля). Обычно от агатовских данных на таких дисках уже мало что осталось.
- PC: читаем все дороги, но не докапываемся (используем только быстрые цепочки для контроля).
- Агат140: дороги 69-79 и нечётные дороги читаем только 1 оборот без контроля,
остальные - как мост2, для обработки используем полные цепочки;
- Агат840: читаем как мост2, для обработки используем полные цепочки;
9) Сопоставляем найденные форматы с используемым дисководом и включаем моргалку, если дисковод не тот.
Имеет смысл сперва сделать 3-5 попыток перечтения с короткими цепочками.
Пусть после второй попытки будет сделан ретрейс головы.
И только затем долбать по всем попытка длинную цепочку декодирования.
Если пользы не было, попробуем ещё раз, с передёргиванием головы для 140ки между фазами.
И опять анализируем результат только короткими цепочками.
Если не получилось - пофигу, дальше тяжёлую математику по последним попыткам будем делать уже офлайн.
Имеет смысл вовсе игнорировать дорожку при сильно размазанном спектре. Неформатированные диски
встречаются нередко, а любая вышеописанная логика именно на них будет мучиться особенно долго.
==
И ещё: плата почти собрана, осталось допаять преобразователь +12 -> -12 вольт и пару разъёмов.
Если источник заработает и нормально заработает с ним привод Alpins, то можно будет плотно посидеть над чертежами платы и заказать исправленную версию. Сейчас полный список изменений включает около 12 пунктов.