Skip to content

Commit

Permalink
Re-implement XOCHIP core from the guts of the old mega core, adjust v…
Browse files Browse the repository at this point in the history
…olume levels, some fixes to Map2D constructors.
  • Loading branch information
coornio committed Sep 13, 2024
1 parent a3970ef commit c9f1cad
Show file tree
Hide file tree
Showing 12 changed files with 1,366 additions and 88 deletions.
2 changes: 2 additions & 0 deletions CubeChip (SDL).vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<ClCompile Include="src\Systems\BYTEPUSHER\Cores\BYTEPUSHER_STANDARD.cpp" />
<ClCompile Include="src\Systems\CHIP8\Chip8_CoreInterface.cpp" />
<ClCompile Include="src\Systems\CHIP8\Cores\CHIP8_MODERN.cpp" />
<ClCompile Include="src\Systems\CHIP8\Cores\XOCHIP.cpp" />
<ClCompile Include="src\Systems\EmuInterface.cpp" />
<ClCompile Include="src\Systems\GameFileChecker.cpp" />
</ItemGroup>
Expand All @@ -54,6 +55,7 @@
<ClInclude Include="src\Systems\BYTEPUSHER\Cores\BYTEPUSHER_STANDARD.hpp" />
<ClInclude Include="src\Systems\CHIP8\Chip8_CoreInterface.hpp" />
<ClInclude Include="src\Systems\CHIP8\Cores\CHIP8_MODERN.hpp" />
<ClInclude Include="src\Systems\CHIP8\Cores\XOCHIP.hpp" />
<ClInclude Include="src\Systems\EmuInterface.hpp" />
<ClInclude Include="src\Systems\GameFileChecker.hpp" />
<ClInclude Include="src\_nlohmann\json.hpp" />
Expand Down
6 changes: 6 additions & 0 deletions CubeChip (SDL).vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
<ClCompile Include="src\Systems\BYTEPUSHER\Cores\BYTEPUSHER_STANDARD.cpp">
<Filter>Source Files\Systems\BYTEPUSHER\Cores</Filter>
</ClCompile>
<ClCompile Include="src\Systems\CHIP8\Cores\XOCHIP.cpp">
<Filter>Source Files\Systems\CHIP8\Cores</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\_nlohmann\json_fwd.hpp">
Expand Down Expand Up @@ -151,5 +154,8 @@
<ClInclude Include="src\Systems\BYTEPUSHER\Cores\BYTEPUSHER_STANDARD.hpp">
<Filter>Source Files\Systems\BYTEPUSHER\Cores</Filter>
</ClInclude>
<ClInclude Include="src\Systems\CHIP8\Cores\XOCHIP.hpp">
<Filter>Source Files\Systems\CHIP8\Cores</Filter>
</ClInclude>
</ItemGroup>
</Project>
5 changes: 5 additions & 0 deletions src/Assistants/HomeDirManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ static auto getFileModTime(const fsPath& filePath) noexcept {
return std::filesystem::last_write_time(filePath, error);
}

static auto getFileSize(const fsPath& filePath) noexcept {
std::error_code error;
return std::filesystem::file_size(filePath, error);
}

/*==================================================================*/
#pragma region HomeDirManager Class

Expand Down
23 changes: 9 additions & 14 deletions src/Assistants/Map2D.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1149,24 +1149,19 @@ class Map2D final {
};
#pragma endregion

private:
#pragma region Main Ctor
explicit Map2D(const paramS rows, const paramS cols)
: mRows{ rows }
, mCols{ cols }
, pData{ std::make_unique<T[]>(rows * cols) }
{}
#pragma endregion

public:
#pragma region Trivial Ctor
Map2D() : Map2D{ 1, 1 } {}

Map2D(const integral auto rows, const integral auto cols)
: Map2D{
std::max<paramS>(1, std::abs(rows)),
std::max<paramS>(1, std::abs(cols))
}
Map2D(const paramS rows, const paramS cols)
: mRows{ std::max(1, std::abs(rows)) }
, mCols{ std::max(1, std::abs(cols)) }
, pData{ std::make_unique<T[]>(mRows * mCols) }
{}
Map2D(const paramU rows, const paramU cols)
: mRows{ rows }
, mCols{ cols }
, pData{ std::make_unique<T[]>(mRows * mCols) }
{}
#pragma endregion

