Play audio in emulator class, update class references from the SNES
This commit is contained in:
@@ -59,8 +59,8 @@ void Emulator::Run() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
snes_.Init(*rom());
|
snes_.Init(*rom());
|
||||||
wanted_frames_ = 1.0 / (snes_.Memory()->pal_timing() ? 50.0 : 60.0);
|
wanted_frames_ = 1.0 / (snes_.Memory().pal_timing() ? 50.0 : 60.0);
|
||||||
wanted_samples_ = 48000 / (snes_.Memory()->pal_timing() ? 50 : 60);
|
wanted_samples_ = 48000 / (snes_.Memory().pal_timing() ? 50 : 60);
|
||||||
loaded = true;
|
loaded = true;
|
||||||
|
|
||||||
countFreq = SDL_GetPerformanceFrequency();
|
countFreq = SDL_GetPerformanceFrequency();
|
||||||
@@ -84,6 +84,12 @@ void Emulator::Run() {
|
|||||||
|
|
||||||
if (loaded) {
|
if (loaded) {
|
||||||
snes_.RunFrame();
|
snes_.RunFrame();
|
||||||
|
|
||||||
|
snes_.SetSamples(audio_buffer_, wanted_samples_);
|
||||||
|
if (SDL_GetQueuedAudioSize(audio_device_) <= wanted_samples_ * 4 * 6) {
|
||||||
|
SDL_QueueAudio(audio_device_, audio_buffer_, wanted_samples_ * 4);
|
||||||
|
}
|
||||||
|
|
||||||
void* ppu_pixels_;
|
void* ppu_pixels_;
|
||||||
int ppu_pitch_;
|
int ppu_pitch_;
|
||||||
if (SDL_LockTexture(ppu_texture_, NULL, &ppu_pixels_, &ppu_pitch_) !=
|
if (SDL_LockTexture(ppu_texture_, NULL, &ppu_pixels_, &ppu_pitch_) !=
|
||||||
@@ -153,7 +159,7 @@ void Emulator::RenderNavBar() {
|
|||||||
|
|
||||||
if (ImGui::Button(ICON_MD_SKIP_NEXT)) {
|
if (ImGui::Button(ICON_MD_SKIP_NEXT)) {
|
||||||
// Step through Code logic
|
// Step through Code logic
|
||||||
snes_.cpu()->RunOpcode();
|
snes_.cpu().RunOpcode();
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("Step Through Code");
|
ImGui::SetTooltip("Step Through Code");
|
||||||
@@ -210,7 +216,7 @@ void Emulator::RenderNavBar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SameLine();
|
SameLine();
|
||||||
ImGui::Checkbox("Logging", snes_.cpu()->mutable_log_instructions());
|
ImGui::Checkbox("Logging", snes_.cpu().mutable_log_instructions());
|
||||||
|
|
||||||
static bool show_memory_viewer = false;
|
static bool show_memory_viewer = false;
|
||||||
|
|
||||||
@@ -257,28 +263,28 @@ void Emulator::RenderBreakpointList() {
|
|||||||
if (ImGui::InputText("##BreakpointInput", breakpoint_input, 10,
|
if (ImGui::InputText("##BreakpointInput", breakpoint_input, 10,
|
||||||
ImGuiInputTextFlags_EnterReturnsTrue)) {
|
ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||||
int breakpoint = std::stoi(breakpoint_input, nullptr, 16);
|
int breakpoint = std::stoi(breakpoint_input, nullptr, 16);
|
||||||
snes_.cpu()->SetBreakpoint(breakpoint);
|
snes_.cpu().SetBreakpoint(breakpoint);
|
||||||
memset(breakpoint_input, 0, sizeof(breakpoint_input));
|
memset(breakpoint_input, 0, sizeof(breakpoint_input));
|
||||||
}
|
}
|
||||||
SameLine();
|
SameLine();
|
||||||
if (ImGui::Button("Add")) {
|
if (ImGui::Button("Add")) {
|
||||||
int breakpoint = std::stoi(breakpoint_input, nullptr, 16);
|
int breakpoint = std::stoi(breakpoint_input, nullptr, 16);
|
||||||
snes_.cpu()->SetBreakpoint(breakpoint);
|
snes_.cpu().SetBreakpoint(breakpoint);
|
||||||
memset(breakpoint_input, 0, sizeof(breakpoint_input));
|
memset(breakpoint_input, 0, sizeof(breakpoint_input));
|
||||||
}
|
}
|
||||||
SameLine();
|
SameLine();
|
||||||
if (ImGui::Button("Clear")) {
|
if (ImGui::Button("Clear")) {
|
||||||
snes_.cpu()->ClearBreakpoints();
|
snes_.cpu().ClearBreakpoints();
|
||||||
}
|
}
|
||||||
Separator();
|
Separator();
|
||||||
auto breakpoints = snes_.cpu()->GetBreakpoints();
|
auto breakpoints = snes_.cpu().GetBreakpoints();
|
||||||
if (!breakpoints.empty()) {
|
if (!breakpoints.empty()) {
|
||||||
Text("Breakpoints:");
|
Text("Breakpoints:");
|
||||||
ImGui::BeginChild("BreakpointsList", ImVec2(0, 100), true);
|
ImGui::BeginChild("BreakpointsList", ImVec2(0, 100), true);
|
||||||
for (auto breakpoint : breakpoints) {
|
for (auto breakpoint : breakpoints) {
|
||||||
if (ImGui::Selectable(absl::StrFormat("0x%04X", breakpoint).c_str())) {
|
if (ImGui::Selectable(absl::StrFormat("0x%04X", breakpoint).c_str())) {
|
||||||
// Jump to breakpoint
|
// Jump to breakpoint
|
||||||
// snes_.cpu()->JumpToBreakpoint(breakpoint);
|
// snes_.cpu().JumpToBreakpoint(breakpoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
@@ -287,8 +293,8 @@ void Emulator::RenderBreakpointList() {
|
|||||||
gui::InputHexByte("PB", &manual_pb_, 50.f);
|
gui::InputHexByte("PB", &manual_pb_, 50.f);
|
||||||
gui::InputHexWord("PC", &manual_pc_, 75.f);
|
gui::InputHexWord("PC", &manual_pc_, 75.f);
|
||||||
if (ImGui::Button("Set Current Address")) {
|
if (ImGui::Button("Set Current Address")) {
|
||||||
snes_.cpu()->PC = manual_pc_;
|
snes_.cpu().PC = manual_pc_;
|
||||||
snes_.cpu()->PB = manual_pb_;
|
snes_.cpu().PB = manual_pb_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,8 +348,8 @@ void Emulator::RenderMemoryViewer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TableNextColumn();
|
TableNextColumn();
|
||||||
mem_edit.DrawContents((void*)snes_.Memory()->rom_.data(),
|
mem_edit.DrawContents((void*)snes_.Memory().rom_.data(),
|
||||||
snes_.Memory()->rom_.size());
|
snes_.Memory().rom_.size());
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,13 +56,13 @@ class Emulator : public SharedRom {
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
const std::map<std::string, void*> data_bindings = {
|
const std::map<std::string, void*> data_bindings = {
|
||||||
{"cpu.A", &snes_.cpu()->A}, {"cpu.D", &snes_.cpu()->D},
|
{"cpu.A", &snes_.cpu().A}, {"cpu.D", &snes_.cpu().D},
|
||||||
{"cpu.X", &snes_.cpu()->X}, {"cpu.DB", &snes_.cpu()->DB},
|
{"cpu.X", &snes_.cpu().X}, {"cpu.DB", &snes_.cpu().DB},
|
||||||
{"cpu.Y", &snes_.cpu()->Y}, {"cpu.PB", &snes_.cpu()->PB},
|
{"cpu.Y", &snes_.cpu().Y}, {"cpu.PB", &snes_.cpu().PB},
|
||||||
{"cpu.PC", &snes_.cpu()->PC}, {"cpu.E", &snes_.cpu()->E}};
|
{"cpu.PC", &snes_.cpu().PC}, {"cpu.E", &snes_.cpu().E}};
|
||||||
emulator_node_ = gui::zeml::Parse(emulator_layout, data_bindings);
|
emulator_node_ = gui::zeml::Parse(emulator_layout, data_bindings);
|
||||||
Bind(emulator_node_.GetNode("CpuInstructionLog"),
|
Bind(emulator_node_.GetNode("CpuInstructionLog"),
|
||||||
[&]() { RenderCpuInstructionLog(snes_.cpu()->instruction_log_); });
|
[&]() { RenderCpuInstructionLog(snes_.cpu().instruction_log_); });
|
||||||
Bind(emulator_node_.GetNode("SnesPpu"), [&]() { RenderSnesPpu(); });
|
Bind(emulator_node_.GetNode("SnesPpu"), [&]() { RenderSnesPpu(); });
|
||||||
Bind(emulator_node_.GetNode("BreakpointList"),
|
Bind(emulator_node_.GetNode("BreakpointList"),
|
||||||
[&]() { RenderBreakpointList(); });
|
[&]() { RenderBreakpointList(); });
|
||||||
@@ -72,6 +72,9 @@ class Emulator : public SharedRom {
|
|||||||
auto snes() -> SNES& { return snes_; }
|
auto snes() -> SNES& { return snes_; }
|
||||||
auto running() const -> bool { return running_; }
|
auto running() const -> bool { return running_; }
|
||||||
void set_audio_buffer(int16_t* audio_buffer) { audio_buffer_ = audio_buffer; }
|
void set_audio_buffer(int16_t* audio_buffer) { audio_buffer_ = audio_buffer; }
|
||||||
|
auto set_audio_device_id(SDL_AudioDeviceID audio_device) {
|
||||||
|
audio_device_ = audio_device;
|
||||||
|
}
|
||||||
auto wanted_samples() const -> int { return wanted_samples_; }
|
auto wanted_samples() const -> int { return wanted_samples_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -108,6 +111,7 @@ class Emulator : public SharedRom {
|
|||||||
float timeAdder = 0.0;
|
float timeAdder = 0.0;
|
||||||
|
|
||||||
int16_t* audio_buffer_;
|
int16_t* audio_buffer_;
|
||||||
|
SDL_AudioDeviceID audio_device_;
|
||||||
|
|
||||||
SNES snes_;
|
SNES snes_;
|
||||||
SDL_Texture* ppu_texture_;
|
SDL_Texture* ppu_texture_;
|
||||||
|
|||||||
@@ -37,45 +37,6 @@ void SNES::Init(Rom& rom) {
|
|||||||
// rom_info_ = memory_.ReadRomHeader();
|
// rom_info_ = memory_.ReadRomHeader();
|
||||||
Reset(true);
|
Reset(true);
|
||||||
|
|
||||||
// Disable the emulation flag (switch to 65816 native mode)
|
|
||||||
// cpu_.E = 0;
|
|
||||||
// cpu_.PB = 0x00;
|
|
||||||
// cpu_.PC = 0x8000;
|
|
||||||
|
|
||||||
// Disable interrupts and rendering
|
|
||||||
memory_.WriteByte(0x4200, 0x00); // NMITIMEN
|
|
||||||
memory_.WriteByte(0x420C, 0x00); // HDMAEN
|
|
||||||
|
|
||||||
// Disable screen
|
|
||||||
memory_.WriteByte(0x2100, 0x8F); // INIDISP
|
|
||||||
|
|
||||||
// Reset PPU registers to a known good state
|
|
||||||
memory_.WriteByte(0x4201, 0xFF); // WRIO
|
|
||||||
|
|
||||||
// Scroll Registers
|
|
||||||
memory_.WriteByte(0x210D, 0x00); // BG1HOFS
|
|
||||||
memory_.WriteByte(0x210E, 0xFF); // BG1VOFS
|
|
||||||
|
|
||||||
memory_.WriteByte(0x210F, 0x00); // BG2HOFS
|
|
||||||
memory_.WriteByte(0x2110, 0xFF); // BG2VOFS
|
|
||||||
|
|
||||||
memory_.WriteByte(0x2111, 0x00); // BG3HOFS
|
|
||||||
memory_.WriteByte(0x2112, 0xFF); // BG3VOFS
|
|
||||||
|
|
||||||
memory_.WriteByte(0x2113, 0x00); // BG4HOFS
|
|
||||||
memory_.WriteByte(0x2114, 0xFF); // BG4VOFS
|
|
||||||
|
|
||||||
// VRAM Registers
|
|
||||||
memory_.WriteByte(0x2115, 0x80); // VMAIN
|
|
||||||
|
|
||||||
// Color Math
|
|
||||||
memory_.WriteByte(0x2130, 0x30); // CGWSEL
|
|
||||||
memory_.WriteByte(0x2131, 0x00); // CGADSUB
|
|
||||||
memory_.WriteByte(0x2132, 0xE0); // COLDATA
|
|
||||||
|
|
||||||
// Misc
|
|
||||||
memory_.WriteByte(0x2133, 0x00); // SETINI
|
|
||||||
|
|
||||||
running_ = true;
|
running_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,7 +252,7 @@ uint8_t SNES::ReadBBus(uint8_t adr) {
|
|||||||
}
|
}
|
||||||
if (adr < 0x80) {
|
if (adr < 0x80) {
|
||||||
CatchUpApu(); // catch up the apu before reading
|
CatchUpApu(); // catch up the apu before reading
|
||||||
return apu_.outPorts[adr & 0x3];
|
return apu_.out_ports_[adr & 0x3];
|
||||||
}
|
}
|
||||||
if (adr == 0x80) {
|
if (adr == 0x80) {
|
||||||
uint8_t ret = ram[ram_adr_++];
|
uint8_t ret = ram[ram_adr_++];
|
||||||
@@ -397,7 +358,7 @@ void SNES::WriteBBus(uint8_t adr, uint8_t val) {
|
|||||||
}
|
}
|
||||||
if (adr < 0x80) {
|
if (adr < 0x80) {
|
||||||
CatchUpApu(); // catch up the apu before writing
|
CatchUpApu(); // catch up the apu before writing
|
||||||
apu_.inPorts[adr & 0x3] = val;
|
apu_.in_ports_[adr & 0x3] = val;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (adr) {
|
switch (adr) {
|
||||||
|
|||||||
@@ -67,9 +67,9 @@ class SNES {
|
|||||||
void SetPixels(uint8_t* pixel_data);
|
void SetPixels(uint8_t* pixel_data);
|
||||||
|
|
||||||
bool running() const { return running_; }
|
bool running() const { return running_; }
|
||||||
auto cpu() -> Cpu* { return &cpu_; }
|
auto cpu() -> Cpu& { return cpu_; }
|
||||||
auto ppu() -> video::Ppu* { return &ppu_; }
|
auto ppu() -> video::Ppu& { return ppu_; }
|
||||||
auto Memory() -> memory::MemoryImpl* { return &memory_; }
|
auto Memory() -> memory::MemoryImpl& { return memory_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Components of the SNES
|
// Components of the SNES
|
||||||
@@ -77,7 +77,6 @@ class SNES {
|
|||||||
Debugger debugger;
|
Debugger debugger;
|
||||||
memory::RomInfo rom_info_;
|
memory::RomInfo rom_info_;
|
||||||
memory::MemoryImpl memory_;
|
memory::MemoryImpl memory_;
|
||||||
audio::AudioRamImpl audio_ram_;
|
|
||||||
|
|
||||||
memory::CpuCallbacks cpu_callbacks_ = {
|
memory::CpuCallbacks cpu_callbacks_ = {
|
||||||
[&](uint32_t adr) { return CpuRead(adr); },
|
[&](uint32_t adr) { return CpuRead(adr); },
|
||||||
@@ -86,7 +85,7 @@ class SNES {
|
|||||||
};
|
};
|
||||||
Cpu cpu_{memory_, clock_, cpu_callbacks_};
|
Cpu cpu_{memory_, clock_, cpu_callbacks_};
|
||||||
video::Ppu ppu_{memory_, clock_};
|
video::Ppu ppu_{memory_, clock_};
|
||||||
audio::Apu apu_{memory_, audio_ram_, clock_};
|
audio::Apu apu_{memory_, clock_};
|
||||||
|
|
||||||
// Currently loaded ROM
|
// Currently loaded ROM
|
||||||
std::vector<uint8_t> rom_data;
|
std::vector<uint8_t> rom_data;
|
||||||
|
|||||||
Reference in New Issue
Block a user