Сайт посвящен ПЭВМ АГАТ: Передовица » Hardware » ДЗУ » Исследование КНГМД 840 » Автомат кодирования и предкомпенсации записи

© 2004-2021 AgatComp

Форум

Общие сведения

Software

Hardware

Агат ↔ PC

Эмуляторы/утилиты

Люди

Макулатура

Всякая всячина

Ссылки

Контакты

Помощь сайту

Последние обновления

Автомат кодирования и предкомпенсации записи

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

Сигналы:

  • Не кодированные данные: поступают побитно на вход D22 из D21.
  • Const $12: на параллельный вход D22 подводится hardwired константа ¤12.
  • Get S12: сигнал от секвенсора. В его отсутствие D22 сдвигает хранимый в ней байт, при наличии Get S12 она загружает константу ¤12.
  • Fs, Wp: сигналы тактирования от секвенсора. В нормальном режиме приходят с одинаковой частотой, но в разных фазах.
  • Режим предкомпенсации: два бита, задаются драйвером. Выбирают таблицу для кодирования (три варианта).
  • Мотор: сигнал включения двигателя. Поступает на вход CS D25 и особого смысла не имеет. Вероятно, таким образом разработчики хотели снизить нагрев схемы.
  • Данные записи (кодированные) - то, что уходит на дисковод. В третьей версии схемы этот сигнал немного растягивается дополнительным одновибратором.

Предкомпенсация записи

Не вдаваясь в физику процесса, очень коротко обсудим: что такое предкомпенсация записи и для чего она нужна ?

Так как диск крутится с постоянной скоростью и объём данных на всех дорожках одинаков, плотность записи (т.е. количество бит на миллиметр поверхности диска) на центральных дорожках возрастает, по сравнению с дорожками, находящимися на краю диска. Поверхность на краю движется мимо головки быстрее, чем поверхность у центра диска. Это приводит к тому, что диск, как устройство хранения потока бит, ведёт себя немного по разному на разных дорожках: в зависимости от комбинации записанных бит некоторые единички могут слегка "сползать" со своих мест и, что ещё хуже - их амплитуда может уменьшиться. Т.е. при чтении они окажуться чуть раньше или чуть позже, чем нужно, а может быть даже потеряются. Эффект выражен в разной степени, в зависимости от номера дорожки. Отчасти "сползание" корректируется автоматом чтения, но, для ещё лучшей коррекции, поток записываемых данных также формируется по разному, в зависимости от комбинации записываемых бит и номера дорожки. Как-то так:

  1    0    1    0    0    0    1      - нормальный поток
  1    0   1     0    0    0    1      - чуть подкорректированный поток

Коррекция в агатовском ПО: цилиндры 0-39 - нет предкомпенсации, 40-59 - слабая предкомпенсация, 60-79 - сильная предкомпенсация. Режим предкомпенсации задаёт драйвер, это не входит в задачи контроллера.

Небольшое отступление: единичка в понимании дисковода - это не определённое значение намагниченности, которое длится заданное время, а изменение намагниченности. Естестенно, изменение происходит очень быстро, но когда дисковод обнаруживает его, он формирует импульс фиксированной длительности (обычно 1 мкс). Однако изменение может произойти чуть раньше или чуть позже - именно это важно для раскодирования данных. В то же время, в силу неидеальности дисковода, моменты изменений могут немного "сползать" на внутренних дорожках. Предкомпенсация направлена на то, чтобы заранее подвинуть изменение намагниченности туда, откуда оно потом вернётся на "правильное" место. Нолик же - это ничто, дисковод не предпринимает никаких действий и при чтении тут не будет никаких изменений намагниченности, соответственно, не будет и никаких импульсов. Поэтому нолик не может никуда "сползти".

ПЗУ D25 и режим обычной записи

С чего начнём распутывать этот клубок ? Пусть это будет прошивка ПЗУ:

00000000  f2 f2 f2 f2 f0 f0 f0 f0  f3 f3 f3 f3 f3 f3 f3 f3
--""-- то же самое до адреса 90 --""--
00000090  f2 f2 f2 f2 f0 f0 f0 f0  f3 f3 fb fb f3 f3 f3 f3
000000a0  f2 f2 f2 f2 f0 f0 f0 f0  f3 f3 f3 f3 fd fd fd fd
000000b0  f2 f2 f2 f2 f0 f0 f0 f0  f3 f3 fb fb f3 f3 f3 f3
000000c0  f2 f2 fa fa f0 f0 f0 f0  f3 f3 f3 f3 fd fd fd fd
000000d0  fc fc f2 f2 f0 f0 f0 f0  fb fb f7 f7 f3 f3 f3 f3
000000e0  f2 f2 fa fa f0 f0 f0 f0  f3 f3 f3 f3 f5 f5 f5 f5
000000f0  fc fc f2 f2 f0 f0 f0 f0  fb fb f7 f7 f3 f3 f3 f3

