|
|
@ -9,7 +9,7 @@ |
|
|
|
|
|
|
|
|
|
|
|
using namespace olc; |
|
|
|
using namespace olc; |
|
|
|
|
|
|
|
|
|
|
|
bool USE_DEBUG_DISPLAY=true; |
|
|
|
bool USE_DEBUG_DISPLAY=false; |
|
|
|
int EMULATOR_SCREEN_WIDTH = 64; |
|
|
|
int EMULATOR_SCREEN_WIDTH = 64; |
|
|
|
int EMULATOR_SCREEN_HEIGHT = 32; |
|
|
|
int EMULATOR_SCREEN_HEIGHT = 32; |
|
|
|
int EMULATOR_PIXEL_SIZE=5; |
|
|
|
int EMULATOR_PIXEL_SIZE=5; |
|
|
@ -66,6 +66,7 @@ public: |
|
|
|
bool USE_ORIGINAL_CHIP8_SET=true; //True means use the original CHIP-8 spec (COSMAC VIP emulation). Set to false to use CHIP-48 spec.
|
|
|
|
bool USE_ORIGINAL_CHIP8_SET=true; //True means use the original CHIP-8 spec (COSMAC VIP emulation). Set to false to use CHIP-48 spec.
|
|
|
|
bool PAUSED=true; |
|
|
|
bool PAUSED=true; |
|
|
|
long instructionCount=0; |
|
|
|
long instructionCount=0; |
|
|
|
|
|
|
|
uint16_t watchMemoryAddress=0; |
|
|
|
|
|
|
|
|
|
|
|
std::string Display8(int number){ |
|
|
|
std::string Display8(int number){ |
|
|
|
std::bitset<8>numb(number); |
|
|
|
std::bitset<8>numb(number); |
|
|
@ -92,7 +93,7 @@ public: |
|
|
|
for (int i=0;i<display.size();i++){ |
|
|
|
for (int i=0;i<display.size();i++){ |
|
|
|
display[i]=0; |
|
|
|
display[i]=0; |
|
|
|
} |
|
|
|
} |
|
|
|
std::ifstream file("ChipWar.ch8",std::ios_base::binary); |
|
|
|
std::ifstream file("chip8-test-suite.ch8",std::ios_base::binary); |
|
|
|
uint16_t counter=0x200; |
|
|
|
uint16_t counter=0x200; |
|
|
|
while (file.good()){ |
|
|
|
while (file.good()){ |
|
|
|
int val = file.get(); |
|
|
|
int val = file.get(); |
|
|
@ -116,6 +117,10 @@ public: |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void OnTextEntryComplete(const std::string &sText) override{ |
|
|
|
|
|
|
|
watchMemoryAddress=std::stoul(sText.c_str(),nullptr,16); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool OnUserUpdate(float fElapsedTime) override |
|
|
|
bool OnUserUpdate(float fElapsedTime) override |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!USE_DEBUG_DISPLAY||!PAUSED){ |
|
|
|
if (!USE_DEBUG_DISPLAY||!PAUSED){ |
|
|
@ -130,6 +135,10 @@ public: |
|
|
|
DrawDisplay(); |
|
|
|
DrawDisplay(); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
|
|
|
|
if (GetKey(G).bPressed){ |
|
|
|
|
|
|
|
TextEntryEnable(true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!IsTextEntryEnabled()){ |
|
|
|
if (GetKey(OEM_6).bPressed){ |
|
|
|
if (GetKey(OEM_6).bPressed){ |
|
|
|
RunInstruction(); |
|
|
|
RunInstruction(); |
|
|
|
instructionCount++; |
|
|
|
instructionCount++; |
|
|
@ -147,6 +156,11 @@ public: |
|
|
|
DrawDisplay(); |
|
|
|
DrawDisplay(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (IsTextEntryEnabled()){ |
|
|
|
|
|
|
|
DrawStringDecal({2,2},"Goto Memory Address: "+TextEntryGetString()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::stringstream s; |
|
|
|
std::stringstream s; |
|
|
|
s<<"PC: 0x"<<std::setfill('0')<< std::setw(4)<<std::hex<<pc; |
|
|
|
s<<"PC: 0x"<<std::setfill('0')<< std::setw(4)<<std::hex<<pc; |
|
|
|
std::string ss=s.str(); |
|
|
|
std::string ss=s.str(); |
|
|
@ -205,6 +219,24 @@ public: |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::stringstream hexMemoryWatch; |
|
|
|
|
|
|
|
hexMemoryWatch<<std::hex<<std::setfill('0')<<std::setw(4)<<watchMemoryAddress; |
|
|
|
|
|
|
|
DrawStringDecal(vi2d{14+EMULATOR_PIXEL_SIZE*EMULATOR_SCREEN_WIDTH,18+21*10},"Memory Region [0x"+hexMemoryWatch.str()+"]:"); |
|
|
|
|
|
|
|
for (int j=0;j<12;j++){ |
|
|
|
|
|
|
|
std::stringstream memj; |
|
|
|
|
|
|
|
memj<<std::hex<<std::setfill('0')<<std::setw(4)<<watchMemoryAddress+16*j; |
|
|
|
|
|
|
|
DrawStringDecal(vi2d{14+EMULATOR_PIXEL_SIZE*EMULATOR_SCREEN_WIDTH,18+21*10+j*10+10},"0x"+memj.str()); |
|
|
|
|
|
|
|
for (int i=0;i<16;i++){ |
|
|
|
|
|
|
|
uint16_t mem = i+j*16+watchMemoryAddress; |
|
|
|
|
|
|
|
if (mem<memory.size()){ |
|
|
|
|
|
|
|
std::stringstream hexval; |
|
|
|
|
|
|
|
hexval<<std::hex<<std::setfill('0')<<std::setw(2)<<(int)memory[mem]; |
|
|
|
|
|
|
|
std::string sss=hexval.str(); |
|
|
|
|
|
|
|
std::transform(sss.begin(),sss.end(),sss.begin(),::toupper); |
|
|
|
|
|
|
|
DrawStringDecal(vi2d{14+EMULATOR_PIXEL_SIZE*EMULATOR_SCREEN_WIDTH+8*8+i*3*8,18+21*10+j*10+10},sss); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
@ -463,18 +495,21 @@ public: |
|
|
|
reg[X]^=reg[Y]; |
|
|
|
reg[X]^=reg[Y]; |
|
|
|
}break; |
|
|
|
}break; |
|
|
|
case 0x4:{//Add VY to VX, set carry bit if overflow occurs.
|
|
|
|
case 0x4:{//Add VY to VX, set carry bit if overflow occurs.
|
|
|
|
reg[0xF]=0; |
|
|
|
bool carryFlag=0; |
|
|
|
if ((int)reg[X]+(int)reg[Y]>255){ |
|
|
|
if ((int)reg[X]+(int)reg[Y]>255){ |
|
|
|
reg[0xF]=1; |
|
|
|
carryFlag=1; |
|
|
|
} |
|
|
|
} |
|
|
|
reg[X]+=reg[Y]; |
|
|
|
reg[X]+=reg[Y]; |
|
|
|
|
|
|
|
reg[0xF]=carryFlag; |
|
|
|
}break; |
|
|
|
}break; |
|
|
|
case 0x5:{// sets VX to the result of VX - VY.
|
|
|
|
case 0x5:{// sets VX to the result of VX - VY.
|
|
|
|
reg[0xF]=0; |
|
|
|
bool carryFlag=0; |
|
|
|
if (reg[X]>reg[Y]){ |
|
|
|
if (reg[X]>reg[Y]){ |
|
|
|
reg[0xF]=1; |
|
|
|
//reg[0xF]=1;
|
|
|
|
|
|
|
|
//carryFlag=1;
|
|
|
|
} |
|
|
|
} |
|
|
|
reg[X]-=reg[Y]; |
|
|
|
reg[X]-=reg[Y]; |
|
|
|
|
|
|
|
reg[0xF]=carryFlag; |
|
|
|
}break; |
|
|
|
}break; |
|
|
|
case 0x6:{//Shift Right
|
|
|
|
case 0x6:{//Shift Right
|
|
|
|
if (USE_ORIGINAL_CHIP8_SET){ |
|
|
|
if (USE_ORIGINAL_CHIP8_SET){ |
|
|
@ -485,15 +520,19 @@ public: |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
reg[X]=reg[Y]; |
|
|
|
reg[X]=reg[Y]; |
|
|
|
} |
|
|
|
} |
|
|
|
reg[0xF]=reg[X]&0x1; |
|
|
|
bool carryFlag=reg[X]&0x1; |
|
|
|
reg[X]>>=1; |
|
|
|
reg[X]>>=1; |
|
|
|
|
|
|
|
reg[0xF]=carryFlag; |
|
|
|
}break; |
|
|
|
}break; |
|
|
|
case 0x7:{//sets VX to the result of VY - VX. It's a reverse subtraction.
|
|
|
|
case 0x7:{//sets VX to the result of VY - VX. It's a reverse subtraction.
|
|
|
|
reg[0xF]=0; |
|
|
|
//reg[0xF]=0;
|
|
|
|
|
|
|
|
bool carryFlag=false; |
|
|
|
if (reg[Y]>reg[X]){ |
|
|
|
if (reg[Y]>reg[X]){ |
|
|
|
reg[0xF]=1; |
|
|
|
//reg[0xF]=1;
|
|
|
|
|
|
|
|
carryFlag=true; |
|
|
|
} |
|
|
|
} |
|
|
|
reg[X]=reg[Y]-reg[X]; |
|
|
|
reg[X]=reg[Y]-reg[X]; |
|
|
|
|
|
|
|
reg[0xF]=carryFlag; |
|
|
|
}break; |
|
|
|
}break; |
|
|
|
case 0xE:{//Shift Left
|
|
|
|
case 0xE:{//Shift Left
|
|
|
|
//std::cout<<"Y is: "<<(int)Y<<std::endl;
|
|
|
|
//std::cout<<"Y is: "<<(int)Y<<std::endl;
|
|
|
@ -505,8 +544,9 @@ public: |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
reg[X]=reg[Y]; |
|
|
|
reg[X]=reg[Y]; |
|
|
|
} |
|
|
|
} |
|
|
|
reg[0xF]=(reg[X]&0x80)>>7; |
|
|
|
bool carryFlag=(reg[X]&0x80)>>7; |
|
|
|
reg[X]<<=1; |
|
|
|
reg[X]<<=1; |
|
|
|
|
|
|
|
reg[0xF]=carryFlag; |
|
|
|
}break; |
|
|
|
}break; |
|
|
|
} |
|
|
|
} |
|
|
|
}break; |
|
|
|
}break; |
|
|
@ -571,11 +611,14 @@ public: |
|
|
|
sound_timer=reg[X]; |
|
|
|
sound_timer=reg[X]; |
|
|
|
}break; |
|
|
|
}break; |
|
|
|
case 0x1E:{//The index register I will get the value in VX added to it.
|
|
|
|
case 0x1E:{//The index register I will get the value in VX added to it.
|
|
|
|
reg[0xF]=0; |
|
|
|
//reg[0xF]=0;
|
|
|
|
|
|
|
|
bool carryFlag=false; |
|
|
|
if (index+reg[X]>=0x1000){ |
|
|
|
if (index+reg[X]>=0x1000){ |
|
|
|
reg[0xF]=1; |
|
|
|
//reg[0xF]=1;
|
|
|
|
|
|
|
|
carryFlag=true; |
|
|
|
} |
|
|
|
} |
|
|
|
index+=reg[X]; |
|
|
|
index+=reg[X]; |
|
|
|
|
|
|
|
reg[0xF]=carryFlag; |
|
|
|
}break; |
|
|
|
}break; |
|
|
|
case 0x0A:{//This instruction “blocks”; it stops executing instructions and waits for key input
|
|
|
|
case 0x0A:{//This instruction “blocks”; it stops executing instructions and waits for key input
|
|
|
|
for (int i=0;i<keymap.size();i++){ |
|
|
|
for (int i=0;i<keymap.size();i++){ |
|
|
|