Guest User

chip8.cpp

a guest
Mar 2nd, 2017
135
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.77 KB | None | 0 0
  1. #include "chip8.h"
  2.  
  3. #include <fstream>
  4. //#include <vector>
  5. #include <iterator>
  6.  
  7. void Chip8::initialize() {
  8.     //pc = 0x200; // program counters starts at 0x200
  9.     //drawFlag = true; // clear screen once
  10.     //waitForKey = false; // bool for the opcode FX0A
  11.     //opcode = 0;
  12.     //I = 0;
  13.     //sp = 0;
  14.     //delayTimer = '\0';
  15.     //soundTimer = '\0';
  16.     mt.seed(rd());
  17.     dist = std::uniform_int_distribution<int>(0, 256);
  18.    
  19.     //extendedScreen = false;
  20.     //forceExit = false;
  21.    
  22.     // load fontset
  23.     std::array<onebyte, FNT_SIZE> chip8_fontset {
  24.         0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
  25.         0x20, 0x60, 0x20, 0x20, 0x70, // 1
  26.         0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
  27.         0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
  28.         0x90, 0x90, 0xF0, 0x10, 0x10, // 4
  29.         0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
  30.         0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
  31.         0xF0, 0x10, 0x20, 0x40, 0x40, // 7
  32.         0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
  33.         0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
  34.         0xF0, 0x90, 0xF0, 0x90, 0x90, // A
  35.         0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
  36.         0xF0, 0x80, 0x80, 0x80, 0xF0, // C
  37.         0xE0, 0x90, 0x90, 0x90, 0xE0, // D
  38.         0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
  39.         0xF0, 0x80, 0xF0, 0x80, 0x80  // F
  40.     };
  41.     std::copy(chip8_fontset.begin(), chip8_fontset.end(), memory.begin());
  42.    
  43.     initOpMap();
  44. }
  45.  
  46. void Chip8::initOpMap() {
  47.     opMap[0x00E0] = &Chip8::CLS;  // 00E0: clear screen
  48.     opMap[0x00EE] = &Chip8::RET;  // 00EE: return from subroutine
  49.     //opMap[0x00FD] = &Chip8::EXIT; // 00FD: exit chip interpreter
  50.     //opMap[0x00FE] = &Chip8::LOW;  // 00FE: disable extended screen mode
  51.     //opMap[0x00FF] = &Chip8::HIGH; // 00FF: enable extended screen mode
  52.     opMap[0x1000] = &Chip8::JP;   // 1NNN: jump to address NNN
  53.     opMap[0x2000] = &Chip8::CALL; // 2NNN: call subroutine at NNN
  54.     opMap[0x3000] = &Chip8::SE;   // 3XNN: skip next instruction if VX == NN
  55.     opMap[0x4000] = &Chip8::SNE;  // 4XNN: skip next instruction if VX != NN
  56.     opMap[0x5000] = &Chip8::SE;   // 5XY0: skip next instruction if VX == VY
  57.     opMap[0x6000] = &Chip8::LD;   // 6XNN: VX = NN
  58.     opMap[0x7000] = &Chip8::ADD;  // 7XNN: VX += NN
  59.     opMap[0x8000] = &Chip8::LD;   // 8XY0: VX = VY
  60.     opMap[0x8001] = &Chip8::OR;   // 8XY1: VX |= VY
  61.     opMap[0x8002] = &Chip8::AND;  // 8XY2: VX &= VY
  62.     opMap[0x8003] = &Chip8::XOR;  // 8XY3: VX ^= VY
  63.     opMap[0x8004] = &Chip8::ADD;  // 8XY4: VX += VY, VF = 1 if carry else VF = 0
  64.     opMap[0x8005] = &Chip8::SUB;  // 8XY5: VX -= VY, VF = 0 if borrow else VF = 1
  65.     opMap[0x8006] = &Chip8::SHR;  // 8XY6: VX >>= 1, VF = LSB
  66.     opMap[0x8007] = &Chip8::SUBN; // 8XY7: VX = VY - VX, VF = 0 if borrow else VF = 1
  67.     opMap[0x800E] = &Chip8::SHL;  // 8XYE: VX <<= 1, VF = MSB
  68.     opMap[0x9000] = &Chip8::SNE;  // 9XY0: skip next instruction if VX != VY
  69.     opMap[0xA000] = &Chip8::LD;   // ANNN: I = NNN
  70.     opMap[0xB000] = &Chip8::JP;   // BNNN: jump to address NNN + V0
  71.     opMap[0xC000] = &Chip8::RND;  // CXNN: VX = rand() & NN
  72.     opMap[0xD000] = &Chip8::DRW;  // DXYN: draw sprite at (VX, VY), width = 8 px, height = N px, VF = 1 if screen px flipped from 1 to 0 else VF = 0, 16x16 px if N == 0
  73.     opMap[0xE09E] = &Chip8::SKP;  // EX9E: skip next instruction if key in VX is pressed
  74.     opMap[0xE0A1] = &Chip8::SKNP; // EXA1: skip next instruction if key in VX is not pressed
  75.     opMap[0xF007] = &Chip8::LD;   // FX07: VX = delay timer
  76.     opMap[0xF00A] = &Chip8::LD;   // FX0A: VX = awaited key press (blocking operation)
  77.     opMap[0xF015] = &Chip8::LD;   // FX15: delay timer = VX
  78.     opMap[0xF018] = &Chip8::LD;   // FX18: sound timer = VX
  79.     opMap[0xF01E] = &Chip8::ADD;  // FX1E: I += VX
  80.     opMap[0xF029] = &Chip8::LD;   // FX29: I = address of sprite for the character in VX (0-F)
  81.     //opMap[0xF030] = &Chip8::LD;   // FX30: I = address of sprite for the character in VX (0-9)
  82.     opMap[0xF033] = &Chip8::LD;   // FX33: (I+0) = MSD of VX, (I+1) = MD of VX, (I+2) = LSD of VX
  83.     opMap[0xF055] = &Chip8::LD;   // FX55: store V0 to including VX in memory starting at I
  84.     opMap[0xF065] = &Chip8::LD;   // FX65: fill V0 to including VX with values from memory starting at I
  85.     //opMap[0xF075] = &Chip8::LD;   // FX75: store V0 to including VX in rpl (X <= 7)
  86.     //opMap[0xF085] = &Chip8::LD;   // FX85: fill V0 to including VX with values from rpl (X <= 7)
  87. }
  88.  
  89. onebyte Chip8::gfxValueAt(unsigned int index) const {
  90.     try {
  91.         return gfx.at(index);
  92.     }
  93.     catch(const std::out_of_range& oor) {
  94.         std::cerr << "Out of Range error: " << oor.what() << std::endl;
  95.         std::cerr << "Used index: " << index << std::endl;
  96.     }
  97.    
  98.     return 0;
  99. }
  100.  
  101. void Chip8::mapKey(unsigned int index, onebyte value) {
  102.     try {
  103.         key.at(index) = value;
  104.     }
  105.     catch(const std::out_of_range& oor) {
  106.         std::cerr << "Out of Range error: " << oor.what() << std::endl;
  107.         std::cerr << "Used index: " << index << std::endl;
  108.     }
  109. }
  110.  
  111. bool Chip8::loadGame(const std::string& name) {
  112.     std::fstream file;
  113.     try {
  114.         file.open(name, std::ios::in | std::ios::binary);
  115.         if(!file.is_open())
  116.             return false;
  117.  
  118.         // determine file size
  119.         file.seekg(0, std::ios_base::end); //file.ignore(std::numeric_limits<std::streamsize>::max());
  120.         std::streamsize length = file.tellg(); //file.gcount();
  121.         file.seekg(0, std::ios_base::beg); //file.clear();
  122.         //file.seekg(0, std::ios_base::beg);
  123.  
  124.         // read data into buffer
  125.         //std::vector<char> buffer(length);
  126.         std::clog << std::distance(memory.begin() + 0x200, memory.end()) << std::endl << length << std::endl;
  127.         //if(std::distance(memory.begin() + 0x200, memory.end()) <= length)
  128.         //    file.read(memory.begin() + 0x200, length); //file.read(buffer.data(), length);
  129.         if(std::distance(memory.begin() + 0x200, memory.end()) >= length)
  130.             std::copy(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), memory.begin() + 0x200);
  131.            
  132.         // copy the game into memory
  133.         //std::copy(buffer.begin(), buffer.end(), memory.begin() + 0x200);
  134.  
  135.         file.close();
  136.     }
  137.     catch(const std::exception &e) {
  138.         std::cerr << "Exception: " << e.what() << std::endl;
  139.  
  140.         if(file.is_open())
  141.             file.close();
  142.  
  143.         return false;
  144.     }
  145.  
  146.     return true;
  147. }
  148.  
  149. void Chip8::fetchOpcode() {
  150.     // opcodes are 2 bytes long so we need to merge the 2 successive bytes together
  151.     // shift memory value left by 8 bits so that we have 16 bytes
  152.     // | with the next value to get the complete opcode
  153.     try {
  154.         opcode = (memory.at(pc) << 8) | memory.at(pc + 1);
  155.     }
  156.     catch(const std::out_of_range& oor) {
  157.         std::cerr << "Out of Range error: " << oor.what() << std::endl;
  158.         std::cerr << "Used indexes: " << pc << " and " << pc + 1 << std::endl;
  159.     }
  160. }
  161.  
  162. void Chip8::executeOpcode() {
  163.     auto item = opMap.end();
  164.     twobyte index = 0;
  165.    
  166.     switch(opcode & 0xF000) {
  167.         case 0x8000:
  168.             index = opcode & 0xF00F;
  169.         break; 
  170.        
  171.         case 0x0000:
  172.         case 0xE000:
  173.         case 0xF000:
  174.             index = opcode & 0xF0FF;
  175.         break;
  176.  
  177.         default:
  178.             index = opcode & 0xF000;
  179.     }
  180.    
  181.     if(index != 0)
  182.         item = opMap.find(index);
  183.     std::clog << "opcode: " << std::hex << (opcode & 0xFFFF) << std::endl;
  184.     if(item != opMap.end())
  185.         (this->*(item->second))();
  186.     else
  187.         std::cerr << "Opcode does not exist: " << opcode << std::endl;
  188. }
  189.  
  190. void Chip8::updateTimers() {
  191.     if(waitForKey)
  192.         return;
  193.    
  194.     if(delayTimer > 0)
  195.         --delayTimer;
  196.  
  197.     if(soundTimer > 0) {
  198.         if(soundTimer == 1)
  199.             printf("BEEP!\n");
  200.  
  201.         --soundTimer;
  202.     }
  203. }
  204.  
  205. // cycle: fetch opcode -> execute opcode -> update timers
  206. void Chip8::emulateCycle() {
  207.     try {
  208.         fetchOpcode();
  209.         executeOpcode();
  210.     }
  211.     catch(const std::out_of_range& oor) {
  212.         std::cerr << "Out of Range error: " << oor.what() << std::endl;
  213.     }
  214.    
  215.    // updateTimers();
  216. }
  217.  
  218. void Chip8::CLS() {
  219.     gfx.fill('\0');      
  220.     drawFlag = true;
  221.     pc += 2;
  222. }
  223.  
  224. void Chip8::RET() {
  225.     --sp;
  226.     pc = stack.at(sp);
  227.     pc += 2;
  228. }
  229.  
  230. /*void Chip8::EXIT() {
  231.     forceExit = true;
  232.     pc += 2;
  233. }
  234.  
  235. void Chip8::LOW() {
  236.     extendedScreen = false;
  237.     pc += 2;
  238. }
  239.  
  240. void Chip8::HIGH() {
  241.     extendedScreen = true;
  242.     pc += 2;
  243. }*/
  244.  
  245. void Chip8::JP(){
  246.     switch(opcode & 0xF000) {
  247.         case 0x1000:
  248.             pc = opcode & 0x0FFF;
  249.         break;
  250.         case 0xB000:
  251.             pc = V.at(0x0) + (opcode & 0x0FFF);
  252.         break;
  253.     }
  254. }
  255.  
  256. void Chip8::CALL(){
  257.     stack.at(sp) = pc;
  258.     ++sp;
  259.     pc = opcode & 0x0FFF;
  260. }
  261.  
  262. void Chip8::SE(){
  263.     switch(opcode & 0xF000) {
  264.         case 0x3000:
  265.             if(V.at((opcode & 0x0F00) >> 8) == (opcode & 0x00FF))
  266.                 pc += 4;
  267.             else
  268.                 pc += 2;
  269.         break;
  270.         case 0x5000:
  271.             if(V.at((opcode & 0x0F00) >> 8) == V.at((opcode & 0x00F0) >> 4))
  272.                 pc += 4;
  273.             else
  274.                 pc += 2;
  275.         break;
  276.     }
  277. }
  278.  
  279. void Chip8::SNE(){
  280.     switch(opcode & 0xF000) {
  281.         case 0x4000:
  282.             if(V.at((opcode & 0x0F00) >> 8) != (opcode & 0x00FF))
  283.                 pc += 4;
  284.             else
  285.                 pc += 2;
  286.         break;
  287.         case 0x9000:
  288.             if(V.at((opcode & 0x0F00) >> 8) != V.at((opcode & 0x00F0) >> 4))
  289.                 pc += 4;
  290.             else
  291.                 pc += 2;
  292.         break;
  293.     }
  294. }
  295.  
  296. void Chip8::LD(){
  297.     switch(opcode & 0xF000) {
  298.         case 0x6000:
  299.             V.at((opcode & 0x0F00) >> 8) = opcode & 0x00FF;
  300.             pc += 2;
  301.         break;
  302.         case 0x8000:
  303.             V.at((opcode & 0x0F00) >> 8) = V.at((opcode & 0x00F0) >> 4);
  304.             pc += 2;
  305.         break;
  306.         case 0xA000:
  307.             I = opcode & 0x0FFF;
  308.             pc += 2;
  309.         break;
  310.         case 0xF000:
  311.             switch(opcode & 0x00FF) {
  312.                 case 0x0007:
  313.                     V.at((opcode & 0x0F00) >> 8) = delayTimer;
  314.                     pc += 2;
  315.                 break;
  316.                 case 0x000A: {
  317.                     waitForKey = true; //bool keyPressed = false;
  318.                     for(int i = 0; i < KEY_SIZE; ++i) {
  319.                         if(key.at(i) == 1) {
  320.                             V.at((opcode & 0x0F00) >> 8) = key.at(i);
  321.                             //keyPressed = true;
  322.                             waitForKey = false;
  323.                             pc += 2;
  324.                             break;
  325.                         }
  326.                     }
  327.                    
  328.                     //if(!keyPressed)
  329.                     //    return;
  330.                 }
  331.                 break;
  332.                 case 0x0015:
  333.                     delayTimer = V.at((opcode & 0x0F00) >> 8);
  334.                     pc += 2;
  335.                 break;
  336.                 case 0x0018:
  337.                     soundTimer = V.at((opcode & 0x0F00) >> 8);
  338.                     pc += 2;
  339.                 break;
  340.                 case 0x0029:
  341.                     I = memory.at(V.at((opcode & 0x0F00) >> 8));
  342.                     pc += 2;
  343.                 break;
  344.                 /*case 0x0030:
  345.                     onebyte value = V.at((opcode & 0x0F00) >> 8);
  346.                     if(value <= 0x9) {
  347.                         I = memory.at(value);
  348.                         pc += 2;
  349.                     }
  350.                 break;*/
  351.                 case 0x0033:
  352.                     memory.at(I) = V.at((opcode & 0x0F00) >> 8) / 100;
  353.                     memory.at(I + 1) = (V.at((opcode & 0x0F00) >> 8) / 10) % 10;
  354.                     memory.at(I + 2) = (V.at((opcode & 0x0F00) >> 8) % 100) % 10;
  355.                     pc += 2;
  356.                 break;
  357.                 case 0x0055: {
  358.                     int max = (opcode & 0x0F00) >> 8;
  359.                     for(int i = 0; i <= max; ++i)
  360.                         memory.at(I + i) = V.at(i);
  361.  
  362.                     pc += 2;
  363.                 }
  364.                 break;
  365.                 case 0x0065: {
  366.                     int max = (opcode & 0x0F00) >> 8;
  367.                     for(int i = 0; i <= max; ++i)
  368.                         V.at(i) = memory.at(I + i);
  369.  
  370.                     pc += 2;
  371.                 }
  372.                 break;
  373.                 /*case 0x0075: {
  374.                     int max = (opcode & 0x0F00) >> 8;
  375.                     if(max <= 7) {
  376.                         for(int i = 0; i <= max; ++i)
  377.                             rpl.at(i) = V.at(i);
  378.                     }
  379.                    
  380.                     pc += 2;
  381.                 }
  382.                 break;
  383.                 case 0x0085: {
  384.                     int max = (opcode & 0x0F00) >> 8;
  385.                     if(max <= 7) {
  386.                         for(int i = 0; i <= max; ++i)
  387.                             V.at(i) = rpl.at(i);
  388.                     }
  389.                    
  390.                     pc += 2;
  391.                 }
  392.                 break;*/
  393.             }
  394.         break;
  395.     }
  396. }
  397.  
  398. void Chip8::ADD(){
  399.     switch(opcode & 0xF000) {
  400.         case 0x7000:
  401.             V.at((opcode & 0x0F00) >> 8) += (opcode & 0x00FF);
  402.             pc += 2;
  403.         break;
  404.         case 0x8000:
  405.             if((opcode & 0x000F) == 0x0004) {
  406.                 if((V.at((opcode & 0x0F00) >> 8) + V.at((opcode & 0x00F0) >> 4)) > 0xFF)
  407.                     V.at(0xF) = 1;
  408.                 else
  409.                     V.at(0xF) = 0;
  410.                
  411.                 V.at((opcode & 0x0F00) >> 8) += V.at((opcode & 0x00F0) >> 4);
  412.                 pc += 2;
  413.             }
  414.         break;
  415.         case 0xF000:
  416.             if((opcode & 0x000F) == 0x000E) {
  417.                 if((I + V.at((opcode & 0x0F00) >> 8)) > 0xFFF)
  418.                     V.at(0xF) = 1;
  419.                 else
  420.                     V.at(0xF) = 0;
  421.                
  422.                 I += V.at((opcode & 0x0F00) >> 8);
  423.                 pc += 2;
  424.             }
  425.         break;
  426.     }
  427. }
  428.  
  429. void Chip8::OR(){
  430.     V.at((opcode & 0x0F00) >> 8) |= V.at((opcode & 0x00F0) >> 4);
  431.     pc += 2;
  432. }
  433.  
  434. void Chip8::AND(){
  435.     V.at((opcode & 0x0F00) >> 8) &= V.at((opcode & 0x00F0) >> 4);
  436.     pc += 2;
  437. }
  438.  
  439. void Chip8::XOR(){
  440.     V.at((opcode & 0x0F00) >> 8) ^= V.at((opcode & 0x00F0) >> 4);
  441.     pc += 2;
  442. }
  443.  
  444. void Chip8::SUB(){
  445.     if((V.at((opcode & 0x0F00) >> 8) - V.at((opcode & 0x00F0) >> 4)) < 0x0)
  446.         V.at(0xF) = 0;
  447.     else
  448.         V.at(0xF) = 1;
  449.    
  450.     V.at((opcode & 0x0F00) >> 8) -= V.at((opcode & 0x00F0) >> 4);
  451.     pc += 2;
  452. }
  453.  
  454. void Chip8::SHR(){
  455.     V.at(0xF) = V.at((opcode & 0x0F00) >> 8) & 0x0001;
  456.     V.at((opcode & 0x0F00) >> 8) >>= 1;
  457.     pc += 2;
  458. }
  459.  
  460. void Chip8::SUBN(){
  461.     if((V.at((opcode & 0x00F0) >> 4) - V.at((opcode & 0x0F00) >> 8)) < 0x0)
  462.         V.at(0xF) = 0;
  463.     else
  464.         V.at(0xF) = 1;
  465.        
  466.     V.at((opcode & 0x0F00) >> 8) = V.at((opcode & 0x00F0) >> 4) - V.at((opcode & 0x0F00) >> 8);
  467.     pc += 2;
  468. }
  469.  
  470. void Chip8::SHL(){
  471.     V.at(0xF) = V.at((opcode & 0x0F00) >> 8) >> 7;
  472.     V.at((opcode & 0x0F00) >> 8) <<= 1;
  473.     pc += 2;
  474. }
  475.  
  476. void Chip8::RND(){
  477.     V.at((opcode & 0x0F00) >> 8) = dist(mt) & (opcode & 0x00FF);
  478.     pc += 2;
  479. }
  480.  
  481. void Chip8::DRW(){
  482.     int x = V.at((opcode & 0x0F00) >> 8);
  483.     int y = V.at((opcode & 0x00F0) >> 4);
  484.     int width = 8;
  485.     int height = opcode & 0x000F;
  486.     onebyte pixel;
  487.  
  488.     /*if(height == 0) {
  489.         width = 16;
  490.         height = 16;
  491.     }*/
  492.    
  493.     V.at(0xF) = 0;
  494.     for(int yline = 0; yline < height; yline++) {
  495.         pixel = memory.at(I + yline);
  496.         for(int xline = 0; xline < width; xline++) {
  497.             if((pixel & (0x80 >> xline)) != 0) {
  498.                 if(gfx.at(x + xline + ((y + yline) * 64)) == 1)
  499.                     V.at(0xF) = 1;
  500.  
  501.                 gfx.at(x + xline + ((y + yline) * 64)) ^= 1;
  502.             }
  503.         }
  504.     }
  505.  
  506.     drawFlag = true;
  507.     pc += 2;
  508. }
  509.  
  510. void Chip8::SKP(){
  511.     if(key.at(V.at((opcode & 0x0F00) >> 8)))
  512.         pc += 4;
  513.     else
  514.         pc += 2;
  515. }
  516.  
  517. void Chip8::SKNP(){
  518.     if(!key.at(V.at((opcode & 0x0F00) >> 8)))
  519.         pc += 4;
  520.     else
  521.         pc += 2;
  522. }
Add Comment
Please, Sign In to add comment