Однако NES, похоже, имеет 2 или 3 байтовые коды операций в зависимости от того, в каком режиме адресации находится процессор. Я не могу придумать какой-либо простой способ выяснить, сколько ящиков нужно читать для каждого опкод.
Код операции по-прежнему остается только одним байтом. Дополнительные байты определяют операнды для тех инструкций, которые имеют явные операнды. Чтобы выполнить декодирование, вы можете создать блок switch
с 256 случаями (на самом деле это не будет 256 случаев, поскольку некоторые коды операций являются незаконными). Это может выглядеть примерно так:
opcode = ReadByte(PC++);
switch (opcode) {
...
case 0x4C: // JMP abs
address = ReadByte(PC++);
address |= (uint16_t)ReadByte(PC) << 8;
PC = address;
cycles += 3;
break;
...
}
Компилятор обычно создает таблицу переходов для случаев, так что вы будете в конечном итоге с достаточно эффективным (хотя и немного раздутый) кода.
Другой альтернативой является создание массива с одной записью для кода операции. Это может быть просто массив указателей на функции с одной функцией для кода операции - или таблица может содержать указатель на одну функцию для извлечения операндов, одну для выполнения фактической операции, а также информацию о количестве циклов, требуемых инструкцией. Таким образом, вы можете использовать много кода. Пример:
const Instruction INSTRUCTIONS[] =
{
...
// 0x4C: JMP abs
{&jmp, &abs_operand, 3},
...
};
Я также возникли проблемы с выясняя, как считать циклы. Как создать часы на языке программирования, чтобы все синхронизировалось?
Подсчет циклов ЦП - это только вопрос увеличения счетчика, как показано в приведенных выше примерах кода.
Чтобы синхронизировать видео с ЦП, самым простым способом было бы запустить ЦП для количества циклов, соответствующих активному периоду отображения одной линии сканирования, затем провести одну линию сканирования, затем запустить ЦП на количество циклов соответствуют периоду горизонтального гашения и начинаются снова.
Когда вы начинаете вовлекать аудио, то, как вы синхронизируете вещи, может зависеть от используемого аудио API. Например, некоторые API могут отправлять вам обратный вызов, на который вы отвечаете, заполняя буфер образцами и возвращая количество сгенерированных выборок. В этом случае вы можете рассчитать количество циклов ЦП, которые были эмулированы с предыдущего обратного вызова, и определить, сколько выборок будет создано на основе этого.
На несвязанной стороне записки, так как NES мало-младшему, мне нужно прочитать programCounter + 1, а затем прочитать programCounter, чтобы получить правильный опкод?
Поскольку код операции является одним байтом, а инструкции на 6502 не упакованы в слово, как на некоторых других архитектурах ЦП, утверждение не имеет большого значения. Это делает релевантным для 16-разрядных операндов, но, с другой стороны, ПК и большинство мобильных телефонов также основаны на малоэтажных процессорах.
Это звучит так, как если бы таблица поиска была уместна. –