В начале этого года я обещал опубликовать детали точной эмуляции эффекта снега после публикации новой версии моего эмулятора. Ну, я передумал, публикация новой версии эмулятора планируется позже, а детали эмуляции эффекта снега я публикую сейчас, вместе с устаревшей версией Спектрамина, в которой впервые была реализована его правильная эмуляция (упд. - увы, не вполне правильная, как выяснилось), и моими тестами снега, являющиеся модификациями известного теста снега с настроечной таблицей.
Эффект снега аппаратно обусловлен интерференцией двух процессов - чтением данных экрана ULA-й и регенерацией памяти процессором. При определенных условиях в биты 6..0 адреса экраной памяти, выставленный ULA-й на шину адреса, подхватывается содержимое битов 6..0 регистра R. В процессе моих исследований выяснился ещё один эффект, определенный теми же причинами, я назвал его эффектом дублей - при определенных условиях интерференция чтения данных экрана ULA-й и регенерации памяти процессором приводит к тому, что ULA не может изменить адрес данных следующей полоски пикселей, и вместо неё снова читает предыдущую. Этот эффект отлично виден на тесте ULA128.
А теперь собственно результаты исследований - информация, необходимая для точной эмуляции снега.
Необходимое условие снега - на 16/48/128/+2 снег появляется, если регистр I содержит значение, которое, если оно взято старшим байтом адреса, указывает на адрес в медленной памяти. Для Спектрум 16/48 это адреса #4000..#7FFF, для 128/+2 это также адреса #C000..#FFFF, если в них сейчас впечатана страница "медленной памяти", для 128/+2 это страницы с нечетными номерами - 1,3,5,7 (не 0,2,4,6). Снега нет на черных амстрадовских машинах (+2A/+2B/+3/...), а также любых клонах Спектрума, кроме, возможно, тех, которые основаны на оригинальной ULA.
Дополнительно выяснилось, что на некоторых 128-х машинах снег приводит к зависанию/сбросу компьютера, а на некоторых - работает ок.
Теперь по фазам снега. Фаза означает, как ложится 4хтактный цикл выборки кода операции на 8тактный цикл вывода юлой 16 пикселей экрана.
Итак:
1) Если 4й такт цикла выборки КОП совпадает с 3м тактом 8тактного цикла вывода юлой 16пикселей, то это приводит к снегу - в адресах чтения пикселей1/атрибутов1 биты 6..0 заменяются на биты 6..0 регистра R (он должен быть уже увеличен в этом цикле выборки КОП). upd.:А страница памяти, из которой выбираются байты снега - это страница, на которую указывает регистр I (а не текущая экранная страница, как я думал раньше).
2) Если 4й такт цикла выборки КОП совпадает с 5м тактом 8тактного цикла вывода юлой 16 пикселей, то это приводит к эффекту дубля - данные пикселей2/атрибутов2 не будут прочитаны, и будет повторно выведена полоска экрана с данными пикселей1/атрибутов1.
3) Для остальных вариантов наложения цикла извлечения КОП на цикл ULA работа ULA штатная, без снега и дублей.
Таким образом, эффект снега проявляется только на нечетных столбцах (если считать с первого), а эффект дублей - только на четных столбцах.
Выражаю благодарность @PheeL (Александр Филянов) и balford (Brendon Alford), запускавшим по моей просьбе мои тесты на своих Спектрумах, и снимавшим результаты на видео. (А также NEO_SPECTRUMAN, TheMartian и Guesser за прояснение вопроса с участием битов регистра R в эффекте снега).
Версию моего эмулятора Спектрамин (1.05) с правильным снегом можно скачать здесь: https://files.fm/u/r7cymnn9m
Тесты снега, старый и мои модификации, и тест ULA128: SnowTests.zip
(Тест snow.tap не вполне корректный - при определенных условиях бега столбцов на экране не будет, что обусловлено отсутствием в тесте выравнивания на начало фрейма. Попробуйте загрузить его с нажатой кннопкой Ctrl перед загрузкой. Быстрый бег столбцов на экране сразу после загрузки тестов вызван несовершенным кодом эмулятора для ускорения пауз между блоками ленты во время загрузки).
- - - Добавлено - - -
Видео моих тестов снега:
Объяснение эффектов снега и дубля на аппаратном уровне от TheMartian с форума SpectrumComputing:
- Пиксели и атрибуты считываются пакетами. Сначала подается сигнал CAS, и задается адрес столбца (это биты 6-0 видеоадреса). Затем сигнал RAS подается дважды, устанавливая адрес строки (биты 13-7), который указывает сначала на байт пикселя, потом на его атрибут. Первый импульс RAS предназначен для байта пикселей, второй для атрибута, изменяются только биты 13-7.
- В циклах RFSH утверждается MREQ, а MREQ контролирует (является) CAS, и поскольку MREQ низок в первой половине T4, он отменяет конкуренцию, но продолжает удерживать биты 6-0 адреса.
- Таким образом, если это происходит в 3м такте пиксельного цикла, это первый пакет пикселей / атрибутов, CAS утверждает адрес обновления, получается снег.
- Если это происходит в 5м такте пиксельного цикла, CAS держится низким между первым и вторым пакетом, поэтому он сохраняет биты 6-0 видеоадреса для второго пакета, получается дубль.
Обновление: Недавно (04.2023) была открыта еще одна особенность эффекта снега. Когда регистр I указывает на медленную страницу памяти на 128й машине, страница, из которой извлекаются байты снега, зависит от: 1) на какую медленную страницу указывает регистр I; 2) какой экран активен.
В таблице показана необходимая страница памяти для выборки снежных байтов:
В этой таблице строки означают номер медленной страницы, на которую указывает регистр I, столбцы означают номер активного экрана, ячейки таблицы означают, с какой страницы извлекаются снежные байты. Спасибо TheMartian, IceKnight и Ричарду Чандлеру за участие.Код:I>Страница Экран 0 (страница 5) Экран 1 (страница 7) 1 1 3 3 1 3 5 5 7 7 5 7
Мой тест, исследующий эту особенность: snow128n.zip В моем тесте регистр I указывает на верхнюю страницу памяти, цвет бордюра указывает номер текущей верхней страницы, цвет бумаги указывает на страницу активного экрана (экран 0 - 5-я страница - голубой, экран 1 - 7я страница - белый), цвет чернил указывает, с какой страницы выбираются снежные байты. Номер цвета означает номер страницы, т.е. синий => 1 => 1я страница памяти.
Видео с этим тестом от Ричарда Чандлера:
Рекомендация для игроделов: чтобы избежать снега, нужно следить, чтобы регистр I вектора прерывания не указывал на медленную память, а, соответственно, вектор прерываний IM 2 не находился в ней. Безопаснее и проще всего размещать вектор прерываний IM 2 в адресах $8000...$BFFF, дабы гарантированно быть в быстрой странице памяти (регистр I в пределах $80...$BF).