Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "chip8.h"
- #include <fstream>
- //#include <vector>
- #include <iterator>
- void Chip8::initialize() {
- //pc = 0x200; // program counters starts at 0x200
- //drawFlag = true; // clear screen once
- //waitForKey = false; // bool for the opcode FX0A
- //opcode = 0;
- //I = 0;
- //sp = 0;
- //delayTimer = '\0';
- //soundTimer = '\0';
- mt.seed(rd());
- dist = std::uniform_int_distribution<int>(0, 256);
- //extendedScreen = false;
- //forceExit = false;
- // load fontset
- std::array<onebyte, FNT_SIZE> chip8_fontset {
- 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
- 0x20, 0x60, 0x20, 0x20, 0x70, // 1
- 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
- 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
- 0x90, 0x90, 0xF0, 0x10, 0x10, // 4
- 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
- 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
- 0xF0, 0x10, 0x20, 0x40, 0x40, // 7
- 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
- 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
- 0xF0, 0x90, 0xF0, 0x90, 0x90, // A
- 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
- 0xF0, 0x80, 0x80, 0x80, 0xF0, // C
- 0xE0, 0x90, 0x90, 0x90, 0xE0, // D
- 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
- 0xF0, 0x80, 0xF0, 0x80, 0x80 // F
- };
- std::copy(chip8_fontset.begin(), chip8_fontset.end(), memory.begin());
- initOpMap();
- }
- void Chip8::initOpMap() {
- opMap[0x00E0] = &Chip8::CLS; // 00E0: clear screen
- opMap[0x00EE] = &Chip8::RET; // 00EE: return from subroutine
- //opMap[0x00FD] = &Chip8::EXIT; // 00FD: exit chip interpreter
- //opMap[0x00FE] = &Chip8::LOW; // 00FE: disable extended screen mode
- //opMap[0x00FF] = &Chip8::HIGH; // 00FF: enable extended screen mode
- opMap[0x1000] = &Chip8::JP; // 1NNN: jump to address NNN
- opMap[0x2000] = &Chip8::CALL; // 2NNN: call subroutine at NNN
- opMap[0x3000] = &Chip8::SE; // 3XNN: skip next instruction if VX == NN
- opMap[0x4000] = &Chip8::SNE; // 4XNN: skip next instruction if VX != NN
- opMap[0x5000] = &Chip8::SE; // 5XY0: skip next instruction if VX == VY
- opMap[0x6000] = &Chip8::LD; // 6XNN: VX = NN
- opMap[0x7000] = &Chip8::ADD; // 7XNN: VX += NN
- opMap[0x8000] = &Chip8::LD; // 8XY0: VX = VY
- opMap[0x8001] = &Chip8::OR; // 8XY1: VX |= VY
- opMap[0x8002] = &Chip8::AND; // 8XY2: VX &= VY
- opMap[0x8003] = &Chip8::XOR; // 8XY3: VX ^= VY
- opMap[0x8004] = &Chip8::ADD; // 8XY4: VX += VY, VF = 1 if carry else VF = 0
- opMap[0x8005] = &Chip8::SUB; // 8XY5: VX -= VY, VF = 0 if borrow else VF = 1
- opMap[0x8006] = &Chip8::SHR; // 8XY6: VX >>= 1, VF = LSB
- opMap[0x8007] = &Chip8::SUBN; // 8XY7: VX = VY - VX, VF = 0 if borrow else VF = 1
- opMap[0x800E] = &Chip8::SHL; // 8XYE: VX <<= 1, VF = MSB
- opMap[0x9000] = &Chip8::SNE; // 9XY0: skip next instruction if VX != VY
- opMap[0xA000] = &Chip8::LD; // ANNN: I = NNN
- opMap[0xB000] = &Chip8::JP; // BNNN: jump to address NNN + V0
- opMap[0xC000] = &Chip8::RND; // CXNN: VX = rand() & NN
- 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
- opMap[0xE09E] = &Chip8::SKP; // EX9E: skip next instruction if key in VX is pressed
- opMap[0xE0A1] = &Chip8::SKNP; // EXA1: skip next instruction if key in VX is not pressed
- opMap[0xF007] = &Chip8::LD; // FX07: VX = delay timer
- opMap[0xF00A] = &Chip8::LD; // FX0A: VX = awaited key press (blocking operation)
- opMap[0xF015] = &Chip8::LD; // FX15: delay timer = VX
- opMap[0xF018] = &Chip8::LD; // FX18: sound timer = VX
- opMap[0xF01E] = &Chip8::ADD; // FX1E: I += VX
- opMap[0xF029] = &Chip8::LD; // FX29: I = address of sprite for the character in VX (0-F)
- //opMap[0xF030] = &Chip8::LD; // FX30: I = address of sprite for the character in VX (0-9)
- opMap[0xF033] = &Chip8::LD; // FX33: (I+0) = MSD of VX, (I+1) = MD of VX, (I+2) = LSD of VX
- opMap[0xF055] = &Chip8::LD; // FX55: store V0 to including VX in memory starting at I
- opMap[0xF065] = &Chip8::LD; // FX65: fill V0 to including VX with values from memory starting at I
- //opMap[0xF075] = &Chip8::LD; // FX75: store V0 to including VX in rpl (X <= 7)
- //opMap[0xF085] = &Chip8::LD; // FX85: fill V0 to including VX with values from rpl (X <= 7)
- }
- onebyte Chip8::gfxValueAt(unsigned int index) const {
- try {
- return gfx.at(index);
- }
- catch(const std::out_of_range& oor) {
- std::cerr << "Out of Range error: " << oor.what() << std::endl;
- std::cerr << "Used index: " << index << std::endl;
- }
- return 0;
- }
- void Chip8::mapKey(unsigned int index, onebyte value) {
- try {
- key.at(index) = value;
- }
- catch(const std::out_of_range& oor) {
- std::cerr << "Out of Range error: " << oor.what() << std::endl;
- std::cerr << "Used index: " << index << std::endl;
- }
- }
- bool Chip8::loadGame(const std::string& name) {
- std::fstream file;
- try {
- file.open(name, std::ios::in | std::ios::binary);
- if(!file.is_open())
- return false;
- // determine file size
- file.seekg(0, std::ios_base::end); //file.ignore(std::numeric_limits<std::streamsize>::max());
- std::streamsize length = file.tellg(); //file.gcount();
- file.seekg(0, std::ios_base::beg); //file.clear();
- //file.seekg(0, std::ios_base::beg);
- // read data into buffer
- //std::vector<char> buffer(length);
- std::clog << std::distance(memory.begin() + 0x200, memory.end()) << std::endl << length << std::endl;
- //if(std::distance(memory.begin() + 0x200, memory.end()) <= length)
- // file.read(memory.begin() + 0x200, length); //file.read(buffer.data(), length);
- if(std::distance(memory.begin() + 0x200, memory.end()) >= length)
- std::copy(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), memory.begin() + 0x200);
- // copy the game into memory
- //std::copy(buffer.begin(), buffer.end(), memory.begin() + 0x200);
- file.close();
- }
- catch(const std::exception &e) {
- std::cerr << "Exception: " << e.what() << std::endl;
- if(file.is_open())
- file.close();
- return false;
- }
- return true;
- }
- void Chip8::fetchOpcode() {
- // opcodes are 2 bytes long so we need to merge the 2 successive bytes together
- // shift memory value left by 8 bits so that we have 16 bytes
- // | with the next value to get the complete opcode
- try {
- opcode = (memory.at(pc) << 8) | memory.at(pc + 1);
- }
- catch(const std::out_of_range& oor) {
- std::cerr << "Out of Range error: " << oor.what() << std::endl;
- std::cerr << "Used indexes: " << pc << " and " << pc + 1 << std::endl;
- }
- }
- void Chip8::executeOpcode() {
- auto item = opMap.end();
- twobyte index = 0;
- switch(opcode & 0xF000) {
- case 0x8000:
- index = opcode & 0xF00F;
- break;
- case 0x0000:
- case 0xE000:
- case 0xF000:
- index = opcode & 0xF0FF;
- break;
- default:
- index = opcode & 0xF000;
- }
- if(index != 0)
- item = opMap.find(index);
- std::clog << "opcode: " << std::hex << (opcode & 0xFFFF) << std::endl;
- if(item != opMap.end())
- (this->*(item->second))();
- else
- std::cerr << "Opcode does not exist: " << opcode << std::endl;
- }
- void Chip8::updateTimers() {
- if(waitForKey)
- return;
- if(delayTimer > 0)
- --delayTimer;
- if(soundTimer > 0) {
- if(soundTimer == 1)
- printf("BEEP!\n");
- --soundTimer;
- }
- }
- // cycle: fetch opcode -> execute opcode -> update timers
- void Chip8::emulateCycle() {
- try {
- fetchOpcode();
- executeOpcode();
- }
- catch(const std::out_of_range& oor) {
- std::cerr << "Out of Range error: " << oor.what() << std::endl;
- }
- // updateTimers();
- }
- void Chip8::CLS() {
- gfx.fill('\0');
- drawFlag = true;
- pc += 2;
- }
- void Chip8::RET() {
- --sp;
- pc = stack.at(sp);
- pc += 2;
- }
- /*void Chip8::EXIT() {
- forceExit = true;
- pc += 2;
- }
- void Chip8::LOW() {
- extendedScreen = false;
- pc += 2;
- }
- void Chip8::HIGH() {
- extendedScreen = true;
- pc += 2;
- }*/
- void Chip8::JP(){
- switch(opcode & 0xF000) {
- case 0x1000:
- pc = opcode & 0x0FFF;
- break;
- case 0xB000:
- pc = V.at(0x0) + (opcode & 0x0FFF);
- break;
- }
- }
- void Chip8::CALL(){
- stack.at(sp) = pc;
- ++sp;
- pc = opcode & 0x0FFF;
- }
- void Chip8::SE(){
- switch(opcode & 0xF000) {
- case 0x3000:
- if(V.at((opcode & 0x0F00) >> 8) == (opcode & 0x00FF))
- pc += 4;
- else
- pc += 2;
- break;
- case 0x5000:
- if(V.at((opcode & 0x0F00) >> 8) == V.at((opcode & 0x00F0) >> 4))
- pc += 4;
- else
- pc += 2;
- break;
- }
- }
- void Chip8::SNE(){
- switch(opcode & 0xF000) {
- case 0x4000:
- if(V.at((opcode & 0x0F00) >> 8) != (opcode & 0x00FF))
- pc += 4;
- else
- pc += 2;
- break;
- case 0x9000:
- if(V.at((opcode & 0x0F00) >> 8) != V.at((opcode & 0x00F0) >> 4))
- pc += 4;
- else
- pc += 2;
- break;
- }
- }
- void Chip8::LD(){
- switch(opcode & 0xF000) {
- case 0x6000:
- V.at((opcode & 0x0F00) >> 8) = opcode & 0x00FF;
- pc += 2;
- break;
- case 0x8000:
- V.at((opcode & 0x0F00) >> 8) = V.at((opcode & 0x00F0) >> 4);
- pc += 2;
- break;
- case 0xA000:
- I = opcode & 0x0FFF;
- pc += 2;
- break;
- case 0xF000:
- switch(opcode & 0x00FF) {
- case 0x0007:
- V.at((opcode & 0x0F00) >> 8) = delayTimer;
- pc += 2;
- break;
- case 0x000A: {
- waitForKey = true; //bool keyPressed = false;
- for(int i = 0; i < KEY_SIZE; ++i) {
- if(key.at(i) == 1) {
- V.at((opcode & 0x0F00) >> 8) = key.at(i);
- //keyPressed = true;
- waitForKey = false;
- pc += 2;
- break;
- }
- }
- //if(!keyPressed)
- // return;
- }
- break;
- case 0x0015:
- delayTimer = V.at((opcode & 0x0F00) >> 8);
- pc += 2;
- break;
- case 0x0018:
- soundTimer = V.at((opcode & 0x0F00) >> 8);
- pc += 2;
- break;
- case 0x0029:
- I = memory.at(V.at((opcode & 0x0F00) >> 8));
- pc += 2;
- break;
- /*case 0x0030:
- onebyte value = V.at((opcode & 0x0F00) >> 8);
- if(value <= 0x9) {
- I = memory.at(value);
- pc += 2;
- }
- break;*/
- case 0x0033:
- memory.at(I) = V.at((opcode & 0x0F00) >> 8) / 100;
- memory.at(I + 1) = (V.at((opcode & 0x0F00) >> 8) / 10) % 10;
- memory.at(I + 2) = (V.at((opcode & 0x0F00) >> 8) % 100) % 10;
- pc += 2;
- break;
- case 0x0055: {
- int max = (opcode & 0x0F00) >> 8;
- for(int i = 0; i <= max; ++i)
- memory.at(I + i) = V.at(i);
- pc += 2;
- }
- break;
- case 0x0065: {
- int max = (opcode & 0x0F00) >> 8;
- for(int i = 0; i <= max; ++i)
- V.at(i) = memory.at(I + i);
- pc += 2;
- }
- break;
- /*case 0x0075: {
- int max = (opcode & 0x0F00) >> 8;
- if(max <= 7) {
- for(int i = 0; i <= max; ++i)
- rpl.at(i) = V.at(i);
- }
- pc += 2;
- }
- break;
- case 0x0085: {
- int max = (opcode & 0x0F00) >> 8;
- if(max <= 7) {
- for(int i = 0; i <= max; ++i)
- V.at(i) = rpl.at(i);
- }
- pc += 2;
- }
- break;*/
- }
- break;
- }
- }
- void Chip8::ADD(){
- switch(opcode & 0xF000) {
- case 0x7000:
- V.at((opcode & 0x0F00) >> 8) += (opcode & 0x00FF);
- pc += 2;
- break;
- case 0x8000:
- if((opcode & 0x000F) == 0x0004) {
- if((V.at((opcode & 0x0F00) >> 8) + V.at((opcode & 0x00F0) >> 4)) > 0xFF)
- V.at(0xF) = 1;
- else
- V.at(0xF) = 0;
- V.at((opcode & 0x0F00) >> 8) += V.at((opcode & 0x00F0) >> 4);
- pc += 2;
- }
- break;
- case 0xF000:
- if((opcode & 0x000F) == 0x000E) {
- if((I + V.at((opcode & 0x0F00) >> 8)) > 0xFFF)
- V.at(0xF) = 1;
- else
- V.at(0xF) = 0;
- I += V.at((opcode & 0x0F00) >> 8);
- pc += 2;
- }
- break;
- }
- }
- void Chip8::OR(){
- V.at((opcode & 0x0F00) >> 8) |= V.at((opcode & 0x00F0) >> 4);
- pc += 2;
- }
- void Chip8::AND(){
- V.at((opcode & 0x0F00) >> 8) &= V.at((opcode & 0x00F0) >> 4);
- pc += 2;
- }
- void Chip8::XOR(){
- V.at((opcode & 0x0F00) >> 8) ^= V.at((opcode & 0x00F0) >> 4);
- pc += 2;
- }
- void Chip8::SUB(){
- if((V.at((opcode & 0x0F00) >> 8) - V.at((opcode & 0x00F0) >> 4)) < 0x0)
- V.at(0xF) = 0;
- else
- V.at(0xF) = 1;
- V.at((opcode & 0x0F00) >> 8) -= V.at((opcode & 0x00F0) >> 4);
- pc += 2;
- }
- void Chip8::SHR(){
- V.at(0xF) = V.at((opcode & 0x0F00) >> 8) & 0x0001;
- V.at((opcode & 0x0F00) >> 8) >>= 1;
- pc += 2;
- }
- void Chip8::SUBN(){
- if((V.at((opcode & 0x00F0) >> 4) - V.at((opcode & 0x0F00) >> 8)) < 0x0)
- V.at(0xF) = 0;
- else
- V.at(0xF) = 1;
- V.at((opcode & 0x0F00) >> 8) = V.at((opcode & 0x00F0) >> 4) - V.at((opcode & 0x0F00) >> 8);
- pc += 2;
- }
- void Chip8::SHL(){
- V.at(0xF) = V.at((opcode & 0x0F00) >> 8) >> 7;
- V.at((opcode & 0x0F00) >> 8) <<= 1;
- pc += 2;
- }
- void Chip8::RND(){
- V.at((opcode & 0x0F00) >> 8) = dist(mt) & (opcode & 0x00FF);
- pc += 2;
- }
- void Chip8::DRW(){
- int x = V.at((opcode & 0x0F00) >> 8);
- int y = V.at((opcode & 0x00F0) >> 4);
- int width = 8;
- int height = opcode & 0x000F;
- onebyte pixel;
- /*if(height == 0) {
- width = 16;
- height = 16;
- }*/
- V.at(0xF) = 0;
- for(int yline = 0; yline < height; yline++) {
- pixel = memory.at(I + yline);
- for(int xline = 0; xline < width; xline++) {
- if((pixel & (0x80 >> xline)) != 0) {
- if(gfx.at(x + xline + ((y + yline) * 64)) == 1)
- V.at(0xF) = 1;
- gfx.at(x + xline + ((y + yline) * 64)) ^= 1;
- }
- }
- }
- drawFlag = true;
- pc += 2;
- }
- void Chip8::SKP(){
- if(key.at(V.at((opcode & 0x0F00) >> 8)))
- pc += 4;
- else
- pc += 2;
- }
- void Chip8::SKNP(){
- if(!key.at(V.at((opcode & 0x0F00) >> 8)))
- pc += 4;
- else
- pc += 2;
- }
Add Comment
Please, Sign In to add comment