Skip to content
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ build/
cmake-build-debug/
.idea/
src/.vscode/
src/dmg_boot.gb
src/dmg_boot.gb
tests/*
.vscode/*
run.sh
output.txt
31 changes: 30 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,35 @@
"ios": "cpp",
"queue": "cpp",
"semaphore": "cpp",
"cinttypes": "cpp"
"cinttypes": "cpp",
"any": "cpp",
"hash_map": "cpp",
"strstream": "cpp",
"charconv": "cpp",
"codecvt": "cpp",
"complex": "cpp",
"condition_variable": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"unordered_set": "cpp",
"optional": "cpp",
"source_location": "cpp",
"format": "cpp",
"fstream": "cpp",
"future": "cpp",
"iomanip": "cpp",
"iostream": "cpp",
"istream": "cpp",
"mutex": "cpp",
"shared_mutex": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdfloat": "cpp",
"text_encoding": "cpp",
"cfenv": "cpp",
"typeindex": "cpp",
"valarray": "cpp",
"variant": "cpp"
}
}
4 changes: 2 additions & 2 deletions run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ elif [[ $last_keyword == "gbemu" ]]; then
echo "making new build directory"
mkdir build
cd build
cmake ..
cmake ..
cmake --build . -j8
./gbemu
else
echo "making new build directory"
mkdir build
cd build
cmake ..
cmake -DDEBUG=on ..
cmake --build . -j8
./gbemu
fi
Expand Down
51 changes: 45 additions & 6 deletions src/audio.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "audio.h"
#include "types.h"

APU::APU()
{
Expand All @@ -16,7 +15,7 @@ APU::APU()
enableVINRight = false;
volumeLeft = 0;
volumeRight = 0;

mMap = nullptr;
channel1 = new PulseChannel(CH1);
channel2 = new PulseChannel(CH2);
channel3 = new WaveChannel();
Expand Down Expand Up @@ -47,6 +46,7 @@ bool APU::init()
channel2->setFrameSequencer(frameSequencer);
channel3->setFrameSequencer(frameSequencer);
channel4->setFrameSequencer(frameSequencer);

return true;
}

Expand All @@ -55,9 +55,16 @@ void APU::test()
printf("APU test\n");
}

// initialize the writehandler of memorymap
void APU::initializeWriteHandler()
{
if (mMap)
mMap->setAudioWriteHandler([this](Word address) { this->onMemoryWrite(address); });
}

void APU::writeByte(Word address, Byte value)
{
printf("APU Address: %X, Value: %X\n", address, value);
printf("APU Address: %04X, Value: %02X\n", address, value);
if (address == 0xFF26)
{
bool enable = (value & 0x80) >> 7;
Expand Down Expand Up @@ -158,7 +165,6 @@ Byte APU::readByte(Word address)

case 0xFF26:
val = (enabled ? 0x80 : 0) | (channel1->isEnabled() ? 0x01 : 0) | (channel2->isEnabled() ? 0x02 : 0) | (channel3->isEnabled() ? 0x04 : 0) | (channel4->isEnabled() ? 0x08 : 0) | 0x70;
printf("APU Read 0xFF26: %X\n", val);
return val;

default:
Expand All @@ -176,7 +182,6 @@ void APU::stepAPU(int cycles)
if (frameSequencerCounter >= 8192)
{
// update envelope clocks and length timers

channel1->run();
channel2->run();
channel3->run();
Expand All @@ -189,6 +194,13 @@ void APU::stepAPU(int cycles)
channel2->setFrameSequencer(frameSequencer);
channel3->setFrameSequencer(frameSequencer);
channel4->setFrameSequencer(frameSequencer);

// Read and write back after updating
Word address[] = { 0xFF19, 0xFF1E, 0xFF23, 0xFF26 };
for (auto addr : address)
{
audioRegisterUpdate(addr, AudioWrite);
}
}
}

Expand All @@ -205,6 +217,33 @@ void APU::clearRegisters()
channel2->powerOff();
channel3->powerOff();
channel4->powerOff();
// Could be done by simply writing 0s but for checking's sake done as such
for (int address = 0xFF10; address <= 0xFF3F; address++)
{
audioRegisterUpdate(address, AudioWrite);
}
}

// Updates APU registers on write in MemoryMap
void APU::onMemoryWrite(Word address)
{
// address where write has occurred
audioRegisterUpdate(address, AudioMemoryWrite);
// Update the audio channel controller register
audioRegisterUpdate(AUDIO_MASTER_CONTROL_REGISTER, AudioWrite);
}

// Write Update
void APU::audioRegisterUpdate(Word address, audioWriteFlag flag)
{
Byte value = 0xFF;
if (flag == AudioMemoryWrite)
{
value = mMap->readMemory(address);
writeByte(address, value);
}
value = readByte(address);
mMap->MemoryWriteBack(address, value);
}

// PulseChannel
Expand Down Expand Up @@ -728,4 +767,4 @@ void NoiseChannel::trigger()
{
LFSR = 0x7FFF;
enabled = dacEnabled;
}
}
74 changes: 47 additions & 27 deletions src/audio.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#pragma once
#include "types.h"
#include "mmap.h"
#include <stdio.h>
#include <SDL.h>
#include <SDL.h> // SDL Audio

#define AUDIO_MASTER_CONTROL_REGISTER 0xFF26

enum Channel
{
Expand All @@ -11,13 +14,21 @@ enum Channel
CH4 = 3
};

// For checking whether Write is due to memory or APU itself
enum audioWriteFlag
{
AudioWrite = 0,
AudioMemoryWrite = 1

};

class PulseChannel
{
private:
Channel channel;
bool enabled;
bool dacEnabled;
int frameSequencer;
bool enabled;
bool dacEnabled;
int frameSequencer;

Byte sweepPeriod;
bool sweepNegate;
Expand All @@ -26,7 +37,7 @@ class PulseChannel
// NRx1
Byte waveDuty;
int lengthTimer;
int maxLengthTimer = 64;
int maxLengthTimer = 64;

Byte envelopeInitialVolume;
bool envelopeIncrease;
Expand All @@ -41,25 +52,24 @@ class PulseChannel
void test();
void writeByte(Word address, Byte value);
Byte readByte(Word address);
bool isEnabled();
void powerOff();
void run();
void set_NRx4(Byte value);
void setFrameSequencer(int frameSequencer);
void trigger();
bool isEnabled();
void powerOff();
void run();
void set_NRx4(Byte value);
void setFrameSequencer(int frameSequencer);
void trigger();
};

class WaveChannel
{
private:

Byte waveRAM[16];
bool dacEnabled;
bool enabled;

int lengthTimer;
int maxLengthTimer = 256;
int frameSequencer;
int frameSequencer;

Byte outputLevel;

Expand All @@ -73,22 +83,22 @@ class WaveChannel
void writeByte(Word address, Byte value);
Byte readByte(Word address);
void trigger();
bool isEnabled();
void powerOff();
void set_NRx4(Byte value);
void run();
void setFrameSequencer(int frameSequencer);
bool isEnabled();
void powerOff();
void set_NRx4(Byte value);
void run();
void setFrameSequencer(int frameSequencer);
};

class NoiseChannel
{
private:
bool enabled;
bool dacEnabled;
bool enabled;
bool dacEnabled;

int lengthTimer;
int maxLengthTimer = 64;
int frameSequencer;
int frameSequencer;

Byte envelopeInitialVolume;
bool envelopeIncrease;
Expand All @@ -112,11 +122,11 @@ class NoiseChannel
void writeByte(Word address, Byte value);
Byte readByte(Word address);
void trigger();
bool isEnabled();
void powerOff();
void set_NRx4(Byte value);
void run();
void setFrameSequencer(int frameSequencer);
bool isEnabled();
void powerOff();
void set_NRx4(Byte value);
void run();
void setFrameSequencer(int frameSequencer);
};

class APU
Expand Down Expand Up @@ -160,12 +170,22 @@ class APU
WaveChannel* channel3;
NoiseChannel* channel4;

// Memory Map
MemoryMap* mMap;

public:
APU();
void test();
bool init();
bool init();
void writeByte(Word address, Byte value);
Byte readByte(Word address);
void stepAPU(int cycles);
void clearRegisters();
void setMemoryMap(MemoryMap* map) { mMap = map; }
// Writes back on Memory Write
void onMemoryWrite(Word address);
// Write update
void audioRegisterUpdate(Word address, audioWriteFlag flag);
// initializes the audioWriteHandler of MemoryMap
void initializeWriteHandler();
};
19 changes: 11 additions & 8 deletions src/gameBoy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,34 @@ GBE::GBE()
gbe_graphics = new PPU();

// audio = new Audio();
// APU = new APU();
gbe_audio = new APU();

// Unify the CPU and MemoryMap
gbe_cpu->setMemory(gbe_mMap);

// Unify the CPU and PPU
gbe_cpu->setPPU(gbe_graphics);

// Unify the PPU and MmeoryMap
// Unify the PPU and MemoryMap
gbe_graphics->setMemoryMap(gbe_mMap);

gbe_graphics->init();

// Unify the APU and MemoryMap
gbe_audio->setMemoryMap(gbe_mMap);
// initialize the write handler
gbe_audio->initializeWriteHandler();

// Open the Boot ROM
if ((bootROM = fopen("../src/dmg_boot.gb", "rb")) == NULL)
printf("boot rom file not opened");
printf("boot rom file not opened\n");

// // Open the Game ROM
// if ((gameROM = fopen("../tests/tetris.gb", "rb")) == NULL)
// printf("game rom file not opened");

// Open the Game ROM
if ((gameROM = fopen("../tests/dmg_sound/rom_singles/03-trigger.gb", "rb")) == NULL)
printf("game rom file not opened");
if ((gameROM = fopen("../tests/dmg_sound/rom_singles/02-len ctr.gb", "rb")) == NULL)
printf("game rom file not opened\n");

// Set the Boot ROM
gbe_mMap->setBootRomFile(bootROM);
Expand Down Expand Up @@ -105,7 +109,6 @@ GBE::GBE()
gbe_mMap->debugWriteMemory(0x133, 0x3E);

executeBootROM();

update();
}

Expand All @@ -122,7 +125,7 @@ void GBE::update()
// update the DIV and TIMA timers
gbe_cpu->updateTimers(s_Cycles);
gbe_graphics->executePPU(s_Cycles);
gbe_mMap->audio->stepAPU(s_Cycles);
gbe_audio->stepAPU(s_Cycles);
s_Cycles = 0;
s_Cycles += gbe_cpu->performInterrupt();
gbe_graphics->pollEvents();
Expand Down
Loading