Skip to content

Instantly share code, notes, and snippets.

@shepgoba
Created June 6, 2020 06:36
Show Gist options
  • Save shepgoba/479db311b8ee6a68d5c3436eeba9bd45 to your computer and use it in GitHub Desktop.
Save shepgoba/479db311b8ee6a68d5c3436eeba9bd45 to your computer and use it in GitHub Desktop.
A Simple CHIP-8 Disassembler
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
char *get_instruction_string(uint16_t opcode) {
char *result = malloc(sizeof(char) * 32);
uint8_t add_newline = 0;
uint8_t arg1 = (opcode & 0x0f00) >> 8;
uint8_t arg2 = (opcode & 0x00f0) >> 4;
uint8_t byte = opcode & 0xff;
switch (opcode & 0xf000) {
case 0x0000: {
if (opcode & 0x000E) {
strcpy(result, "ret");
add_newline = 1;
} else {
strcpy(result, "cls");
}
break;
}
case 0x1000: {
snprintf(result, 32, "jp $%x", opcode & 0x0fff);
add_newline = 1;
break;
}
case 0x2000: {
snprintf(result, 32, "call $%x", opcode & 0x0fff);
break;
}
case 0x3000: {
snprintf(result, 32, "se V%x, $%x", arg1, byte);
break;
}
case 0x4000: {
snprintf(result, 32, "sne V%x, $%x", arg1, byte);
break;
}
case 0x5000: {
snprintf(result, 32, "se V%x, V%x", arg1, arg2);
break;
}
case 0x6000: {
snprintf(result, 32, "ld V%x, $%x", arg1, byte);
break;
}
case 0x7000: {
snprintf(result, 32, "add V%x, $%x", arg1, byte);
break;
}
case 0x8000: {
switch (opcode & 0x000f) {
case 0x0: {
snprintf(result, 32, "ld V%x, V%x", arg1, arg2);
break;
}
case 0x1: {
snprintf(result, 32, "or V%x, V%x", arg1, arg2);
break;
}
case 0x2: {
snprintf(result, 32, "and V%x, V%x", arg1, arg2);
break;
}
case 0x3: {
snprintf(result, 32, "xor V%x, V%x", arg1, arg2);
break;
}
case 0x4: {
snprintf(result, 32, "add V%x, V%x", arg1, arg2);
break;
}
case 0x5: {
snprintf(result, 32, "sub V%x, V%x", arg1, arg2);
break;
}
case 0x6: {
snprintf(result, 32, "shr V%x {, V%x}", arg1, arg2);
break;
}
case 0x7: {
snprintf(result, 32, "subn V%x, V%x", arg1, arg2);
break;
}
case 0xE: {
snprintf(result, 32, "shl V%x {, V%x}", arg1, arg2);
break;
}
}
break;
}
case 0x9000: {
snprintf(result, 32, "sne V%x, V%x", arg1, arg2);
break;
}
case 0xA000: {
snprintf(result, 32, "ld I, $%x", opcode & 0x0fff);
break;
}
case 0xB000: {
snprintf(result, 32, "jp V0, $%x", opcode & 0x0fff);
break;
}
case 0xC000: {
snprintf(result, 32, "rnd V%x, $%x", opcode & 0x0fff);
break;
}
case 0xD000: {
snprintf(result, 32, "drw V%x, V%x, $%x", arg1, arg2, opcode & 0x000f);
break;
}
case 0xE000: {
if ((opcode & 0x000f) == 0xE) {
snprintf(result, 32, "skp V%x", arg1);
} else {
snprintf(result, 32, "sknp V%x", arg1);
}
break;
}
case 0xF000: {
switch (opcode & 0x00ff) {
case 0x07: {
snprintf(result, 32, "ld V%x, dt", arg1);
break;
}
case 0x0A: {
snprintf(result, 32, "ld V%x, {keypress}", arg1);
break;
}
case 0x15: {
snprintf(result, 32, "ld dt, V%x", arg1);
break;
}
case 0x18: {
snprintf(result, 32, "ld st, V%x", arg1);
break;
}
case 0x1E: {
snprintf(result, 32, "add I, V%x", arg1);
break;
}
case 0x29: {
snprintf(result, 32, "ld F, V%x", arg1);
break;
}
case 0x33: {
snprintf(result, 32, "ld B, V%x", arg1);
break;
}
case 0x55: {
snprintf(result, 32, "ld [I], V%x", arg1);
break;
}
case 0x65: {
snprintf(result, 32, "ld V%x, [I]", arg1);
break;
}
}
break;
}
default:
strcpy(result, "");
}
if (add_newline) {
uint8_t offset = strlen(result);
result[offset] = '\n';
result[offset + 1] = 0;
}
return result;
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("Enter a file to disassemble\n");
return -1;
}
FILE *file = fopen(argv[1], "rb");
if (!file) {
printf("could not open file");
return -1;
}
uint16_t rom_addr = 0x200;
uint16_t num = 0;
printf("rom_start:\n");
while (fread(&num, sizeof(uint16_t), 1, file) != 0) {
uint16_t opcode = ((num & 0xff00) >> 8) | ((num & 0xff) << 8);
char *instruction_string = get_instruction_string(opcode);
printf("0x%04x: %s\n", rom_addr, instruction_string);
free(instruction_string);
rom_addr += 2;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment