Pull to refresh
Comments 78
Причина выяснена, объяснение (весьма упрощенное, конечно) дано ближе к концу статьи. На самом деле, поскольку есть полная модель процессора в Verilog (благодаря реверсу, который Вячеслав проделал), можно пройтись по всем деталям.
С этого помента поподробнее — о каком реверсе идёт речь? Насколько я знаю копировали КР580ВМ80А, калькуляторы (МК-54, МК-61), а вот с БК вроде на этом уровне никто не работал… или работал?
Ого. Круто. Интересно — никто не пытался эмулятор поверх этого устроить? Слишком медленно получается или «не особо и нужно»?

Любители калькуляторов таки создали себе эмулятор с ЕГГОГами и «оборотнями», а БК пока отстаёт…
На моей памяти, на форуме ZX-PK.ru обсуждалась такая возможность. По-моему, как раз в теме, на которую сослался Wesha.

Кстати, о птицах: я буквально недавно получил обратно свои БКшные кассеты тогдашних лет, написал (на Ruby) с ленты, и сейчас потихоньку считываю свою коллекцию с лент.

Эти #$@ (форумные администраторы) отключили регистрацию. Оставил заявку неделю назад — молчание. (А мне есть чего сказать: например, в описании протокола по этой ссылке есть фактические ошибки.


Пока что размещаю на гитхабе.

Я заметил только два отличия между моим и Вашим описанием:
1. длина конечного тона у меня 128, а у Вас 256,
2. скважность нулевого импульса у Вас 1:1, а у меня 2:1.
Но это не «ошибки», это оптимизация. Я трассировал ПЗУшную подпрограмму чтения, а не записи, чтобы оптимизировать входные данные (то есть для меня не важно как записывает на ленту стандартная ПЗУшная процедура). В том виде, в котором я описал, данные пригодны для чтения, но занимают меньше.

А я — подпрограмму записи (кстати, очень легкая для понимания!), и там это выглядит так:


1) у Вас нарисовано, что синхробит идёт перед импульсом данных. На самом деле он идёт после. Дело в том, что любые биты выводятся с последующим синхробитом (подпрограмма одна и та же ж!) — в том числе и вот эта единица в конце — и они поменялись местами: у Вас [ пилот, ограничивающий импульс, 1 ] + [ (0, импульс данных), (0, импульс данных),… ], и последний 0-импульс приклеился к "pilotone (9)" — у меня (ещё до того, как я начал освежать код в памяти) с самого начала были подозрения — а с какого перепугу у Вас там число ипульсов не круглое (в восьмеричной системе, конечно). А на деле — выводится [ пилот, ограничивающий импульс, 1, 0 ] + [ (импульс данных, 0), (импульс данных, 0)… ], и следующий маркер должен быть "pilotone (8)".


2) У Вас нарисовано, что после "DATA (file)" сразу идёт "DATA (checksum)". Это неправильно, товарищи, надо говорить "ширее" после контрольной суммы идёт ещё один маркер, точно такой же, как и перед ней.


3) У Вас в конце файла идёт "pilotone(128)", а на самом деле идёт там должно быть [ "end tone четверной длины", "pilotone(256)", 1, 0 ] — но это уже непринципиально, т.к. этот маркер Неуловимый Джо мало кто вообще читает.


Я понимаю, что для чтения Ваши ошибки непринципиальны — но мы же составляем документацию, в которой должно описываться, как вещи оказываются такими, какими они есть, а не только то, что мы видим в результате. Разница в том, что если бы Вы писали документацию на ядерную бомбу, она при вашем подходе она была бы в стиле "нажимаешь кнопочку, и оно громко бабахает", а у меня — "при инициации просходит обжимка ядра из урана точно рассчитанными взрывами" и ещё 100 страниц :)


Кстати, попутно в недрах интернета я обнаружили "исходники Дябина", которые на самом деле не являются тем, что реально залито в БК (то, что реально залито — это декомпиляция Фролкина с комментарями Зальцмана, могу залить фотографии распечаток — руки пока не дошли полностью распознать их в текст).

после контрольной суммы идёт ещё один маркер, точно такой же, как и перед ней.

Тут у меня описка — следует читать "после заголовка идёт ещё один маркер, точно такой же, как и перед ним" (пока до меня дошло, Хабр уже закрыл редактирование).

