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

Вопрос этот мучает меня довольно давно и я немало гуглил и задавался этим вопросом на других (непрофильных) форумах, так что хочу задать его теперь здесь.

Если вдруг кто не совсем в курсе напомню, что основную часть видеопамяти в спектруме занимает битмап 1 бит/пиксель в котором каждый байт описывает горизонтальную полоску из восьми пикселей. Строка из 256 пикселей экрана описывается подряд идущими 32 байтами, но вот строки перемежаются в памяти несколько замысловато, что наглядно видно при загрузке экранных заставок игр.
Если бы раскладка видепамяти была бы линейной, то в двоичном виде адрес каждого байта можно было бы описать следующей битовой маской:
010YYYYY YYYXXXXX

где биты X это позиция каждого байта в строке, а биты Y — номер строки
Но в спектруме три нижних бита верхнего байта адреса поменяны местами с верхними тремя битами нижнего байта адреса:
010TTWWW YYYXXXXX

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

Так вот — зачем так, а не иначе?
Я встречал несколько разных версий такого положения вещей:

1. Синклер использовал какой то уже доступный на рынке и дешевый компонент видеосистемы и в нём была именно такая раскладка.
Против такой версии, имхо, выступает тот факт, что ULA был кастомным.

2. В спектруме видеочип занимается регенерацией первых 16Кб ОЗУ и такая раскладка как то этому помогает.
Однако, изучив подробнее то как происходит регенерация памяти я нахожу эту версию тоже слабой.

3. Синклер предполагал, что основную часть времени пользователи компьютера будут проводить в редакторе бейсика и сделал упор на быстром выводе текстовой информации. А такая раскладка при выводе символа позволяет одним инкрементом верхнего байта адреса переходить к следующему байту знакоместа.
Я лично нахожу эту версию наиболее правдоподобной, но встречал немало её противников.

А какие у вас мысли по этому поводу?

P.S.

Правильный ответ дал в комментариях Lethargeek.
Я продублирую тут свои выводы сделанные по его наводке:
Сперва напомню как работает DRAM — этот дешевый вариант памяти требует периодического обновления своего содержимого — во времена спектрума для этого некий внешний чип должен был инициировать чтение (или запись) памяти. Но не каждой ячейки, а каждой страницы памяти — память состояла из страниц довольно большого объёма. По факту при чтении байта из заданного адреса чип DRAM извлекал во временный буфер содержимое всей страницы памяти, брал из него нужный байт и перезаписывал/обновлял содержимое всей страницы. При этом важно заметить, что селектор страницы в микросхемах применяемых в памяти спектрума содержался в нижнем байте адреса, а селектор байта внутри страницы — в верхнем (даже в семи битах, но неважно).
Это и является ключём к режиму page mode — залочив память на чтение с адреса можно было получив результат не снимать лок, а требовать отдать еще один байт, при условии что он лежит внутри той же страницы памяти — пока она удерживалась во временном буфере можно было значительно сэкономить на операции чтения.
А далее — магия — организация видеопамяти спектрума такова, что у адресов битового паттерна знакоместа и его атрибута один и тот же нижний байт адреса!
Этим и пользовался ULA (видеочипная составляющая) спектрума, чтобы читать и битовый паттерн и его цвет в один присест за 170нс вместо полагающихся 320нс на чтение двух разрозненных байт из памяти.
То, что раскладка получилась удобной для текстового вывода являлось логичным следствием этой оптимизации, но не причиной всего этого безобразия. Сама причина — скорость извлечения памяти. Спасибо Lethargeek за наводку.

17 комментариев

avatar
Третья версия рулит. При выводе текста INC H мало того, что быстрее, чем ADD HL,BC, так ещё и не требует целой регистровой пары под константу приращения адреса на следующую строку. Вариант с приращением адреса через аккумулятор ещё (намного) медленнее. Какие тут могут быть возражения?

Только вот, боюсь, Синклер вообще ничего такого не предполагал, ибо вообще был далек от разработки как железа, так и софта.
  • Weiv
  • 0
