diff --git a/cpp/chip8_disasm.cpp b/cpp/chip8_disasm.cpp new file mode 100644 index 0000000..7cda277 --- /dev/null +++ b/cpp/chip8_disasm.cpp @@ -0,0 +1,221 @@ +#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); +}