Expand Down
160 changes: 153 additions & 7 deletions src/Systems/CHIP8/Chip8_CoreInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,53 @@ bool Chip8_CoreInterface::keyHeld_P2(const u32 keyIndex) const noexcept {

/*==================================================================*/

void Chip8_CoreInterface::handlePreFrameInterrupt() noexcept {
switch (mInterrupt)
{
case Interrupt::FRAME:
mInterrupt = Interrupt::CLEAR;
mActiveCPF = std::abs(mActiveCPF);
return;

case Interrupt::SOUND:
if (!mSoundTimer) {
mInterrupt = Interrupt::FINAL;
mActiveCPF = 0;
}
return;

case Interrupt::DELAY:
if (!mSoundTimer) {
mInterrupt = Interrupt::CLEAR;
mActiveCPF = std::abs(mActiveCPF);
}
return;
}
}

void Chip8_CoreInterface::handleEndFrameInterrupt() noexcept {
switch (mInterrupt)
{
case Interrupt::INPUT:
if (keyPressed(mInputReg, mTotalFrames)) {
mInterrupt = Interrupt::CLEAR;
mActiveCPF = std::abs(mActiveCPF);
mBuzzerTone = calcBuzzerTone();
mSoundTimer = 2;
isBuzzerEnabled(true);
}
return;

case Interrupt::ERROR:
case Interrupt::FINAL:
setCoreState(EmuState::HALTED);
mActiveCPF = 0;
return;
}
}

/*==================================================================*/

void Chip8_CoreInterface::processFrame() {
if (isSystemStopped()) { return; }
else [[likely]] { ++mTotalFrames; }
Expand All @@ -111,6 +158,19 @@ void Chip8_CoreInterface::processFrame() {
renderVideoData();
}

/*==================================================================*/

std::string Chip8_CoreInterface::formatOpcode(const u32 OP) const {
char buffer[5];
std::format_to(buffer, "{:04X}{}", OP, '\0');
return buffer;
}

void Chip8_CoreInterface::instructionError(const u32 HI, const u32 LO) {
blog.newEntry(BLOG::INFO, "Unknown instruction: " + formatOpcode(HI << 8 | LO));
triggerInterrupt(Interrupt::ERROR);
}

void Chip8_CoreInterface::triggerInterrupt(const Interrupt type) noexcept {
mInterrupt = type;
mActiveCPF = -std::abs(mActiveCPF);
Expand All @@ -121,17 +181,95 @@ void Chip8_CoreInterface::triggerCritError(const std::string& msg) noexcept {
triggerInterrupt(Interrupt::ERROR);
}

std::string Chip8_CoreInterface::formatOpcode(const u32 OP) const {
char buffer[5];
std::format_to(buffer, "{:04X}{}", OP, '\0');
return buffer;
/*==================================================================*/

bool Chip8_CoreInterface::setPermaRegs(const s32 X) noexcept {
const auto path{ *sPermaRegsPath / HDM->getFileSHA1() };

if (std::filesystem::exists(path)) {
if (!std::filesystem::is_regular_file(path)) {
blog.newEntry(BLOG::ERROR, "SHA1 file is malformed: " + path.string());
return true;
}

char tempV[16]{};
std::ifstream in(path, std::ios::binary);

if (in.is_open()) {
in.seekg(0, std::ios::end);
const auto totalBytes{ in.tellg() };
in.seekg(0, std::ios::beg);

in.read(tempV, std::min<std::streamsize>(totalBytes, X));
in.close();
} else {
blog.newEntry(BLOG::ERROR, "Could not open SHA1 file to read: " + path.string());
return true;
}

std::copy_n(mRegisterV, X, tempV);

std::ofstream out(path, std::ios::binary);
if (out.is_open()) {
out.write(tempV, 16);
out.close();
} else {
blog.newEntry(BLOG::ERROR, "Could not open SHA1 file to write: " + path.string());
return true;
}
} else {
std::ofstream out(path, std::ios::binary);
if (out.is_open()) {
out.write(reinterpret_cast<const char*>(mRegisterV), X);
if (X < 16) {
const char padding[16]{};
out.write(padding, 16 - X);
}
out.close();
} else {
blog.newEntry(BLOG::ERROR, "Could not open SHA1 file to write: " + path.string());
return true;
}
}
return false;
}

void Chip8_CoreInterface::instructionError(const u32 HI, const u32 LO) {
blog.newEntry(BLOG::INFO, "Unknown instruction: " + formatOpcode(HI << 8 | LO));
triggerInterrupt(Interrupt::ERROR);
bool Chip8_CoreInterface::getPermaRegs(const s32 X) noexcept {
const auto path{ *sPermaRegsPath / HDM->getFileSHA1() };

if (std::filesystem::exists(path)) {
if (!std::filesystem::is_regular_file(path)) {
blog.newEntry(BLOG::ERROR, "SHA1 file is malformed: " + path.string());
return true;
}

std::ifstream in(path, std::ios::binary);
if (in.is_open()) {
in.seekg(0, std::ios::end);
const auto totalBytes{ static_cast<s32>(in.tellg()) };
in.seekg(0, std::ios::beg);

in.read(reinterpret_cast<char*>(mRegisterV), std::min(totalBytes, X));
in.close();

if (totalBytes < X) {
std::fill_n(mRegisterV + totalBytes, X - totalBytes, u8());
}
} else {
blog.newEntry(BLOG::ERROR, "Could not open SHA1 file to read: " + path.string());
return true;
}
} else {
std::fill_n(
std::execution::unseq,
mRegisterV, X, u8{}
);
}
return false;
}

/*==================================================================*/

void Chip8_CoreInterface::copyGameToMemory(
u8* dest, const u32 offset
) noexcept {
Expand All @@ -151,3 +289,11 @@ void Chip8_CoreInterface::copyFontToMemory(
cFontData, size, dest + offset
);
}

/*==================================================================*/

f32 Chip8_CoreInterface::calcBuzzerTone() const noexcept {
return (160.0f + 8.0f * (
(mCurrentPC >> 1) + mStackTop + 1 & 0x3E
)) / ASB->getFrequency();
}
30 changes: 25 additions & 5 deletions src/Systems/CHIP8/Chip8_CoreInterface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class Chip8_CoreInterface : public EmuInterface {
bool mLoresExtended{};
bool mManualRefresh{};
bool mPixelTrailing{};
bool mBuzzerEnabled{};
} Trait;

enum class Interrupt {
Expand All @@ -69,6 +70,15 @@ class Chip8_CoreInterface : public EmuInterface {
ERROR, // end state, error occured
};

enum class Resolution {
ERROR,
HI, // 128 x 64 - 2:1
LO, // 64 x 32 - 2:1
TP, // 64 x 64 - 2:1
FP, // 64 x 128 - 2:1
MC, // 256 x 192 - 4:3
};

/*==================================================================*/

void addCoreState(const EmuState state) noexcept { Trait.mCoreState |= state; }
Expand All @@ -84,9 +94,11 @@ class Chip8_CoreInterface : public EmuInterface {
bool isLoresExtended() const noexcept { return Trait.mLoresExtended; }
bool isManualRefresh() const noexcept { return Trait.mManualRefresh; }
bool isPixelTrailing() const noexcept { return Trait.mPixelTrailing; }
bool isBuzzerEnabled() const noexcept { return Trait.mBuzzerEnabled; }
void isLoresExtended(const bool state) noexcept { Trait.mLoresExtended = state; }
void isManualRefresh(const bool state) noexcept { Trait.mManualRefresh = state; }
void isPixelTrailing(const bool state) noexcept { Trait.mPixelTrailing = state; }
void isBuzzerEnabled(const bool state) noexcept { Trait.mBuzzerEnabled = state; }

/*==================================================================*/

Expand All @@ -107,14 +119,15 @@ class Chip8_CoreInterface : public EmuInterface {
}

f32 mBuzzerTone{};
u32 mPlanarMask{ 0x1 };

u32 mCurrentPC{};
u32 mRegisterI{};

u8 mDelayTimer{};
u8 mSoundTimer{};
u32 mDelayTimer{};
u32 mSoundTimer{};

u8 mStackTop{};
u32 mStackTop{};
u8* mInputReg{};

u8 mRegisterV[16]{};
Expand All @@ -128,18 +141,25 @@ class Chip8_CoreInterface : public EmuInterface {
void triggerInterrupt(const Interrupt type) noexcept;
void triggerCritError(const std::string& msg) noexcept;

bool setPermaRegs(const s32 X) noexcept;
bool getPermaRegs(const s32 X) noexcept;

void copyGameToMemory(u8* dest, const u32 offset) noexcept;
void copyFontToMemory(u8* dest, const u32 offset, const u32 size) noexcept;

virtual void handlePreFrameInterrupt() noexcept = 0;
virtual void handleEndFrameInterrupt() noexcept = 0;
virtual void handlePreFrameInterrupt() noexcept;
virtual void handleEndFrameInterrupt() noexcept;

virtual void handleTimerTick() noexcept = 0;
virtual void instructionLoop() noexcept = 0;

virtual void renderAudioData() = 0;
virtual void renderVideoData() = 0;

virtual void prepDisplayArea(const Resolution mode) = 0;

f32 calcBuzzerTone() const noexcept;

public:
Chip8_CoreInterface() noexcept;
~Chip8_CoreInterface() noexcept;
Expand Down
Loading

0 comments on commit c9f1cad

Please sign in to comment.