Выглядит немного гадски ? Вот я так сперва подумал. Но затем...

Шаг первый: вспомним, что в дампе каждому адресу соответствует байт, но выходов у ПЗУ всего четыре. Старшую цифру можно отбросить.

Шаг два: внимательно смотрим распиновку: заметьте, что старший разряд данных поступает на младший разряд счётчика. Все четыре бита стоят задом наперёд. Почему ? Не знаю. Просто в справочниках выходы 556рт4 маркируются в одном направлении (и этот дамп снят в соответствии со справочником), а в агатовских схемах - наоборот. Значит следует развернуть биты в дампе.

Шаг три: внимательно смотрим на D26. Он считает вверх (сигнал счёта вниз D26.4 не используется), но по сигналу Wp, вместо очередного такта счёта, загружает данные с параллельного входа. На выходе переноса D26.12 возникает импульс в тот момент, когда счётчик переходит со значения 15 в значение 0.

Правильно предположим, что в какие-то моменты счётчик загружает данные, а затем считает до 15 и, затем, 0. Так как только в этом случае на дисковод будут уходить хоть какие-то данные. Следовательно в ПЗУ хранятся дополнения до 16. Следовательно, число шагов будет равно 16 - n, где n - числа, хранимые в ячейках ПЗУ.

Шаг четыре: на два старших адресных входа ПЗУ подключены сигналы выбора режима предкомпенсации записи. 00, 01 - нет предкомпенсации, 10 - слабая предкомпенсация, 11 - сильная. Три отдельные таблицы по адресам $00-$7F, $80-$BF, $C0-$FF.

Итого получается:

				Нет предкомпенсации
00 -  xx00xx            xx01xx            xx1xxx
        12                16                 4

				Слабая предкомпенсация
00 -  00000x   00001x   00010x   00011x   00100x   00101x   00110x   00111x   
        12       12       16       16        4        4        4        4
10 -  01000x   01001x   01010x   01011x   01100x   01101x   01110x   01111x   
        12       12       16       16        4        3        4        4
20 -  10000x   10001x   10010x   10011x   10100x   10101x   10110x   10111x   
        12       12       16       16        4        4        5        5
30 -  11000x   11001x   11010x   11011x   11100x   11101x   11110x   11111x   
        12       12       16       16        4        3        4        4

				Сильная предкомпенсация
00 -  00000x   00001x   00010x   00011x   00100x   00101x   00110x   00111x   
        12       11       16       16        4        4        5        5
10 -  01000x   01001x   01010x   01011x   01100x   01101x   01110x   01111x   
        13       12       16       16        3        2        4        4
20 -  10000x   10001x   10010x   10011x   10100x   10101x   10110x   10111x   
        12       11       16       16        4        4        6        6
30 -  11000x   11001x   11010x   11011x   11100x   11101x   11110x   11111x   
        13       12       16       16        3        2        4        4

Первая колонка - адрес внутри таблицы. Десятичное число - количество тактов !4 МГц от сигнала Wp до импульса записи. Двоичное число - адрес, в котором символом x отмечены разряды, которые не имеют значения (т.е. содержимое ячеек совпадает).

Например, режим отсутствия предкомпенсации, адрес $00: в нём биты A3 = A2 = 0 - следовательно, смотрим самую левую верхнюю ячейку в таблице xx00xx, там значение 12 - столько тактов будет отсчивать счётчик до появления импульса записи. Кажется. Но не совсем так. И сейчас рассмотрим - почему.

Всё дело в том, что длительность одного бита кодированного потока (т.е. бит синхронизации или бит данных) соответствует 8 шагам секвенсора. Но так как двух соседних единиц в потоке быть не может, один цикл счёта D26 (от заданной в ПЗУ константы до нуля) синтезирует два бита: ноль и следующую за ним или перед ним единицу. Если в таблице указано число 16 - это значит, что счётчик будет перезапущен до того, как досчитает до конца. Таким образом значение 16 в таблице - это не синтезируемый с некоторой задержкой импульс, а полная пауза - два нуля.

