Откопал крайне любопытный документ по NextOS + esxDOS для Next: raw.githubusercontent.com/z88dk/techdocs/master/targets/zx-next/nextos/nextzxos_api.pdf
Например, в разделе про esxDOS там есть очень ценное замечание, что не обязательно всякий раз вызывать функцию GetSetDrv чтобы получить номер текущего диска когда нужно вызвать функцию которой нужно передать номер диска. Оказывается в аккумуляторе можно передать символьные значения:
A='*' для текущего диска и
A='$' для системного диска (где установлена NextOS или, видимо, сама esxDOS)
Так же там есть важное замечание, что к любым вызовам надо относится так, что они уничтожают AF,BC,DE,HL, но сохраняют все остальные регистры (например тот же IX).
В общем полезно почитать…
Таким образом переход к виртуальной машине дает возможность переноса на множество других платформ. А никогда не возникало ощущения, что аппаратные возможности платформы (ядра процессора) могли бы способствовать эффективному исполнению инструкций ВМ? Например у DEC в его последнем CISC-е VAX новые инструкции могли вносится как микрокод и нативно расширяли систему команд. В случае VM это конечно в большей степени касается вызова шитого кода.
Не могу точно сказать насчет первенства в JIT компиляции, DEC тоже делала шаги в эту сторону, кроме всего прочего снабжая ядро виртуальной машины профилировщиком, принимающим решение на определенной итерации начать «инлайнить код», то есть приложение становилось шустрее и шустрее, в зависимости от времени его работы.
У МК-85, приходилось читать Отрохова, разработчик Бейсика пошел на применение шитого кода для плавающей арифметики. Формально это тоже некая часть VM. Я хочу сказать что в определенный момент, когда сложность написания процедур, даже в такой удобной и интуитивно понятной
системе команд как PDP-11, начинает достигать пределов возможностей человеческого мозга. В таком случае уйти в форт-машину или еще какую либо VM, в конечном счете связано даже не с борьбой за плотность или переносимость кода, а за возможность продолжать вести разработку.
Как Вы и отметили растра 4:3, получить количество точек по горизонтали можно умножив кол-во строк на 4/3. Для PAL и SECAM это 800 элементов в строке. Не спорю конечно кинескоп и качество исполнения видеотракта дадут свои ограничения, на эти возможности.
У меня есть несколько вопросов, буду признателен за ответы.
1. Почему именно телевизионный растр?
2. Чем вызваны Ваши предпочтения накладываемые на видеоадаптер по разрешению и цветности, только ли ограничениями ТВ растра?
На 8 битах, имхо, оптимум — 256x192 точек как в спектруме. Ну во первых 256x256 это перебор с точки зрения стандартного соотношения сторон картинки 4:3. А 256x192 это как раз 4:3. Во вторых насколько я понял телевизионный сигнал что NTSC что PAL имеет предел эффективного разрешения по цвету в строке и потому о 640 например уже речи быть не может. Вроде бы предел это где то от ~400 что ли, но не скажу тут точно.
Однако действительно вопрос глубже — как «выдавить» при этом нормальную цветность.
Монохром как мы знаем в спектруме том же отнимает 6144 байта и раскраска знакоместами порождает клэшинг при попытке графонить графоний. Да и скроллинг в играх, а давайте уже не лукавить — игры это для нас очень важно — просто убивает и производительность и всё на свете — апдейтить 6Кб с приличным фпс — трудно для восьми бит.
Поэтому, имхо, оптимальность картинки в целом надо искать на пересечении текста и консольных принципов тайловой графики, причём одно плавно вытекает из другого, ибо не зря в Famicom/NES/Денди память тайлов офдоки называют CHR (character) ROM/RAM, ибо технически это действительно 256-значные символы квадратно-гнездовой сетки 8x8.
Однако Famicom, имхо, пример как немного перемудрили и ради призрачной экономии зарезали немало хорошего.
Главное — это аппаратный скроллинг по как минимум двум страницам видеотекста бесшовно перетекающий с прокрутной одна в другую.
Причём вот именно страницы текста имеют разрешение 32x32 символа, т.е. по вертикали виртуальное разрешение 256 пикселей, но оно используется чтобы организовывать бесшовный скроллинг с «проворотом» между границ.
Две экранных области текста пристыковани друг к другу слева-направо, над ними как бы «летает» видеоокно 256x192 на кинескоп управляемое одним 8-битным регистром прокрутки по вертикали и одним 9-битным регистром прокрутки по горизонтали (512 эффективных пикселей).
Но конечно чтобы игры на таком тексте делать еще нужны аппаратные спрайты.
В общем по лекалам денди я бы сделал так:
4Кб — память A изображений 256 тайлов 8x8 2bpp
4Кб — память B изображений 256 тайлов 8x8 2bpp
(одна область формирует тайлы для фона, другая — для спрайтов)
1Кб — текстовая видеостраница X 32x32 символа
1Кб — текстовая видеостраница Y 32x32 символа
(если произвольно скроллить, то видеостраницы пристыкованы прямоугольником «XY»)
256 байт — цветовые атрибуты видеостраницы X
256 байт — цветовые атрибуты видеостраницы Y
(2 бита на знакоместо/тайл выбирают ему палитру из 4-х возможных, в одном байте описывается 4 соседних символа/тайла квадратиком, что удобно для концепции метатайлов).
Но с таким потайловым и удобным для скроллинга фоном нужно конечно еще спрайты. Именно для них нужна память изображений Б ибо одной там реально маловато.
А чтобы всякие Elite делать нужно иметь второй видеорежим где первые 8Кб можно превратить в монохром, т.е. уже чистую графику.
Да с текстом претензии к видеоадаптерам возрастают. Если предположить что 256х256 это всего лишь массив для отображения на экране, тогда можно пойти чуть дальше и представить, что для его отображения используется 2х2 точки в растре разрешением 800х600. Ну а раз есть такое разрешение то можно сделать еще один шажок с наложением текстового слоя с знакоместом 8х8 как 80х60 из области ~5Кб но точкой для него 1х1. Два растра точно конечно не совмещаются, но в этом может быть и нет необходимости. В принципе добиться включения слоя с текстом в слой с графикой можно меняя размеры знакоместа.
В плане разрешающей способности — я думаю, что не столько важно количество точек, сколько цветовое разрешение. Скажем, если брать тот же C64, при формальном разрешении 320x200, фактически используемое в большинстве картинок — обычно 160x200 (не считая спрайтов) и никого это особо не беспокоит, поскольку в 160x200 с цветами довольно неплохо (4 цвета на знакоместо из 16-ти доступных, в отличии от 320x200, где вроде два из 16). При этом, если вспомнить платформы с разрешением 320x200 и честным «цвет на точку» (например, PC EGA), то уровень графики там в среднем невысок. Другими словами, это уже слишком много. Я думаю, что идеалом было бы что-то типа 256x256 квадратных точек при четырёх цветах на знакоместо из 16 доступных (т.е. слева и справа рамки, картинка «высокая»). 256 — потому что в байт влезает, в отличии от 320. В жизни такое разрешение не использовалось, поскольку неоптимально для текстовых применений — практически тот же объём памяти выгоднее использовать для 320x200, чтобы получить хотя бы 40 столбцов в текстовых редакторах.
Трудно не согласится! Любое ограничение играет в пользу творческого процесса. Можно по взрослым платформам лицезреть как доступность ресурсов работает против них… черт возьми снова законы диалектики :) Было бы интересно увидеть размышления на тему полезного ограничения в разрешающей способности видеоадаптеров для платформы 64К. Есть ли золотая середина?
Мне представляется, что [естественное] ограничение в 64к для восьмибитных платформ, по теперешним временам — это плюс, а не минус. Это примерно из той же серии, что ограничения в 256b, 4k, 640k и т.д. в intro/demo конкурсах. Если не хватает 64к, есть абсолютно доступные PC, Mac, смартфоны.
К слову — даже если посмотреть на Амигу, снятие ограничений пошло, на мой взгляд, ей непосредственно во вред. В среднем качество софта (демо и интро в первую очередь) сильно ниже, чем таковое у 8-битных платформ (того же C64).
Потому что адекватный человек (даже, хе-хе, демомейкер) не будет САМ СЕБЕ создавать сложности — он будет полностью использовать те возможности, которые ему даёт платформа. Это касается и памяти и отсутствий ограничения на число цветов на знакоместо и лёгкость проигрывания сэмплов и пр. Счастье, кстати, что REU для C64 не были широко доступны в своё время и не стали стандартом. Сейчас иногда делают демки для REU (ram expansion unit, до 512K обычно) но, как правило, бросается в глаза, что они написаны просто чтобы как-то использовать REU. Ну там картинку большего размера покрутить, к примеру. Или не возиться с непрерывной подгрузкой с диска, а загрузить сразу всё в буфер.
Хорошее замечание, включу в пример, часть кода. LINK — это регистр в который попадает значение IP для следующей инструкции, в случае записи в IP. То есть в случае с переходом (записью адреса перехода в IP) следующая инструкция на которую будет указывать IP это туда куда надо вернутся.
#label -> IP ; Переход на адрес label и запись адреса следующей инструкции в LINK
R1 -> ALU.A
.........
label:
..............
LINK -> IP ; возврат на команду R1 -> ALU.A
Можно сохранять LINK как и в случае с LR в ARM либо в ОЗУ, либо один из регистров общего назначения. Допустим R4 это стек.
; push LINK
R4 -> ADDR
LINK -> DATA ; LINK 16 битный регистр, будет записан в память как слово за два такта
R4 -> ALU.A
#2 -> ALU.B
ADD -> R4 ; R4 += 2
; pop LINK
R4 -> ALU.A
#-2 -> ALU.B
ADD -> R4
ADD -> ADDR
DATA -> IP ; IP - 16-битный регистр, буден считан за два такта
А вот очень хороший пример! Действительно либо адрес в 16бит и борьба за каждый байт (ЕМНИП, Стив Возняк неплохо это показал запихнув в 256 байт монитор для Apple-I), либо 24/32 бита — «счастье всем и никто не уйдет обиженным». Адресного пространства так много что ARM выделяет в нем области для манипуляцией битами. :)
Недавно были опубликованы исходники порта Doom на SNES созданного Рэнди Линденом считай что своими силами (id software вообще поначалу не была в курсе): gbx.ru/?showtopic=142214
По ссылке я новость написал с минимумом технических подробностей (но история сама, имхо, интересная), но сам же заинтересовался чипом SuperFX — это 16-битный процессор с архитектурой созданной под влиянием идей RISC который на 16-битной SNES позволял эффективно рисовать 3Д-графику — у ЦП SNES с этим есть ряд проблем. А у SuperFX прям как у Z80Next есть команда PutPixel и много прочего. Чип SuperFX впаивался в картридж SNES аки маппер в денди и рулил и педалил 3Д-графоний на 16 битах.
Думаю краткий обзор архитектуры SuperFX станет предметом моей следующей статьи, но тут распишу идею из него которая мне тоже понравилась и которую в таком виде нигде не видел.
Опкоды там как правило однобайтовые, но бывают префиксы.
Шестнадцать 16-битных регистров во многих инструкциях кодируются в четырёх битах как в статье: 0xAB, где A — код инструкции, а B — код регистра. Из этого правила есть немало исключений, но рассмотрим, например, операцию сложения:
ADD R5
В своей первичной форме она рассматривает R0 как аккумулятор и к нему прибавляет указанный в инструкции регистр R5. Т.е. берёт аккумулятор и R5, складывает их и результат записывает обратно в аккумулятор. Окей.
Однако можно временно на одну эффективную инструкцию сменить что будет являться приёмником операции — это делает инструкция TO:
TO R4
ADD R5
Здесь эффект будет таков, что сумма R0 и R5 будет записана в R4. После выполнения ADD приёмник по умолчанию опять станет R0.
Точно так же есть однобайтовая инструкция FROM которая так же меняет временно какой регистр будет служить первым операндом:
FROM R3
TO R4
ADD R5
Выполнит следующее: сумма R5 и R3 запишется в R4, а аккумулятор окажется вообще не при делах.
Для еще больше краткости есть однобайтовая же инструкция WITH которая сразу выставляет и FROM и TO в один и тот же указанный регистр.
Но и это еще не всё — WITH взводит еще один внутренний флаг который модифицирует поведение инструкций FROM и TO если они встречаются после неё. В SuperFX отсутствует специализированная команда MOVE, зато если после WITH сразу же идёт FROM, то происходит копирование из регистра указанного во FROM в регистре запомненном в WITH. И наоборот — инструкция TO скопирует из регистра запомненного по FROM в регистр указанный в себе.
FROM Rn ; код 0xBn - выставляет Sreg в n
TO Rn ; код 0x1n - выставляет Dreg в n
WITH Rn ; код 0x2n - выставляет и Sreg и Dreg в n
Довольно забавная система команд — байтово-ориентированная, но постоянно на каких то полухаках, префиксах и сменах текущих целей и назначений.
Каждый боролся за плотность кода как мог. :)))
Ахаха:D А всё началось с того, что я попросил Виктора впилить ldix и lddx как хоть какую-то альтернативу блиттеру, который они наотрез отказались делать. А дальше всё вышло из под контроля:D
Ну если не лезть внутрь ЦП, то это вполне реальный путь и он всё-равно будет теоретически намного быстрее обычного калькулятора, т.к. процессору останется исполнить ну десяток-два максимум инструкций.
Но вообще надо аккуратно исследовать вопрос — ведь калькулятор это в сути своей пресолиднейший кусок ROM, т.к. он и есть все функции бейсика включая USR которая должна обратно вывалиться в режим процессора.
Калькулятор держит стек в памяти как и ряд переменных в basic vars позволяющих определить где он заканчивается. Поэтому технически можно было бы обставить это дело таким образом, что код в RST 28 каким то образом запускает процесс калькулятора как нечто внешнее (накормив тем же адресом откуда надо выполнять инструкции), а по сигналу завершения берёт HL из известных переменных бейсика как он в общем то и делает скорее всего в оригинале.
Это как? Внешний доступ к памяти возможен, к регистрам — нет, а ведь в них по итогу калькуляторных процедур определённые значения ожидаются. Разве что обманом заставить проц по im0 выполнить команды загрузок, да еще нужные значения им подсунуть. Твой аух сумеет разве такое?
Поэтому я рекомендую все таки вызывать функцию, можно один раз и сохранять результат. Этот вариант проверено работает везде.
Например, в разделе про esxDOS там есть очень ценное замечание, что не обязательно всякий раз вызывать функцию GetSetDrv чтобы получить номер текущего диска когда нужно вызвать функцию которой нужно передать номер диска. Оказывается в аккумуляторе можно передать символьные значения:
A='*' для текущего диска и
A='$' для системного диска (где установлена NextOS или, видимо, сама esxDOS)
Так же там есть важное замечание, что к любым вызовам надо относится так, что они уничтожают AF,BC,DE,HL, но сохраняют все остальные регистры (например тот же IX).
В общем полезно почитать…
Таким образом переход к виртуальной машине дает возможность переноса на множество других платформ. А никогда не возникало ощущения, что аппаратные возможности платформы (ядра процессора) могли бы способствовать эффективному исполнению инструкций ВМ? Например у DEC в его последнем CISC-е VAX новые инструкции могли вносится как микрокод и нативно расширяли систему команд. В случае VM это конечно в большей степени касается вызова шитого кода.
Не могу точно сказать насчет первенства в JIT компиляции, DEC тоже делала шаги в эту сторону, кроме всего прочего снабжая ядро виртуальной машины профилировщиком, принимающим решение на определенной итерации начать «инлайнить код», то есть приложение становилось шустрее и шустрее, в зависимости от времени его работы.
У МК-85, приходилось читать Отрохова, разработчик Бейсика пошел на применение шитого кода для плавающей арифметики. Формально это тоже некая часть VM. Я хочу сказать что в определенный момент, когда сложность написания процедур, даже в такой удобной и интуитивно понятной
системе команд как PDP-11, начинает достигать пределов возможностей человеческого мозга. В таком случае уйти в форт-машину или еще какую либо VM, в конечном счете связано даже не с борьбой за плотность или переносимость кода, а за возможность продолжать вести разработку.
Как Вы и отметили растра 4:3, получить количество точек по горизонтали можно умножив кол-во строк на 4/3. Для PAL и SECAM это 800 элементов в строке. Не спорю конечно кинескоп и качество исполнения видеотракта дадут свои ограничения, на эти возможности.
У меня есть несколько вопросов, буду признателен за ответы.
1. Почему именно телевизионный растр?
2. Чем вызваны Ваши предпочтения накладываемые на видеоадаптер по разрешению и цветности, только ли ограничениями ТВ растра?
Однако действительно вопрос глубже — как «выдавить» при этом нормальную цветность.
Монохром как мы знаем в спектруме том же отнимает 6144 байта и раскраска знакоместами порождает клэшинг при попытке графонить графоний. Да и скроллинг в играх, а давайте уже не лукавить — игры это для нас очень важно — просто убивает и производительность и всё на свете — апдейтить 6Кб с приличным фпс — трудно для восьми бит.
Поэтому, имхо, оптимальность картинки в целом надо искать на пересечении текста и консольных принципов тайловой графики, причём одно плавно вытекает из другого, ибо не зря в Famicom/NES/Денди память тайлов офдоки называют CHR (character) ROM/RAM, ибо технически это действительно 256-значные символы квадратно-гнездовой сетки 8x8.
Однако Famicom, имхо, пример как немного перемудрили и ради призрачной экономии зарезали немало хорошего.
Главное — это аппаратный скроллинг по как минимум двум страницам видеотекста бесшовно перетекающий с прокрутной одна в другую.
Причём вот именно страницы текста имеют разрешение 32x32 символа, т.е. по вертикали виртуальное разрешение 256 пикселей, но оно используется чтобы организовывать бесшовный скроллинг с «проворотом» между границ.
Две экранных области текста пристыковани друг к другу слева-направо, над ними как бы «летает» видеоокно 256x192 на кинескоп управляемое одним 8-битным регистром прокрутки по вертикали и одним 9-битным регистром прокрутки по горизонтали (512 эффективных пикселей).
Но конечно чтобы игры на таком тексте делать еще нужны аппаратные спрайты.
В общем по лекалам денди я бы сделал так:
4Кб — память A изображений 256 тайлов 8x8 2bpp
4Кб — память B изображений 256 тайлов 8x8 2bpp
(одна область формирует тайлы для фона, другая — для спрайтов)
1Кб — текстовая видеостраница X 32x32 символа
1Кб — текстовая видеостраница Y 32x32 символа
(если произвольно скроллить, то видеостраницы пристыкованы прямоугольником «XY»)
256 байт — цветовые атрибуты видеостраницы X
256 байт — цветовые атрибуты видеостраницы Y
(2 бита на знакоместо/тайл выбирают ему палитру из 4-х возможных, в одном байте описывается 4 соседних символа/тайла квадратиком, что удобно для концепции метатайлов).
Но с таким потайловым и удобным для скроллинга фоном нужно конечно еще спрайты. Именно для них нужна память изображений Б ибо одной там реально маловато.
А чтобы всякие Elite делать нужно иметь второй видеорежим где первые 8Кб можно превратить в монохром, т.е. уже чистую графику.
К слову — даже если посмотреть на Амигу, снятие ограничений пошло, на мой взгляд, ей непосредственно во вред. В среднем качество софта (демо и интро в первую очередь) сильно ниже, чем таковое у 8-битных платформ (того же C64).
Потому что адекватный человек (даже, хе-хе, демомейкер) не будет САМ СЕБЕ создавать сложности — он будет полностью использовать те возможности, которые ему даёт платформа. Это касается и памяти и отсутствий ограничения на число цветов на знакоместо и лёгкость проигрывания сэмплов и пр. Счастье, кстати, что REU для C64 не были широко доступны в своё время и не стали стандартом. Сейчас иногда делают демки для REU (ram expansion unit, до 512K обычно) но, как правило, бросается в глаза, что они написаны просто чтобы как-то использовать REU. Ну там картинку большего размера покрутить, к примеру. Или не возиться с непрерывной подгрузкой с диска, а загрузить сразу всё в буфер.
Можно сохранять LINK как и в случае с LR в ARM либо в ОЗУ, либо один из регистров общего назначения. Допустим R4 это стек.
И еще по вашему процессору я не понял как делается CALL — LR вроде есть, но непонятно что в него записывать.
P.S. Статья про SuperFX будет крайне интересна!
По ссылке я новость написал с минимумом технических подробностей (но история сама, имхо, интересная), но сам же заинтересовался чипом SuperFX — это 16-битный процессор с архитектурой созданной под влиянием идей RISC который на 16-битной SNES позволял эффективно рисовать 3Д-графику — у ЦП SNES с этим есть ряд проблем. А у SuperFX прям как у Z80Next есть команда PutPixel и много прочего. Чип SuperFX впаивался в картридж SNES аки маппер в денди и рулил и педалил 3Д-графоний на 16 битах.
Думаю краткий обзор архитектуры SuperFX станет предметом моей следующей статьи, но тут распишу идею из него которая мне тоже понравилась и которую в таком виде нигде не видел.
Опкоды там как правило однобайтовые, но бывают префиксы.
Шестнадцать 16-битных регистров во многих инструкциях кодируются в четырёх битах как в статье: 0xAB, где A — код инструкции, а B — код регистра. Из этого правила есть немало исключений, но рассмотрим, например, операцию сложения:
В своей первичной форме она рассматривает R0 как аккумулятор и к нему прибавляет указанный в инструкции регистр R5. Т.е. берёт аккумулятор и R5, складывает их и результат записывает обратно в аккумулятор. Окей.
Однако можно временно на одну эффективную инструкцию сменить что будет являться приёмником операции — это делает инструкция TO:
Здесь эффект будет таков, что сумма R0 и R5 будет записана в R4. После выполнения ADD приёмник по умолчанию опять станет R0.
Точно так же есть однобайтовая инструкция FROM которая так же меняет временно какой регистр будет служить первым операндом:
Выполнит следующее: сумма R5 и R3 запишется в R4, а аккумулятор окажется вообще не при делах.
Для еще больше краткости есть однобайтовая же инструкция WITH которая сразу выставляет и FROM и TO в один и тот же указанный регистр.
Но и это еще не всё — WITH взводит еще один внутренний флаг который модифицирует поведение инструкций FROM и TO если они встречаются после неё. В SuperFX отсутствует специализированная команда MOVE, зато если после WITH сразу же идёт FROM, то происходит копирование из регистра указанного во FROM в регистре запомненном в WITH. И наоборот — инструкция TO скопирует из регистра запомненного по FROM в регистр указанный в себе.
Довольно забавная система команд — байтово-ориентированная, но постоянно на каких то полухаках, префиксах и сменах текущих целей и назначений.
Каждый боролся за плотность кода как мог. :)))
Но вообще надо аккуратно исследовать вопрос — ведь калькулятор это в сути своей пресолиднейший кусок ROM, т.к. он и есть все функции бейсика включая USR которая должна обратно вывалиться в режим процессора.
+ еще загрузить корректный указатель стека кроме HL
как-то не особо «просто» уже всё это