Единица и синхроимпульс?
Возможно. Мы чего-то там на ходу правили в JS-конвертере, я уже не помню. Надо посмотреть код.
у Вас нарисовано, что синхробит идёт перед импульсом данных. На самом деле он идёт после
Пожалуй, Вы правы! Описанный мной формат будет читаться (я же проверял), но формально он описан со сдвигом на один синхроимпульс. Поправлю при случае.

У Вас в конце файла идёт «pilotone(128)», а на самом деле идёт там должно быть
Не должно, потому я описываю не как ПЗУ выводит звук, а как я его готовлю для чтения. Действительно, можно сократить ещё больше, но какой-то из копировальщиков обломался на коротком пилотоне, поэтому я оставил такой.

Тьфу ты, тут одну минуточку, параграф, помеченный 2) выше вычеркните, я там спросонья всё перепутал, сейчас напишу по новой. Но смысл в том, что один маркер Вы таки забыли.


Не должно, потому я описываю не как ПЗУ выводит звук, а как я его готовлю для чтения.

А я описываю то, что человек реально встретит на ленте; а как он захочет это обрабатывать — это уже дело пятнадцатое: например, всё, что после контрольной суммы, вполне можно смело скатать в трубочку и засунуть, но на ленте-то оно есть!

Понятно, но в моём случае не важно что БК пишет на ленту, потому что там получается много лишнего. Важно что можно скормить компьютеру, чтобы он побыстрее это съел, но не подавился :)

Во-первых, это зависит от Вашей задачи: если только прочитать, то таки да, а вот если правдоподбно писать...


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

А, вот: параграф 2) следует читать:


2) у Вас нарисовано, что после стартового 4096-импульсного пилотона с конечной единицей сразу идёт заголовок. Это неправильно: перед заголовком идёт маркерная последовательность — точно такая же, как перед основными данными файла. (Причина — в том, что 20 байт заголовка выводит та же самая подпрограмма, которая потом выводит тело файла — то есть идут вызовы CALL write_array(HEADER); CALL write_array(BODY);.)


В общем, смотрите мой гитхаб по ссылке выше, там код правильный :)

Внёс исправления в своё описание на zx-pk. Благодарю за замечания.

Спасибо за исправления. На данный момент я почти доковырял формат HELP7, читалка будет на гитхабе по тому же адресу.

Добавил парсинг файлов FOCAL. На очереди Бейсик.

А что он делает (в документации не написано)? Переводит в текстовый файл?

Вы бы присоединялись к Телеграм-чату, там народ любит такие новости! t.me/bk0010_11m
А что он делает (в документации не написано)? Переводит в текстовый файл?

Да (ну, в текстовую строку, которую записать в файл сумеет любой джун).


Вы бы присоединялись к Телеграм-чату, там народ любит такие новости! t.me/bk0010_11m

Когда тг перестанет требовать телефон при регистрации. "Ну нет у меня телевизора, НЕТУ!!!" ©

UFO landed and left these words here
Вообще, очень часто встречается в других процессорах, которые при MOVB меняют флаги, например Motorola 68000. И это поведение использовали игроделы.

Такой порядок команд возник вследствие оптимизации программы. Раньше никто настолько не заморачивался, чтобы уложить демку в 256 байт, да ещё добиться максимальной скорости.

Как уже совершенно верно тут заметили, это сделано ради экономии места за счет уменьшения числа инструкций.

Увлекательно и захватывающе. Как детектив. Правда, я не совсем понял. Этот баг присутствует и в оригинальном процессоре, или только в отечественном клоне?

Спасибо! 1801ВМ1 — отечественная разработка, от PDP-11 позаимствована лишь система команд и общая архитектура.
Про какой-либо аналогичный баг на PDP-11 мне ничего не известно. По документации (ссылка есть в статье), инструкция MOVB на PDP-11 не влияет на флаг С.
А вы сам как думаете, есть ли никому доселе не известный баг процессора К1801ВМ1 в компьютере, где нет процессора К1801ВМ1?
Сколько живу, думал, что это именно клон :) А сейчас залез на вики, почитал про него, может кто расскажет, а использовалась эта возможность: «Микропроцессор поддерживает работу в многопроцессорной (до 4-х процессоров) конфигурации. Номер процессора задаётся входами PA0 и PA1 (выводы 27 и 26)»? Просто всегда думал, что это уже более новое изобретение — распаралеливание процессоров.
Компьютер БК разрабатывался начиная с 1979-го года, в прототипе было два процессора. Потом от этой идеи отказались и в 1983-ем году появилась однопроцессорная конструкция, весьма близкая к той, что в итоге пошла в массовый тираж.
Просто всегда думал, что это уже более новое изобретение — распаралеливание процессоров.