avatar
Возражения могут быть в мотивации — какой смысл в ускорении вывода текста, когда скорость ввода в редакторе Бейсика невероятно низкая и реально может падать до символа в одну-две секунды. Скорость вывода символов в сравнении со скоростью редактора вообще никакой погоды не делает.

Также возникает вопрос: почему, если прицел был на ускорение вывода, не дожали? Много раз обсуждалось, что можно было сделать, например, как в Векторе: inc l — переход к столбцу, inc h — переход к строке. Или другие варианты, так или иначе обходящие деление экрана на трети, которое скорость вывода символов точно не повышает. Т.е. в ряду оптимальных решений то, что реализовано в ZX, далеко не самое эффективное из возможных.

Точно могут ответить только инженеры, но вероятно на самом деле было больше одного фактора. Возможно включая 2 и 3.
avatar
Ну, имхо, дело не в самом редакторе бейсика, а в том, что вывод текста был обозначен как приматив.
А вывод текста в основном опирается на print_string и именно для print_string как раз легко делать и вывод одного символа и переход к следующему за ним символу. Я писал процедуры вывода текста на спектруме и нашёл, что и то и другое легко делать при данной раскладке видеопамяти. То что экран побит на трети замедляет переход к следующему символу крайне редко.
А по поводу (2) — я не понимаю чем оно вообще могло бы быть полезно.
avatar
Я тоже не понимаю. Судя по тому, как сделана регенерация динамической памяти процессором с использованием регистра R, для регенерации нужно, чтобы из памяти регулярно, последовательно, и циклично читались ячейки из любого 128-байтового блока ячеек ОЗУ. ULA это обеспечивает регулярным чтением видеоатрибутов при выводе строки картинки, то есть структура пиксельной видеопамяти для регенерации не важна.
avatar
Мда, тут я ступил. ULA читает 32 байта атрибутов 8 раз подряд, а потом переходит к следующей 32-байтной строке атрибутов. То есть при существующей структуре видеопамяти сначала 8 раз читается первые 32-байтные блоки 128-байтных блоков, потом — вторые, потом — третьи, и так далее. Видимо, для регенерации этого достаточно. Во время вывода верхнего/нижнего бордюра и вертикального обратного хода луча чтения видеоОЗУ вообще не происходит, а это всяко больше по времени, чем переход к следующему 32байтному блоку во время вывода растра.
avatar
А причем тут скорость ввода в редакторе Бейсика, если речь идет о скорости вывода текстов Бейсиком?

Подозреваю, что дожимать было некуда — любая другая структура видеопамяти была бы менее эффективной в плане производительности вывода текстов, равно как и в плане объёма видеоОЗУ. Деление экрана на трети — побочный эффект от возможности перехода к следующей пиксельной строке инкрементом старшего байта адреса.
avatar
Скорость работы Бейсика в целом, и редактора в частности, делает даже многократную разницу в скорости отрисовки символов несущественной. И этот Бейсик существовал до начала разработки ZX Spectrum, т.е. было ясно, чего ожидать.

