Эмулятор 6502 на C / C ++: как отделить код режима адресации от фактического кода инструкции

В свободное время я начинаю писать очень простой эмулятор C ++ для процессора 6502. Раньше я записывал много ассемблерного кода для этого процессора, поэтому все коды операций, режимы адресации и другие вещи не имеют большого значения.

6502 имеет 56 различных инструкций плюс 13 режимов адресации, что дает в общей сложности 151 различный код операции. Для меня скорость не является проблемой, поэтому вместо написания огромного оператора switch-case и повторения одного и того же кода снова и снова (разные коды операций могут ссылаться на одну и ту же инструкцию с использованием другого режима адресации) я хотел бы отделить фактический код инструкции от код режима адресации: я нашел это решение очень изящным, так как для этого нужно было бы написать только 13 функций режима адресации и 56 функций команд без повторения.

здесь функции режима адресации:

// Addressing modes
uint16_t Addr_ACC(); // ACCUMULATOR
uint16_t Addr_IMM(); // IMMEDIATE
uint16_t Addr_ABS(); // ABSOLUTE
uint16_t Addr_ZER(); // ZERO PAGE
uint16_t Addr_ZEX(); // INDEXED-X ZERO PAGE
uint16_t Addr_ZEY(); // INDEXED-Y ZERO PAGE
uint16_t Addr_ABX(); // INDEXED-X ABSOLUTE
uint16_t Addr_ABY(); // INDEXED-Y ABSOLUTE
uint16_t Addr_IMP(); // IMPLIED
uint16_t Addr_REL(); // RELATIVE
uint16_t Addr_INX(); // INDEXED-X INDIRECT
uint16_t Addr_INY(); // INDEXED-Y INDIRECT
uint16_t Addr_ABI(); // ABSOLUTE INDIRECT

все они возвращают фактический адрес памяти (16 бит), используемый инструкцией для чтения / записи операнда / результата

прототип функции инструкции:

void Op_ADC(uint16_t addr);
void Op_AND(uint16_t addr);
void Op_ASL(uint16_t addr);
    ...

он принимает 16-битный адрес, выполняет свои собственные операции, обновляет флаги состояния и / или регистры и фиксирует результаты (если есть) по тому же адресу памяти.

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

Функции команд должны быть полностью независимыми от режима адресации.