А там не предусматривалось никакого распареллеливания. Симметричная мультипроцессорность, это уже более современная фишка. Тогда центральный процессор был всего один, но могли быть периферийные, которые решали другие задачи. Например, в дальней родственнице БК-0010, школьной Электронике УКНЦ как раз стоит два таких процессора. Один центральный, другой управляет периферией.
А могли быть и разные процессоры, например, тот же i8086 умел работать в связке с двумя другими, арифметическим i8087 и процессором ввода-вывода i8089. Последний, впрочем, не попал в конструкцию IBM PC, потому не так известен, как первые два.
Интересно почему не попал? Из-за удешевления? Так то выделить ввод-вывод на отдельный процессор логично.
Сопроцессор это дорогое удовольствие для РС. По этому он был опциональным до 486-х
Here are list of these price for these Intel 8087 Math CoProcessor (USD):

Model: Model Number, Suggested Unit Price

8087: BOX8087, $142
8087-2: BOX8087-2, $205
8087-1: BOX8087-1, $270

Source: Intel Corporation, «Personal Computer Enhancement» brochure, Order No. 245.2 10-89/75K/AL/GO, October 1989

По этой же причине IBM не использовало I8089 в IBM PC
Вставить 8089 в дизайн материнской платы образца 1981 года с ISA-шиной скорее всего просто так нельзя. Те компьютеры, где он реально стоял (Apricot PC, Altos 586) это либо рабочие станции очень высокого ценового уровня, либо вообще не PC по архитектуре внутри с очень условной с ним совместимостью. Для 8089 нужен арбитр шины (8289) и вообще желательно что-нибудь вроде EISA-шины, которая появилась через 8 лет, или Мультибас, который в обычных PC не применялся. Да, все из-за удешевления, но, конечно, ни IBM и никто другой даже в самых смелых планах вряд ли думали, что это семейство окажется настолько живучим и не закладывали туда таких решений на десятилетия вперед.
Для 8089 нужен арбитр шины (8289)

В IBM PC же есть арбитр шины :) Там 8088 работает в максимальном режиме, чтобы была возможность установки сопра.
Для ограниченных целей (сопряжение 16-битного чипа, взятого из комплекта 8085 с 20-битной адресной шиной). Арбитража в том смысле, какой был на EISA, там нет, на EISA — Multiple Bus Mastering, до 7 устройств, на XT-Bus он очень ограничен и только для устройств, встроенных в материнскую плату, не для слотов расширения. «An important feature of the EISA bus is that the host or any bus master can access any memory device or peripheral in the system, even if their bus widths differ.» — чем в общем и занимался 8089, у него тоже была эта функция. В этом плане наверное можно рассматривать шины MCA, EISA как дальнейшие развитие, универсализацию тех же идей. И ранние PC с «ассиметричной» многопроцессорностью, (Compaq SystemPro 386/486), как мне кажется, в принципе повторяют ту же схему с гипотетическим 8089.
Для ограниченных целей (сопряжение 16-битного чипа, взятого из комплекта 8085 с 20-битной адресной шиной).