И это очень интересная величина: обратите внимание, что она встречается в таблице чаще всего. Ей соответствует любой адрес, у которого A3 = 0 и A2 = 1.

Что интересно: при отсутствии предкомпенсации вообще встречается всего три значения: A3 = A2 = 0 - значение 12 и A3 = 1 - значение 4. Остальные биты в этом режиме не важны. Построим диаграммку:

  A3 A2    время: 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f     на диск запишутся
   0  0                                               1                   0    1
   0  1									  0    0
   1  0                       1						  1    0
   1  1                       1						  1    0

Ничего не напоминает ?

A3 - бит до кодирования, A2 - следующий за ним бит. Время от 0 до 7 - бит данных, 8-f - бит синхронизации. В период 0-7 пишется бит A3, в период 8-F пишется единица при условии, что A3 и A2 равны нулю. Вот и вся работа автомата. На диск ушел закодированный MFM-поток.

Дальше можно расковырять поправки в таблицах слабой и сильной предкомпенсации. Они, в меньшей или большей степени, сдвигают единицы в зависимости от предыдущих и последующих бит. Могут сдвинуть их на более раннее или более позднее время. В слабой предкомпенсации есть только сдвиг бита данных на один шаг (3 или 5 вместо 4), в сильной предкомпенсации есть сдвиги на 2 шага для бита данных и на 1 шаг для бита синхронизации.

Кстати, а сколько это во времени - один шаг ? Это около 250 нс. (И в скобках замечу: 1818вг93 предполагала только два режима предкомпенсации. А здесь - три.)

Теперь становится ясным и назначение регистра D22 - это просто линия задержки, которая хранит несколько бит данных, как недавно записанных, так и тех, запись которых ещё предстоит. Но в каждый текущий момент записывается именно значение бита D3 и, следующего за ним, расчитанного, бита синхронизации. Разобрав содержимое D25 становится видно, что, фактически, используются только пять бит: два записанных, текущий и два, стоящих в очереди на запись.

Попробуем собрать все случаи в режиме слабой предкомпенсации: 001xx, xx100, 10101, x111x - нет предкомпенсации (такт 4), x1101 - бит данных будет записан чуть раньше (такт 3), 1011x - бит данных будет записан чуть позже (такт 5). Точно также можно разобрать и случаи сильной предкомпенсации.

Стек передачи байт в режиме записи: часть 1

Основное изучили, теперь можно взять курс на механизм синтеза синхросбоя.

Согласно документации, запись синхросбоя выполняется драйвером следующим образом: записывается байт со значением ¤A4, затем на запись отправляется байт ¤FF и, не дожидаясь готовности (освобождения) регистра записи, драйвер должен дёрнуть бит, запускающий запись синхросбоя (на полной схеме тракта записи он был обозначен как "Запись синхро"). После этого драйвер ждёт готовности регистра записи и затем может записывать пролог очередного поля (адреса, данных или чего угодно ещё).

Но попробуем теперь понять, в каких регистрах какие значения у нас будут ?

В то время, как байт ¤A4 отправился на запись, драйвер ждёт освобождения регистра записи, чтобы записать в него байт ¤FF. Занятость регистра означает, что ¤A4 ещё пока в 580вв55. Следовательно из D21 в D22 кочует предыдущий байт, идущий на диск. Когда запись этого байта дойдёт до бита D3, возникнет сигнал "следующий байт". Кстати, а почему на D3 ? А потому что D21 в этот момент передаст последний бит D0 в D22 и будет свободен. А биты с D3 по D0 будут ещё будут катиться по конвееру D22.

И вот теперь драйвер записал ¤FF в 580вв55, а D21 захватил байт ¤A4. ЦП немного тормозит, драйвера бывают написаны по разному, но примерно к записи бита D2 предыдущего байта сигнал "запись синхросбоя" дойдёт от драйвера до секвенсора. И теперь нам следует, наконец, начать изучать его программу.

Программа секвенсора: запись

