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
61 changes: 55 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 @@ -125,6 +132,7 @@ void APU::writeByte(Word address, Byte value)

Byte APU::readByte(Word address)
{
printf("Address: %04X\n", address);
if (address >= 0xFF10 && address <= 0xFF14)
{
return channel1->readByte(address);
Expand Down Expand Up @@ -158,7 +166,7 @@ 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);
// printf("APU Read 0xFF26: %04X\n", val);
return val;

default:
Expand All @@ -175,8 +183,8 @@ void APU::stepAPU(int cycles)

if (frameSequencerCounter >= 8192)
{
printf("FrameSquencer start\n");
// update envelope clocks and length timers

channel1->run();
channel2->run();
channel3->run();
Expand All @@ -189,6 +197,14 @@ 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);
}
printf("FramerSequencer ends\n");
}
}

Expand All @@ -205,6 +221,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)
{
value = mMap->readMemory(address);
writeByte(address, value);
}
value = readByte(address);
mMap->MemoryWriteBack(address, value);
}

// PulseChannel
Expand Down Expand Up @@ -246,6 +289,7 @@ void PulseChannel::writeByte(Word address, Byte value)
// Sound length/Wave pattern duty
waveDuty = (value & 0xC0) >> 6;
lengthTimer = maxLengthTimer - (value & 0x3F);
printf("PC: lengthTimer\n");
return;
case 0xFF12:
case 0xFF17:
Expand Down Expand Up @@ -276,6 +320,7 @@ void PulseChannel::writeByte(Word address, Byte value)
}
if (value & 0x80)
{
printf("WC triggered\n");
trigger();
}
return;
Expand Down Expand Up @@ -431,6 +476,7 @@ void WaveChannel::writeByte(Word address, Byte value)
// NR31
// Sound length
lengthTimer = maxLengthTimer - value;
printf("WC: lengthTimer\n");
return;
case 0xFF1C:
// NR32
Expand All @@ -453,6 +499,7 @@ void WaveChannel::writeByte(Word address, Byte value)
}
if (value & 0x80)
{
printf("WC triggered\n");
trigger();
}
return;
Expand Down Expand Up @@ -590,6 +637,7 @@ void NoiseChannel::writeByte(Word address, Byte value)
// NR41
// Sound length
lengthTimer = maxLengthTimer - (value & 0x3F);
printf("NC: lengthtimer\n");
return;
case 0xFF21:
// NR42
Expand Down Expand Up @@ -618,6 +666,7 @@ void NoiseChannel::writeByte(Word address, Byte value)
}
if (value & 0x80)
{
printf("NC Triggered...\n");
trigger();
}
return;
Expand Down Expand Up @@ -728,4 +777,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();
};
Loading