diff --git a/roms/logo_chip8.ch8 b/roms/chip8-test-suite/1-chip8-logo.ch8 similarity index 100% rename from roms/logo_chip8.ch8 rename to roms/chip8-test-suite/1-chip8-logo.ch8 diff --git a/roms/logo_ibm2.ch8 b/roms/chip8-test-suite/2-ibm-logo.ch8 similarity index 100% rename from roms/logo_ibm2.ch8 rename to roms/chip8-test-suite/2-ibm-logo.ch8 diff --git a/roms/chip8-test-suite/3-corax+.ch8 b/roms/chip8-test-suite/3-corax+.ch8 new file mode 100644 index 0000000..317029b Binary files /dev/null and b/roms/chip8-test-suite/3-corax+.ch8 differ diff --git a/roms/chip8-test-suite/4-flags.ch8 b/roms/chip8-test-suite/4-flags.ch8 new file mode 100644 index 0000000..431f3b0 Binary files /dev/null and b/roms/chip8-test-suite/4-flags.ch8 differ diff --git a/roms/chip8-test-suite/5-quirks.ch8 b/roms/chip8-test-suite/5-quirks.ch8 new file mode 100644 index 0000000..5206652 Binary files /dev/null and b/roms/chip8-test-suite/5-quirks.ch8 differ diff --git a/roms/chip8-test-suite/6-keypad.ch8 b/roms/chip8-test-suite/6-keypad.ch8 new file mode 100644 index 0000000..88250bf Binary files /dev/null and b/roms/chip8-test-suite/6-keypad.ch8 differ diff --git a/roms/chip8-test-suite/7-beep.ch8 b/roms/chip8-test-suite/7-beep.ch8 new file mode 100644 index 0000000..27c205f Binary files /dev/null and b/roms/chip8-test-suite/7-beep.ch8 differ diff --git a/roms/chip8-test-suite/8-scrolling.ch8 b/roms/chip8-test-suite/8-scrolling.ch8 new file mode 100644 index 0000000..eb546e7 Binary files /dev/null and b/roms/chip8-test-suite/8-scrolling.ch8 differ diff --git a/roms/logo_ibm.ch8 b/roms/ibm.ch8 similarity index 100% rename from roms/logo_ibm.ch8 rename to roms/ibm.ch8 diff --git a/src/main.c b/src/main.c index 85dcb2c..8903eed 100644 --- a/src/main.c +++ b/src/main.c @@ -2,12 +2,18 @@ #include "mem.h" #include "vcpu.h" +#include int main(int argc, char *argv[]) { + /* unsigned char byte=137; */ + /* unsigned char u,t,h; */ + /* VCPUDoubleDabble(byte,&u,&t,&h); */ + /* printf("%d: %01d%01d%01d\n",byte,h,t,u); */ + /* return 0; */ // Initialize MemInit(); - MemLoadROM("../roms/logo_chip8.ch8"); + MemLoadROM("../roms/chip8-test-suite/3-corax+.ch8"); ScreenInit(800,400); VCPUInit(); diff --git a/src/screen.c b/src/screen.c index 2744ee1..f4eb7ae 100644 --- a/src/screen.c +++ b/src/screen.c @@ -15,7 +15,7 @@ void ScreenInit(int width, int height){ SetTraceLogLevel(LOG_ERROR); // Disable anoying raylib logs InitWindow(width, height, "Chip-8 Emulator"); - SetTargetFPS(80); // Set game to run at 60 frames-per-second + SetTargetFPS(200); // Set game to run at 60 frames-per-second } void ScreenClear() { diff --git a/src/vcpu.c b/src/vcpu.c index c4187cb..c3e1e5e 100644 --- a/src/vcpu.c +++ b/src/vcpu.c @@ -26,83 +26,109 @@ void VCPUFetch(){ void VCPUDecode(){ State.X=(State.opcode>>8) & 0xF; State.Y=(State.opcode>>4) & 0xF; - State.N=State.opcode & 0xF; + State.N=State.opcode & 0x0F; + State.NN=State.opcode & 0xFF; + State.NNN=State.opcode & 0x0FFF; +} - State.NN=State.Y; - State.NN=State.NN<<4; - State.NN=State.NN | State.N; - - State.NNN=State.opcode&0x0FFF; +void VCPUDoubleDabble(unsigned char x, unsigned char *u, unsigned char *t, unsigned char *h){ + unsigned int bcd=x; + for(int i=0;i<8;i++){ + bcd=bcd<<1; + unsigned char byte=bcd & 0xFF; + unsigned char units=(bcd>>8) & 0xF; + unsigned char tens=(bcd>>12) & 0xF; + unsigned char hundreds=(bcd>>16) & 0xF; + //printf("hundreds:%04b tens:%04b units:%04b byte:%08b\n",hundreds,tens,units,byte); + if(i<7){ + if(units>4) + units+=3; + if(tens>4) + tens+=3; + if(hundreds>4) + hundreds+=3; + } + bcd = (hundreds<<16) | (tens << 12) | (units << 8) | byte; + } + *u=bcd>>8 & 0xF; + *t=bcd>>12 & 0xF; + *h=bcd>>16 & 0xF; } void VCPUExecute(){ - // VCPUDump(); + VCPUDump(); switch(State.opcode >> 12){ case 0x0: // Clear screen or return from subroutine - if(State.N == 0){ // Clear screen + if(State.N == 0x0){ // Clear screen ScreenClear(); } - else { // Return from subroutine + else if(State.N == 0xE) { // Return from subroutine State.PC=State.stack[State.S]; State.S--; } - break - ;; + break; + case 0x1: // Jump State.PC=State.NNN; - break - ;; + break; + case 0x2: // Call State.S++; State.stack[State.S]=State.PC; State.PC=State.NNN; - break - ;; + break; + case 0x3: // SE: VX, byte if(State.V[State.X]==State.NN) State.PC+=2; break; - ;; + case 0x4: // SNE: VX, byte if(State.V[State.X]!=State.NN) State.PC+=2; break; - ;; + case 0x5: // SE: VX, VY - if(State.V[State.X]==State.V[State.Y]) - State.PC+=2; + if(State.N == 0){ + if(State.V[State.X]==State.V[State.Y]) + State.PC+=2; + } break; - ;; + case 0x6: State.V[State.X]=State.NN; - break - ;; + break; + case 0x7: - State.V[State.X]+=State.NN; - break - ;; + State.V[State.X]=State.V[State.X] + State.NN; + break; + case 0x8: // Register operations switch(State.N){ + case 0x0: // VX = VY + State.V[State.X]=State.V[State.Y]; + break; + case 0x1: // VX = VX OR VY State.V[State.X]=State.V[State.X] | State.V[State.Y]; break; - ;; + case 0x2: // VX = VX AND VY State.V[State.X]=State.V[State.X] & State.V[State.Y]; break; - ;; + case 0x3: // VX = VX XOR VY State.V[State.X]=State.V[State.X] ^ State.V[State.Y]; break; - ;; + case 0x4: // VX = VX + VY - if(State.V[State.X] + State.V[State.Y] > 255) + if((State.V[State.X] + State.V[State.Y]) > 255) State.V[REG_FLAG]=1; else State.V[REG_FLAG]=0; - State.V[State.X]=(State.V[State.X] + State.V[State.Y]) & 0xFF; + State.V[State.X]=State.V[State.X] + State.V[State.Y]; break; - ;; + case 0x5: // VX = VX - VY if(State.V[State.X] > State.V[State.Y]) State.V[REG_FLAG]=1; @@ -110,7 +136,7 @@ void VCPUExecute(){ State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.X] - State.V[State.Y]; break; - ;; + case 0x6: // VX = VX SHR 1 if(State.V[State.X] & 0x1 == 1) State.V[REG_FLAG]=1; @@ -118,55 +144,57 @@ void VCPUExecute(){ State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.X] >> 1; break; - ;; + case 0x7: // VX = VY - VX - if(State.V[State.X] < State.V[State.Y]) + if(State.V[State.Y] > State.V[State.X]) State.V[REG_FLAG]=1; else State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.Y] - State.V[State.X]; break; - ;; + case 0xE: // VX = VX SHL 1 - if(State.V[State.X] >> 15 == 1) + if(State.V[State.X] >> 7 == 1) State.V[REG_FLAG]=1; else State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.X] << 1; break; - ;; + } - break - ;; - case 0x9: // SNE: VX, VY - if(State.V[State.X]!=State.V[State.Y]) - State.PC+=2; break; - ;; + + case 0x9: // SNE: VX, VY + if(State.N==0){ + if(State.V[State.X]!=State.V[State.Y]) + State.PC+=2; + } + break; + case 0xA: State.I=State.NNN; - break - ;; + break; + case 0xB: State.PC=State.V[0]+State.NNN; - break - ;; + break; + case 0xC: unsigned short n = rand() % 255 + 1; State.V[State.X]=n & State.NN; - break - ;; + break; + case 0xD: // Draw a sprite - int X=State.V[State.X]%63; - int Y=State.V[State.Y]%31; + int X=State.V[State.X]&63; + int Y=State.V[State.Y]&31; State.V[REG_FLAG]=0; // Set flag to 0 - int width,height; + int width, height; ScreenWH(&width,&height); for(char row=0;row=height) break; - char sprite; + unsigned char sprite; MemRead(&sprite,1,State.I+row); // Load sprite // Draw sprite for(int shift=0;shift<8;shift++){ @@ -178,51 +206,56 @@ void VCPUExecute(){ } } break; - ;; + case 0xE: // TODO - break;; + break; + case 0xF: switch(State.NN){ case 0x07: // Get timer State.V[State.X]=State.DT; break; - ;; + case 0x0A: // TODO break; - ;; + case 0x15: // Set timer State.DT=State.V[State.X]; break; - ;; + case 0x18: // Set sound timer State.ST=State.V[State.X]; break; - ;; + case 0x1E: // I = I + VX State.I=State.I+State.V[State.X]; break; - ;; + case 0x29: // TODO break; - ;; + case 0x33: - // TODO + unsigned char units, tens, hundreds; + VCPUDoubleDabble(State.V[State.X],&units,&tens,&hundreds); + MemCopy(&hundreds,1,State.I); + MemCopy(&tens,1,State.I+1); + MemCopy(&units,1,State.I+2); + // printf("hundreds:%d tens:%d units:%d byte:%d\n",hundreds,tens,units,State.V[State.X]); break; - ;; + case 0x55: MemCopy(State.V,0xF,State.I); break; - ;; + case 0x65: MemRead(State.V,0xF,State.I); break; - ;; + } break; - ;; } } diff --git a/src/vcpu.h b/src/vcpu.h index dbcba0a..fccd397 100644 --- a/src/vcpu.h +++ b/src/vcpu.h @@ -25,10 +25,10 @@ typedef struct VCPU_State { // Intruction (opcode + decoded fields) unsigned short opcode; - char X; - char Y; - char N; - char NN; + unsigned char X; + unsigned char Y; + unsigned char N; + unsigned char NN; unsigned short NNN; } VCPU_State; @@ -36,4 +36,5 @@ void VCPUInit(); void VCPUFetch(); void VCPUDecode(); void VCPUExecute(); +void VCPUDoubleDabble(unsigned char x, unsigned char *u, unsigned char *t, unsigned char *h); void VCPUDump();