Почему у ZX Spectrum нелинейная раскладка видеопамяти

Если у вас был ZX Spectrum, то даже без навыков программирования графики в ассемблере вы постоянно должны были замечать странную вещь при загрузке игр с магнитофона — линейная заливка видеопамяти данными визуально выглядела нелинейно:





Графическое разрешение спектрума — 256x192 пикселей. Визуально экран как бы поделен на три части — так называемые «трети экрана» каждая из которых состоит из восьми строк символов, 32 символа 8x8 пикселей в строке. Строка пикселей описывается 32 байтами монохромного изображения (8 пикселей на байт) идущих в памяти линейно, но вот строки чередуются весьма замысловатым образом. Данные о цвете (таблица атрибутов) хранятся сразу после данных пикселей, являются квадратным массивом 32x24 байт и применяются к блокам 8x8 пикселей по сути описывая какой цвет будет у всех нулевых и какой цвет будет у всех единичных пикселей данного блока (символа), что было продуманным компромиссом между потреблением памяти и графико/цветовыми возможностями компьютера, порождая однако сильную головную боль у всех кто хотел выйти за рамки вывода текста и выводить графические данные в цвете. Но это отдельная песня.

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

010yyyyy yyyxxxxx

Здесь биты X (от 0 до 32) — это номер полоски в строке, а биты Y (от 0 до 191) — номер строки. Но в спектруме три нижних бита верхнего байта адреса поменяны местами с верхними тремя битами нижнего байта адреса:

010ttwww yyyxxxxx

При этом получается, что биты X по прежнему описывают номер байта в строке, но у других бит возникает новый специфический смысл.
Биты T (от 0 до 2) определяют треть экрана, биты Y (от 0 до 7) — вертикальную позицию знакоместа в этой трети, а биты W (от 0 до 7) вертикальную полоску пикселей внутри знакоместа. В силу такой раскладки заливка видеопамяти и выглядит как на гифке выше.
Так зачем же так сделано?

Я слышал много вариантов объяснения этому — использование уже готовых микросхем с такой системой, упрощение регенерации памяти, ускорение вывода текста… но все они оказались неверными.

Как ни странно, но для объяснения такого положения вещей придётся вспомнить ключевые особенности динамического ОЗУ или DRAM. ОЗУ реализованное на транзисторах по схеме триггера называется статическим — Static RAM (SRAM) и по природе своей сохраняет информацию до тех пор пока к нему подводится ток. Но оно дорогое и применяется в современных компьютерах в основном в роли кэша процессора. Основное же ОЗУ реализовано как динамическое Dynamic RAM (DRAM) — в нём биты хранятся в виде зарядов микроскопических конденсаторов и эти конденсаторы постоянно «утекают» и теряют заряд, поэтому периодически их надо обновлять в процессе называемом регенерацией. Периодически надо считывать или записывать ячейку памяти — при этом её содержимое в конденсаторе обновляется и начинает «утекать» снова. Обновлять память надо довольно быстро, но обновляются не отдельные биты или байты, а большие блоки называемые «строками» в которых отдельные байты представлены как «столбцы». У чипа памяти сперва запрашивается строка — при этом он извлекает её во внутренний буфер–защёлку всю за раз, а потом опрашивается столбец — и вот здесь уже нужный байт выдаётся наружу. И в этот же момент происходит обновление всей строки из защёлки — происходит регенерация этой строки. Адресные линии памяти спектрума разведены таким образом, что нижние (именно нижние) 7 бит адреса являются номером строки в чипах памяти, а верхние 9 бит выступают в роли столбца (правда после разброски по нескольким чипам).

И вот здесь возникает интересный момент — эти чипы имеют функцию ускорения доступа к памяти — так называемый page mode. Когда адрес строки уже выставлен и строка считана в защёлку, то повторные обращения к столбцам можно делать без выставления строки — экономится время как на выставление адреса строки, так и на считывание самой строки в защёлку.

Когда видеочип спектрума выводит очередную полоску пикселей ему нужно считать два байта — саму полоску из пиксельных данных и её цвета из таблицы атрибутов.

И вот тут то и выстреливает магия «нелинейной» видеопамяти — оказывается, при такой адресации как принята в спектруме нижний байт адреса полоски пикселей всегда совпадает с нижним байтом адреса его атрибутов. То есть эти байты всегда находятся в одной и той же строке чипа памяти.

Более того, если адрес полоски пикселей имеет битовое представление 010ttwww yyyxxxxx, то адрес его атрибутов равен 010110tt yyyxxxxx — то есть просто откидывается компонента www и некоторые биты преставляются местами с полным сохранением нижнего байта адреса. Это позволяет видеоконтроллеру при отрисовке видеопамяти воспользоваться ускоренным режимом считывания с сохранением адреса строки и считывать пиксели и их атрибуты за 170 нс вместо 320 нс которые нужно было бы тратить на считывание двух байт из разных страниц. И это было важно для инженеров, потому что процессор и видеочип конкурировали за одну и ту же память, приоритет отдавался видеочипу и процессор вынужден был ждать если хотел работать с ней в тот же момент когда видеочип производит отрисовку.

Вот почему у ZX Spectrum такая странная раскладка видеопамяти.

3 комментария

avatar
Оформил результат предыдущей темы в виде подробной статьи.
avatar
P.S. предыдущая тема — это тут: hype.retroscene.org/blog/889.html
avatar
А ещё такая раскладка видеопамяти производила (и производит) завораживающий эффект при загрузке экранов) На меня, по крайней мере)
  • Weiv
  • +1
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.