From 0b435475eaae5b75f80ce1c45fd4be7fb0eed365 Mon Sep 17 00:00:00 2001 From: Gentoo Date: Sat, 18 Jul 2020 11:27:07 +1000 Subject: initial commit --- Makefile | 15 +++++ main.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 247 insertions(+) create mode 100644 Makefile create mode 100644 main.c 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 +#include +#include +#include +#include + +#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; +} -- cgit v1.2.3