Не совсем понял, что вы имеете в виду. Арбитр 8289 служит для управления захватом шины между двумя процессорами. Причем оба они, 8087 и 8088/8086, имеют ту же ширину шины, что и компьютер, 20 бит адреса, 8 или 16 бит данных.
16-битный там DMA-контроллер 8237. «As a member of the Intel MCS-85 device family, the 8237 is an 8-bit device with 16-bit addressing. However, it is compatible with the 8086/88 microprocessors. The IBM PC and PC XT models (machine types 5150 and 5160) have an 8088 CPU and an 8-bit system bus architecture; the latter interfaces directly to the 8237, but the 8088 has a 20-bit address bus, so four additional 4-bit address latches, one for each DMA channel, are added alongside the 8237 to augment the address counters. However, because these external latches are separate from the 8237 address counters, they are never automatically incremented or decremented during DMA operations, making it impossible to perform a DMA operation across a 64 KiB address boundary» (Wiki-en). Причем в минимальном режиме 8086 ничего, кроме этих защелок, для работы не нужно, однако именно в максимальном режиме 8086 нужен арбитр шины (не все источники понимают или приводят эту разницу). Источник информации — книга Pablo Mary «Microprocessors and Microcontrollers», глава 14.18
Самому теперь такой вопрос интересен — а на упрощенных клонах PC, где не было в конструкции и гнезда под 8087 и/или контроллера DMA (IBM PcJr) появлялся арбитр шины, или же выбрасывали и его тоже?
Не знаю насчет PCjr, но на советских домашних IBM-совместимых машинках, а-ля Поиск, Электроника МС1502, Квазар и т.д., процессор работал в минимальном режиме, и не было ни контроллера DMA, ни арбитра. Просто проц обвязывался регистрами для защелки адреса и данных, и шинными формирователями, ну и сам непосредственно рулил регистрами.
Логично. Кстати, встречал информация, что 8089 попал в некоторые советские ПК («Нивка» (также СМ1820)[1] — 32-разрядный персональный компьютер, ограниченно совместимый с IBM PS/2. Выпускался Киевским НПО «Электронмаш». Окончание разработки и выпуск первой ревизии датируется 1990 годом.)
Насчет Нивки не знаю, но знаю точно, что он был в ЕС-1842, причем он использовался там как собственный процессор в контроллере жесткого диска.
Да, упрощение конструкции и удешевление. Установка i8089, даже если не учитывать его собственную стоимость, значительно усложняет архитектуру материнки. Необходимо было бы разводить две раздельные шины, одну внутреннюю для общения процессоров с памятью и ПЗУ, вторую внешнюю для подключения периферии, со всей обвязкой. Поскольку компьютер планировался для массового потребителя, его решили делать без лишних наворотов. И так спасибо, что и DMA включили, и аж пять слотов расширения.
Как раз PDPшки (у нас — СМки) параллелились. Была и двухвходовая память, всякие трюки с взаимным пробросом окон в адресных пространствах процессоров и п.р
Есть ли какая-то возможность использовать этот баг как фичу?
Например, пока не пофиксят эмуляторы, этот баг дает возможность отличить выполнение на реальном железе от выполнения из-под эмулятора.

Почему на Вашем телеграм-канале не работает превью через /s/? А то скачивать клиента не хочется.

Для этого надо иметь тг-аккаунт. А я свой номер телефона налево и направо не раздаю.

Вроде бы недавно отменили обязательное указание номера телефона
Ну я просто знаю что теперь при регистрации теперь не обязательно указывать номер телефона. Сам проверить не могу, ибо уже зареган)
что показало, что я на верном пути. Осталось сузить «круг подозреваемых».

на этом моменте я ощутил накал страстей
Надеюсь, было интересно.

Да, отличный тех.детектив, спасибо!
Уверен, что в хоть одной игре на БКшке есть код, который эксплуатирует этот баг.
Когда я писал игры для ПК-01 Львов, то там тоже нашел баг связанный со звуком и сменой палитры — можно было сопровождать звуковые эффекты визуальными.
К сожалению у меня был монохромный дисплей. На цветном это выглядело отвратно.
Уверен, что в хоть одной игре на БКшке есть код, который эксплуатирует этот баг.

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

Что интересно, если не путаю, то на таком проце (или ВМ2?) делался компьютер управления ракетным огнем для Курска — баллистика, вот это все. Кажется модернизация под новое вооружение. Дюжина параллельных одноплатных машин в шкафу, в виде гроба в рост человека (буквально — граненые пирамидальные крышки-дверцы).

Наверное не на таком (там для оборонки были другие серии), но на подобном. Это же любимая архитектура МЭП в СССР, на ней делалось всё, от калькуляторов до станков ЧПУ.

Камень тот же, но в керамике. ДВК ж были по сути.
Что то отбирали (очень много брака), но все равно, плат столько для дубляжа, они часто сбоили в работе, и сделать с этим ничего было нельзя. Помимо того, что работали минимум три (4?) параллельно по требованиям надежности вычислений. Да 4, и 16 плат.

