Тыкать в ZX Spectrum

Я играю со старым ZX Spectrum 48k и мне интересно, как именно можно вводить коды POKE.

Вы загружаете игру с ленты - затем каким-то образом вырываетесь из типа программы в операторах POKE и снова запускаете программу?

Я много искал по этому вопросу, но не смог точно выяснить, как это делается, поэтому любые выводы по этому поводу будут высоко оценены.

5 ответов

Прежде всего, значение PEEK и POKE:

10 let x = PEEK 40000: REM returns (reads) the value (0-255) in position 40000
20 POKE 40000, 201: REM writes the 201 value in position 40000

Большинство программ загружают небольшую программу BASIC, называемую загрузчиком. Это было что-то вроде:

10 cls
20 print "Loading AWESOME GAME!!!"
20 load "" screen$
30 load "" code 40000
40 randomize usr 40000

Смысл должен быть прост: загрузите экранную презентацию (строка 20), чтобы развлечь пользователя, пока загружается программа на ассемблере (сама игра) (строка 30), и, наконец, запустите игру (строка 40).

О линии 40, usr 40000 это выражение, которое делает трюк, вызывая сборку в позиции 40000. Инструкция Randomize просто инициализирует случайное семя, используемое rndдумал, что это на самом деле никогда не вернется.

Итак, первые попытки будут:

  1. Нажмите "перерыв" (более или менее эквивалентный Ctrl+C), введите listи поместите тычки в строку 35, то есть, как только программа была загружена, но она еще не была выполнена.

  2. Вместо того, чтобы печатать load "" чтобы запустить игру, наберите merge "" (это использовалось, чтобы объединить основную программу в памяти с той в ленте). Процесс остановится перед выполнением загрузчика. Это полезно, когда загрузчик включает poke Инструкция, которая отключила BREAK.

Проблема с этими методами заключалась в том, что сначала попытки скрыть внутренности загрузчика были наивными (такими как включение инструкции PAPER 0: INK 0 или что-то подобное в строке 10, делающей все временно невидимыми), но вскоре они получат гораздо более сложным, вплоть до того, чтобы быть на самом деле программой ассемблера, включенной в REM инструкции.

Следующим шагом было проанализировать заголовки кода сборки, загруженного после основного загрузчика, определить адрес дампа и длину кода и создать свой собственный загрузчик, в который можно было бы включить poke инструкции, которые вы хотели. Многие журналы распространяли загрузчики такого типа, которые предназначались для загрузки до исходного (загрузчик искал определенные блоки, минуя оригинальный базовый загрузчик).

Поэтому разработчики решили включить сборочные блоки в ленту без заголовков, а также защитить загрузчик. Или включая загрузчик, который просто загружает программу сборки, которая заменяет загрузчик в ПЗУ, используя разные скорости, без информации заголовка и т. Д. Или включая загрузчик, который загружает блок без заголовка, включая экран презентации и код для игры.

И тогда появилось специальное оборудование, такое как Multiface-1. Читая руководство по Multiface-1, вы можете увидеть, как при запуске программного обеспечения multiface (включенного в ПЗУ периферийного оборудования), нажав красную кнопку (которая вызвала NMI (не маскируемое прерывание)), было показано меню, позволяющее сэкономить память в этой точке. (и сохраненный код будет свободен от какой-либо защиты, открывая, таким образом, путь для создания собственного загрузчика с pokes), или даже исследует (PEEK) текущие значения по конкретным адресам в памяти и введите POKEнепосредственно (с помощью которого вы могли бы найти начало тех рутин, например, которые уменьшают ваши жизни в одной).

Инструкции POKE обычно были такими (это упрощение): POKE addr, 0 или же POKE addr, 201, Число addr было началом рутины, уменьшающей количество доступных жизней или обнаруживающей столкновение с врагом.

Код 0 - это инструкция сборки NOP (без операции). Во время NOP процессор ничего не делает.

Код 201 или C9 это сборка RET (возврат) инструкция, что означает возврат для подпрограммы. В бейсике вы бы вызвали подпрограмму с GOSUB и вернуться с его конца с RETURN, В ассемблере эта же пара называется CALL/RET.