Перед вами листинг части программы секвенсора, отвечающей за запись. Справа и слева, в крайних колонках, указан номер шага. Обозначения команд:

  • Wph - сигнал записи кода из ПЗУ D25 в счётчик D26.
  • go XX - переход на шаг XX. Если этой команды в строке нет - это переход на следующую строку.
  • =>n - команда сдвига в регистр D21 значения n. Это не важно для записи, но вы можете проверить, что это, в самом деле, происходит. Я не проверял ;)
  • ==> - сдвиг регистра D22. Оба сдвига происходят по одной команде, так что этот значёк - только напоминалка.
  • BC> - ставится флажек о том, что на следующем шаге будет выполнена модификация счётчика бит D23. Следующий шаг строкой ниже либо в том месте, куда произойдёт переход по go и/или по изменению входящих данных.
  • <BC++ / BC=8 - если на предыдущем шаге был BC> то на этом шаге будет увеличено или сброшено на 8 значение счётчика D23.
  • getbyte S12 - в регистр D22 будет загружена константа ¤12.

Программа состоит из четырёх частей. Исполняющаяся часть выбирается в зависимости наличия сигнала "запись синхро" - его формирует драйвер и сигнала "следующий байт" - его формирует счётчик D23. В любой момент, если один из этих сигналов изменится, произойдёт переход на соответствующую часть.

Но чем различаются разные части ? Все команды в них почти одинаковые, различия только в некоторых переходах go. Желтым цветом отмечены части, которые различаются в зависимости от наличия/отсутствия сигнала "запись синхро" и рыжим цветом - отличия при наличии сигнала "следующий байт".

Обычно исполняется часть программы в самой левой колонке от шага ¤20 до ¤3F. Она не сложная. Начнём с конца:

  • Шаг ¤3F: задаёт сдвиг регистров D21 и D22, а также действие со счётчиком бит D23. Ни одна из операций ещё не выполняется на этом шаге! Одновременно выполняется переход на шаг ¤30.
  • Шаг ¤30: фактически обновляются счётчики и регистры, причем D23 увеличивается на единицу. Переход на шаг ¤21.
  • Шаг ¤21: у этого шага появляется команда Wp, она загружает в счётчик D26 новое значение из D25, соответствующее очередной комбинации записываемых бит.
  • Шаг ¤22: пока ещё Wp остаётся висеть, но исполнение переходит на шаг ¤33.
  • Шаги ¤33-3E: секвенсор просто ждёт, счётчик D26 считает, синтезирует паузу нужной длительности и выдаёт импульс записи.

Видно, что цикл длится 16 тактов. Во время записи он почти всегда исполняется именно такое время.

Что произойдёт, если появится сигнал "следующий байт" ? Он может возникнуть после модификации D23 на шаге ¤30. Серой стрелкой показан соответствующий переход в третью слева колонку. В нижней половине (шаги ¤20-3F) она отличается только тем, что на шаге ¤30 в регистр D23 будет записано число 8 - начнётся отсчёт бит очередного байта.

Формирование синхросбоя

Теперь о том, что происходит при появлении команды "запись синхро". Смотрим желтые отметки. Они стоят на всех шагах, которые проходит программа при записи обычного байта. Даже на некоторых, которые не проходит (¤20). Как только, во время записи любого бита, поступает сигнал "запись синхро" исполнение переходит на ¤20 шагов выше. Т.е. на верхнюю половину программы. Она почти ничем не отличается от нижней, таким образом этот переход - своеобразное защёлкивание требования записать синхросбой. Даже если сам сигнал "запись синхро" будет снят (а он и будет снят на следующем шаге) или - наоборот - если драйвер его выдаст несколько раз - в любом случае программа будет продолжать выполнение в верхней половине.

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

Шаг ¤00 не имеет значения - он не исполняется в нормальном режиме, так как на него нет ссылок. А вот на шаге ¤10 третьей колонки как раз закончилась запись последнего бита. И теперь выполняется переход на шаг ¤23, но так как в этот момент будет переключен счётчик бит D23, переход произойдёт в первую колонку. Шаги с ¤23 до ¤2A пустые, но на них будет выставлен сигнал Wp. Это как раз 8 шагов, во время которых счётчик D26 будет постоянно загружать в себя длительность следующего интервала, но не будет выполнять счёт. На шаге ¤2A будет выполнен переход на шаг ¤21, затем ¤22 и затем Wp будет снят - исполнение вернётся в привычную колею.