Искали баг в процессоре, нашли его во всех его эмуляторах, получается.

Ну, строго говоря, в процессоре тоже. Спецификации-то не соответствует, в отличие от эмуляторов.

Мы не знаем умышленно ли сделано такое поведение и умышленно ли сокрыто в спецификациях.
Но мы знаем, что теперь это недокументированная фича и что все эмуляторы надо исправлять.
Этот микропроцессор появился на базе другой советской разработки, а именно, однокристального микрокомпьютера 1801ВЕ1, у которого была своя, полностью оригинальная система команд и архитектура (Электроника НЦ). Первые прототипы того, что позже стало БК-0010, были собраны именно на ВЕ1 (с 79 по 81 г.). Однако, в связи с тем, что в 82 году МЭП СССР закрыло все работы по НЦ, процессор пришлось лихорадочно переделывать под архитектуру и систему команд, cовместимую с Электроникой 60 (клон PDP-11), как того хотело министерство. Поэтому, Ваш вариант с «закладкой» я исключаю, как не имеющий под собой оснований (иначе была бы вероятность поиметь проблемы с совместимостью). Более вероятно, что это баг, который появился в процессе спешной переделки микрокода под новую систему команд.
Это зависит от того, какая ставится цель: если эмуль должен следовать спецификациям, то да.
А если он должен работать как настоящее железо — то это ошибка в эмуляторе.
Правильная интерпретация того, что было сделано, это а) нашли баг в процессоре и б) как следствие, во всех эмуляторах.
Есть такой проект BKUNIX (основана на ядре LSX (вариант UNIX V6ruen)), если я ничего не путаю в ней были какието, случайные/спорадические вылетания/зависания. Не может ли это быть связано с операцией MOVB, или другой еще не известной операции портящей флаги?
Именно поэтому, вставка NOP восстанавливает правильное поведение.

Уважаемый автор! Я тут в процессе разработки своего дизассемблера вспомнил такой момент про флаги, а именно — давайте посмотрим на табличку:


команда / восьмеричный код / двоичный код / примечание
----------------
CLC / 000241 / 0 000 000 010 100 001 / очистить флаг C
CLV / 000242 / 0 000 000 010 100 010 / очистить флаг V
CLZ / 000244 / 0 000 000 010 100 100 / очистить флаг Z
CLN / 000250 / 0 000 000 010 101 000 / очистить флаг N
CCC / 000257 / 0 000 000 010 101 111 / очистить все флаги
----------------
SEC / 000261 / 0 000 000 010 110 001 / установить флаг C
SEV / 000262 / 0 000 000 010 110 010 / установить флаг V
SEZ / 000264 / 0 000 000 010 110 100 / установить флаг Z
SEN / 000270 / 0 000 000 010 111 000 / установить флаг N
SCC / 000277 / 0 000 000 010 111 111 / установить все флаги

После чего немедленно становится очевидным, что на самом деле команда — одна, c кодом 0 000 000 010 1XN ZCV, где X — признак "устанавливать или сбрасывать биты по маске", а NZVC — маска, определяющая, какие именно биты нужно изменить (установить или сбросить). И действительно, коды команд, для которых в ассемблерах не предусмотрено мнемоник — например, 000272, изменяют несколько бит одновременно. Кроме того, очевидно, что где-то в процессоре есть скрытый регистр, в котором биты состояния хранятся — потому что при исполнении этих команд надо эти биты достать, BIC или BIS их по маске, и записать обратно.


Так к чему этот я? Да к тому, что код команды NOP — 000240, то есть 0 000 000 010 100 000, маска NZVC — нулевая, и соответственно никакие биты изменяться не должны! Однако вытаскивание их из этого скрытого регистра и запись их обратно (в неизменном состоянии!) всё равно имеет место быть! Что и объясняет наблюдаемое Вами поведение с "самоисправлением" битов при добавлении NOP.


Довеском — существует и вторая, недокументированная команда NOP, с кодом 000260 :) Схема та же: всё по той же нулевой маске не сбрасываем, а устанавливаем биты, ровно с тем же эффектом.

Вдогон: сегодня на сон грядущий перечитывал PDP-11 Handbook, именно так эти команды и описаны на стр. 92.

Only those users with full accounts are able to leave comments. Log in, please.