Комментарии 17
В порядке "стилистических" придирок: лучше избегать таких типов, как WORD, потому что их трактовка различается от платформы к платформе. На ПК исторически сложилось, что слово = 16 разрядов независимо от разрядности процессора, но, скажем, на 32-разрядных ARM слово -- таки 32 бита, ну а на том же 6502 слов на уровне терминологии вообще не было. Так что я предпочитаю, чтобы разрядность подобных типов прямо у них и указывалась (лично я использую всякие там int8/uint8 и т.д. и т.п.).
Насчёт "множества режимов адресации": восемь -- это много, лишь немногие архитектуры имели больше, ну а десятков действительно разных режимов, возможно, нигде никогда и не было. Нет, если считать за разные виды адресации один и тот же вид, но с разными регистрами, то можно и сотни насчитать -- но разными они таки не будут.
Ну и, наконец, эмуляция процессора -- это хорошо, но она приобретает смысл лишь в случае эмуляции целого компьютера -- и таких проектов весьма много. А без этого... Ну, сделали выполнение команд, и что дальше? Даже не поиграешь в какую-нибудь древнюю игрушку для Эпла-2, Денди или нашего Агата, которые как раз на 6502 были :)
ну а десятков действительно разных режимов, возможно, нигде никогда и не было.
если считать для всех видов инструкций и для всех типов памяти например в AVR архитектуре то больше десятка насчитать наверно можно, там для разных диапазонов памяти свои инструкции. Например к регистрам можно обращаться как к памяти по адресу а можно как к регистрам, в самих регистрах есть веделенный диапазон с которым могут работать только определенные инструкции, память IO регистров - это другой специальный тип памяти там тоже есть спец-режимы для разных областей, а еще есть память программ в которой тоже можно данные хранить и есть спец инструкции для их извлечения, еще есть еeprom память, память подключаемая по внешней шине... Это то что помню навскидку.
Десяток -- да, но не несколько десятков, думаю. В VAX-11, кажется, 12 было. В AVR8 -- да, примерно как Вы написали (точно уж не помню, писал под неё только один раз на асме, хоть и коммерческий проект был -- но 10+ лет назад, подробности, есно, давно выветрились).
А вот если говорить о памяти, подключаемой как внешнее устройство (скажем, EEPROM на I2C), то проц об этом ничего не знает и никаких особых видов адресации не имеет: там доступы выполняются к регистрам контроллера I2C или какая там шина используется.
Насколько я помню, у 6502 было 13 документированных режимов адресации. Правда, были среди них и такие, которые, например, использовались только одной командой. И, действительно, 13 и даже 8 – это много.
Другое дело, что конкретно мнемокод AND допускает 8 документированных режимов адресации.
В большинстве проектов эмуляторов, что я видел, декодер сделан на switch-case. Удивляет?
Не нужно думать, что вы умнее всех остальных разработчиков эмуляторов.
Switch/case это самое оптимальное решение, как раз потому, что код сложен в одном месте.
Уже догадались, какой стала вторая и последняя итерация? Таблица вызовов!
Компилятор превращает switch/case в таблицу автоматически.
Рекомендую ознакомиться с этим проектом (потактовый эмулятор 6502)
https://github.com/floooh/chips/blob/master/chips/m6502.h
Легко читать, легко понять.
построение на их основе полноценных систем
Тем более нужен потактовый эмулятор, потому что результат может меняться в зависимости от того, на каком такте команды вы запишете данные в регистр железки (или в память).
Кстати о потактовых эмуляторах: чисто для интереса делал эмулятор zx-spectrum и там пришлось делать эмулятор процессора z80 не потактовый, но поцикловый. Один машинный цикл - это несколько тактов, а одна команда процессора - несколько машинных циклов.
Это нужно было, чтобы реализовать конкурентный доступ к видеопамяти со стороны процессора и подсистемы видео
На самом деле любой код операции в 6502 имеет предопределённую семантику, просто некоторые документированы, а некоторые нет. Если рассмотреть систему команд 6502 на более низком уровне, то отдельные биты в кодах команд отвечают за определённые микрооперации, исходя из чего и получается операционная семантика команды в целом.
В любом случае, вешать останов эмулятора на какой-то код команды – плохое для практического использования решение, потому что ситуация, когда исполнение начинает гулять по случайным байтам – не редкость. Архитектура 6502 гарантирует, что мы остановимся при этом на первом BRK (вот только не помню, нет ли дополнительных недокументированных опкодов у BRK, помимо $00).
Отличный проект. Спасибо что поделились. На старых процессорах хорошо если: register, direct, indirect, indexed - есть вообще. На старом Intel встречал: можно 8 bit , а можно - 16 bit двумя регистрами.
А почему MOS6502_Status
сделан байтами, а не битовыми полями? Как раз слово состояния процессора автоматически получилось.
Именно битовыми полями и сделан.
struct MOS6502_Status {
BYTE C :1; // Carry Flag
BYTE Z :1; // Zero Flag
BYTE I :1; // Interrupt Disable
BYTE D :1; // Decimal Mode
BYTE B :1; // Break Command
BYTE NU :1; // Not Used
BYTE V :1; // Overflow Flag
BYTE N :1; // Negative Flag
}
Тут единичка после двоеточия означает, что переменной из всего BYTE отведен только один бит.
Нельзя не напомнить, об одном из первопроходцев эмуляторостроения Марате Файзулине, и его странице посвященной эмуляции разных систем. Так же на этой странице находится статья "Как написать эмулятор Компьютера"
У его коллеги тоже есть интересные статьи про эмуляцию, например «Семь видов интерпретаторов виртуальной машины. В поисках самого быстрого».
Путешествие в мир эмуляторов микропроцессоров