Я назвал более эффективную структуру видеопамяти, реализованную в серийном компьютере.
avatar
Восьмикилобайтная страница видеопамяти Вектора дает черно-белую картинку 256x256. Действительно, программно адресовать нужный байт видеопамяти проще. Но при этом — черно-белая картинка, и на килобайт с лишним больше объем. Раскрашивание атрибутами, как в Спектруме, потребует ещё килобайт. Итого — 9 кб вместо 6.75 в Спектруме. Эффективно обработать такую видеопамять процессор не успевает, он и Спектрумовскую-то не очень. То есть — объем видеоОЗУ увеличивается, отношение частоты процессора к объему видеоОЗУ, или графическая производительность, падает, место под память для программ уменьшается. Так что такая структура видеопамяти эффективна только в плане некоторого удобства программирования, во всех остальных — не очень.
avatar
'Некоторое удобство' — возможность вывода спрайтов произвольной высоты без таблицы строк и без down hl. Ну или пиксельного скролла по вертикали и знакоместного по горизонтали единственным LDIR'ом. И никто не заставляет делать растр 256 пикселей в высоту. Напротив, логично иметь нормальные более-менее квадратные пиксели и нормальное соотношение сторон экрана, а лишние байты в строке можно отдать тем же атрибутам, при желании.
avatar
Если делать растр не 256 пикселей в высоту, а, скажем, 192, а лишние байты в столбце отдать атрибутам, у нас будут в каждом столбце участки неиспользуемой памяти — для атрибутов 8х8 по 256-192-24=40 байт, т.е. в целом для 8x8 — 40*32=1280 байт будут не особо при делах. Ну да, что-то в машинном коде впихнуть туда можно, при большом желании, но для бейсика эта память будет по большей части неиспользуемой. Очень эффективно. Ну и при такой организации видеопамяти про скроллинг единственным LDIR-ом можно забыть.
avatar
можно сделать больше строк или атрибуты 8x4
про скроллинг лдиром лучше вообще забыть)))
avatar
Ок. При 224 пиксельных строках, и 28 атрибутах 8х8 на столбец неиспользуемые участки в памяти на столбец будут по 4 байта. 4*32=128 байт. Можно раскидать в них системные переменные Бейсика, или какие-нибудь палитры для атрибутов в столбце задавать. Действительно, неплохо.
avatar
Richard Altwasser's patent for the Spectrum's graphics mode
www.wipo.int/pctdb/en/wo.jsp?WO=1983003916
avatar
Вспомнилось, что у TMS9918 в Mode 2 довольно похожая организация памяти, с третями, но с атрибутами 8x1 (аналогично мультиколору Timex'а). Следующая линия символа inc l, следующее знакоместо l+8, но порядок следования знакомест можно менять — как бы текстовый режим со своим набором в 256 символов для каждой трети, то есть следующий уровень сложности по сравнению с ZX. Это 1979 год, так что влияние на ход мысли разработчиков ZX вполне возможно.
avatar
Наиболее далека от истины третья версия, наиболее близка — первая. Только «дешёвый и доступный компонент» не одной видеосистемы, а всего компа целиком — дешёвая медленная память, читать которую юла успевала с минимальным торможением процессора только в спецрежиме page mode, для чего в адресах пиксельной линии и соответствующего атрибута должны были совпадать семь бит минимум (в спектруме совпадает восемь). Да еще и размер видеопамяти экономили (напомню, спектрум начался с модели 16k). Хотя в 8k вполне можно было уложить вектороподобную раскладку для page mode read (могла, правда, усложниться схема регенерации).
avatar
И, похоже, это правильный ответ! :) www.zxdesign.info/harlequinDRAM.shtml
Почитал интернеты по этим ключевым словам и да — похоже это была главная причина.
Поясню для тех кому некогда читать это вкратце. Сперва напомню как работает DRAM — этот дешевый вариант памяти требует периодического обновления своего содержимого — во времена спектрума для этого некий внешний чип должен был инициировать чтение (или запись) памяти. Но не каждой ячейки, а каждой страницы памяти — память состояла из страниц довольно большого объёма. По факту при чтении байта из заданного адреса чип DRAM извлекал во временный буфер содержимое всей страницы памяти, брал из него нужный байт и перезаписывал/обновлял содержимое всей страницы. При этом важно заметить, что селектор страницы в микросхемах применяемых в памяти спектрума содержался в нижнем байте адреса, а селектор байта внутри страницы — в верхнем (даже в семи битах, но неважно).
Это и является ключём к режиму page mode — залочив память на чтение с адреса можно было получив результат не снимать лок, а требовать отдать еще один байт, при условии что он лежит внутри той же страницы памяти — пока она удерживалась во временном буфере можно было значительно сэкономить на операции чтения.
А далее — магия — организация видеопамяти спектрума такова, что у адресов битового паттерна знакоместа и его атрибута один и тот же нижний байт адреса!
Этим и пользовался ULA (видеочипная составляющая) спектрума, чтобы читать и битовый паттерн и его цвет в один присест за 170нс вместо полагающихся 320нс на чтение двух разрозненных байт из памяти.
То, что раскладка получилась удобной для текстового вывода являлось логичным следствием этой оптимизации, но не причиной всего этого безобразия. Сама причина — скорость извлечения памяти. Спасибо за наводку!
avatar
оформил в виде отдельной статьи подробно всё разжёвывающей hype.retroscene.org/blog/890.html
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.