bkread
Утилиты работы с файлами БК001x-xx
Давным-давно
(в восьмидесятые годы)
почти в другой галактике
(в СССР) жил странный советский
народ. Все у этого народа было
не как у людей.
И главным отличием этих существ
была неодолимая любовь к трудностям...
БК0010 - первый (и последний) советский
массовый домашний компьютер.
Вместе с компьютером потребитель получал
интерпретатор "языка высокого уровня" Фокал
(изобретенного в лабораториях DEC в шестидесятые годы) с которым шли первые
компьютеры
или, так называемый, "Вильнюсский" Бейсик,
поставляемый с более поздними моделями,
а еще позднее и то и другое (Фокал в "блоке МСТД").
Единственным устройством для хранения программ
и данных, предусмотренным заводом-изготовителем для этого чуда советской
техники был бытовой магнитофон, на который через примитивный аудиовыход
БК со скоростью ~1200 бод можно было записывать информацию. И пользователи
копили эти программы бобинами, стопками кассет МК-60, на которых-же и производился
обмен программами между ними.
Постепенно, времена и приоритеты менялись
- некоторые пользователи просто забросили свои БК в пользу более прогрессивных
РС, а некоторые обзавелись контроллерами дисководов и перешли к работе
на них. А к середине девяностых про БК, похоже, окончательно забыли. Теперь
с БК реально уже никто не работает. Но, я уверен, бобины и кассеты с записанными
на них произведениями остались практически у всех бывших пользователей
БК. И иногда хочется посмотреть, что же на них...
Содержание:
Однажды
мне стукнула в голову мысль "сохранить для потомков" свои программы, которые
я писал для БК пятнадцать лет назад. И я с удивлением ;) обнаружил, что
не имею возможности прочесть данные с моих бобин ни на одном из имеющихся
у меня навороченных компьютеров - ни в одном из них почему то не предусмотрено
БК-совместимого магнитофонного интерфейса. И это повергло меня в пучину
ПНИР (Псевдонаучно-исследовательской работы), целью которой было обучение
компьютера чтению данных с магнитофонных лент и дальнейшее приведение этих
данных в удобочитаемый вид, а результатом - представленные ниже утилиты.
Очевидно,
что снятие информации с магнитофонных лент возможно только через аудиокарту
и очевидно (мне по крайней мере), что программы считывания и преобразования
следует писать под один из вариантов Unix, чтобы обеспечить их переносимость.
Что, собственно было сделано и выставляется сейчас для всеобщего рассмотрения.
Внимание! Данные, излагаемые мною далее
получены при анализе отрывков нескольких руководств по БК, схеме компьютера,
дизассемблированных кодов Монитора БК и осциллограмм снятых с выходов БК.
Поэтому они не претендуют на полноту и точность. Хотя, на основе этих данных
и созданы успешно функционирующая программы, сведения, очевидно, не свободны
от огрех. Я выражаю особую признательность П. Б.
Эльтерману за предоставленные им личные записи и результаты его
экспериментов с драйвером магнитофона, которые позволили серьезно ускорить
эту работу.
Прежде
чем описывать входящие в пакет утилиты, я приведу краткое описание способа,
принятого в БК для записи информации на ленту. Для кодирования записываемых
данных используются последовательности импульсов, составляющие передаваемые
данные и служебную информацию.
Логически данные (записанный файл) выглядят
на ленте так:
Стартовая
синхропоследовательность |
Маркер начала |
Заголовок |
Данные |
Концевая синхропоследовательность |
С точки зрения читающей программы стартовая
настроечная последовательность представляет собой 100008
нулевых одиночных импульсов (один импульс - один период сигнала см. рис.).
Длина (продолжительность) такого импульса в дальнейшем определяет "эталонную
единичную длину" для всех последующих данных.
Рисунок. Одиночный импульс.
Маркер начала это 108
нулевых одиночных импульсов, заголовок
- 248 байт информации о записаном файле и следующие за этим
108 нулевых импульсов, данные
- это, собственно, данные файла, заканчивающиеся двухбайтовой контрольной
суммой,
концевая настроечная последовательность
- 4008 нулевых одиночных импульсов. Все элементы, кроме массива
данных, заканчиваются синхроимпульсами, за которыми следует единичный
бит (синхропоследовательностью).
Каждый бит кодируется двумя импульсами - информационным и синхронизирующим.
Нулевой бит кодируется двумя одинаковыми импульсами одиночной длины (см.
рис.). Первый импульс своей длительностью определяет значение бита ("0"),
второй - синхронизирующий.
Рисунок. Нулевой бит.
Единичный бит кодируется первым импульсом, с полупериодом вдвое больше
одиночного (вчетверо длиннее) и следующим за ним синхроимпульсом одиночной
длины (см. рис.).
Рисунок. Единичный бит (реально).
Реально, при записи амплитуда единичного импульса понижается вдвое соответственно,
в идеале при воспроизведении его размах также должен быть меньше (см. рис.).
Однако, за счет нелинейности частотных характерисик трактов магнитофонов
и выходного тракта БК, при считывании можно считать что амплитуда импульсов
одинакова и, скорее всего именно поэтому драйвер магнитофона БК так и запрограммирован.
Рисунок. Единичный бит (идеально).
Синхроимпульс
представляет собой одиночный импульс утороенной длины. Данный тип импульса
в комбинации с единичным битом образует синхропоследовательность
и используется для обозначения границ элементов, образующих файл на ленте.
Синхроимпульс также передается с половинной амплитудой. Синхропоследовательность,
образующую разделительный элемент между полями в файле можно видеть на
рисунке.
Рисунок. Синхропоследовательность.
Фактически, синхропоследовательность это последовательность из импульсов
тройной, двойной, а, затем, единичной длины.
Биты записываются
в порядке увеличения разряда в байте, т.е. нулевой бит - первым, седьмой
- последним. Для примера на следующем рисунке приведена последовательность,
импульсов образующая комбинацию битов "0101" в виде, выводимом драйвером
БК.
Рисунок. Последовательность бит "1010"
На рисунке обозначены значения каждого импульса. При этом "1D"
и "0D" означают стартовые (значащие) импульсы
в двухимпульсных посылках, кодирующих единичный и нулевой биты соответственно,
а "0S" означает синхроимпульс (по длительности
совпадающий с "0D").
Теперь
можно рассмотреть поля файла отдельно.
Внимание! Данные
длиной в слово хранятся и записываются в БК в формате LSB (младший байт
первый), что следует учитывать при написании или портировании утилит работы
с файлами под системы, использующие MSB формат (большинство RISC систем).
Как
уже указывалось, в начале файла записывается настроечная последовательность
из 100008 нулевых одиночных импульсов, которая используется
для детектирования начал файла и настройки ПО на скорость воспроизведения
данных. В конце настроечной последовательности записывается синхропоследовательность.
Маркер
начала, как это следует из косвенных данных к которым у меня был доступ,
должен содержать параметры записи (типа, инверсии данных, порядка байт
и пр.). Однако, так-как в реальных условиях никакие опции не используются,
и не заложены в алгоритмы работы драйвера магнитофона БК, можно считать,
что он содержит 108 нулевых одиночных импульсов и синхропоследовательность
в конце.
Заголовок
содержит следующие поля:
Байты |
Записанная информация |
0-1 |
Адрес памяти, с которого
записан файл |
2-3 |
Длина области данных
(без контрольной суммы) |
4-248 |
Имя файла |
Таким образом, максимальная длина имени файла - 16 символов (байт). Если
имя файла содержит меньше 16 символов, ПО БК, как правило, заполняло остающиеся
байты пробелами (408). Заголовок записывается сплошным потоком
бит, никаких разделителей байтов не предусмотрено. В конце заголовка записывается
108 нулевых импульсов и синхропоследовательность.
Данные
так же записываются сплошным потоком бит без разделителей байтов в потоке.
В
конце записываемого массива данных помещается двухбайтовая контрольная
сумма, которая получается в результате 16 разрядного беззнакового суммирования
с переносом всех байтов массива данных. В терминах ассемблера алгоритм
подсчета контрольной суммы выглядит так:
MOV START, R1
MOV LENGTH, R2
CLR R0
LOOP: MOVB (R1)+,
R3
BIC #177400, R3 ; СБРОС СТАРШИХ
БИТ В СЛУЧАЕ ПЕРЕНОСА ЗНАКА
ADD R3, R0
ADC R0
; УЧЕСТЬ ВОЗНИКНОВЕНИЕ ПЕРЕНОСА
SOB R2, LOOP
...
; R0 СОДЕРЖИТ КОНТРОЛЬНУЮ СУММУ
Сразу за контрольной суммой записывается импульс
шестикратной
длительности, назначение которого - точно обозначить конец данных и вызвать
гарантированную ошибку в случае пропуска данных при чтении.
Назначение
конечной синхрополедовательности мне не известно и не понятно.
Алгоритм
чтения данных с ленты на основе вышеизложенного получается довольно простым,
хотя и содержит несколько неочевидных моментов, суть которых рассмотрена
после описания:
-
Анализировать сигнал, пока на входе не появится группа из NSTART
однородных импульсов.
-
Настроить временные интервалы на основе среднего из NTUNE
последующих интервалов.
-
Продолжить чтение импульсов до синхропоследовательности.
-
Прочесть маркер начала и убедиться в его правильности.
-
Прочесть заголовок и убедиться в его правильности.
-
Прочесть данные.
-
Подсчитать контрольную сумму и убедиться в правильности
считывания данных.
-
Константы NSTART и NTUNE
в
оригинальном драйвере равны 40008 и 2008 соответственно.
Хотя искуственное разделение непрерывной настроечной последовательности
может показаться неразумным, связано оно с определенными особенностями
функционирования контроллера DRAM на КР1801ВП13, которые при работе программы
записи на МЛ могут в начале последовательности ускорить работу ЦП за счет
временного уменьшения времени доступа к оперативной памяти как результата
работы алгоритмов (все временные задержки при записи формируются программными
циклами), в результате чего при чтении могли бы неправильно быть вычислены
счетчики, ответственные за измерение длительности импульсов. Однако, при
чтении фактически пропускается NSTART
импульсов,
что гарантирует прохождение интервала времени, достаточного для стабилизации
скорости, а счетчики формируются уже на основе последующих
NTUNE
импульсов.
-
Видимо для упрощения, в оригинальном драйвере длина маркера не контролируется,
алгоритм пропускает все импульсы единичной длины
до появления синхропоследовательности.
-
Аналогично, в оригинальном драйвере не проверяется значение следующего
за синхроимпульсом бита в синхропоследовательности,
алгоритм просто читает (и пропускает) следующий за синхроимпульсом
бит.
Утилита
bkread
- основная программа пакета осуществляет чтение с магнитной ленты файлов,
записанных по алгоритмам, принятым в БК. Хотя программа функционирует согласно
оригинального алгоритма БК, написана она была без знания оного, на основе
анализа осциллограмм. Затем, некоторую ясность внесли чтения смутных мануалов
к компьютеру, что дало возможность сделать программу полностью рабочей,
а появление материалов Эльтермана - закрепить полученное, исправить мелкие
недочеты и довести программу до "публичного" вида.
bkread читает информацию с магнитофона
через аудиовход. Вызов утилиты производится следующей командой:
$ bkread [ключи] [имя]
после этого программа приступает к чтению информации с ленты. Если параметр
имя
отсутствует, то все встречающиеся при воспроизведении файлы сохраняются,
в текущей директории, если задано определенное имя,
то сохраняются только файлы с совпадающим именем. В случае, если в директории
уже имеются файлы с таким именем то к имени прибавляется префикс ".nnn",
где nnn - возрастающее число, гарантирующее от записи файла поверх
существующих.
В
командной строке можно задавать следующие ключи:
-
Ключи управления аудиовходом:
-
-r число - число задает коэффициент
усиления картой входного сигнала. Значение должно находиться в пределах
от 0 до 100 (минимальное и максимальное усиление). Если ключ -r не задан,
то коэффициент усиления зависит от особенностей ОС. В случае Solaris коэффициент
усиления остается равным последнему, установленному одной из утилит (в
т.ч. и bkread).
-
-m число - коэффициент усиления цепи
мониторинга входного сигнала. Значение должно находиться в пределах от
0 до 100 (минимальное и максимальное усиление). Если ключ -r не задан,
то коэффициент усиления зависит от особенностей ОС. В случае Solaris коэффициент
усиления остается равным последнему, установленному одной из утилит (в
т.ч. и bkread).
-
-R число - задать альтернативный коэффициент
дискретизации аудиоданных, число соответствует количеству тысяч снимаемых
за секунду значений. Значение по умолчанию - 44000 (т.е. -R
44, CD quality).
-
Ключи управления анализатором:
-
-a число - задает максимальное количество
адаптаций скорости при чтении файла. В bkread
используется
адаптивный алгоритм анализа сигнала, позволяющий по ходу чтения динамически
изменять скоростные коэффициенты, что позволяет компенсировать неравномерность
скорости воспроизведения (записи) на магнитофоне. По умолчанию количество
таких адаптаций неограничено.
-
-e число - задает уровень нуля. По
умолчанию нулевому уровню соответствует среднее значение между максимальным
и минимальным значениями амплитуды, выдаваемыми аудиокартой. В некоторых
случаях, например при искажениях сигнала или при помехах бывает полезно
сместить уровень со среднего значения в одну из сторон. Значение должно
лежать в пределах от 0 до 255 так-как bkread
использует 8-битный режим ввода.
-
-s число - задает количество единичных
импульсов, используемых при определении синхропоследовательности. По умолчанию
используется число, принятое в драйвере МЛ БК - 42008. Впоследствии
число разделяется на количество импульсов, необходимых для получения среднего
значения длительности единичного импульса по формуле (n/218)
и количество импульсов для детектирования настроечной последовательности
по формуле (n-n/218) соответвенно.
-
-p 0|1 - задает какую часть полупериода
на входе считать единичным импульсом - отрицательную (0) или положительную
(1). По умолчанию используется положительная часть.
-
Ключ -v включает режим вывода расширенной
диагностики (автор всегда задает этот ключ, поскольку наблюдать за происходящим
довольно интересно). Пример сессии чтения приведен ниже. Читается содержимое
монитора БК.
$ ./bkread -v -r 80 -m 20 -e 132 MONITOR
Audio: recording gain = 204
Audio: monitor gain = 51
Audio: sample_rate = 44000
Analyzer: edge level = 132
Reader: Synchro tuning pattern count = 2176
Listening for header synchros (S=2048; T=128)...
Synchros detected. Pattern length = 7.
Pattern length after tuning = 8.
Patterns lengths: 0 = 8; 1 = 16.
Signal Period Analyzer Line (2..40):
--000000000111111111111SSSSSSSSSSSSSSSS
---------------------------------------
000000001111111111222222222233333333334
234567890123456789012345678901234567890
File Name = "MONITOR "
Data Length = 20000 (octal).
Data Address = 100000 (octal).
Tape Checksum = 17341 (octal).
Data Checksum = 17341 (octal).
Saving file to: MONITOR (8214 bytes).
Listening for header synchros (S=2048; T=128)...
^CSignal (2) received. Program stopped.
Думаю, вывод утилиты с ключем -v достаточно мнемоничен, чтобы его не комментировать.
Работа прерывается по сигналу SIGINT (в терминах Unix), в данном случае
этот сигнал вызывался нажатием комбинации Ctrl-C (см. termio(7I)).
Программа сохраняет файлы под именами, заданными в заголовках на МЛ.
Оконечные пробелы отбрасываются. Если файл с таким именем уже имеется на
диске, bkread записывает его под тем-же
именем, добавляя ".n" в конец (n последовательно увеличивается до тех пор,
пока файла с таким именем не обнаружится на диске).
Утилита
dasm1
представляет собой простейший вариант дизассемблера из набора команд процессора
КР1801ВМ1 в вид текстовой формат, близкий к формату MACRO-11(tm),
позволяющий сравнительно легко разбираться в двоичных кодах программ для
БК. Фактически, dasm представляет собой
несколько доработанный вариант дизассемблера, который я в написал в 1988
году для ДВК-2, на которой мне довелось работать в то время.
Командная
строка для вызова dasm следующая:
$ dasm [-a | -b | -c | -f forced_file]
tape_file
Где ключ -a, -b и -c задают формат дополнительного вывода данных:
-
-a указывает необходимость вывода ASCII
кодов;
-
-b указывает необходимость вывода байтовых
кодов
-
-c отменяет пословный вывод кодов.
При всех заданых ключах (dasm -a -b)
вывод принимает следующий вид:
; Disassembler V01.5.1 BK 001x-xx (bkread)
; Alexander "las" Lunev
; Start address = 100000
; Length = 20000
; Tape file name: MONITOR
; Command Operand(s) Address Codes
;
$START$:JMP MONITOR !100000: 000167 000254 167 000 254 000 "w.╛."
EMT_4P:.WORD 100742 !100004: 100742 342 201 "??"
EMT_6P:.WORD 101010 !100006: 101010 010 202 ".┌"
Непосредственно за кодами инструкций, после восклицательного знака (комментарий)
следуют: обязательный адрес, пословная расшифровка кода команды, ее байтовые
коды, (все в восьмеричном исчислении) и ее строковое представление.
Ключ -f задает файл форсированных меток, т.е. если (как правило ;) дизассемблер
неверно интерпретирует участки кода как данные или как коды, когда они
таковыми не являются, то можно форсировать интерпретацию данных в нужном
представлении.
Сам файл устанвок имеет достаточно примитивный
формат:
<type> <addr> <label>
...
Пустые строки и комментарии в файле не допускаются; type
- тип форсируемой области, допустимые значения c
(code) и d (data); addr
- адрес начала области (восьмеричный); label
- имя для метки, которая будет обозначать начало области. Легко видеть,
что приведенном выше примере вывода dasm был использован файл форсированных
меток содержащий следующие строки:
d 100004 EMT_4P
d 100006 EMT_6P
Длина имени метки - не более 7 символов.
Внимание! dasm
- достаточно примитивная утилита, которая не будет совершенствоваться или
исправляться в дальнейшем, ввиду подготовки к выходу более совершенного
JDasm, идущего в составе JavaPDP. Это, однако не мешает любителям программирования
на C модифицировать и дополнять программу с целью приведения ее в "божеский
вид".
Утилита
focal2txt,
как и следует из имени переводит файлы из внутреннего представления Фокала
в текстовой вид.
Командная
строка для вызова focal2txt следующая:
$ focal2txt tape_file
Утилита выводит программу в текстовом представлении в стандартный вывод.
Никаких преобразований кодировок не производится, поэтому для просмотра
или печати программ следует использовать те или иные перекодирующие утилиты.
В ближайшее время готовится к выходу Java-апплет для просмотра программ
на языках Фокал БК-0010 и Бейсик БК-0010, за дополнительной информацией
обращайтесь по адресу elder@technologist.com.
Для
компиляции утилит следует сначала подправить Makefile под параметры ваших
ОС и компилятора С, а затем, командой
$ make
создать исполняемые модули.
Теоретически, данные программы должны работать под любой UNIX-подобной
ОС, хотя проверялись они мной только под Solaris 7 (Intel и SPARC) с компиляторами
gcc. Я буду рад новостям относительно любых новых патформ (кроме, пожалуй,
Windows), на которые удалось перенести эти утилиты или появленрию для них
графических wrapper-ов, скажем, на Tcl/Tk. Все сообщения о переносах, ошибках
и модификациях программ прошу присылать на мой E-Mail адрес - elder@technologist.com.
А. Лунев (las)
Лето 2000