GO WEST, часть 2
Ну вот я и созрел написать вторую часть талмуда по классическим спектрумам. Первая часть никому не понравилась, потому что в ней было многабукаф и никаких картинок. Попробую исправиться: напишу меньше букаф.
Эта секция касается первых двух типов классических спектрумов: 48K и 128K/+2. Насколько я знаю, все описанные в этой секции чудеса были исправленые в поздних спектрумах от Amstrad (т.е. +2a/+2b/+3).
Все самые распространённые затыки отечественного софта на западных спектрумах связаны с «портом» #FF. Самая главная проблема с этим портом заключается в том, что его НЕТ! Т.е., в старых спектрумах нет специального порта, который бы иногда читал данные из экранной памяти, как это пытались иногда воспроизвести в радиолюбительских поделках в дремучих 1990-х. Что происходит на самом деле связано с так называемой плавающей шиной. Нам, как программистам, не очень важно знать, что это означает на уровне железа, кто к кому припаян или, наоборот, не припаян. Практические последствия наличия плавающей шины на классических спектрумах таковы:
Практические последствия всех этих ужасов такие:
Продолжение следует
ПЛАВАЮЩАЯ ШИНА (И «ПОРТ» #FF)
Эта секция касается первых двух типов классических спектрумов: 48K и 128K/+2. Насколько я знаю, все описанные в этой секции чудеса были исправленые в поздних спектрумах от Amstrad (т.е. +2a/+2b/+3).
Все самые распространённые затыки отечественного софта на западных спектрумах связаны с «портом» #FF. Самая главная проблема с этим портом заключается в том, что его НЕТ! Т.е., в старых спектрумах нет специального порта, который бы иногда читал данные из экранной памяти, как это пытались иногда воспроизвести в радиолюбительских поделках в дремучих 1990-х. Что происходит на самом деле связано с так называемой плавающей шиной. Нам, как программистам, не очень важно знать, что это означает на уровне железа, кто к кому припаян или, наоборот, не припаян. Практические последствия наличия плавающей шины на классических спектрумах таковы:
- Во-первых, у нас есть порт #FF. Если сказать совсем точно, у нас есть нетривиальное поведение любых несуществующих портов. Это, конечно, довольно общо. Можно составить табличку:
Модели Порты, которые при чтении будут вести себя как «порт» #FF 48K любой порт с нечётным адресом 128К/+2 любой порт с адресом соответствующим маске xxxxxxxx xxxxxx11
Что считывается из всех этих портов? Текущее значение на шине данных. Если у нас в момент чтения порта рисуется бордер, будет скачано значение #FF. Если у нас в данный момент рисуется экран (т.е. читаются данные из экранной памяти), в зависимости от точного такта, когда выполняется чтение, вы можете получить значение рисующегося в данный момент байта растра или атрибутов. Большую часть времени это поведение вполне себе бесполезно, но
- Некоторые старые программы использовали порт #FF чтобы узнать когда начал рисоваться экран. Это полезно в тех случаях, когда программа рисует экран «за лучом». На практике, это означает, что программа может потратить до ~14 тысяч тактов на свои внутренние дела (точное число тактов обсудим в третьей части), потом дождаться начала рисования экрана (цикл ждущий пока значение порта #FF не изменится на что-то отличное от #FF) и начать рисовать изображение для следующего кадра поверх уже отображённой экранной памяти. У рисования за лучом по такой схеме много недостатков: эта схема не работает на машинах без порта #FF, кроме того, эта схема довольно неэффективна на турбированных компьютерах. Тем не менее, оригинальные релизы Arkanoid, Cobra, Sidewize и Short Circuit использовали именно такую схему рендера.
- Теперь представьте себе, что вы подключили к своему спектруму Kempston джойстик. Тогда у вас появился новый порт 31, биты которого указывают нам что и где нажато. Как обычно проверяют наличие кемпстона? читая значение из порта 31 и проверяя, чтобы старшие 3 бита в прочитанном значении были сброшены (на младшие биты полагаться нельзя — пользователь может мять джойстик в руках). Идея эта, в общем, правильная, вот только на классических спектрумах БЕЗ кемпстон джойстика легко можно попасть впросак, так как порт 31 — нечётный и вместо порта кемпстона вы считаете значение с плавающей шины. Если в данный момент рисуется бордер — всё пройдёт ОК, но вот если в данный момент рисуется экран — можно запросто считать экранный байт со сброшенными старшими битами и решить, что кемпстон у нас есть, хотя на самом деле это, конечно, не так. Решается эта проблема так: тест наличия кемпстона нужно всегда проводить сразу после прерывания, на бордере, там где плавающая шина точно не будет фокусничать:
ei halt ; must ensure that test is done during the border in a,(#1f) inc a jr nz,haveKempston doNotHaveKempston:
- Некоторые старые программы использовали порт #FF чтобы узнать когда начал рисоваться экран. Это полезно в тех случаях, когда программа рисует экран «за лучом». На практике, это означает, что программа может потратить до ~14 тысяч тактов на свои внутренние дела (точное число тактов обсудим в третьей части), потом дождаться начала рисования экрана (цикл ждущий пока значение порта #FF не изменится на что-то отличное от #FF) и начать рисовать изображение для следующего кадра поверх уже отображённой экранной памяти. У рисования за лучом по такой схеме много недостатков: эта схема не работает на машинах без порта #FF, кроме того, эта схема довольно неэффективна на турбированных компьютерах. Тем не менее, оригинальные релизы Arkanoid, Cobra, Sidewize и Short Circuit использовали именно такую схему рендера.
- Во-вторых, модели 128K/+2 имеют баг в железе. Проявляется он следующим образом: если попробовать считать значение из порта #7FFD, вместо чтения, классический спектрум положит в порт #7FFD текущее значение плавающей шины. Вместо #7FFD, как всегда, можно подставить любой порт с адресом, соответветствующим маске: 0xxxxxxx xxxxxx0x
Качественный, породистый баг. Если не знать в чём дело, можно крепко напороться.
Я не знаю наверняка, остался ли этот баг в более поздних моделях +2a/+2b/+3. Некоторые пишут, что остался, некоторые пишут что нет. Нужно проверять на железе.
- Во-третьих, плавающая шина проявляется ещё в одной ситуации. При исполнении некоторых команд, периодически, процессор выставляет на шину адрес IR (с целью регенерации памяти). Обыкновенно это не создаёт никаких проблем, но если регистр I содержит адрес соответствующее медленной памяти (#40-#7F), то в определённых ситуациях ULA немного сходит с ума и не прочитывает значения экранной памяти корректно, выдавая вместо них какую-то белиберду. ОК, не совсем белиберду. Вместо экранного адреса, выставленного на шину ULA, спектрум прочитывает данные из адреса, старший байт которого верный, но младший байт берётся из регистра R. T.e., фактически, ULA берёт неправильные байты из правильной трети экрана (это верно и для растра и для атрибутов).
Этот эффект называется «снегом». Вот пара примеров спектрумовского снега:
Снег точно есть на 48K и 128K/+2. Некоторые пишут, что снег на 128K/+2 машинах может привести к сбросу компьютера; я не имел возможности это проверить. На +2a/+2b/+3 проблема со снегом была исправлена.
Практические последствия всех этих ужасов такие:
- Никогда не кладите вектор прерываний IM2 в медленную память.
- Никогда не читайте из порта #7FFD, или даже шире, никогда не читайте из портов 0xxxxxxx xxxxxx0x, если вы не уверены на 100% на каком компьютере вы находитесь. Чтение из этих портов на классических 128K машинах — чревато.
- Работая с железом доступным по нечётному порту, типа кемпстона, всё время продумывайте, что произойдёт с вашей программой, если этого железа не окажется в наличии и вы начнёте читать содержимое экрана. Защищена ли ваша программа от фокусов с портом #FF?
Продолжение следует
20 комментариев
Про снег хорошо!
Хотя кто-то писал что случайно закодил скроллер.
Т.е. идея здоровая в общем.
thanks!
М.б. нужно просто проверить на твоём реале…
А что за страшный порт #FF, я всё равно так и не понял :(
думая при этом, что ты о нём знаешь всё :)
спасибо!
ждём продолжения банкета! )
Недавно разыскали плавающую шину и на этих моделях.
Тут вот всё подробнее.
Your text to link...
Релизы идеально называть именами не больше 8 букв для сохранения совместимости с разными файловыми системами.
Старая кассетная школа говорит нам, что имя может быть 10 символов — ОК.
Однако если вы пошли дальше, и пишите длинное название релиза, учитывайте, что в браузере DivIDE FatWare видно всего лишь 19 символов (имя точка расширение). Если у вас несколько версий файлов и СУТЬ указана в конце (например финальный релиз Tiratok) то после копирования их на DivIDE просто невозможно понять, какой из файлов нужен.
Могу подтвердить, что на сером +2 Dizzy 3 сбрасывается в самом начале игры, в буквальном смысле — с первым снегом.