Можно ли процедурным образом определить количество циклов, выполняемых конкретной инструкцией на 6502?

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

Мне интересно, есть ли способ процедурно определить количество циклов, которые будет выполнять инструкция, основываясь исключительно на режиме адресации и чтении / записи памяти.

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

Все инструкции нулевой страницы занимают 3 цикла, плюс дополнительные 2 цикла, если изменение памяти на месте.

Все проиндексированные инструкции нулевой страницы занимают 4 цикла, плюс дополнительные 2 цикла, если изменение памяти на месте.

...И так далее.

Итак, есть ли какой-нибудь полностью документированный, процедурный способ определения количества циклов для инструкции, подобной приведенной выше? Существуют ли исключения, которые нарушают детерминизм в такой формуле?

1 ответ

Решение

Да - и так написаны почти все точные эмуляторы *; см. документы, такие как 64doc.txt. Это не намного сложнее, чем простой подсчет доступа к памяти - 6502 будет выполнять доступ к памяти каждый цикл, обычно он может получить значимый результат в течение оставшейся части цикла после доступа (т.е. я немного машу рукой, чтобы избежать обсуждение того, что конвейеризировано, а что нет; см. документацию).

Так, например, для ADC #54 процессор должен (i) прочитать код операции; (ii) читать операнд. Это два цикла.

За ADC ($32), Y это:

  1. читать код операции
  2. читать операнд
  3. читать с $32, чтобы получить младший байт адреса
  4. прочитайте от $33, чтобы получить старший байт адреса, добавьте Y к младшему байту адреса
  5. чтение из (старший байт адреса):(младший байт адреса + Y), так как было только время для выполнения вычисления младшего байта
  6. о, подождите, если был перенос, то последний результат был неправильным, лучше перечитайте еще раз. Если нет, то отлично, все хорошо, не беспокойтесь об этом цикле.

Так что это либо 5, либо 6 циклов.

Вы всегда можете эмулировать доступ к памяти больше как пошаговую синхронизированную вещь и выполнять фактическую операцию как ортогональный шаг. Также легко использовать одну и ту же логику для чтения, записи или чтения-изменения-записи: чтение и запись имеют одинаковое время, но в конце имеют разный доступ к памяти, все команды tead-modify-write записывают значение чтения обратно для цикла Разрабатывая реальный результат, напишите реальный результат.

*) поскольку одновременное выполнение всех обращений к памяти, за исключением избыточных, то небольшое искажение времени вперед абсолютно не похоже на реальное аппаратное обеспечение. И это сбивает вас с толку, как только доступ к памяти будет связан с чем-либо с независимой концепцией времени - таймером или чем-то, что может генерировать прерывания, или просто самой ОЗУ, если машина сканирует ОЗУ для вывода видео; не берите в голову, что это требует, чтобы вы добавили специальные случаи вокруг инструкций как CLI а также SEI**. Эмуляторы больше не нужно структурировать, как в 1990-х годах.

**) Состояние IRQ определяется в предпоследнем цикле каждой операции. CLI а также SEI отрегулируйте бит во время последнего цикла. Так что даже если прерывание ожидает, то CLI не приведет к прерыванию, пока после инструкции после CLI, Который сам может быть SEI, Так что CLI/SEI пара в ожидании прерывания должна привести к отключению обработчика прерываний после SEI выполнено с установленным флагом прерывания. Это происходит естественным образом, если вы эмулируете циклическое поведение 6502, как правило, становится огромным хаком, если вы работаете по принципу "операция за операцией" и искажением времени. Или, что более вероятно, такие эмуляторы просто неправильно понимают поведение.

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