#include #include #include #include #include #include #include template std::uint8_t get_nibble(T value, int nr) { return ((value >> (nr * 4)) & 0xF); } template std::vector get_file_vector(std::ifstream& file_stream) { file_stream.seekg(0, std::ios::end); const std::size_t file_size = file_stream.tellg(); file_stream.seekg(0, std::ios::beg); std::vector file_contents(file_size); file_stream.read((char*)&file_contents[0], file_size); return file_contents; } void disassemble(const std::vector& program) { for (auto inst : program) { if (inst == 0) { break; } switch (get_nibble(inst, 3)) { case 0x0: if (inst == 0x00E0) { printf("CLS\n"); } else if (inst == 0x00EE) { printf("RET\n"); } else { printf("SYS %03x\n", inst & 0xFFF); } break; case 0x1: printf("JMP %03x\n", inst & 0xFFF); break; case 0x2: printf("CALL %03x\n", inst & 0xFFF); break; case 0x3: printf("SE V%X, %02x\n", get_nibble(inst, 2), inst & 0xFF); break; case 0x4: printf("SNE V%X, %02x\n", get_nibble(inst, 2), inst & 0xFF); break; case 0x5: printf("SE V%X, V%X\n", get_nibble(inst, 2), get_nibble(inst, 1)); break; case 0x6: printf("LD V%X, %02x\n", get_nibble(inst, 2), inst & 0xFF); break; case 0x7: printf("ADD V%X, %02x\n", get_nibble(inst, 2), inst & 0xFF); break; case 0x8: switch (inst & 0xF) { case 0x0: printf("LD V%X, V%X\n", get_nibble(inst, 2), get_nibble(inst, 1)); break; case 0x1: printf("OR V%X, V%X\n", get_nibble(inst, 2), get_nibble(inst, 1)); break; case 0x2: printf("AND V%X, V%X\n", get_nibble(inst, 2), get_nibble(inst, 1)); break; case 0x3: printf("XOR V%X, V%X\n", get_nibble(inst, 2), get_nibble(inst, 1)); break; case 0x4: printf("ADD V%X, V%X\n", get_nibble(inst, 2), get_nibble(inst, 1)); break; case 0x5: printf("SUB V%X, V%X\n", get_nibble(inst, 2), get_nibble(inst, 1)); break; case 0x6: printf("SHR V%X {, V%X}\n", get_nibble(inst, 2), get_nibble(inst, 1)); break; case 0x7: printf("SUBN V%X V%X\n", get_nibble(inst, 2), get_nibble(inst, 1)); break; case 0xE: printf("SHL V%X {, V%X}\n", get_nibble(inst, 2), get_nibble(inst, 1)); break; default: break; } break; case 0x9: if (get_nibble(inst, 0) == 0) { printf("SNE V%X, V%X\n", get_nibble(inst, 2), get_nibble(inst, 1)); } break; case 0xA: printf("LD I, %03x\n", inst & 0xFFF); break; case 0xB: printf("JP V0, %03x\n", inst & 0xFFF); break; case 0xC: printf("RND V%X, %02x\n", get_nibble(inst, 2), inst & 0xFF); break; case 0xD: printf("DRW V%X, V%X, %x\n", get_nibble(inst, 2), get_nibble(inst, 1), get_nibble(inst, 0)); break; case 0xE: switch (inst & 0xFF) { case 0x9E: printf("SKP V%X\n", get_nibble(inst, 2)); break; case 0xA1: printf("SKNP V%X\n", get_nibble(inst, 2)); break; default: break; } break; case 0xF: switch (inst & 0xFF) { case 0x07: printf("LD V%X, DT\n", get_nibble(inst, 2)); break; case 0x0A: printf("LD V%X, K\n", get_nibble(inst, 2)); break; case 0x15: printf("LD DT, V%X\n", get_nibble(inst, 2)); break; case 0x18: printf("LD ST, V%X\n", get_nibble(inst, 2)); break; case 0x1E: printf("ADD I, V%X\n", get_nibble(inst, 2)); break; case 0x29: printf("LD F, V%X\n", get_nibble(inst, 2)); break; case 0x33: printf("LD B, V%X\n", get_nibble(inst, 2)); break; case 0x55: printf("LD [I], V%X\n", get_nibble(inst, 2)); break; case 0x65: printf("LD V%X, [I]\n", get_nibble(inst, 2)); default: break; } break; default: break; } } } int main(int argc, char* argv[]) { if (argc < 2) { std::cout << "Usage: " << argv[0] << " [CHIP8 ROM]" << std::endl; return 1; } const std::string file_path = argv[1]; if (!std::filesystem::exists(file_path)) { std::cout << "Could not find file." << std::endl; return 1; } std::ifstream file_stream(file_path, std::ios::binary); if (!file_stream) { std::cout << "Could not open file." << std::endl; return 1; } const auto file_contents = get_file_vector(file_stream); disassemble(file_contents); }