Add chip8_disasm.cpp
This commit is contained in:
221
cpp/chip8_disasm.cpp
Normal file
221
cpp/chip8_disasm.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
template<typename T>
|
||||
std::uint8_t get_nibble(T value, int nr) {
|
||||
return ((value >> (nr * 4)) & 0xF);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> 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<T> file_contents(file_size);
|
||||
file_stream.read((char*)&file_contents[0], file_size);
|
||||
|
||||
return file_contents;
|
||||
}
|
||||
|
||||
void disassemble(const std::vector<std::uint16_t>& 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<std::uint16_t>(file_stream);
|
||||
|
||||
disassemble(file_contents);
|
||||
}
|
||||
Reference in New Issue
Block a user