|
|
| (не показано 5 промежуточных версий этого же участника) |
| Строка 1: |
Строка 1: |
| {{emuverse}} | | {{emuverse}} |
|
| |
|
| '''Формат файлов BASIC 02''' — способ хранения программ на дисках [[Искра-226]]. Файловая система унаследована от [[Wang 2200]], представление программы — оригинальное и с Wang несовместимо. | | '''Файловая система Искры 226''' — способ хранения файлов на дисках [[Искра-226]]. Унаследована от [[Wang 2200]] и совпадает с ней побайтово; содержимое файлов — оригинальное и с Wang несовместимо. |
|
| |
|
| Программа может храниться в двух видах: '''текстовом''' (плоский текст в [[КОИ-8]]) и '''токенизированном'''. Оба вида имеют одинаковую внешнюю структуру и различаются одним байтом в заголовочном секторе.
| | Статья описывает файловую систему, указатель каталога и текстовое представление программ. Отдельно вынесены: |
|
| |
|
| == Общее устройство ==
| | * [[Искра-226/Кодирование BASIC-файлов]] — токенизированная запись программы; |
| На диске располагаются физические сектора размером 128 байт — 77 дорожек, 26 секторов на дорожке, одна сторона. Физические сектора попарно объединены в логические размером 256 байт со сквозной нумерацией. Далее везде будут подразумеваться логические сектора.
| | * [[Искра-226/Файлы данных BASIC 02]] — записи, значения и способы доступа; |
| | * [[Искра-226/Графический буфер BASIC 02]] — формат рисунка. |
|
| |
|
| Файлу выделяется непрерывный диапазон секторов, границы которого записаны в «Указателе каталога». Раскладка внутри диапазона: | | == Диск == |
| | |
| | Физический сектор — 128 байт; 77 дорожек по 26 секторов, одна сторона. Физические сектора попарно объединены в логические по 256 байт со сквозной нумерацией. Далее везде подразумеваются логические сектора. Полный объём тома — 1001 сектор, 256 256 байт. |
| | |
| | Типы файлов: |
| | |
| | * '''ПФ''' — программный файл: программа на Бейсике в текстовом либо оттранслированном виде; |
| | * '''ФД''' — файл данных. |
| | |
| | Файлу выделяется непрерывный диапазон секторов, границы записаны в указателе каталога. |
|
| |
|
| {| class="wikitable" | | {| class="wikitable" |
| Строка 17: |
Строка 27: |
| | следующие N || поток содержимого | | | следующие N || поток содержимого |
| |- | | |- |
| | … || резерв, заполнен нулями | | | … || резерв, нули |
| |- | | |- |
| | последний выделенный || control record | | | последний выделенный || концевая запись |
| |} | | |} |
|
| |
|
| Таким образом, любой файл занимает на диске как минимум на 512 байт больше, чем размер его полезных данных.
| | Размер файла на диске не меняется, поэтому при перезаписи более коротким содержимым '''хвост не затирается''': там остаются фрагменты предыдущих версий, иногда в другом представлении. Обработку следует прекращать на первой встреченной концевой записи. |
| | |
| Размер файла на диске уменьшать нельзя, поэтому при перезаписи файла более коротким содержимым '''старые данные в хвосте не затираются'''. Там могут остаться читаемые фрагменты предыдущих версий файла, иногда в другом представлении. Их нельзя принимать за часть текущего файла, поэтому необходимо завершать обработку файла при нахождении первой control record. | |
| | |
| Искра-226 поддерживает работу с двумя типами файлов: ПФ — «Программные файлы» и ФД — «Файлы данных». Программные файлы всегда содержат программу на Бейсике, в текстовом или упакованном токенизированном виде. Файлы данных, соответственно, данные, доступные из программ пользователя.
| |
|
| |
|
| В соответствии с документацией, Искра-226 поддерживает прямой доступ программ к секторам диска, при этом к записанным таким образом дискам всё нижеизложенное может быть неприменимо, так как форматом хранения полностью управляет программа пользователя по своему усмотрению.
| | Диски прямого доступа (запись по абсолютным адресам секторов) указателя каталога не имеют; формат содержимого таких дисков задаёт программа пользователя. Загрузочные диски с интерпретатором имеют собственный формат: нулевой сектор начинается сигнатурой <code>06 90 09 90 07 90</code>, за ней 18 знаков имени и даты версии. |
| | |
| Также, в наличии имеется несколько системных дисков, на которых содержатся различные версии интерпретатора Бейсика, с которых производится начальная загрузка компьютера. Эти диски имеют свой формат и здесь не рассматриваются.
| |
|
| |
|
| == Указатель каталога == | | == Указатель каталога == |
| Начиная с 0 сектора на диске располагается «Указатель каталога».
| |
|
| |
|
| Первые 16 байт содержат служебную информацию в следующем составе: | | Начинается с сектора 0. Первые 16 байт нулевого сектора — параметры диска: |
|
| |
|
| {| class="wikitable" | | {| class="wikitable" |
| ! Смещение !! Размер !! Значение | | ! Смещение !! Размер !! Значение |
| |- | | |- |
| | 0-1 || 2 || размер Указателя каталога в секторах, 16 бит big-endian | | | 0–1 || 2 || размер указателя каталога в секторах (<code>LS</code>), старший байт первым |
| |- | | |- |
| | 2-3 || 2 || номер последнего использованного сектора, 16 бит big-endian | | | 2–3 || 2 || текущий конец каталога — первый свободный сектор |
| |- | | |- |
| | 4–5 || 2 || размер тома (обычно 1000), 16 бит big-endian | | | 4–5 || 2 || конец области каталога |
| |- | | |- |
| | 6–15 || 10 || нули | | | 6–15 || 10 || нули |
| |} | | |} |
|
| |
|
| После служебной информации идут 16-байтовые записи каталога, описывающие файлы. По непонятной причине записи каталога не сгруппированы в начале указателя, а распределены по всем его секторам. Неиспользованные записи заполнены нулями. Следовательно, для чтения указателя каталога необходимо пройти все его сектора, игнорируя нулевые строки.
| | Размер указателя задаётся при создании каталога оператором <code>SCRATCH DISK</code> параметром <code>LS=</code>, по умолчанию 24, допустимо 1…255; в дальнейшем не меняется. В нулевом секторе помещается 15 записей, в остальных 16. Неиспользованные записи заполнены нулями. |
| | |
| | Записи '''не сгруппированы''' в начале указателя и не упорядочены по секторам файлов: номер сектора, в который попадает запись, вычисляется хешированием имени. Для чтения каталога надо пройти все его секторы, пропуская нулевые записи. |
| | |
| | === Хеш имени файла === |
| | |
| | Номер сектора указателя вычисляется по «старому» хешу Wang 2200: |
| | |
| | имя дополнить пробелами до восьми байт |
| | tmp = 0 |
| | для каждого байта имени: tmp = tmp XOR байт |
| | tmp = 3 × tmp |
| | tmp = (tmp mod 256) + (tmp div 256) |
| | сектор = tmp mod LS |
| | |
| | Свёртка выполняется исключающим ИЛИ, не сложением. «Новый» хеш Wang, введённый в MVP OS 2.5, на Искре не применяется. |
| | |
| | Хеш '''вырождается при <code>LS</code>, кратном трём''': после умножения на 3 и складывания половинок результат всегда кратен трём, поэтому занятыми оказываются только каждый третий сектор указателя. При <code>LS = 24</code> все записи попадают в секторы 0, 12, 15 и 18. |
| | |
| | Запись кладётся в первый свободный слот своего сектора, слоты заполняются подряд от начала. Правило переполнения сектора неизвестно. |
| | |
| | Освобождение слота выполняется '''обнулением первых восьми байт''' записи; имя при этом остаётся на диске. Оператор <code>SCRATCH</code> запись не обнуляет, а помечает. |
|
| |
|
| == Запись каталога == | | == Запись каталога == |
|
| |
|
| 16 байт, побайтово совпадает с Wang 2200. | | 16 байт, совпадает с Wang 2200. |
|
| |
|
| {| class="wikitable" | | {| class="wikitable" |
| ! Смещение !! Размер !! Значение | | ! Смещение !! Размер !! Значение |
| |- | | |- |
| | 0 || 1 || статус: <code>10</code> — активна, <code>11</code> — удалена (scratched), <code>00</code> — свободна | | | 0 || 1 || статус, битовое поле; '''бит 0''' — файл вычеркнут |
| |- | | |- |
| | 1 || 1 || тип файла: <code>80</code> — программа, <code>00</code> — данные | | | 1 || 1 || тип файла: <code>80</code> — программа, <code>00</code> — данные |
| Строка 71: |
Строка 95: |
| |} | | |} |
|
| |
|
| Байт типа '''не различает''' текстовое и токенизированное представление: у обоих <code>80</code>.
| | Наблюдаемые значения статуса: <code>10</code> — активна, <code>11</code> и <code>21</code> — вычеркнута, <code>00</code> — свободна. Сравнивать статус на точное равенство нельзя, значим только бит 0. Бит 5 (значение <code>21</code>) предположительно помечает переименование. |
|
| |
|
| Указатель каталога всегда начинается с нулевого сектора диска; за ним идёт область каталога. Число секторов указателя задаётся при создании каталога оператором <code>SCRATCH DISK</code> параметром <code>LS=</code>, по умолчанию равно 24 и в дальнейшем не меняется; допустимы значения от 1 до 255. В нулевом секторе помещается до 15 записей, в остальных — до 16: первые 16 байт нулевого сектора занимает блок параметров диска. Номер сектора указателя, в который попадает имя файла, вычисляется функцией от самого имени, поэтому порядок имён в указателе не совпадает с порядком размещения файлов в области каталога.<ref name="balasanyan" />
| | Байт типа '''не различает''' текстовое и оттранслированное представление программы: у обоих <code>80</code>. |
|
| |
|
| Оператор <code>LIST DC</code> выводит типы файлов как <code>P</code> (программный), <code>D</code> (файл данных), <code>SP</code> и <code>SD</code> (вычеркнутые из каталога программный и файл данных соответственно), что соответствует сочетанию байта статуса и байта типа в записи.<ref name="balasanyan" /> | | Оператор <code>LIST DC</code> выводит типы как <code>P</code> (программный), <code>D</code> (данные), <code>SP</code> и <code>SD</code> (вычеркнутые), что соответствует сочетанию байта статуса и байта типа.<ref name="balasanyan" /> |
| | |
| | Тип «данные» ничего не говорит о внутреннем устройстве файла: он может содержать как логические записи, так и сырые блоки, записанные оператором <code>DATA SAVE BA</code>. |
|
| |
|
| === Пример === | | === Пример === |
| Строка 82: |
Строка 108: |
| └───┘ └───┘ └───┘ └─────────────────────┘ | | └───┘ └───┘ └───┘ └─────────────────────┘ |
| Активная запись, программа, секторы 49…63, имя <code>DIG DEM</code>. | | Активная запись, программа, секторы 49…63, имя <code>DIG DEM</code>. |
| | |
| | == Размещение файлов == |
| | |
| | * Файлы лежат подряд в порядке создания, диапазоны секторов не пересекаются. |
| | * Место вычеркнутого файла заново не занимается: <code>SCRATCH</code> только помечает запись. |
| | * Первый файл начинается с сектора <code>LS</code>, сразу за указателем. |
| | * Поле «текущий конец» равно последнему занятому сектору плюс единица, но обрезается по концу области каталога; при разборе границу надёжнее брать по записям каталога. |
|
| |
|
| == Заголовочный сектор == | | == Заголовочный сектор == |
| Строка 92: |
Строка 125: |
| | 1–8 || имя файла, дополнено пробелами | | | 1–8 || имя файла, дополнено пробелами |
| |- | | |- |
| | 9 || признак формата записи, см. ниже | | | 9 || признак формата записи |
| |- | | |- |
| | 10–255 || нули | | | 10–255 || нули |
| |} | | |} |
|
| |
|
| Байт 9 — единственный признак, по которому различаются два представления программы. Наблюдались значения <code>20</code> (текстовое) и <code>21</code> (токенизированное), каждое на двух файлах. | | Байт 9 (в справочнике<ref name="vtoraya" /> назван «признак защиты») — битовое поле, единственный признак, различающий два представления программы: '''бит 0''' — программа оттранслирована (параметр <code>T</code> оператора <code>SAVE DC</code>), '''бит 2''' — защищена (параметр <code>P</code>); оба вместе соответствуют параметру <code>G</code>. |
| | |
| === Связь с параметрами оператора SAVE DC ===
| |
| | |
| Документация<ref name="balasanyan" /> описывает три параметра специальных форматов записи программы:
| |
| | |
| {| class="wikitable"
| |
| ! Параметр !! Действие
| |
| |-
| |
| | <code>T</code> || программа записывается в оттранслированной форме — во внутреннем формате машины, что сокращает занимаемое место и время загрузки
| |
| |-
| |
| | <code>P</code> || программа защищается от просмотра и записи; после загрузки возможно только выполнение, режим сохраняется до оператора <code>CLEAR</code>
| |
| |-
| |
| | <code>G</code> || оттранслированная и защищённая форма одновременно
| |
| |}
| |
| | |
| Отсюда следует, что '''текстовое представление — это режим по умолчанию''', а токенизированное включается явным указанием параметра <code>T</code>. Термин «оттранслированная форма» в документации обозначает именно токенизированную запись.
| |
| | |
| Документированные значения байта 9 (в источнике он назван «признак защиты»):<ref name="vtoraya" />
| |
|
| |
|
| {| class="wikitable" | | {| class="wikitable" |
| Строка 129: |
Строка 144: |
| |} | | |} |
|
| |
|
| Таким образом байт 9 — битовое поле: '''бит 0''' — программа оттранслирована (параметр <code>T</code>), '''бит 2''' — программа защищена (параметр <code>P</code>); сочетание обоих соответствует параметру <code>G</code>. Значения <code>22</code> и <code>23</code> не используются.
| | Значения <code>22</code> и <code>23</code> не используются. Текстовое представление — режим по умолчанию, оттранслированное включается явным параметром <code>T</code>. |
|
| |
|
| Значения <code>20</code>, <code>21</code> и <code>25</code> наблюдались на дисковых образах (<code>25</code> — у файла <code>STAT05</code>, защищённого и оттранслированного одновременно), <code>24</code> взято из документации.
| | Защищённая программа после загрузки может только выполняться; режим снимается оператором <code>CLEAR</code>. |
|
| |
|
| == Секторы потока == | | == Секторы потока == |
|
| |
|
| Первые два байта каждого сектора потока — служебные, в содержимое не входят. | | Первые два байта каждого сектора программного потока — служебные, в содержимое не входят. У секторов файла данных служебный заголовок занимает '''один''' байт. |
|
| |
|
| '''Байт 0''' — позиция сектора: | | '''Байт 0''' — позиция сектора: |
|
| |
|
| {| class="wikitable" | | {| class="wikitable" |
| ! Значение !! Смысл | | ! Код !! Смысл |
| |- | | |- |
| | <code>02</code> || первый сектор потока | | | <code>02</code> || первый сектор потока |
| |- | | |- |
| | <code>8F</code> || промежуточный | | | <code>03</code> || последний сектор потока |
| |- | | |- |
| | <code>03</code> || последний | | | <code>1C</code> || концевая запись |
| | |- |
| | | <code>8B</code> || запись целиком в одном секторе (только файлы данных) |
| | |- |
| | | <code>8F</code> || промежуточный сектор |
| |} | | |} |
|
| |
|
| В токенизированных программах все секторы потока наблюдались с маркером <code>02</code>; позиционная разметка <code>02</code>/<code>8F</code>/<code>03</code> подтверждена на текстовых файлах и на потоке значений переменных. Причина различия не установлена. | | В оттранслированных программах все секторы потока идут с маркером <code>02</code>. Позиционная разметка <code>02</code>/<code>8F</code>/<code>03</code> наблюдается в текстовых файлах и в потоках данных. |
|
| |
|
| '''Байт 1''' — только у программных секторов. Во всех исследованных потоках программы он равен <code>80</code>. | | '''Байт 1''' программных секторов равен <code>80</code>. Как признак «программа или данные» он непригоден: у секторов данных на позиции 1 стоит первый байт идентификатора значения. Надёжные признаки — байт 9 заголовочного сектора и байт типа записи каталога. |
|
| |
|
| {{Внимание|У секторов данных служебный заголовок занимает '''один''' байт, а не два. То, что во всех наблюдавшихся секторах данных на позиции 1 стоял <code>00</code>, объясняется не разметкой потока, а тем, что это первый байт двухбайтового идентификатора значения, и <code>00</code> в нём означает числовой тип. Для сектора, начинающегося со строкового значения, значение будет другим. Использовать байт 1 как признак «программа или данные» нельзя; надёжный признак — байт 9 заголовочного сектора и байт типа в записи каталога.}}
| | == Концевая запись == |
| | |
| Двухбайтовая длина служебного заголовка программных секторов подтверждается арифметикой: длины записей строк сходятся только при пропуске двух байтов на каждой пересекаемой границе сектора.
| |
| | |
| В токенизированном файле сначала идут секторы программы, за ними могут следовать секторы значений переменных с собственной нумерацией.
| |
| | |
| Маркер <code>03</code> имеет содержательный смысл: документация<ref name="balasanyan" /> описывает файл как область, в которой между последней записью данных и последним сектором файла остаются неиспользованные секторы, а концевая запись помечает сектор, откуда можно продолжать запись. Таким образом <code>03</code> — не просто «последний по счёту сектор», а граница записанной области, и всё, что лежит за ней до конца выделенного диапазона, к текущему содержимому файла не относится.
| |
| | |
| == Control record ==
| |
| | |
| Лежит в '''последнем выделенном''' секторе, а не сразу за содержимым.
| |
|
| |
|
| 1C <длина: 2 байта, старший первым> | | 1C <длина: 2 байта, старший первым> |
|
| |
|
| Остаток сектора — нули. Маркер <code>1C</code> соответствует по роли байту <code>20</code> в Wang. Второй источник<ref name="vtoraya" /> описывает эту структуру как признак конца файла <code>1C</code>, за которым во втором и третьем байтах сектора записано число реально занятых секторов, а остальные байты нулевые; последний сектор файла данных устроен так же, как последний сектор программного файла. | | Остаток сектора — нули. Соответствует по роли байту <code>20</code> в Wang. |
|
| |
|
| Документация<ref name="balasanyan" /> отдельно указывает, что последний сектор файла отводится под служебную информацию, а концевая запись занимает ещё один сектор, поэтому при создании файла его размер следует заказывать на два сектора больше, чем требуется собственно под данные.
| | Счётчик равен '''собственной позиции записи от начала файла''', считая с единицы, то есть числу занятых секторов вместе с заголовком. Он же — графа «Использовано» в выдаче <code>LIST DC</code>. |
|
| |
|
| Счётчик соответствует графе «Использовано», которую показывает оператор <code>LIST DC</code>. Согласно документации<ref name="balasanyan" /> он '''не поддерживается системой автоматически''': значение заносит прикладная программа оператором <code>DATA SAVE DC END</code>, записывающим односекторную концевую запись в текущий сектор из таблицы устройств. Если признак конца данных не записан, в графе «Использовано» всегда стоит 00001; если записан — число реально использованных секторов.
| | * У программных файлов концевую запись пишет сам оператор <code>SAVE DC</code>; она есть всегда. |
| | * У файлов данных её пишет прикладная программа оператором <code>DATA SAVE DC END</code>. Если признак конца не записан, в графе «Использовано» стоит 00001. |
| | * Оператор <code>DATA SAVE DC OPEN</code> пишет в '''последний''' сектор файла запись <code>1C 00 01</code> — единственный случай, когда счётчик не равен позиции. |
|
| |
|
| Там, где значение выставлено, оно равно '''заголовок + секторы содержимого + сам control record''', то есть совпадает с правилом Wang:
| | Запись лежит не обязательно в последнем выделенном секторе: если файлу дали запас или его положили на место вычеркнутого файла большего размера, за ней остаётся нулевой хвост. |
|
| |
|
| {| class="wikitable"
| | Счётчик — не инвариант файловой системы и при разборе ненадёжен: у файлов, записанных не операторами <code>DATA SAVE DC</code>, он произволен. Границы файла следует брать из каталога. |
| ! Файл !! Секторов содержимого !! Счётчик !! Ожидаемо
| |
| |-
| |
| | <code>ФС</code> || 5 || 7 || 1+5+1 = 7
| |
| |-
| |
| | <code>ДЕМ6</code> || 16 || 18 || 1+16+1 = 18
| |
| |}
| |
| | |
| {{Внимание|Счётчик не является инвариантом файловой системы и при разборе ненадёжен. У <code>#СТАТИСТ</code> он равен 48 при 46 секторах содержимого — значение, по-видимому, осталось от предыдущей, более длинной версии программы, остатки которой лежат в резерве того же файла. У <code>DIG DEM</code> счётчик равен 6 при 5 секторах содержимого, то есть на единицу меньше ожидаемого; возможная причина в том, что там последней операцией была запись потока данных, а не программы. Границы файла следует брать из каталога, а конец данных определять по структуре записей.}}
| |
|
| |
|
| == Текстовое представление == | | == Текстовое представление == |
|
| |
|
| Программа хранится плоским текстом. Кодировка — КОИ-8 (ГОСТ 19768-74): прописная кириллица в 0xE0–0xFF, строчная в 0xC0–0xDF. Номера строк записаны обычными ASCII-цифрами. | | Программа хранится плоским текстом. Кодировка — [[КОИ-8]] (ГОСТ 19768-74): прописная кириллица в <code>E0</code>–<code>FF</code>, строчная в <code>C0</code>–<code>DF</code>. Номера строк записаны обычными цифрами. |
|
| |
|
| * Разделитель строк — байт '''<code>85</code>'''. | | * Разделитель строк — байт '''<code>85</code>'''. |
| Строка 193: |
Строка 196: |
| * Байт <code>24</code> (<code>$</code>) отображается на экране Искры как <code>¤</code>. | | * Байт <code>24</code> (<code>$</code>) отображается на экране Искры как <code>¤</code>. |
|
| |
|
| Выбор <code>85</code> возможен именно потому, что кириллица занимает только верхнюю четверть кодовой таблицы и диапазон 0x80–0x9F остаётся свободным. К самой кодировке КОИ-8 это соглашение отношения не имеет и за пределами Искры не встречается.
| | Байт <code>85</code> свободен потому, что диапазон <code>80</code>–<code>9F</code> в КОИ-8 не занят. Тем же байтом машина разделяет строки в символьном буфере операторов <code>SAVE</code> и <code>LOAD</code> и выдаёт нажатие клавиши CR/LF. |
|
| |
|
| Разбор: склеить содержимое секторов, отбрасывая по два служебных байта, разбить по <code>85</code>, отбросить нули. | | Разбор: склеить содержимое секторов, отбрасывая по два служебных байта, разбить по <code>85</code>, отбросить нули. |
| Строка 203: |
Строка 206: |
| Заголовок сектора, затем <code>5 REM ПЕТРЕНКО …</code>, разделитель, <code>8 PRINT …</code>. | | Заголовок сектора, затем <code>5 REM ПЕТРЕНКО …</code>, разделитель, <code>8 PRINT …</code>. |
|
| |
|
| == Токенизированное представление == | | == Виды дисков == |
| | |
| === Сборка потока ===
| |
| | |
| Склеить содержимое секторов с байтом 1 равным <code>80</code>, отбрасывая по два служебных байта у каждого. Далее смещения даны от начала полученного потока.
| |
| | |
| === Пролог и таблицы ===
| |
| | |
| Поток начинается с трёх 16-битных длин, '''старший байт первым''', за которыми следуют три таблицы:
| |
|
| |
|
| {| class="wikitable" | | {| class="wikitable" |
| ! Смещение !! Размер !! Значение | | ! Вид !! Признак |
| |- | | |- |
| | 0 || 2 || L1 — длина таблицы 1 в байтах, запись 8 байт | | | с каталогом || байты 0–1 нулевого сектора — разумный <code>LS</code>, дальше 16-байтовые записи |
| |- | | |- |
| | 2 || 2 || L2 — длина таблицы 2 в байтах, запись 4 байта | | | загрузочный || сектор 0 начинается с <code>06 90 09 90 07 90</code> |
| |- | | |- |
| | 4 || 2 || L3 — длина таблицы 3 в байтах, запись 4 байта | | | пакет ассемблера || сектор 0 начинается с <code>7E E1 F3 ED E2</code> (<code>~АСМБ</code>) |
| |- | | |- |
| | 6 || L1 || таблица 1 | | | прямого доступа || каталога нет, есть заголовочные секторы <code>01 <имя> <признак></code> |
| |- | | |- |
| | 6+L1 || L2 || таблица 2 | | | пустой || нули |
| |-
| |
| | 6+L1+L2 || L3 || таблица 3
| |
| |} | | |} |
|
| |
| '''Программа начинается по смещению <code>6 + L1 + L2 + L3</code>.'''
| |
|
| |
| Проверено на четырёх файлах:
| |
|
| |
| {| class="wikitable"
| |
| ! Файл !! L1 !! L2 !! L3 !! Старт !! Первая строка
| |
| |-
| |
| | <code>DIG DEM</code> || 24 || 20 || 0 || 50 || <code>0 GOTO 10</code>
| |
| |-
| |
| | <code>#СТАТИСТ</code> || 216 || 488 || 108 || 818 || <code>999 REM КОНЕЦ</code>
| |
| |-
| |
| | <code>ДЕМ6</code> || 392 || 256 || 0 || 654 || <code>10 REM "ДЕМ6". ГОРОСКОП</code>
| |
| |-
| |
| | <code>EDITOR</code> || 448 || 800 || 0 || 1254 || <code>10 % EDITOR. ВЕРСИЯ 4.1</code>
| |
| |}
| |
|
| |
| Формула даёт точную границу, эвристический поиск начала программы не требуется.
| |
|
| |
| ==== Таблица 1 ====
| |
|
| |
| '''Таблица 1 описывает переменные, объявленные в <code>DIM</code>.''' Запись — 8 байт:
| |
|
| |
| {| class="wikitable"
| |
| ! Смещение !! Размер !! Значение
| |
| |-
| |
| | 0–1 || 2 || адрес переменной в памяти, младший байт первым
| |
| |-
| |
| | 2–3 || 2 || тип: <code>00 08</code> — символьная, <code>2D 08</code> — числовая или целая
| |
| |-
| |
| | 4–5 || 2 || для массивов — число элементов, младший байт первым
| |
| |-
| |
| | 6–7 || 2 || размерный код, младший байт первым
| |
| |}
| |
|
| |
| Размерный код равен '''<code>2 × размер элемента</code>''', а его младший бит означает, что длина была задана явно. Для числовых переменных код 16 (размер элемента 8 байт), для целых 4 (2 байта), для символьных <code>2 × длина + 1</code>: длина 8 → 17, 64 → 129, 128 → 257, 253 → 507.
| |
|
| |
| Символьная переменная, объявленная без указания длины, получает длину по умолчанию 16 и '''чётный''' код 32. В <code>STAT01A</code> так объявлены <code>B6¤(400)</code> и <code>B7¤(10)</code>, у обоих код 32, тогда как у всех переменных с явной длиной в том же файле код нечётный и точен. Поэтому нечётность кода нельзя использовать как признак символьного типа — для этого служат байты 2–3.
| |
|
| |
| ===== Двумерные массивы =====
| |
|
| |
| У двумерного массива вторая размерность записывается в байты 2–3, на место признака типа, а первая остаётся в поле числа элементов. Размерности '''не перемножаются''', поэтому оператор <code>DIM</code> восстанавливается точно.
| |
|
| |
| Единственный исследованный пример — <code>Q(7,8)</code> в файле <code>STAT01A</code>:
| |
|
| |
| 00 00 08 00 07 00 10 00
| |
|
| |
| Байты 2–3 равны 8 (вторая размерность), байты 4–5 равны 7 (первая), размерный код 16 — числовая. Опознание надёжно: соседние записи таблицы содержат 13 и 8 элементов, а в тексте <code>DIM</code> вокруг <code>Q(7,8)</code> стоят <code>A(13)</code> и <code>E(8)</code>.
| |
|
| |
| Практическое правило: если байты 2–3 не равны <code>2D 08</code> и не <code>00 08</code>, запись описывает двумерный массив, а в этих байтах лежит вторая размерность.
| |
|
| |
| {{Внимание|1=Пример единственный и получен из удалённого файла, целостность которого не гарантирована. Как при двумерности кодируется тип переменной, установить не удалось: у <code>Q(7,8)</code> байты 2–3 заняты размерностью, и признака числового типа в записи не остаётся. Символьный двумерный массив в материале не встретился.}}
| |
|
| |
| ===== Порядок записей обратен порядку объявления =====
| |
|
| |
| Память под переменные выделяется '''сверху вниз''', от верхней границы, а записи в таблице отсортированы по возрастанию адреса. Поэтому '''первая переменная в <code>DIM</code> оказывается последней записью таблицы''', и сопоставлять их нужно с конца.
| |
|
| |
| Проверено на файле <code>EDITOR</code>: 7 операторов <code>DIM</code> объявляют 50 переменных, L1 = 448 = 56 записей. При обратном сопоставлении разность адресов соседних записей совпадает с ожидаемым размером переменной '''у 44 из 50''' точно, а оставшиеся 6 расходятся ровно на 1 байт — это нечётные длины (<code>A¤1</code>, <code>K¤253</code>, <code>G¤19</code>), округляемые вверх до чётной.
| |
|
| |
| {{Внимание|1='''Адреса в таблице 1 могут быть нулевыми.''' В файле <code>STAT05</code> все 11 записей имеют адрес <code>0000</code>, поэтому любое правило, опирающееся на разность адресов соседних записей, там неприменимо. Разборщику следует проверять адреса на ненулевое значение перед использованием.
| |
|
| |
| Остальные поля при этом заполнены и корректны: обратный порядок относительно <code>DIM</code> сохраняется, размерный код точен для всех строковых переменных, у массива <code>K(9)</code> число элементов равно 9.}}
| |
|
| |
| Размер выделяемой памяти:
| |
|
| |
| * скалярная символьная переменная — объявленная длина, округлённая вверх до чётной;
| |
| * массив — <code>N × размер элемента + 6</code>, где 6 байт занимает дескриптор.
| |
|
| |
| Формула для массивов проверена на 20 массивах <code>EDITOR</code> без единого расхождения: <code>V¤(20)64</code> → 1286, <code>S¤(48)64</code> → 3078, <code>P%(300)</code> → 606, <code>X(2)</code> → 22.
| |
|
| |
| ===== Таблица отражает состояние на момент сохранения =====
| |
|
| |
| Число записей может превышать число переменных в <code>DIM</code>. В <code>STAT01A</code> записей 26 при 23 объявленных переменных, и три лишние стоят в области самых низких адресов, то есть выделены последними.
| |
|
| |
| Это переменные <code>X</code>, <code>Y</code> и <code>G¤</code>, переопределённые оператором <code>MAT REDIM</code>: у каждой в таблице по два дескриптора — исходный из <code>DIM</code> с числом элементов 200 и текущий с числом 300, где 300 является значением времени выполнения. Подтверждается с другой стороны: в токенах <code>DIM</code> именно эти три переменные получили индексы <code>40</code>, <code>41</code>, <code>42</code>, тогда как все остальные — обычные значения подряд.
| |
|
| |
| В <code>EDITOR</code> шесть записей таблицы 1 также не соответствуют ни одному <code>DIM</code>; их тип (<code>59 07</code>, <code>27 01</code>) отличается от остальных, и связать их с конкретными переменными не удалось.
| |
|
| |
| ==== Таблицы 2 и 3 ====
| |
|
| |
| Записи по 4 байта: <code><адрес: 2 байта, младший первым> <флаг> <байт></code>. Флаг принимает значения <code>10</code>, <code>21</code>, <code>80</code>, <code>81</code>, <code>90</code>, <code>91</code>, <code>A0</code>, <code>A1</code>. Встречаются записи с нулевым адресом — предположительно незанятые слоты. Формат записей в обеих таблицах одинаков, граница между ними определяется только счётчиками пролога.
| |
|
| |
| Число записей — <code>L2 / 4</code> и <code>L3 / 4</code>: длины в прологе даны в байтах, а запись занимает 4 байта, а не 8.
| |
|
| |
| Таблица 2 содержит скалярные переменные, не объявленные в <code>DIM</code>. Их адреса образуют ряд с шагом 8 — под скаляр отводится 8 байт независимо от того, числовой он или целый. Записи с нулевым адресом встречаются вперемешку с обычными; вероятно, это слоты, которым память не выделена.
| |
|
| |
| === Индексы переменных и их имена ===
| |
|
| |
| Переменные адресуются в коде однобайтовым индексом. Индексы назначаются '''в порядке первого появления переменной в тексте программы''', а не по алфавиту и не по типу.
| |
|
| |
| Для переменных, объявленных в <code>DIM</code>, это даёт прямое соответствие: операторы <code>DIM</code> перечисляют свои переменные подряд, в том же порядке, в каком они записаны в исходном тексте. В <code>EDITOR</code> семь операторов <code>DIM</code> занимают индексы <code>01</code>–<code>32</code> непрерывно; индекс <code>00</code> достался переменной <code>R2%</code>, встретившейся раньше — в строке 30, до первого <code>DIM</code>. В <code>ДЕМ6</code>, где до <code>DIM</code> переменных не было, нумерация начинается с <code>00</code>.
| |
|
| |
| {{Внимание|1='''Имена переменных в оттранслированном файле не сохраняются.''' Таблицы содержат дескрипторы памяти — адрес, тип, размер, — но не имена.
| |
|
| |
| Проверка на <code>EDITOR</code>, где программа сохранена одновременно в текстовом и оттранслированном виде: сопоставление 866 общих строк дало однозначное имя для 146 индексов из 160, и ни одно поле таблиц с этими именами не коррелирует. В таблице 1 поле по смещению 4–5 совпадает у <code>Y¤4</code> и <code>Z¤253</code> (72), у <code>D¤8</code> и <code>Q5¤40</code> (204); в таблице 2 последний байт записи совпадает у заведомо разных переменных (<code>D%</code> и <code>I%</code>, <code>J%</code> и <code>E</code>).
| |
|
| |
| Это согласуется с назначением параметра <code>T</code>: при выполнении имена не нужны, всё адресуется по индексу, а отказ от их хранения и даёт заявленную экономию места. Практическое следствие — '''читаемый листинг из оттранслированного файла восстановить нельзя'''. Восстанавливается структура программы, но переменные остаются безымянными, если не сохранилась текстовая версия того же исходника.}}
| |
|
| |
| === Записи строк ===
| |
|
| |
| Программа — последовательность записей, разделённых байтом '''<code>FE</code>'''. Перед первой записью разделителя нет.
| |
|
| |
| <номер строки: 2 байта BCD> <len: 1 байт> <тело>
| |
|
| |
| <code>len</code> считается '''включая сам байт len''' и до следующего <code>FE</code>. Следующий разделитель находится по адресу <code>адрес(len) + len</code>.
| |
|
| |
| В отличие от текстового представления, записи '''пересекают''' границу сектора; два служебных байта нового сектора в длину не входят.
| |
|
| |
| ==== Выравнивание в конце сектора ====
| |
|
| |
| Если до конца сектора остаётся слишком мало места, чтобы разместить трёхбайтовый заголовок очередной записи, остаток сектора заполняется нулями, а запись начинается с первого байта следующего сектора. Такие нули стоят '''после''' разделителя <code>FE</code> и в длину записи не входят.
| |
|
| |
| В файле <code>EDITOR</code> (1422 строки) это встречается 9 раз, все — на позициях 248–251 от начала содержимого сектора. Разборщик, не учитывающий выравнивание, теряет синхронизацию именно в этих местах.
| |
|
| |
| === Операторы ===
| |
|
| |
| Тело записи — последовательность операторов:
| |
|
| |
| <токен глагола: 1 байт> <len: 1 байт> <операнды: len байт>
| |
|
| |
| Здесь <code>len</code> — длина только операндов, сам байт len не считается. <code>len = 00</code> означает оператор без операндов, например голый <code>PRINT</code>.
| |
|
| |
| Наличие явной длины у каждого оператора позволяет разрезать программу на операторы, ещё не зная значений токенов. Эта особенность вынужденная: в отличие от Wang, где многословные команды собираются из нескольких токенов вперемешку с обычным ASCII и границы видны по самому потоку, у Искры весь текст программы переведён в токены и поток непрозрачен.
| |
|
| |
| ==== Пример разбора ====
| |
|
| |
| Строка 2000 файла <code>#СТАТИСТ</code>, длина 0x54 = 84:
| |
|
| |
| 20 00 54
| |
| 23 01 23 GOSUB ' 35
| |
| 4C 39 E3 1F «БУДЕТЕ …» DD 00 DD E3 12 «-[1] ИЛИ ДВУМЯ [2]» DD
| |
| PRINT "…";F¤;"…";
| |
| 41 01 5C INPUT F%
| |
| 36 03 5D D9 0E N7=N3
| |
| 24 06 0E D7 11 D3 20 01 IF N3<N6THEN2001
| |
| 36 03 5D D9 11 N7=N6
| |
|
| |
| Сумма: 3 + 59 + 3 + 5 + 8 + 5 = 83, плюс байт длины = 84.
| |
|
| |
| == Таблица токенов ==
| |
|
| |
| === Глаголы ===
| |
|
| |
| Основной массив значений восстановлен из прошивки интерпретатора (алфавитный список ключевых слов по смещению 0x1840 и 51-байтовый массив перестановки по 0x19B6). Отмеченные записи проверены или исправлены сопоставлением токенизированной и текстовой версий одной программы.
| |
|
| |
| {| class="wikitable"
| |
| ! Токен !! Оператор !! Примечание
| |
| |-
| |
| | <code>21</code> || GOTO || подтверждено
| |
| |-
| |
| | <code>22</code> || GOSUB || подтверждено
| |
| |-
| |
| | <code>23</code> || GOSUB' || в прошивочной таблице пропуск; значение выведено из данных
| |
| |-
| |
| | <code>24</code> || IF || подтверждено
| |
| |-
| |
| | <code>25</code> || KEYIN || подтверждено
| |
| |-
| |
| | <code>26</code> || ON || подтверждено
| |
| |-
| |
| | <code>27</code> || DEFFN' || подтверждено
| |
| |-
| |
| | <code>28</code> || PRINTUSING || в опубликованной таблице ошибочно указан GOSUB'; исправлено по данным
| |
| |-
| |
| | <code>29</code> || DATA || подтверждено
| |
| |-
| |
| | <code>2A</code> || SAVE ||
| |
| |-
| |
| | <code>2B</code> || RENUMBER ||
| |
| |-
| |
| | <code>2C</code> || CLEAR ||
| |
| |-
| |
| | <code>2D</code> || LOAD ||
| |
| |-
| |
| | <code>2E</code> || LIST ||
| |
| |-
| |
| | <code>2F</code> || RUN || подтверждено
| |
| |-
| |
| | <code>30</code> || RETURN CLEAR || подтверждено
| |
| |-
| |
| | <code>34</code> || ON ERROR || подтверждено
| |
| |-
| |
| | <code>35</code> || LET ||
| |
| |-
| |
| | <code>36</code> || ''(присваивание без ключевого слова)'' || подтверждено
| |
| |-
| |
| | <code>3F</code> || <code>%</code> (краткая форма REM) || подтверждено
| |
| |-
| |
| | <code>40</code> || $GIO ||
| |
| |-
| |
| | <code>41</code> || INPUT || подтверждено
| |
| |-
| |
| | <code>42</code> || STOP || подтверждено
| |
| |-
| |
| | <code>43</code> || AND( || подтверждено
| |
| |-
| |
| | <code>44</code> || READ || подтверждено
| |
| |-
| |
| | <code>45</code> || BOOL ||
| |
| |-
| |
| | <code>46</code> || DIM || подтверждено
| |
| |-
| |
| | <code>47</code> || CONVERT || подтверждено
| |
| |-
| |
| | <code>48</code> || PACK( || подтверждено
| |
| |-
| |
| | <code>4A</code> || ADD ||
| |
| |-
| |
| | <code>4B</code> || BIN( ||
| |
| |-
| |
| | <code>4C</code> || PRINT || подтверждено
| |
| |-
| |
| | <code>4D</code> || ROTATE || подтверждено
| |
| |-
| |
| | <code>4E</code> || COM ||
| |
| |-
| |
| | <code>50</code> || HEXPRINT ||
| |
| |-
| |
| | <code>51</code> || RESTORE || подтверждено
| |
| |-
| |
| | <code>52</code> || NEXT || подтверждено
| |
| |-
| |
| | <code>53</code> || REWIND ||
| |
| |-
| |
| | <code>54</code> || SELECT || подтверждено
| |
| |-
| |
| | <code>55</code> || BACKSPACE ||
| |
| |-
| |
| | <code>56</code> || REM || подтверждено
| |
| |-
| |
| | <code>57</code> || FOR || подтверждено
| |
| |-
| |
| | <code>58</code> || SKIP ||
| |
| |-
| |
| | <code>59</code> || END ||
| |
| |-
| |
| | <code>5A</code> || DEFFN ||
| |
| |-
| |
| | <code>5C</code> || RES ||
| |
| |-
| |
| | <code>5D</code> || UNPACK( || подтверждено
| |
| |-
| |
| | <code>5E</code> || RETURN || подтверждено
| |
| |-
| |
| | <code>5F</code> || TRACE ||
| |
| |-
| |
| | <code>61</code> || OR( ||
| |
| |-
| |
| | <code>62</code> || XOR( ||
| |
| |-
| |
| | <code>64</code> || INIT || подтверждено
| |
| |-
| |
| | <code>66</code> || DATA LOAD BT || подтверждено
| |
| |-
| |
| | <code>68</code> || DATA SAVE BT || подтверждено
| |
| |-
| |
| | <code>6D</code> || COPY ||
| |
| |-
| |
| | <code>6E</code> || DATA SAVE BA || подтверждено
| |
| |-
| |
| | <code>70</code> || DATA LOAD BA || подтверждено
| |
| |-
| |
| | <code>71</code> || DATA LOAD DA || подтверждено
| |
| |-
| |
| | <code>74</code> || DATA LOAD DC || выведено из данных
| |
| |-
| |
| | <code>75</code> || DATA LOAD DC OPEN T || выведено из данных
| |
| |-
| |
| | <code>79</code> || DBACKSPACE ||
| |
| |-
| |
| | <code>7A</code> || DSKIP ||
| |
| |-
| |
| | <code>7B</code> || LIMITS || подтверждено
| |
| |-
| |
| | <code>7D</code> || LOAD DC || выведено из данных
| |
| |-
| |
| | <code>7E</code> || MOVE ||
| |
| |-
| |
| | <code>80</code> || SAVE DC || выведено из данных
| |
| |-
| |
| | <code>81</code> || SCRATCH ||
| |
| |-
| |
| | <code>83</code> || VERIFY ||
| |
| |}
| |
|
| |
| Пометка «подтверждено» означает сверку с текстовым листингом той же программы. Основная часть подтверждений получена на файле <code>EDITOR</code> автоматическим сопоставлением 866 общих строк: в строках, где число операторов в обоих представлениях совпало, первый глагол каждого оператора сверялся с первым словом соответствующего оператора текста. Так подтверждены 34 значения, включая <code>21</code> = GOTO (147 совпадений), <code>4C</code> = PRINT (212), <code>24</code> = IF (266).
| |
|
| |
| Отдельно стоит краткая форма комментария <code>%</code> (токен <code>3F</code>): она встречается в <code>EDITOR</code> 122 раза против 7 у полного <code>REM</code> (токен <code>56</code>), и её операнд записывается сырым текстом без префикса <code>E3</code> — так же, как у <code>REM</code>.
| |
|
| |
| Значения назначены не по алфавиту, а тематическими группами с запасом внутри каждой: управление ходом выполнения в 0x21–0x2F, ввод-вывод около 0x41–0x4C, дисковые операции в 0x74–0x83. Составные дисковые команды получают '''один''' токен на всю фразу, тогда как в Wang та же команда собирается из нескольких (<code>DATA</code> + <code>LOAD</code> + <code>DC</code>).
| |
|
| |
| Документация<ref name="balasanyan" /> описывает также операторы <code>DATA SAVE DC END</code>, <code>DATA SAVE DC CLOSE</code> и <code>DATA LOAD DC OPEN</code>. Последний соответствует найденному токену <code>75</code>, поэтому остальные с высокой вероятностью занимают свободные значения в диапазоне 0x70–0x78 — при разборе новых файлов имеет смысл проверять этот участок в первую очередь.
| |
|
| |
| === Операнды ===
| |
|
| |
| {| class="wikitable"
| |
| ! Токен !! Значение !! Достоверность
| |
| |-
| |
| | <code>00</code>–<code>~BF</code> || ссылка на переменную по индексу || подтверждено
| |
| |-
| |
| | <code>CC</code> || GOSUB в составе <code>ON … GOSUB</code> || подтверждено
| |
| |-
| |
| | <code>CD</code> || GOTO в составе <code>ON … GOTO</code> || подтверждено
| |
| |-
| |
| | <code>D0</code> || <code>)</code> || вероятно
| |
| |-
| |
| | <code>D1</code> || TO || подтверждено
| |
| |-
| |
| | <code>D3</code> || THEN, далее 2 байта BCD — номер строки || подтверждено
| |
| |-
| |
| | <code>D4</code> || <code>></code> || вероятно
| |
| |-
| |
| | <code>D5</code> || <code><></code> в позиции операции, <code>AT(</code> в позиции операнда || подтверждено
| |
| |-
| |
| | <code>D6</code>, <code>D8</code> || остальные знаки сравнения || вероятно
| |
| |-
| |
| | <code>D7</code> || <code><</code> || подтверждено
| |
| |-
| |
| | <code>D9</code> || <code>=</code> || подтверждено
| |
| |-
| |
| | <code>DB</code> || <code>#</code> || подтверждено
| |
| |-
| |
| | <code>DC</code> || <code>/</code> || вероятно
| |
| |-
| |
| | <code>DD</code> || <code>;</code> || подтверждено
| |
| |-
| |
| | <code>DE</code> || <code>,</code> || подтверждено
| |
| |-
| |
| | <code>DF</code> || <code>*</code> в позиции операции, <code>TAB(</code> в позиции операнда || подтверждено
| |
| |-
| |
| | <code>E0</code> || <code>^</code> в позиции операции, ссылка на массив целиком в позиции операнда || подтверждено
| |
| |-
| |
| | <code>E1</code> || функция <code>STR</code> || подтверждено
| |
| |-
| |
| | <code>E2</code> || шестнадцатеричный литерал <code>HEX(…)</code>: <code>E2 <len> <len байт></code> || подтверждено
| |
| |-
| |
| | <code>E3</code> || строковый литерал: <code>E3 <len> <len байт КОИ-8></code> || подтверждено
| |
| |-
| |
| | <code>E5</code> || число с фиксированной точкой, см. ниже || подтверждено
| |
| |-
| |
| | <code>E6</code> || число с порядком, см. ниже || подтверждено
| |
| |-
| |
| | <code>E7</code> || числовая константа: <code>E7 <2 байта BCD></code>, диапазон 0–9999 || подтверждено
| |
| |-
| |
| | <code>E8</code> || числовая константа: <code>E8 <байт BCD></code>, диапазон 0–99 || подтверждено
| |
| |-
| |
| | <code>E9</code> || <code>-</code>, бинарный или унарный || подтверждено
| |
| |-
| |
| | <code>EA</code> || <code>+</code> || вероятно
| |
| |-
| |
| | <code>EB</code> || <code>(</code> || вероятно
| |
| |-
| |
| | <code>F2</code> || <code>ABS(</code> || подтверждено
| |
| |-
| |
| | <code>F3</code> || <code>INT(</code> || подтверждено
| |
| |-
| |
| | <code>F6</code> || <code>SQR(</code> || подтверждено
| |
| |-
| |
| | <code>F7</code> || <code>LOG(</code> || подтверждено
| |
| |-
| |
| | <code>FE</code> || разделитель записей строк || подтверждено
| |
| |}
| |
|
| |
| === Двузначность токенов старшей половины ===
| |
|
| |
| Часть токенов диапазона <code>D0</code>–<code>EF</code> читается по-разному в зависимости от того, ожидается ли на их месте знак операции или очередной операнд. Интерпретатор различает их по состоянию разбора, отдельного признака в файле нет.
| |
|
| |
| {| class="wikitable"
| |
| ! Токен !! В позиции операции !! В позиции операнда
| |
| |-
| |
| | <code>DF</code> || <code>*</code> || <code>TAB(</code>
| |
| |-
| |
| | <code>D5</code> || <code><></code> || <code>AT(</code>
| |
| |-
| |
| | <code>E9</code> || <code>-</code> бинарный || <code>-</code> унарный
| |
| |-
| |
| | <code>E0</code> || <code>^</code> || ссылка на массив целиком
| |
| |}
| |
|
| |
| Ссылка на массив целиком записывается как <code>E0</code> и порядковый номер переменной в <code>DIM</code>: <code>74 02 E0 09</code> соответствует <code>DATA LOAD DC G¤()</code>, а <code>E0 09 D1 E0 00</code> — <code>G¤()TOX()</code>.
| |
|
| |
| Каждое прочтение подтверждено не менее чем двумя независимыми строками <code>STAT05</code>: <code>TAB(17)</code> кодируется как <code>DF E8 17 D0</code>, а <code>.5*LOG(</code> — как <code>E5 01 50 DF F7</code>; <code>K(1)<>1</code> и <code>PRINT AT(9,10)</code> оба дают <code>D5</code>; <code>K0*(-1)</code> даёт <code>DF EB E9 E8 01 D0</code>, где <code>E9</code> стоит в позиции операнда.
| |
|
| |
| Разборщик с одним фиксированным значением на токен на таких строках даёт неверный листинг, поэтому таблицу операндов нужно применять с учётом позиции.
| |
|
| |
| У дисковых операторов (<code>7D</code>, <code>80</code>, <code>81</code>) первый операнд — идентификатор дисковода: <code>0</code> означает <code>F</code>, <code>1</code> — <code>R</code>.
| |
|
| |
| === Числовые константы ===
| |
|
| |
| Целые константы кодируются двумя токенами в зависимости от величины: <code>E8</code> — один байт BCD (0–99), <code>E7</code> — два байта BCD (0–9999).
| |
|
| |
| Для дробных чисел служат токены <code>E5</code> и <code>E6</code>. За токеном следует байт-описатель, затем цифры числа в BCD по две на байт; если цифр нечётное число, последняя тетрада заполняется нулём. В описателе '''старшая тетрада — количество цифр до запятой, младшая — общее количество цифр'''.
| |
|
| |
| {| class="wikitable"
| |
| ! Запись !! Байты !! Описатель !! Цифры
| |
| |-
| |
| | <code>.5</code> || <code>E5 01 50</code> || 0 / 1 || 5
| |
| |-
| |
| | <code>.08</code> || <code>E5 02 08</code> || 0 / 2 || 08
| |
| |-
| |
| | <code>2.5</code> || <code>E5 12 25</code> || 1 / 2 || 25
| |
| |-
| |
| | <code>.196854</code> || <code>E5 06 19 68 54</code> || 0 / 6 || 196854
| |
| |-
| |
| | <code>.000344</code> || <code>E5 06 00 03 44</code> || 0 / 6 || 000344
| |
| |}
| |
|
| |
| Токен <code>E6</code> устроен так же, но после цифр мантиссы идёт дополнительный байт порядка: <code>1E6</code> кодируется как <code>E6 11 10 06</code> — одна цифра мантиссы, одна цифра до запятой, порядок 6.
| |
|
| |
| Номер метки в <code>GOSUB'</code> хранится '''двоичным''', а не в BCD.
| |
|
| |
| === Подпрограммы с параметрами ===
| |
|
| |
| Аргументы <code>GOSUB'</code> следуют сразу за байтом метки и разделяются токеном <code>DE</code>; скобки не кодируются. Вызов <code>GOSUB ' 5(1,1,N-2)</code> даёт:
| |
|
| |
| 23 0B 05 E8 01 DE E8 01 DE 0D E9 E8 02
| |
|
| |
| Объявление <code>DEFFN'</code> содержит метку, четыре нулевых байта и индексы формальных параметров. Нули, по-видимому, отведены под адрес возврата, заполняемый при выполнении. Объявление <code>DEFFN ' 5(N1,D1,D2)</code> даёт:
| |
|
| |
| 27 08 05 00 00 00 00 12 20 21
| |
|
| |
| Оператор <code>ON … GOTO</code> кодируется как индекс переменной, токен <code>CD</code> и номера строк по два байта BCD подряд без разделителей.
| |
|
| |
| === Индексация массивов ===
| |
|
| |
| У обращения к элементу массива '''нет открывающей скобки''': ссылка на переменную сама открывает список индексов, а <code>D0</code> его закрывает.
| |
|
| |
| 01 32 D0 → 01(32)
| |
| 2A 03 E8 01 D0 D0 → 2A(03,1)
| |
|
| |
| Токен <code>EB</code> используется только как группирующая скобка в выражениях:
| |
|
| |
| EB 34 E9 33 E9 E8 01 D0 → (34*33*1)
| |
|
| |
| Разборщик, ожидающий <code>EB</code> перед индексом массива, рассинхронизируется.
| |
|
| |
| == Поток значений переменных ==
| |
|
| |
| Секторы, следующие за программой в токенизированном файле, содержат значения переменных, записанные в том же формате, что и обычные файлы данных. Структура описана в документации<ref name="balasanyan" />.
| |
|
| |
| Служебная информация в секторе двух видов:
| |
|
| |
| * '''идентификатор сектора''' — 1 байт в начале сектора, значение <code>02</code> (признак данных);<ref name="vtoraya" /> под данные остаются 255 байт;
| |
| * '''идентификатор значения''' — 2 байта перед каждым значением, содержат тип (числовое или символьное) и длину.
| |
|
| |
| Размеры значений:
| |
|
| |
| {| class="wikitable"
| |
| ! Тип !! Значение !! Со служебными байтами !! Значений в секторе
| |
| |-
| |
| | целое || 2 байта || 4 байта || 63
| |
| |-
| |
| | действительное || 8 байт || 10 байт || 25
| |
| |-
| |
| | символьное || длина значения || длина + 2 || —
| |
| |}
| |
|
| |
| Значение, не помещающееся в секторе целиком, переносится в следующий сектор полностью. Элементы массивов записываются построчно.
| |
|
| |
| === Пример ===
| |
|
| |
| В файле <code>DIG DEM</code> сектор данных начинается с идентификатора сектора <code>02</code>, за которым идут 25 записей по 10 байт:
| |
|
| |
| 00 08 <8 байт значения>
| |
|
| |
| Идентификатор <code>00 08</code> означает числовое значение длиной 8 байт. Двадцать пятая запись заканчивается на пятом байте от конца сектора, оставшиеся 5 байт не используются: 1 + 25 × 10 + 5 = 256. Расчёт сходится точно и подтверждает однобайтовую длину идентификатора сектора.
| |
|
| |
| == Алгоритм разбора ==
| |
|
| |
| # Прочитать запись каталога: первый и последний сектор, тип должен быть <code>80</code>.
| |
| # Прочитать первый сектор: проверить байт 0 = <code>01</code>, взять имя, прочитать байт 9.
| |
| # Если байт 9 = <code>20</code>: склеить содержимое секторов, разбить по <code>85</code>, отбросить нули, перекодировать КОИ-8. Готово.
| |
| # Если байт 9 = <code>21</code>: собрать поток из секторов с байтом 1 = <code>80</code>; прочитать L1, L2, L3; перейти к смещению <code>6 + L1 + L2 + L3</code>.
| |
| # Для каждой записи: номер строки из двух байтов BCD, длина из третьего, тело до следующего <code>FE</code>. Если по отсчитанной длине не оказалось <code>FE</code> — поток рассинхронизирован, разбор остановить.
| |
| # После <code>FE</code> пропустить нулевые байты выравнивания, если следующая запись не помещалась в остаток сектора.
| |
| # Тело разрезать на операторы по схеме <code><глагол><len><операнды></code>.
| |
|
| |
| Обработку файла следует прекращать на '''первом''' встреченном секторе с маркером <code>1C</code>, а не доходить до конца выделенного диапазона: за control record могут лежать остатки предыдущей, более длинной версии файла.
| |
|
| |
| Число записей в таблицах 2 и 3 равно <code>L2 / 4</code> и <code>L3 / 4</code> — запись в них вдвое короче, чем в таблице 1.
| |
|
| |
| Байт длины в каждой записи и в каждом операторе даёт бесплатную проверку целостности на каждом шаге.
| |
|
| |
|
| == Отличия от Wang 2200 == | | == Отличия от Wang 2200 == |
| Строка 718: |
Строка 229: |
| | Запись каталога || 16 байт || совпадает побайтово | | | Запись каталога || 16 байт || совпадает побайтово |
| |- | | |- |
| | Маркер control record || <code>20</code> || <code>1C</code> | | | Хеш имени || «старый» и «новый» || только «старый» |
| | |- |
| | | Маркер концевой записи || <code>20</code> || <code>1C</code> |
| |- | | |- |
| | Маркер заголовка || <code>40</code> (<code>50</code> для защищённых) || <code>01</code> | | | Маркер заголовка || <code>40</code> (<code>50</code> для защищённых) || <code>01</code> |
| Строка 724: |
Строка 237: |
| | Маркеры секторов || битовое поле в старшей тетраде || отдельные значения <code>02</code>/<code>8F</code>/<code>03</code> | | | Маркеры секторов || битовое поле в старшей тетраде || отдельные значения <code>02</code>/<code>8F</code>/<code>03</code> |
| |- | | |- |
| | Конец строки в программе || <code>0D 00 00</code> || <code>FE</code> как разделитель | | | Представление программы || ключевые слова в токенах, остальное ASCII || несовместимо, см. [[Оттранслированное представление BASIC 02]] |
| |-
| |
| | Конец блока || <code>FD</code> (EOB) / <code>FE</code> (EOD) || не используется
| |
| |-
| |
| | Диапазон токенов || 0x80–0xFB, 124 значения || глаголы 0x21–0x83, операнды 0xD0–0xEB
| |
| |-
| |
| | Текст в программе || ключевые слова в токенах, остальное обычный ASCII || всё в токенах, ASCII только внутри строковых литералов
| |
| |-
| |
| | Переменные || имена в открытом виде || индексы в таблицу, имена не хранятся
| |
| |-
| |
| | Длина оператора || отсутствует || обязательный байт после каждого глагола
| |
| |} | | |} |
|
| |
|
| Таблицы токенов не имеют между собой ничего общего: систематического сдвига нет, совпадений по отдельным байтам нет. Инструментарий Wang для детокенизации переиспользовать нельзя. Совпадает только уровень файловой системы.
| | Совпадает только уровень файловой системы. Инструментарий Wang для разбора самих программ непригоден. |
| | |
| Вероятная причина расхождения — кодировка. В Wang верхняя половина таблицы свободна и отдана под ключевые слова; у Искры она занята кириллицей, поэтому глаголы перенесены вниз, а от литерального ASCII в потоке отказались полностью.
| |
| | |
| == Не установлено ==
| |
| | |
| # Полная таблица токенов: часть значений в диапазонах 0x31–0x33, 0x37–0x3E, 0x49, 0x4F, 0x5B, 0x60, 0x63, 0x65, 0x67, 0x69–0x6C, 0x72, 0x73, 0x76–0x78, 0x7C, 0x7F, 0x82 не занята в известной таблице.
| |
| # Смысл поля по смещению 4–5 записи таблицы 1 у скалярных переменных: у массивов там число элементов, у скаляров значения повторяются у разных переменных и с именем не связаны. В <code>STAT05</code> у десяти скалярных строк это поле образует убывающую последовательность с шагом 6 в порядке объявления (205, 200, 194, 188, …, 152) независимо от их длин, что указывает скорее на указатель, чем на характеристику самой переменной.
| |
| # Назначение байтов 2–3 записей таблиц 2 и 3 и шести записей таблицы 1 с типами <code>59 07</code> и <code>27 01</code>.
| |
| # Кодировка типа переменной у двумерных массивов: байты 2–3 заняты второй размерностью, признака типа в записи не остаётся. Символьный двумерный массив в материале не встретился.
| |
| # Причина, по которой переменные, переопределённые оператором <code>MAT REDIM</code>, получают в токенах <code>DIM</code> индексы из диапазона <code>40</code> и выше.
| |
| # Точное соответствие индексов переменных записям таблицы 2.
| |
| # Природа двухбайтового хвоста без префикса в конце каждого оператора <code>DATA</code> (<code>C9 04</code>, <code>EE 04</code>, <code>00 00</code> в <code>ДЕМ6</code>): в длину оператора он входит, но ни под <code>E7</code>, ни под <code>E8</code> не подходит.
| |
| # Причина различия разметки секторов между токенизированными и текстовыми потоками: в текстовых файлах наблюдается позиционная схема <code>02</code>/<code>8F</code>/<code>03</code>, в токенизированных все секторы программы идут с маркером <code>02</code>.
| |
| # Токены операторов <code>DATA SAVE DC END</code> и <code>DATA SAVE DC CLOSE</code>.
| |
|
| |
|
| == Примечания == | | == Примечания == |
|
| |
|
| <references> | | <references> |
| <ref name="balasanyan">Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987. — 264 с.: ил. — разделы 5.1, 5.2, 11.5, 18.1, 18.4, 18.7.</ref> | | <ref name="balasanyan">Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987. — 264 с.: ил.</ref> |
| <ref name="vtoraya">Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение: справочное руководство. — Киев, 1988. — структура программного файла и файла данных, значения признака защиты.</ref> | | <ref name="vtoraya">Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение: справочное руководство. — Киев, 1988.</ref> |
| </references> | | </references> |
|
| |
|
| == Источники == | | == Источники == |
|
| |
|
| * Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987. — 264 с.: ил. | | * Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987. |
| * Реконструкция по образам дисков: файлы <code>TRANSFER</code>, <code>ФС</code> (текстовые), <code>DIG DEM</code>, <code>#СТАТИСТ</code>, <code>ДЕМ6</code> (токенизированные), <code>EDITOR</code> (сохранён в обоих представлениях — 182 сектора, 1422 строки; основной материал для проверки структуры таблиц и таблицы токенов), <code>STAT05</code> (защищённый и оттранслированный, с расчётами с плавающей точкой; материал для разбора формата констант и двузначности токенов), <code>STAT01A</code> (защищённый и оттранслированный; единственный образец с двумерным массивом и с переменными, переопределёнными через <code>MAT REDIM</code>).
| | * Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение. — Киев, 1988. |
| | | * [http://www.wang2200.org/disk_org.html Wang 2200 Disk Organization] — файловая система и хеш имени для сопоставления. |
| Дамп <code>STAT01A</code> снят с удалённого файла, поэтому его целостность не гарантирована; выводы по нему опираются только на таблицу 1 и операторы <code>DIM</code>, взаимно согласованные по всем 23 объявленным переменным.
| | * Реконструкция по 42 образам дисков: 303 записи каталога, 94 файла программ. |
| | |
| При сверке представлений следует учитывать, что текстовая и оттранслированная копии одной программы на диске могут относиться к разным её версиям. В <code>STAT05</code> текстовый листинг строки 240 содержит вызов <code>ABS</code>, отсутствующий в оттранслированной копии, что подтверждается длиной оператора.
| |
| * Таблица глаголов — из прошивки интерпретатора, по материалам проекта [https://github.com/elaranovikova/iskra226 elaranovikova/iskra226].
| |
| * Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение: справочное руководство. — Киев, 1988. | |
| * Структура файловой системы Wang для сопоставления — [http://www.wang2200.org/disk_org.html Wang 2200 Disk Organization]. | |
|
| |
|
| [[Категория:Искра-226]] | | [[Категория:Искра-226]] |
|
Этот документ создан для Emuverse и распространяется на условиях лицензии CC-BY-SA-3.0.
|
Файловая система Искры 226 — способ хранения файлов на дисках Искра-226. Унаследована от Wang 2200 и совпадает с ней побайтово; содержимое файлов — оригинальное и с Wang несовместимо.
Статья описывает файловую систему, указатель каталога и текстовое представление программ. Отдельно вынесены:
Диск
Физический сектор — 128 байт; 77 дорожек по 26 секторов, одна сторона. Физические сектора попарно объединены в логические по 256 байт со сквозной нумерацией. Далее везде подразумеваются логические сектора. Полный объём тома — 1001 сектор, 256 256 байт.
Типы файлов:
- ПФ — программный файл: программа на Бейсике в текстовом либо оттранслированном виде;
- ФД — файл данных.
Файлу выделяется непрерывный диапазон секторов, границы записаны в указателе каталога.
| Сектор |
Содержимое
|
| первый |
заголовок файла
|
| следующие N |
поток содержимого
|
| … |
резерв, нули
|
| последний выделенный |
концевая запись
|
Размер файла на диске не меняется, поэтому при перезаписи более коротким содержимым хвост не затирается: там остаются фрагменты предыдущих версий, иногда в другом представлении. Обработку следует прекращать на первой встреченной концевой записи.
Диски прямого доступа (запись по абсолютным адресам секторов) указателя каталога не имеют; формат содержимого таких дисков задаёт программа пользователя. Загрузочные диски с интерпретатором имеют собственный формат: нулевой сектор начинается сигнатурой 06 90 09 90 07 90, за ней 18 знаков имени и даты версии.
Указатель каталога
Начинается с сектора 0. Первые 16 байт нулевого сектора — параметры диска:
| Смещение |
Размер |
Значение
|
| 0–1 |
2 |
размер указателя каталога в секторах (LS), старший байт первым
|
| 2–3 |
2 |
текущий конец каталога — первый свободный сектор
|
| 4–5 |
2 |
конец области каталога
|
| 6–15 |
10 |
нули
|
Размер указателя задаётся при создании каталога оператором SCRATCH DISK параметром LS=, по умолчанию 24, допустимо 1…255; в дальнейшем не меняется. В нулевом секторе помещается 15 записей, в остальных 16. Неиспользованные записи заполнены нулями.
Записи не сгруппированы в начале указателя и не упорядочены по секторам файлов: номер сектора, в который попадает запись, вычисляется хешированием имени. Для чтения каталога надо пройти все его секторы, пропуская нулевые записи.
Хеш имени файла
Номер сектора указателя вычисляется по «старому» хешу Wang 2200:
имя дополнить пробелами до восьми байт
tmp = 0
для каждого байта имени: tmp = tmp XOR байт
tmp = 3 × tmp
tmp = (tmp mod 256) + (tmp div 256)
сектор = tmp mod LS
Свёртка выполняется исключающим ИЛИ, не сложением. «Новый» хеш Wang, введённый в MVP OS 2.5, на Искре не применяется.
Хеш вырождается при LS, кратном трём: после умножения на 3 и складывания половинок результат всегда кратен трём, поэтому занятыми оказываются только каждый третий сектор указателя. При LS = 24 все записи попадают в секторы 0, 12, 15 и 18.
Запись кладётся в первый свободный слот своего сектора, слоты заполняются подряд от начала. Правило переполнения сектора неизвестно.
Освобождение слота выполняется обнулением первых восьми байт записи; имя при этом остаётся на диске. Оператор SCRATCH запись не обнуляет, а помечает.
Запись каталога
16 байт, совпадает с Wang 2200.
| Смещение |
Размер |
Значение
|
| 0 |
1 |
статус, битовое поле; бит 0 — файл вычеркнут
|
| 1 |
1 |
тип файла: 80 — программа, 00 — данные
|
| 2–3 |
2 |
первый сектор файла, старший байт первым
|
| 4–5 |
2 |
последний сектор файла, старший байт первым
|
| 6–7 |
2 |
не используются
|
| 8–15 |
8 |
имя файла, дополнено пробелами справа
|
Наблюдаемые значения статуса: 10 — активна, 11 и 21 — вычеркнута, 00 — свободна. Сравнивать статус на точное равенство нельзя, значим только бит 0. Бит 5 (значение 21) предположительно помечает переименование.
Байт типа не различает текстовое и оттранслированное представление программы: у обоих 80.
Оператор LIST DC выводит типы как P (программный), D (данные), SP и SD (вычеркнутые), что соответствует сочетанию байта статуса и байта типа.[1]
Тип «данные» ничего не говорит о внутреннем устройстве файла: он может содержать как логические записи, так и сырые блоки, записанные оператором DATA SAVE BA.
Пример
0 1 2 3 4 5 6 7 8 9 A B C D E F
10 80 00 31 00 3F 00 00 44 49 47 20 44 45 4D 20
└───┘ └───┘ └───┘ └─────────────────────┘
Активная запись, программа, секторы 49…63, имя DIG DEM.
Размещение файлов
- Файлы лежат подряд в порядке создания, диапазоны секторов не пересекаются.
- Место вычеркнутого файла заново не занимается:
SCRATCH только помечает запись.
- Первый файл начинается с сектора
LS, сразу за указателем.
- Поле «текущий конец» равно последнему занятому сектору плюс единица, но обрезается по концу области каталога; при разборе границу надёжнее брать по записям каталога.
Заголовочный сектор
| Смещение |
Значение
|
| 0 |
01
|
| 1–8 |
имя файла, дополнено пробелами
|
| 9 |
признак формата записи
|
| 10–255 |
нули
|
Байт 9 (в справочнике[2] назван «признак защиты») — битовое поле, единственный признак, различающий два представления программы: бит 0 — программа оттранслирована (параметр T оператора SAVE DC), бит 2 — защищена (параметр P); оба вместе соответствуют параметру G.
| Значение |
Символ |
Защита |
Представление
|
20 |
пробел |
нет |
текстовое
|
21 |
! |
нет |
оттранслированное
|
24 |
¤ |
есть |
текстовое
|
25 |
% |
есть |
оттранслированное
|
Значения 22 и 23 не используются. Текстовое представление — режим по умолчанию, оттранслированное включается явным параметром T.
Защищённая программа после загрузки может только выполняться; режим снимается оператором CLEAR.
Секторы потока
Первые два байта каждого сектора программного потока — служебные, в содержимое не входят. У секторов файла данных служебный заголовок занимает один байт.
Байт 0 — позиция сектора:
| Код |
Смысл
|
02 |
первый сектор потока
|
03 |
последний сектор потока
|
1C |
концевая запись
|
8B |
запись целиком в одном секторе (только файлы данных)
|
8F |
промежуточный сектор
|
В оттранслированных программах все секторы потока идут с маркером 02. Позиционная разметка 02/8F/03 наблюдается в текстовых файлах и в потоках данных.
Байт 1 программных секторов равен 80. Как признак «программа или данные» он непригоден: у секторов данных на позиции 1 стоит первый байт идентификатора значения. Надёжные признаки — байт 9 заголовочного сектора и байт типа записи каталога.
Концевая запись
1C <длина: 2 байта, старший первым>
Остаток сектора — нули. Соответствует по роли байту 20 в Wang.
Счётчик равен собственной позиции записи от начала файла, считая с единицы, то есть числу занятых секторов вместе с заголовком. Он же — графа «Использовано» в выдаче LIST DC.
- У программных файлов концевую запись пишет сам оператор
SAVE DC; она есть всегда.
- У файлов данных её пишет прикладная программа оператором
DATA SAVE DC END. Если признак конца не записан, в графе «Использовано» стоит 00001.
- Оператор
DATA SAVE DC OPEN пишет в последний сектор файла запись 1C 00 01 — единственный случай, когда счётчик не равен позиции.
Запись лежит не обязательно в последнем выделенном секторе: если файлу дали запас или его положили на место вычеркнутого файла большего размера, за ней остаётся нулевой хвост.
Счётчик — не инвариант файловой системы и при разборе ненадёжен: у файлов, записанных не операторами DATA SAVE DC, он произволен. Границы файла следует брать из каталога.
Текстовое представление
Программа хранится плоским текстом. Кодировка — КОИ-8 (ГОСТ 19768-74): прописная кириллица в E0–FF, строчная в C0–DF. Номера строк записаны обычными цифрами.
- Разделитель строк — байт
85.
- Строка не пересекает границу сектора; хвост сектора заполняется нулями.
- Байт
24 ($) отображается на экране Искры как ¤.
Байт 85 свободен потому, что диапазон 80–9F в КОИ-8 не занят. Тем же байтом машина разделяет строки в символьном буфере операторов SAVE и LOAD и выдаёт нажатие клавиши CR/LF.
Разбор: склеить содержимое секторов, отбрасывая по два служебных байта, разбить по 85, отбросить нули.
Пример
02 80 35 20 52 45 4D 20 F0 E5 F4 F2 E5 EE EB EF … 85 38 20 50 52 49 4E 54 …
Заголовок сектора, затем 5 REM ПЕТРЕНКО …, разделитель, 8 PRINT ….
Виды дисков
| Вид |
Признак
|
| с каталогом |
байты 0–1 нулевого сектора — разумный LS, дальше 16-байтовые записи
|
| загрузочный |
сектор 0 начинается с 06 90 09 90 07 90
|
| пакет ассемблера |
сектор 0 начинается с 7E E1 F3 ED E2 (~АСМБ)
|
| прямого доступа |
каталога нет, есть заголовочные секторы 01 <имя> <признак>
|
| пустой |
нули
|
Отличия от Wang 2200
|
Wang 2200 |
Искра-226
|
| Запись каталога |
16 байт |
совпадает побайтово
|
| Хеш имени |
«старый» и «новый» |
только «старый»
|
| Маркер концевой записи |
20 |
1C
|
| Маркер заголовка |
40 (50 для защищённых) |
01
|
| Маркеры секторов |
битовое поле в старшей тетраде |
отдельные значения 02/8F/03
|
| Представление программы |
ключевые слова в токенах, остальное ASCII |
несовместимо, см. Оттранслированное представление BASIC 02
|
Совпадает только уровень файловой системы. Инструментарий Wang для разбора самих программ непригоден.
Примечания
- ↑ Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987. — 264 с.: ил.
- ↑ Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение: справочное руководство. — Киев, 1988.
Источники
- Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987.
- Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение. — Киев, 1988.
- Wang 2200 Disk Organization — файловая система и хеш имени для сопоставления.
- Реконструкция по 42 образам дисков: 303 записи каталога, 94 файла программ.