#import // For open() #import #import // For fstat() "to get he file length" #import // For mmap() #import #import #import #import // close() //#ifdef HAVE_DEBUG #define DEBUG_PRINT(format , ... ) printf ( "[DEBUG " __FILE__ ":%d] " format "\n" , __LINE__, ## __VA_ARGS__ ); //#else //#define DEBUG_PRINT( format , args... ) //#endif #define bswap16(x) (((((short)(x)) >> 8) & 0xff) | ((((short)(x)) & 0xff) << 8)) #define n1(x) (x&0xF000>>12) #define n2(x) (x&0x0F00>> 8) #define n3(x) (x&0x00F0>> 4) #define n4(x) (x&0x000F ) void process8(short opcode); void dumpreg(void); unsigned char V[16]; // CPU registers unsigned short *rom; // rom file unsigned short opcode; // current opcode unsigned int ip; // instruction pointer int main(int a, char**b) { int fd; struct stat statbuf; // for the file length fd = open("Chip8Test",O_RDONLY); if (fd == -1) return 1; //TODO return value explanation fstat(fd,&statbuf); rom = mmap(NULL, statbuf.st_size , PROT_READ, MAP_PRIVATE, fd, 0); if (rom == MAP_FAILED) return 3; DEBUG_PRINT("Opened and mmap()'d rom file"); while ( 1 ) { short type; memcpy(&opcode,rom +ip,2); opcode = bswap16(opcode); type = opcode & 0xF000; /* parse the opcode here */ switch(type) { case 0x8000 : process8(opcode); case 0x1000 : ip = (opcode & 0x0FFF) -1 ; break; //1NNN Jump to the address NNN of the file case 0x3000 :if(V[n2(opcode)]== (opcode&0x00FF)) ip++; break; //3XKK Skip next instruction if VX == KK case 0x6000 : V[ n2(opcode) ] = (opcode&0x00FF); break; //6XKK VX = KK case 0x7000 : V[ n2(opcode) ]+= (opcode&0x00FF); break; //7XKK VX = VX + KK case 0xC000 : V[ n2(opcode) ] = rand() + (opcode&0x00FF); break;//CXKK VX = Random number AND KK case 0x0000 : goto out; default : DEBUG_PRINT("Unknown opcode ip:%d opcode:%x",ip,opcode) } ip++; } out: /* Dump the registers */ dumpreg(); // cleanup munmap(rom,statbuf.st_size); close(fd); return 0; } void process8(short opcode) { short type = opcode & 0x000F; /* parse the opcode here */ switch(type) { case 0 : V[ n2(opcode) ] = V[ n3(opcode) ]; break; //8XY0 VX = VY case 1 : V[ n2(opcode) ] |= V[ n3(opcode) ]; break; //8XY1 VX = VX OR VY case 2 : V[ n2(opcode) ] &= V[ n3(opcode) ]; break; //8XY2 VX = VX AND VY case 3 : V[ n2(opcode) ] ^= V[ n3(opcode) ]; break; //8XY3 VX = VX XOR VY case 4 : V[ n2(opcode) ] += V[ n3(opcode) ]; //8XY4 VX = VX + VY, if ( V[ n2(opcode) ] < V[ n3(opcode) ] ) // Sets VF to 1 if there is a carry, 0 if there isn't V[15] = 1; else V[15] = 0; break; case 5 : V[ n2(opcode) ] -= V[ n3(opcode) ]; //8XY5 VX = VX - VY, if ( V[ n2(opcode) ] > V[ n3(opcode) ] ) // VF is set to 0 if there is a borrow, 1 if there isn't. V[15] = 0; else V[15] = 1; break; case 6 : V[15] = opcode&0x0001; V[ n2(opcode) ] >>= 1; break; //8X06 VX = VX SHIFT RIGHT 1, VF is set to the lost bit. case 7 : V[ n2(opcode) ] = V[ n3(opcode) ] - V[ n2(opcode) ]; //8XY7 VX = VY - VX, if ( V[ n2(opcode) ] < V[ n3(opcode) ] ) // VF is set to 0 if there is a borrow, 1 if there isn't. V[15] = 0; else V[15] = 1; break; case 0xE: V[15] = opcode&0x8000; V[ n2(opcode) ] <<= 1; break; //8X0E VX = VX SHIFT LEFT 1 , VF is set to the lost bit. default : DEBUG_PRINT("Unknown opcode ip:%d opcode:%x",ip,opcode) } } void dumpreg(void) { int i; for(i=0; i<16; i++) printf("Register V%x : 0x%x\n",i,V[i]); }