person Gianluca Ghettini    schedule 23.11.2013    source источник
comment
Внутренне используя 16-битный режим адресации, вы можете просто отобразить полный контекст (A, X, Y, SP, ST, PC, что еще?) На адрес 0x10000; ваши функции должны быть изменены, чтобы принимать адрес uint32_t, из которого фактически используются только первые 0x10008 или около того байта.   -  person Aki Suihkonen    schedule 23.11.2013
comment
Если инструкции относятся к независимому режиму, то зачем им нужен флаг, чтобы знать источник данных? Возможно, вам будет полезно найти или воссоздать схему путей данных процессора; обычно мультиплексоры подаются на входные порты ALU, поэтому вы можете сосредоточиться на функциональных блоках, которые получают эти данные, и на тех, которые их используют. Учитывая, что все это состояние, видимое и скрытое внутри модели программирования, является фактически глобальным, использование глобальных переменных (или машинной структуры, на которую вы передаете указатель) в порядке, если это упрощает вашу реализацию.   -  person Chris Stratton    schedule 23.11.2013
comment
@Chris: На данный момент они не являются полностью агностическими, потому что в одном случае возвращаемое значение uin16_t представляет адрес памяти, а в режиме аккумулятора представляет фактическое содержимое регистра A. Функция инструкции принимает аргумент uint16_t и, учитывая, что это невозможно определить, является ли это адресом памяти или 8-битным значением, для этого также должен потребоваться логический флаг или что-то в этом роде.   -  person Gianluca Ghettini    schedule 23.11.2013
comment
Я бы подумал, что ваши функции выборки операндов должны отменять ссылку на адрес памяти для получения данных и предоставлять это функции ALU. Думаю, это действительно поможет вам понять из блок-схемы, как на самом деле работает процессор. По сути, есть несколько частей, которые не зависят от остальных, а затем (по крайней мере теоретически) управляющий ROM, который декодирует биты командного слова в более широкий набор сигналов, которые управляют различными переключателями тракта данных. Или, возможно, 6502 микропрограммирован (признаюсь, что не проверял). Любой из них должен работать.   -  person Chris Stratton    schedule 23.11.2013
comment
@Aki: это кажется очень хорошим решением, браво! Я могу придумать немного другое решение, в котором только регистр A отображается в дополнительное место 0x10000, остальные мне на самом деле не нужны. В качестве возвращаемого значения снова потребуется uint32_t.   -  person Gianluca Ghettini    schedule 23.11.2013
comment
@ Крис: это не микропрограмма. Он имеет простой PLA, в котором фактическое значение кода операции включает / выключает все внутренние части ЦП; набор инструкций почти ортогонален   -  person Gianluca Ghettini    schedule 23.11.2013
comment
Да, использование только A в адресе 0x10000 было моей первой идеей, но потом я понял, что налог, тай и т. Д. Могут использовать тот же механизм внутри. Но решать тебе ...   -  person Aki Suihkonen    schedule 23.11.2013
comment
Почему бы не обработать каждый этап: {выборка операнда, ALU, обратная запись} в собственном маленьком переключателе между возможными функциями, основанном на соответствующих битах командного слова и игнорируя все остальное. Вроде бы он должен быть достаточно компактным.   -  person Chris Stratton    schedule 23.11.2013
comment
1) Я думаю, вы обнаружите, что скорость имеет значение, как только вы заставите ее работать и попытаетесь запустить ее на чем-то интересном, и вдруг гигантский оператор switch будет иметь значение 2) 151 процедура из 5 строк? Думаю, я бы просто укусил пулю и сделаю это; Я подозреваю, что ты закончишь за 2 часа. (Этот обмен, вероятно, просто отвлекает). У вас наверняка будут общие подпрограммы, реализующие режимы адресации, и в этом вы получите преимущество.   -  person Ira Baxter    schedule 23.11.2013
comment
Попросите функции режима адресации возвращать указатель на данные.   -  person brian beuning    schedule 23.11.2013
comment
Режим АККУМУЛЯТОРА на самом деле является своего рода ПОДРАЗУМЕВАЕМЫМ режимом. Оба режима не используют адрес. Вы должны реализовать такие инструкции как отдельные инструкции. Пример: реализовать две инструкции для ROL: ROL A и ROL memory (которые могут быть ABSOLUTE или INDEXED-X ABSOLUTE).   -  person Martin Rosenau    schedule 23.11.2013
comment
Мартин: Вы абсолютно правы, и ваше решение очень хорошо сочетается с моим кодом ... Моя основная цель состояла в том, чтобы не повторять какой-либо код инструкции, но я думаю, что решение является разумным. Есть всего пара инструкций, которые используют режим аккумулятора (а те, которые используют подразумеваемый режим, не используют никаких других режимов адресации)   -  person Gianluca Ghettini    schedule 24.11.2013
comment
@Martin: перепишите свой последний комментарий как ответ, и я его приму.   -  person Gianluca Ghettini    schedule 28.11.2013
comment
эй ... Наконец-то я это сделал: посмотрите на: code.google.com/p/mos6502 < / а>   -  person Gianluca Ghettini    schedule 08.01.2014


Ответы (1)


В Sharp6502 (мой движок эмуляции 6502, написанный на C #) я рассматриваю внутренние регистры и внешнюю память как объекты первого класса - класс MemoryManager создает экземпляр объекта для внешней памяти, а другой - для внутренних регистров, сопоставленных с другим числовым диапазоном. Следовательно, доступ к памяти и доступ к регистрам идентичны на функциональном уровне, поскольку на них обоих ссылаются через MemoryManager в соответствии с тем, что в основном является индексом.

Дифференциация адресного режима - это просто вопрос фильтрации битовой последовательности эмулируемой инструкции и выполнения очень простых вычислений для определения индекса, который должен быть передан в MemoryManager - это может подразумеваться или требовать еще одного или двух байтов, но лежащий в основе механизм идентичен для каждой инструкции.

person Eight-Bit Guru    schedule 24.11.2013