Почему у ZX Spectrum нелинейная раскладка видеопамяти?
Вопрос этот мучает меня довольно давно и я немало гуглил и задавался этим вопросом на других (непрофильных) форумах, так что хочу задать его теперь здесь.
Если вдруг кто не совсем в курсе напомню, что основную часть видеопамяти в спектруме занимает битмап 1 бит/пиксель в котором каждый байт описывает горизонтальную полоску из восьми пикселей. Строка из 256 пикселей экрана описывается подряд идущими 32 байтами, но вот строки перемежаются в памяти несколько замысловато, что наглядно видно при загрузке экранных заставок игр.
Если бы раскладка видепамяти была бы линейной, то в двоичном виде адрес каждого байта можно было бы описать следующей битовой маской:
где биты X это позиция каждого байта в строке, а биты Y — номер строки
Но в спектруме три нижних бита верхнего байта адреса поменяны местами с верхними тремя битами нижнего байта адреса:
Здесь биты 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 за наводку.
Если вдруг кто не совсем в курсе напомню, что основную часть видеопамяти в спектруме занимает битмап 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 комментариев
Только вот, боюсь, Синклер вообще ничего такого не предполагал, ибо вообще был далек от разработки как железа, так и софта.
Также возникает вопрос: почему, если прицел был на ускорение вывода, не дожали? Много раз обсуждалось, что можно было сделать, например, как в Векторе: inc l — переход к столбцу, inc h — переход к строке. Или другие варианты, так или иначе обходящие деление экрана на трети, которое скорость вывода символов точно не повышает. Т.е. в ряду оптимальных решений то, что реализовано в ZX, далеко не самое эффективное из возможных.
Точно могут ответить только инженеры, но вероятно на самом деле было больше одного фактора. Возможно включая 2 и 3.
А вывод текста в основном опирается на print_string и именно для print_string как раз легко делать и вывод одного символа и переход к следующему за ним символу. Я писал процедуры вывода текста на спектруме и нашёл, что и то и другое легко делать при данной раскладке видеопамяти. То что экран побит на трети замедляет переход к следующему символу крайне редко.
А по поводу (2) — я не понимаю чем оно вообще могло бы быть полезно.
Подозреваю, что дожимать было некуда — любая другая структура видеопамяти была бы менее эффективной в плане производительности вывода текстов, равно как и в плане объёма видеоОЗУ. Деление экрана на трети — побочный эффект от возможности перехода к следующей пиксельной строке инкрементом старшего байта адреса.
Я назвал более эффективную структуру видеопамяти, реализованную в серийном компьютере.
про скроллинг лдиром лучше вообще забыть)))
www.wipo.int/pctdb/en/wo.jsp?WO=1983003916
Почитал интернеты по этим ключевым словам и да — похоже это была главная причина.
Поясню для тех кому некогда читать это вкратце. Сперва напомню как работает DRAM — этот дешевый вариант памяти требует периодического обновления своего содержимого — во времена спектрума для этого некий внешний чип должен был инициировать чтение (или запись) памяти. Но не каждой ячейки, а каждой страницы памяти — память состояла из страниц довольно большого объёма. По факту при чтении байта из заданного адреса чип DRAM извлекал во временный буфер содержимое всей страницы памяти, брал из него нужный байт и перезаписывал/обновлял содержимое всей страницы. При этом важно заметить, что селектор страницы в микросхемах применяемых в памяти спектрума содержался в нижнем байте адреса, а селектор байта внутри страницы — в верхнем (даже в семи битах, но неважно).
Это и является ключём к режиму page mode — залочив память на чтение с адреса можно было получив результат не снимать лок, а требовать отдать еще один байт, при условии что он лежит внутри той же страницы памяти — пока она удерживалась во временном буфере можно было значительно сэкономить на операции чтения.
А далее — магия — организация видеопамяти спектрума такова, что у адресов битового паттерна знакоместа и его атрибута один и тот же нижний байт адреса!
Этим и пользовался ULA (видеочипная составляющая) спектрума, чтобы читать и битовый паттерн и его цвет в один присест за 170нс вместо полагающихся 320нс на чтение двух разрозненных байт из памяти.
То, что раскладка получилась удобной для текстового вывода являлось логичным следствием этой оптимизации, но не причиной всего этого безобразия. Сама причина — скорость извлечения памяти. Спасибо за наводку!