Я сейчас пытаюсь реализовать эмулятор CHIP-8.В этих эмуляторах вы читаете содержимое картриджа, который дает вам «коды операций», значения, соответствующие функции.Я не хочу писать огромный оператор switch case
, чтобы позаботиться об этих кодах операций (в контексте эмулятора CHIP-8 это нормально, так как там не слишком много кодов операций, но в контексте эмулятора Gameboy, дляНапример, он может дать несколько огромных операторов switch case
).
Мой подход заключается в следующем:
У меня есть структура, содержащая диапазон для кода операции, имя функции и указательк функции (void* func
).
struct instruction {
std::pair<uint16_t, uint16_t> range;
std::string name;
void* func;
instruction(std::pair<uint16_t, uint16_t> range, std::string name, void* func) {
this->range = range;
this->name = name;
this->func = func;
}
};
Мой класс выглядит следующим образом (пожалуйста, не бейте меня, я сейчас все положил public
, но когда все заработает, все перейдет в приват):
class Chip8 {
public:
Chip8();
virtual ~Chip8();
void set_opcodes(void);
bool load_cartridge(std::string path);
void output_cartridge_contents(void);
bool verifiy_instructions(void);
void JUMP(void);
// 0 -> 0x1FF: interpreter (unused since the emulator is running outside of the memory)
// 0x200 -> 0xE9F: cartridge data
// 0xEA0 -> 0xEFF: call stack, internal use, and other variables
// 0xF00 -> 0xFFF: display refresh
std::vector<uint8_t> memory;
std::vector<uint8_t> registers;
// Index register
uint16_t I;
// Program counter
uint16_t pc;
std::vector<uint8_t> stack;
// Stack pointer
uint8_t sp;
std::vector<instruction> instr;
// Timers
uint8_t delay_timer;
uint8_t sound_timer;
uint16_t opcode;
// Screen
bool gfx[64 * 32];
};
Давайте рассмотрим пример функции, JUMP
void Chip8::JUMP(void) {
this->pc = (this->opcode & 0x0FFF);
}
Затем я заполняю вектор, содержащий все реализованные коды операций,
this->instr.push_back(instruction(std::pair<uint16_t, uint16_t>(0x1000,0x1FFF), std::string("JUMP"), (void*)&Chip8::JUMP))
.текущий код операции читается, затем сравнивается с диапазоном реализованных функций (например, если код операции 0x1225
, будет вызвана функция JUMP).Когда найдена правильная функция, вызывается следующий код (i
- это индекс правильного instruction
в показанном выше instr
векторе):
this->instr[i].func;
Но когда я это делаю,ничего не происходит (т.е. значение pc
не изменяется, std::cout
ничего не выводит на консоль и т. д.).Я пробовал несколько подходов (изменив тип func
на void (*func)(void)
, пытаясь вызвать this->instr[i].func();
), но пока не повезло.Я думаю, что я что-то здесь упускаю.У кого-нибудь есть указатели?
Спасибо