Если бы у вас был 201, то это фактически означало бы, что подпрограмма (скажем, вычитание одной из ваших жизней), такая как:

9950 let lives = lives - 1
9960 return

был преобразован в:

9950 return
9960 return

Если у вас было значение 0, та же самая процедура была преобразована в:

9950
9960 return

Коды POKE, напечатанные в журналах ZX Spectrum, обычно предполагают наличие подключаемого аппаратного устройства (например, Multiface). Как только игра загрузится, вы можете нажать кнопку Multiface, чтобы остановить игру, ввести POKEs, а затем вернуться в игру.

Без специального устройства вам нужно поиграться с программами загрузчика, как описано в других ответах. Вам нужно загрузить исходную небольшую загрузочную программу, а затем BREAK в код. Если вам повезет, код сделает что-то простое с загрузкой в ​​оставшейся части игры, а затем выполнит реальную игру с машинным кодом, используя вызов RANDOMIZE USR. В этом случае вы можете изменить программу BASIC в загрузчике так, чтобы она выполняла POKES после загрузки игры, но до ее запуска.

Тем не менее, во многих играх это сложно сделать, потому что они содержат собственный код загрузчика. Это часто пишется в машинном коде, встроенном в небольшую программу BASIC в операторах REM. Машинный код загрузит игру и выполнит ее, и, поскольку они никогда не возвращают управление БЕЙСИК-коду, нет возможности ввести POKE. Если вы достаточно преданы своему делу, вы можете попытаться изменить машинный код, чтобы либо вернуть управление обратно в BASIC, чтобы вы могли ВЫДЕЛАТЬ, либо выполнить РОК через вызовы машинного кода. Это довольно сложно, потому что, если я правильно помню, редактор использовал для шифрования строк, содержащих непечатаемые символы в операторах REM. Существовали такие программные инструменты, как RoyBot, которые могли бы помочь вам изменить код в памяти.

Некоторые разработчики игр делали действительно сумасшедшие вещи, чтобы предотвратить взлом игры, такие как реализация кода загрузчика, который фактически перезаписывал свой собственный код во время его выполнения.

Большинство программ Spectrum используют двухэтапный процесс для запуска игры:

  1. Загрузите и запустите небольшую программу BASIC
  2. Эта небольшая BASIC-программа затем загружает намного более длинный машинный код и затем переходит к точке входа машинного кода (например, RANDOMIZE USR 28455).

Если вам удастся остановиться между этими шагами, вы можете POKE вокруг (чтобы увеличить количество жизней,...), а затем запустить машинный код с RANDOMIZE USR 28455, если вы как-то узнали правильный адрес.

После запуска машинной программы обычно невозможно остановить ее и вернуться к интерпретатору BASIC. Если машинная программа не предоставляет какой-либо явный (или непреднамеренный) способ сделать это.

В качестве временного решения, чтобы найти правильный тычок, и после загрузки и BREAK программы вы можете искать такие команды, как:

      LD A,3

В игре с 3 жизнями на старте. Код в HEX для этой команды:

      3E 03 -> in hex
62 3  -> in decimal

Найдите эти данные и измените, например, 03 на 255 (255 - максимальное значение allowebd). Тогда проверьте это.

Как я помню из давних времен.... Когда загружается игра Spectrum, она изначально загружается в небольшую загрузочную программу и запускает ее, лента продолжается и загружается основная часть программы. Последняя команда в загрузчике Затем программа выдает команду poke, которая вызывает все загруженное и запускает игру. Итак, насколько я помню, вы должны приостановить ленту, как только загрузится программа-загрузчик, и остановить строку кода от автоматического выдачи финального удара, а затем продолжить. Затем, как только основная масса загружена, вы запускаете свой удар из командной строки, а затем исходный удар, чтобы начать игру. Программа-загрузчик будет загружена после первого набора красных и синих линий, за которыми следуют очень короткие желтые и синие линии на экране (насколько я помню, печатается название программы, найденной в этот момент). Остановите ленту, нажмите Break, затем List, чтобы увидеть код. Удачи и отличный вопрос!

Другие вопросы по тегам