Advertisement
Guest User

Untitled

a guest
Oct 22nd, 2024
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.99 KB | Source Code | 0 0
  1. #include <bits/time.h>
  2. #include <stdbool.h>
  3. #include <stdint.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <time.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <SDL2/SDL.h>
  11.  
  12. #define CPU_CLOCK_HZ 540
  13. #define TIMER_HZ 60
  14. #define CYCLES_PER_TIMER_TICK (CPU_CLOCK_HZ / TIMER_HZ)
  15. #define TIME_BETWEEN_TICKS (1000000 / TIMER_HZ)
  16.  
  17. typedef struct {
  18.     uint8_t  V[16];
  19.     uint16_t I, SP, PC;
  20.     uint8_t  DT, ST;
  21.  
  22.     uint16_t stack[16];
  23.     uint8_t  displayFB[64 * 32];
  24.     uint8_t  memory[0x1000];
  25. } chip8_t;
  26.  
  27. uint64_t BuiltInFont[10] = {0x2080F0F0909090F0, 0xF0F0E0F010F07020, 0x10808090F010F010, 0x80909010F080F010, 0x4090F010F0F090F0, 0xF04020F090F090F0, 0xE0F0F0F090F0F010, 0x80F090F0E090E090, 0x80F080909090E0F0, 0x80602080F0F080F0};
  28.  
  29. uint8_t KeyboardState[16];
  30.  
  31. SDL_Window*   window;
  32. SDL_Renderer* renderer;
  33.  
  34. int chip8_PrepareMemory(chip8_t* chip8, const char* FileName) {
  35.     memcpy((void*)chip8->memory, (void*)BuiltInFont, 80);
  36.     int    ROM_FileHandle = open(FileName, 0);                   if (ROM_FileHandle                                                  < 0) {fprintf(stderr, "Cound not find specified ROM.\n");  return -1;}
  37.     size_t ROM_Size       = lseek(ROM_FileHandle, 0, SEEK_END);  if ((ROM_Size < 0) || (ROM_Size > 0x1000 - 0x200)                      ) {fprintf(stderr, "Invalid ROM size.\n");              return -1;}
  38.     ;                                                            if (lseek(ROM_FileHandle, 0, SEEK_SET)                              < 0) {                                                     return -1;}
  39.     ;                                                            if (read (ROM_FileHandle, (void*)&(chip8->memory[0x200]), ROM_Size) < 0) {                                                     return -1;}
  40.     return 0;
  41. }
  42.  
  43. void chip8_display_update(chip8_t* chip8) {
  44.     SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
  45.     SDL_RenderClear(renderer);
  46.     SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
  47.  
  48.     SDL_Rect rect;
  49.     for (int i = 0; i < 32; i++)  for (int j = 0; j < 64; j++)  if (chip8->displayFB[i*64 + j])  {rect.x = j*8; rect.y = i*8; rect.h = rect.w = 8;  SDL_RenderFillRect(renderer, &rect);}
  50.     SDL_RenderPresent(renderer);
  51. }
  52.  
  53. int chip8_execute(chip8_t* chip8) {
  54.     uint8_t nibble1 = (chip8->memory[chip8->PC    ] & 0xF0) >> 4;
  55.     uint8_t nibble2 = (chip8->memory[chip8->PC    ] & 0x0F);
  56.     uint8_t nibble3 = (chip8->memory[chip8->PC + 1] & 0xF0) >> 4;
  57.     uint8_t nibble4 = (chip8->memory[chip8->PC + 1] & 0x0F);
  58.  
  59.     switch (nibble1) {
  60.         case 0:
  61.             if (nibble3 == 0xE && nibble4 == 0xE) {
  62.                 if (chip8->SP == 0) return -1;
  63.                 chip8->SP--;
  64.                 chip8->PC = chip8->stack[chip8->SP] + 2;
  65.                 return 0;
  66.             } else if (nibble3 == 0xE) {
  67.                 for (int i = 0; i < 32*64; i++) chip8->displayFB[i] = 0;
  68.             }
  69.             break;
  70.         case 2:
  71.             chip8->stack[chip8->SP] = chip8->PC;
  72.             chip8->PC = ((nibble2 << 8) | (nibble3 << 4) | (nibble4));
  73.             chip8->SP++;
  74.             return 0;
  75.         case 7:
  76.             if (chip8->V[nibble2] + ((nibble3 << 4) | (nibble4)) > 256) chip8->V[nibble2] = ((nibble3 << 4) | (nibble4)) - (255-chip8->V[nibble2]) - 1;
  77.             else chip8->V[nibble2] = chip8->V[nibble2] + ((nibble3 << 4) | (nibble4));
  78.             break;
  79.  
  80.         case 1:    chip8->PC         = ((nibble2 << 8) | (nibble3 << 4) | (nibble4));                return 0;
  81.         case 6:    chip8->V[nibble2] = (                 (nibble3 << 4) | (nibble4));                break;
  82.         case 0xA:  chip8->I          = ((nibble2 << 8) | (nibble3 << 4) | (nibble4));                break;
  83.         case 0xB:  chip8->PC         = ((nibble2 << 8) | (nibble3 << 4) | (nibble4)) + chip8->V[0];  return 0;
  84.  
  85.         case 3:  if (chip8->V[nibble2] == ((nibble3 << 4) | (nibble4))) chip8->PC += 2;  break;
  86.         case 4:  if (chip8->V[nibble2] != ((nibble3 << 4) | (nibble4))) chip8->PC += 2;  break;
  87.         case 5:  if (chip8->V[nibble2] == chip8->V[nibble3]           ) chip8->PC += 2;  break;
  88.         case 9:  if (chip8->V[nibble2] != chip8->V[nibble3]           ) chip8->PC += 2;  break;
  89.  
  90.         case 8:
  91.             if (nibble4 == 0) {chip8->V[nibble2]  = chip8->V[nibble3];                    } else
  92.             if (nibble4 == 1) {chip8->V[nibble2] |= chip8->V[nibble3];  chip8->V[0xF] = 0;} else
  93.             if (nibble4 == 2) {chip8->V[nibble2] &= chip8->V[nibble3];  chip8->V[0xF] = 0;} else
  94.             if (nibble4 == 3) {chip8->V[nibble2] ^= chip8->V[nibble3];  chip8->V[0xF] = 0;} else
  95.             if (nibble4 == 4) {
  96.                 if (chip8->V[nibble2] + chip8->V[nibble3] > 256) {chip8->V[nibble2] = chip8->V[nibble3] - (255 - chip8->V[nibble2]) - 1;  chip8->V[0xF] = 1;}
  97.                 else                                             {chip8->V[nibble2] = chip8->V[nibble2] +        chip8->V[nibble3];       chip8->V[0xF] = 0;}
  98.             } else if (nibble4 == 5) {
  99.                 if (chip8->V[nibble2] >= chip8->V[nibble3]) {chip8->V[nibble2] -=          chip8->V[nibble3];                             chip8->V[0xF] = 1;}
  100.                 else                                        {chip8->V[nibble2]  = 0x100 - (chip8->V[nibble3] - chip8->V[nibble2]);        chip8->V[0xF] = 0;}
  101.             } else if (nibble4 == 7) {
  102.                 if (chip8->V[nibble3] >= chip8->V[nibble2]) {chip8->V[nibble2] =          chip8->V[nibble3] - chip8->V[nibble2];          chip8->V[0xF] = 1;}
  103.                 else                                        {chip8->V[nibble2] = 0x100 - (chip8->V[nibble2] - chip8->V[nibble3]);         chip8->V[0xF] = 0;}  
  104.             } else if (nibble4 == 6)   {uint8_t lsb =   chip8->V[nibble3]       & 1;   chip8->V[nibble2] = chip8->V[nibble3] / 2;             chip8->V[0xF] = lsb;
  105.             } else if (nibble4 == 0xE) {uint8_t msb = ((chip8->V[nibble3] >> 7) & 1);  chip8->V[nibble2] = chip8->V[nibble3] * 2;             chip8->V[0xF] = msb;
  106.             } else {
  107.                 return -1; 
  108.             }
  109.             break;
  110.         case 0xC:
  111.             srand(time(NULL));
  112.             uint8_t random = rand() % 256;
  113.             chip8->V[nibble2] = (random & ((nibble3 << 4) | (nibble4)));
  114.             break;
  115.         case 0xD:
  116.             size_t x = chip8->V[nibble2];
  117.             size_t y = chip8->V[nibble3];
  118.  
  119.             chip8->V[0xF] = 0;
  120.  
  121.             for (int i = 0; i < nibble4; i++){
  122.                 uint8_t spriteRow = chip8->memory[chip8->I + i];
  123.                 for (int j = 0;  j < 8;  j++){
  124.                     int dispIndex = ((x + j)%64) + (((y + i)%32)*64);
  125.                     uint8_t currSprPixelState = ((spriteRow & (0b10000000 >> j))  >> (7-j));
  126.                     if (chip8->displayFB[dispIndex] && currSprPixelState) chip8->V[0xF] = 1;
  127.                     chip8->displayFB[dispIndex] ^= currSprPixelState;
  128.                 }
  129.             }
  130.             break;
  131.         case 0xE:
  132.             if (nibble3 ==   9 && nibble4 == 0xE) {if (chip8->V[nibble2] > 0xF) return -1;  if ( KeyboardState[chip8->V[nibble2]]) chip8->PC += 2;}  else
  133.             if (nibble3 == 0xA && nibble4 ==   1) {if (chip8->V[nibble2] > 0xF) return -1;  if (!KeyboardState[chip8->V[nibble2]]) chip8->PC += 2;}  break;
  134.         case 0xF:
  135.             if (nibble3 == 0 && nibble4 == 7) {
  136.                 chip8->V[nibble2] = chip8->DT;
  137.             } else if (nibble3 == 0 && nibble4 == 0xA) {
  138.                 static int key = 0;
  139.                 static bool keyPressDetected = false;
  140.  
  141.                 if (!keyPressDetected) {
  142.                     for (int i = 0; i < 16; i++){
  143.                         if (KeyboardState[i]){
  144.                             keyPressDetected = true;
  145.                             key = i;
  146.                             break;
  147.                         }
  148.                     }
  149.                 } else {
  150.                     if(!KeyboardState[key]){
  151.                         keyPressDetected = false;
  152.                         chip8->V[nibble2] = key;
  153.                         chip8->PC += 2;
  154.                     }  
  155.                 }
  156.                 return 0;
  157.             }
  158.             else if (nibble3 == 1 && nibble4 == 0x5) chip8->DT =      chip8->V[nibble2];
  159.             else if (nibble3 == 1 && nibble4 ==   8) chip8->ST =      chip8->V[nibble2];
  160.             else if (nibble3 == 1 && nibble4 == 0xE) chip8->I +=      chip8->V[nibble2];
  161.             else if (nibble3 == 2 && nibble4 ==   9) chip8->I  = 5 * (chip8->V[nibble2] & 0xF);
  162.             else if (nibble3 == 3 && nibble4 ==   3) {
  163.                 chip8->memory[chip8->I    ] = chip8->V[nibble2] / 100 % 10;
  164.                 chip8->memory[chip8->I + 1] = chip8->V[nibble2] / 10  % 10;
  165.                 chip8->memory[chip8->I + 2] = chip8->V[nibble2]       % 10;
  166.             } else if (nibble3 == 5 && nibble4 == 5) {memcpy(                 (void*)&chip8->memory[chip8->I], (void*)chip8->V, nibble2 + 1);  chip8->I += nibble2 + 1;
  167.             } else if (nibble3 == 6 && nibble4 == 5) {memcpy((void*)chip8->V, (void*)&chip8->memory[chip8->I],                  nibble2 + 1);  chip8->I += nibble2 + 1;
  168.             } else {
  169.                 return -1;
  170.             }
  171.             break;
  172.         default:
  173.             return -1;
  174.     }
  175.     chip8->PC += 2;
  176.     return 0;
  177. }
  178.  
  179. chip8_t* chip8_init(int argc, char** argv) {
  180.     if (argc < 2) {fprintf(stderr, "No ROM specified.\n"  );  return NULL;} else
  181.     if (argc > 2) {fprintf(stderr, "Too many arguments.\n");  return NULL;}
  182.     chip8_t* chip8 = malloc(sizeof(chip8_t));
  183.     memset((void*)chip8, 0, sizeof(chip8_t));
  184.     chip8->PC = 0x200;
  185.     if (chip8_PrepareMemory(chip8, argv[1]) != 0) {fprintf(stderr, "Failed to initialize memory image!\n");  return NULL;}
  186.     return chip8;
  187. }
  188.  
  189. int main(int argc, char** argv) {
  190.     ;                                                                                                                                   if (SDL_Init(SDL_INIT_EVERYTHING) !=    0) {fprintf(stderr, "Failed to initialize SDL!\n"     );                              SDL_Quit();  return 1;}
  191.     window         = SDL_CreateWindow("Emul8tor", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 64 * 8, 32 * 8, SDL_WINDOW_SHOWN);  if (window                        == NULL) {fprintf(stderr, "Could not create SDL window!\n"  );                              SDL_Quit();  return 1;}
  192.     renderer       = SDL_CreateRenderer(window, -1, 0);                                                                                 if (renderer                      == NULL) {fprintf(stderr, "Could not create SDL renderer!\n");  SDL_DestroyWindow(window);  SDL_Quit();  return 1;}
  193.     chip8_t* chip8 = chip8_init(argc, argv);                                                                                            if (chip8                         == NULL) {                                                                                               return 1;}
  194.  
  195.     struct timespec StartTime, EndTime;
  196.     size_t          ElapsedTime, SleepTime;
  197.     SDL_Event       Event;
  198.     bool            quit = false;
  199.  
  200.     while(!quit) {
  201.         clock_gettime(CLOCK_MONOTONIC, &StartTime);
  202.  
  203.         for (size_t i = 0; i < CYCLES_PER_TIMER_TICK; i++) {
  204.             while (SDL_PollEvent(&Event)) {
  205.                 SDL_KeyboardEvent kbEvent  = Event.key;
  206.                 int               KeyIndex = kbEvent.keysym.sym;
  207.                 int               KeyValue = -1;
  208.  
  209.                 if (Event.type == SDL_QUIT   )  quit     = true;  else
  210.                 if (Event.type == SDL_KEYDOWN)  KeyValue = 1;     else
  211.                 if (Event.type == SDL_KEYUP  )  KeyValue = 0;
  212.  
  213.                 if (KeyValue >= 0) {
  214.                     if ((KeyIndex >= SDLK_0) && (KeyIndex <= SDLK_9) {KeyboardState[KeyIndex - SDLK_0] = KeyValue;}
  215.                     if ((KeyIndex >= SDLK_a) && (KeyIndex <= SDLK_f) {KeyboardState[KeyIndex - SDLK_a] = KeyValue;}
  216.                     break;
  217.                 }
  218.             }
  219.             if (chip8_execute(chip8) != 0) {printf("ERROR: Failed to execute instruction at 0x%x\n\n", chip8->PC);  quit = true;  break;}
  220.         }
  221.         clock_gettime(CLOCK_MONOTONIC, &EndTime);
  222.         ElapsedTime = (EndTime.tv_sec - StartTime.tv_sec) * 1'000'000 + (EndTime.tv_nsec - StartTime.tv_nsec) / 1000;
  223.         SleepTime   = TIME_BETWEEN_TICKS - ElapsedTime;
  224.         if (SleepTime > 0) usleep(SleepTime);
  225.         if (chip8->DT > 0) chip8->DT--;
  226.         if (chip8->ST > 0) chip8->ST--;
  227.         chip8_display_update(chip8);   
  228.     }
  229.     free(chip8);
  230.     SDL_Quit();
  231.     return 0;
  232. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement