summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGentoo <installgentoo@endianness.com>2020-07-18 11:27:07 +1000
committerGentoo <installgentoo@endianness.com>2020-07-18 11:27:07 +1000
commit0b435475eaae5b75f80ce1c45fd4be7fb0eed365 (patch)
tree4702bccc6a5a20e7e7e00faa9c0a51f687f7cbbd
downloadchip8-deassembler-0b435475eaae5b75f80ce1c45fd4be7fb0eed365.tar.gz
chip8-deassembler-0b435475eaae5b75f80ce1c45fd4be7fb0eed365.tar.bz2
chip8-deassembler-0b435475eaae5b75f80ce1c45fd4be7fb0eed365.zip
initial commit
-rw-r--r--Makefile15
-rw-r--r--main.c232
2 files changed, 247 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c2204ae
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+CC=gcc
+CFLAGS=-O3 -march=native -flto -pipe
+
+OBJ = main.o
+DEPS = main.h lookup.h number_sprites.h
+
+%.o: %.c $(DEPS)
+ $(CC) -c -o $@ $< $(CFLAGS) $(LIBS)
+
+out: $(OBJ)
+ $(CC) -o $@ $^ $(CFLAGS) $(LIBS)
+
+clean:
+ rm $(OBJ)
+ rm out
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..ccbd5ae
--- /dev/null
+++ b/main.c
@@ -0,0 +1,232 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define MAX 80
+
+//opcodes are two bytes and stored big endian.
+int main()
+{
+uint8_t opcode[2];
+
+int jmpNum = 0;
+int jmp[MAX]; //where all the jmp positions are stored
+
+FILE *input = fopen("TETRIS", "r");
+if (!input){fprintf(stderr, "Program not found.\n"); return 1;}
+
+fseek(input, 0L, SEEK_END);
+int size = ftell(input);
+rewind(input);
+
+char *program = malloc(sizeof(char)*size);
+if (!program){fprintf(stderr, "Malloc failed!\n"); exit(1);}
+
+int result = fread(program, 1, size, input);
+if (!result){fprintf(stderr, "Fread failed!\n"); exit(1);}
+fclose(input);
+
+bool isData = false; //set as soon as the end of data is detected.
+
+FILE *output = fopen("output.asm", "w");
+int position = 0;//position in program
+
+position = 0;//reset position for 2nd pass where deassembly actually happens.
+
+while(position < size)
+{
+if (!isData){fprintf(output, "%d:\t", position);}
+else
+ {
+ fprintf(output,"Data:\n");
+ for (;position < size; position += 2)
+ {
+ //very slow but seems to work
+ for (int i = 0; i < jmpNum; ++i)
+ {
+ if (jmp[i] == position)//exit data mode if next instruction is called by the program
+ {
+ isData = false;
+ fprintf(output, "%d:\t", position);
+ goto keep_going;
+ }
+ }
+ fprintf(output,"%02X%02X\n", program[position] & 0xFF,program[position+1] & 0xFF);
+ }
+ fclose(output);
+ free(program);
+ exit(0);
+ }
+
+keep_going: memcpy(opcode, program+position, 2*sizeof(char));
+position += 2;//read next opcode next time
+
+switch ((opcode[0] & 0xF0) >> 4)
+ {
+ case 0x0://0NNN or 00E0 or 00EE
+ switch(opcode[1])
+ {
+ case 0xE0://00E0
+ fprintf(output, "00E0\t; Display clear\n");
+ break;
+ case 0xEE://00EE
+ fprintf(output, "00EE\t; return\n");
+ //check if next instruction can be jpm'd to (and therefore is not data) or assume that is data if there is no such jmp
+ isData = true;
+ for (int i = 0; i < jmpNum; ++i)
+ {
+ if (jmp[i] == position){isData = false; break;}//next instruction is not data as the program jumps to it
+ }
+ break;
+ default://0NNN
+ fprintf(output, "Call RCA 1802 program at %d\n", (opcode[0]&0x0F)*0x100+opcode[1]-512);
+ break;
+ }
+ break;
+ //1NNN
+ case 0x1:
+ fprintf(output,"%02X%02X\t; Jump to: %d\n",opcode[0],opcode[1],(opcode[0] & 0x0F)*0x100+opcode[1]-512);
+ if (jmpNum < MAX){jmp[jmpNum++] = (opcode[0] & 0x0F)*0x100+opcode[1]-512;}
+ break;
+ //2NNN
+ case 0x2:
+ fprintf(output,"%02X%02X\t; Call subroute at %d\n", opcode[0], opcode[1], (opcode[0] & 0x0F)*0x100+opcode[1]-512);
+ if (jmpNum < MAX){jmp[jmpNum++] = (opcode[0] & 0x0F)*0x100+opcode[1]-512;}
+ break;
+ case 0x3://3XNN
+ fprintf(output,"%02X%02X\t; if (V%X==%d): skip the next opcode.\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[1]);
+ if (jmpNum < MAX){jmp[jmpNum++] = position+2;}
+ break;
+ case 0x4://4XNN
+ fprintf(output,"%02X%02X\t; if (V%X!=%d): skip the next opcode.\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[1]);
+ if (jmpNum < MAX){jmp[jmpNum++] = position+2;}
+ break;
+ case 0x5://5XY0
+ fprintf(output,"%02X%02X\t; if (V%X==V%X): skip the next opcode.\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[1] & 0xF0);
+ if (jmpNum < MAX){jmp[jmpNum++] = position+2;}
+ break;
+ case 0x6://6XNN
+ fprintf(output,"%02X%02X\t; V%X=%d\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[1]);
+ break;
+ case 0x7://7XNN
+ fprintf(output,"%02X%02X\t; V%X += %d\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[1]);
+ break;
+ case 0x8://8XY0 or 8XY1 or 8XY2 or 8XY3 or 8XY4 or 8XY5 or 8XY6 or 8XY7 or 8XYE
+ switch(opcode[1] & 0x0F)
+ {
+ case 0x0://8XY0
+ fprintf(output,"%02X%02X\t; V%X = V%X\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[1] & 0xF0);
+ break;
+ case 0x1://8XY1
+ fprintf(output,"%02X%02X\t; V%X = V%X|V%X\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[0] & 0x0F, opcode[1] & 0xF0);
+ break;
+ case 0x2://8XY2
+ fprintf(output,"%02X%02X\t; V%X = V%X&V%X\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[0] & 0x0F, opcode[1] & 0xF0);
+ break;
+ case 0x3://8XY3
+ fprintf(output,"%02X%02X\t; V%X = V%X^V%X\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[0] & 0x0F, opcode[1] & 0xF0);
+ break;
+ case 0x4://8XY4
+ fprintf(output,"%02X%02X\t; V%X += V%X\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[1] & 0xF0);
+ break;
+ case 0x5://8XY5
+ fprintf(output,"%02X%02X\t; V%X -= V%X: VF is set to 0 if there's a borrow and to 1 when there isn't.\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[1] & 0xF0);
+ break;
+ case 0x6://8XY6
+ fprintf(output,"%02X%02X\t; VF = V%X>>7 then V%X >>= 1 \n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[0] & 0x0F);
+ //Stores the least significant bit of VX in VF
+ //and then shifts VX to the right by 1
+ //OR
+ //Set register VF to the least significant bit in V[x]
+ //Store the value of register VY shifted right one bit in register VX
+ break;
+ case 0x7://8XY7
+ fprintf(output,"%02X%02X\t; V%X = V%X - V%X: VF is set to 0 if there's a borrow and to 1 when there isn't.\n",opcode[0],opcode[1],opcode[0] & 0x0F,opcode[0] & 0x0F,opcode[1] & 0xF0);
+ //V[x] = V[y] - V[x]; //Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
+ break;
+ case 0xE://8XYE
+ fprintf(output,"%02X%02X\t; VF = V%X>>7 then V%X <<= 1;\n",opcode[0],opcode[1],opcode[0] & 0x0F,opcode[0] & 0x0F);
+ break;
+ default:
+ fprintf(stderr, "Illegal Instruction\n"); exit(1);
+ break;
+ }
+ break;
+ case 0x9://9XY0
+ fprintf(output,"%02X%02X\t; if (V%X != V%X): Skip next instruction.\n",opcode[0],opcode[1],opcode[0] & 0x0F, opcode[1] & 0xF0);
+ break;
+ case 0xA://ANNN
+ fprintf(output,"%02X%02X\t; I = %d\n",opcode[0],opcode[1],(opcode[0] & 0xF)*0x100+opcode[1]-512);
+ break;
+ case 0xB://BNNN
+ fprintf(output,"%02X%02X\t; Jump to V0+%d\n",opcode[0],opcode[1],(opcode[0] & 0xF)*0x100+opcode[1]-512);
+ break;
+ case 0xC://CXNN
+ fprintf(output,"%02X%02X\t; V%X = rand() & %d\n",opcode[0],opcode[1],opcode[0]&0x0F,opcode[1]);
+ break;
+ case 0xD://DXYN
+ fprintf(output,"%02X%02X\t; draw(X=V%X, Y=V%X, %d)\n",opcode[0],opcode[1],opcode[0]&0x0F,(opcode[1]&0xF0)>>4,opcode[1]&0x0F);
+ break;
+ case 0xE://EX9E or EXA1
+ switch(opcode[1])
+ {
+ case 0x9E://EX9E
+ fprintf(output,"%02X%02X\t; Skip next instruction if key in V%X is held down\n",opcode[0],opcode[1],opcode[0]&0x0F);
+ break;
+ case 0xA1://EXA1
+ fprintf(output,"%02X%02X\t; Skip next instruction if key in V%X isn't held down\n",opcode[0],opcode[1],opcode[0]&0x0F);
+ break;
+ default:
+ fprintf(stderr, "Illegal Instruction\n"); exit(1);
+ break;
+ }
+ break;
+ case 0xF://FX07 or FX0A or FX15 or FX18 or FX1E or FX29 or FX33 or FX55 or FX65
+ switch (opcode[1])
+ {
+ case 0x07://FX07
+ fprintf(output,"%02X%02X\t; V%X = Delay timer.\n",opcode[0],opcode[1],opcode[0]&0x0F);
+ break;
+ case 0x0A://FX0A
+ fprintf(output,"%02X%02X\t; V%X = 0-9 (from keypress and is a blocking operation).\n",opcode[0],opcode[1],opcode[0]&0x0F);
+ break;
+ case 0x15://FX15
+ fprintf(output,"%02X%02X\t; Delay timer = V%X.\n",opcode[0],opcode[1],opcode[0]&0x0F);
+ break;
+ case 0x18://FX18
+ fprintf(output,"%02X%02X\t; Sound timer = V%X.\n",opcode[0],opcode[1],opcode[0]&0x0F);
+ break;
+ case 0x1E://FX1E
+ fprintf(output,"%02X%02X\t; VF = (I+V%X)>0xFFF.\n",opcode[0],opcode[1],opcode[0]&0x0F);
+ break;
+ case 0x29://FX29
+ fprintf(output,"%02X%02X\t; I=spriteChar(V%X): I equals a pointer to the character corresponding to the value in V%X.\n",opcode[0],opcode[1],opcode[0]&0x0F,opcode[0]&0x0F);
+ break;
+ case 0x33://FX33
+ fprintf(output,"%02X%02X\t; I = V%X / 100, I+1 = (V%X / 10) %% 10, I+2 = (V%X %% 100) %% 10\n",opcode[0],opcode[1],opcode[0]&0x0F,opcode[0]&0x0F,opcode[0]&0x0F);
+ break;
+ case 0x55://FX55
+ fprintf(output,"%02X%02X\t; Store V0 to V%X (including V%X) in memory starting at address I\n",opcode[0],opcode[1],opcode[0]&0x0F,opcode[0]&0x0F);
+ break;
+ case 0x65://FX65
+ fprintf(output,"%02X%02X\t; Fill V0 to V%X (including V%X) with values in memory starting at address I\n",opcode[0],opcode[1],opcode[0]&0x0F,opcode[0]&0x0F);
+ break;
+ default:
+ fprintf(stderr, "Illegal Instruction\n"); exit(1);
+ break;
+ }
+ break;
+
+ default:
+ fprintf(stderr, "Illegal Instruction\n"); exit(1);
+ break;
+ }
+}
+
+fclose(output);
+free(program);
+
+return 0;
+}