Чего мы добивались ? В конце последнего бита секвенсор притормозил на 8 шагов поступление очередного бита и сформировал нолик в потоке записи. Но именно один нолик. Это всё ? Нет ! Не следует упускать из виду ещё одно важное действие: перед тем, как вернуться вниз левой колонки, в третьей колонке на шаге ¤1F вместо загрузки очередного бита из D21 в D22 секвенсор командует загрузить в D22 константу ¤12.

Хм ? А зачем ? Если честно - не знаю. Я не нашел объяснения. Но рассмотрим, что должно записаться на диск, если следовать инструкции.

Стек передачи байт в режиме записи: часть 2

В предыдущей серии: И вот теперь драйвер записал ¤FF в 580вв55, а D21 захватил байт ¤A4. ЦП немного тормозит, драйвера бывают написаны по разному, но примерно к записи бита D2 предыдущего байта сигнал "запись синхросбоя" дойдёт от драйвера до секвенсора.

Секвенсор, как мы видели, в этом случае продолжит запись байта... Так, ещё раз: какого байта? В D21 у нас байт ¤A4. В D22 хвост предыдущего байта. Секвенсор "защёлкнул" требование синтезировать синхросбой, но ему остаётся записать ещё 6-7 бит. Допустим, предыдущий байт был ¤AA:

Биты данных: 1 0 1 0
Биты синхро:  0 0 0 0

Это была вторая цифра ¤AA. Теперь пойдут разряды из ¤A4:

Биты данных: 1 0 1 0  
Биты синхро:  0 0 0 1

Кстати, а почему последний синхро 1 ? А потому, что в байте ¤A4: следующий бит данных - нолик. Он ещё не успел попасть на диск, но секвенсор о нём знает.

Итого 8 бит. Теперь ¤FF переходит из 580вв55 в D21. А секвенсор вспоминает, что надо бы записать лишний нолик:

Биты синхро: 0

Что дальше ? А дальше бы пошли оставшиеся биты ¤A4. Но перед записью нолика секвенсор загрузил в D21 константу ¤12. Она и будет записываться. От бита D3:

Биты данных: 0 0 1 0
Биты синхро:  1 0 0 0

Записали 4 бита, что там дальше ? Дальше к записи подъехал ¤FF.

Биты данных: 1 1 1 1
Биты синхро:  0 0 0 0

И так далее. Итого:

Биты данных: ...... 1 0 1 0    1 0 1 0        0 0 1 0    1 1 1 1
Биты синхро:         0 0 0 0    0 0 0 1   0    1 0 0 0    0 0 0 0 ......

 Всё вместе:  10001000 10001001 0 01001000 10101010

Так зачем нужно было защёлкивание константы ¤12 в D22 ? Ведь можно было потребовать записать не ¤A4, а ¤A2 ? Разве получили бы не тоже самое ?

Возможно, изначально требование записывать ¤A4 отсутствовало, разработчики надеялись весь шаблон синхросбоя впихнуть в программу секвенсора и удачно подобранную константу, которая бы загружалась по команде секвенсора, но затем отказались от этой идеи.

Обратите внимание, что из ¤A4 используются не только 4 старших разряда, но и D3 - от него формируется последний бит синхронизации, хотя сам D3 уже не попадает в запись.

Кстати, а где у нас ¤FF ? А он как раз будет потерян при чтении, ему будут соответствовать значения 0-7 счётчика D23. И всё же его старший разряд важен. Дело в том, что после сбоя синхронизации автомат начинает читать данные только получив единичку (немного напоминает 140ку, не так ли ? ;). Её он считает первым битом данных и все нули перед ней будет пропускать. Так что без неё сеанса магии не состоится. Ну а значения остальных 7 бит не важны.

Итак, попробуем расшифровать полученную последовательность. Хвост байта ¤AA отбросим - там может быть любое значение, оставим только ¤A4 SYNC ¤FF:

          Читаем с диска:  10001001 0 01001000 10101010
Фазы декодера, вариант 1:  sds!dsds d sdsdsds! dsdsdsds - случай, когда у нас фаза была сбита до синхросбоя
Фазы декодера, вариант 2:  dsdsdsds d sdsdsds! dsdsdsds - случай, когда синхро была в порядке до синхросбоя

Видно, что программа чтения способна распознать здесь и начало байта ¤FF и отличить биты данных от бит синхронизации. Как же она устроена ? Об этом - в следующем разделе.

P.S. Заметили, что добавленный нолик ни в каком случае не является элементом синхросбоя? Вокруг него даже не набирается трёх нулей. Такая вот ирония. Я над ней порядком посидел.