Add DMA to SNES
This commit is contained in:
@@ -6,6 +6,7 @@ add_executable(
|
|||||||
app/emu/audio/spc700.cc
|
app/emu/audio/spc700.cc
|
||||||
app/emu/audio/dsp.cc
|
app/emu/audio/dsp.cc
|
||||||
app/emu/video/ppu.cc
|
app/emu/video/ppu.cc
|
||||||
|
app/emu/memory/dma.cc
|
||||||
app/emu/cpu.cc
|
app/emu/cpu.cc
|
||||||
app/emu/snes.cc
|
app/emu/snes.cc
|
||||||
${YAZE_APP_CORE_SRC}
|
${YAZE_APP_CORE_SRC}
|
||||||
|
|||||||
75
src/app/emu/memory/dma.cc
Normal file
75
src/app/emu/memory/dma.cc
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#include "app/emu/memory/dma.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace yaze {
|
||||||
|
namespace app {
|
||||||
|
namespace emu {
|
||||||
|
|
||||||
|
void DMA::StartDMATransfer(uint8_t channelMask) {
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
if ((channelMask & (1 << i)) != 0) {
|
||||||
|
Channel& ch = channels[i];
|
||||||
|
|
||||||
|
// Validate channel parameters (e.g., DMAPn, BBADn, A1Tn, DASn)
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Determine the transfer direction based on the DMAPn register
|
||||||
|
bool fromMemory = (ch.DMAPn & 0x80) != 0;
|
||||||
|
|
||||||
|
// Determine the transfer size based on the DMAPn register
|
||||||
|
bool transferTwoBytes = (ch.DMAPn & 0x40) != 0;
|
||||||
|
|
||||||
|
// Perform the DMA transfer based on the channel parameters
|
||||||
|
std::cout << "Starting DMA transfer for channel " << i << std::endl;
|
||||||
|
|
||||||
|
for (uint16_t j = 0; j < ch.DASn; ++j) {
|
||||||
|
// Read a byte or two bytes from memory based on the transfer size
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Write the data to the B-bus address (BBADn) if transferring from
|
||||||
|
// memory
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Update the A1Tn register based on the transfer direction
|
||||||
|
if (fromMemory) {
|
||||||
|
ch.A1Tn += transferTwoBytes ? 2 : 1;
|
||||||
|
} else {
|
||||||
|
ch.A1Tn -= transferTwoBytes ? 2 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the channel registers after the transfer (e.g., A1Tn, DASn)
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MDMAEN = channelMask; // Set the MDMAEN register to the channel mask
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMA::EnableHDMATransfers(uint8_t channelMask) {
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
if ((channelMask & (1 << i)) != 0) {
|
||||||
|
Channel& ch = channels[i];
|
||||||
|
|
||||||
|
// Validate channel parameters (e.g., DMAPn, BBADn, A1Tn, A2An, NLTRn)
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Perform the HDMA setup based on the channel parameters
|
||||||
|
std::cout << "Enabling HDMA transfer for channel " << i << std::endl;
|
||||||
|
|
||||||
|
// Read the HDMA table from memory starting at A1Tn
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Update the A2An register based on the HDMA table
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Update the NLTRn register based on the HDMA table
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HDMAEN = channelMask; // Set the HDMAEN register to the channel mask
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace emu
|
||||||
|
} // namespace app
|
||||||
|
} // namespace yaze
|
||||||
@@ -58,70 +58,6 @@ void audio_callback(void* userdata, uint8_t* stream, int len) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void DMA::StartDMATransfer(uint8_t channelMask) {
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
if ((channelMask & (1 << i)) != 0) {
|
|
||||||
Channel& ch = channels[i];
|
|
||||||
|
|
||||||
// Validate channel parameters (e.g., DMAPn, BBADn, A1Tn, DASn)
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// Determine the transfer direction based on the DMAPn register
|
|
||||||
bool fromMemory = (ch.DMAPn & 0x80) != 0;
|
|
||||||
|
|
||||||
// Determine the transfer size based on the DMAPn register
|
|
||||||
bool transferTwoBytes = (ch.DMAPn & 0x40) != 0;
|
|
||||||
|
|
||||||
// Perform the DMA transfer based on the channel parameters
|
|
||||||
std::cout << "Starting DMA transfer for channel " << i << std::endl;
|
|
||||||
|
|
||||||
for (uint16_t j = 0; j < ch.DASn; ++j) {
|
|
||||||
// Read a byte or two bytes from memory based on the transfer size
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// Write the data to the B-bus address (BBADn) if transferring from
|
|
||||||
// memory
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// Update the A1Tn register based on the transfer direction
|
|
||||||
if (fromMemory) {
|
|
||||||
ch.A1Tn += transferTwoBytes ? 2 : 1;
|
|
||||||
} else {
|
|
||||||
ch.A1Tn -= transferTwoBytes ? 2 : 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the channel registers after the transfer (e.g., A1Tn, DASn)
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MDMAEN = channelMask; // Set the MDMAEN register to the channel mask
|
|
||||||
}
|
|
||||||
|
|
||||||
void DMA::EnableHDMATransfers(uint8_t channelMask) {
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
if ((channelMask & (1 << i)) != 0) {
|
|
||||||
Channel& ch = channels[i];
|
|
||||||
|
|
||||||
// Validate channel parameters (e.g., DMAPn, BBADn, A1Tn, A2An, NLTRn)
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// Perform the HDMA setup based on the channel parameters
|
|
||||||
std::cout << "Enabling HDMA transfer for channel " << i << std::endl;
|
|
||||||
|
|
||||||
// Read the HDMA table from memory starting at A1Tn
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// Update the A2An register based on the HDMA table
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// Update the NLTRn register based on the HDMA table
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HDMAEN = channelMask; // Set the HDMAEN register to the channel mask
|
|
||||||
}
|
|
||||||
|
|
||||||
ROMInfo SNES::ReadRomHeader(uint32_t offset) {
|
ROMInfo SNES::ReadRomHeader(uint32_t offset) {
|
||||||
ROMInfo romInfo;
|
ROMInfo romInfo;
|
||||||
|
|
||||||
@@ -289,9 +225,7 @@ void SNES::Run() {
|
|||||||
running_ = true;
|
running_ = true;
|
||||||
|
|
||||||
const double targetFPS = 60.0; // 60 frames per second
|
const double targetFPS = 60.0; // 60 frames per second
|
||||||
|
const double frame_time = 1.0 / targetFPS;
|
||||||
const double frameTime = 1.0 / targetFPS;
|
|
||||||
|
|
||||||
double frame_accumulated_time = 0.0;
|
double frame_accumulated_time = 0.0;
|
||||||
|
|
||||||
auto last_time = std::chrono::high_resolution_clock::now();
|
auto last_time = std::chrono::high_resolution_clock::now();
|
||||||
@@ -316,9 +250,9 @@ void SNES::Run() {
|
|||||||
apu.UpdateClock(delta_time);
|
apu.UpdateClock(delta_time);
|
||||||
apu.Update();
|
apu.Update();
|
||||||
|
|
||||||
if (frame_accumulated_time >= frameTime) {
|
if (frame_accumulated_time >= frame_time) {
|
||||||
// renderer.Render();
|
// renderer.Render();
|
||||||
frame_accumulated_time -= frameTime;
|
frame_accumulated_time -= frame_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleInput();
|
HandleInput();
|
||||||
@@ -376,7 +310,6 @@ void SNES::NmiIsr() {
|
|||||||
void SNES::VBlankRoutine() {
|
void SNES::VBlankRoutine() {
|
||||||
// Execute code that needs to run during VBlank, such as transferring data to
|
// Execute code that needs to run during VBlank, such as transferring data to
|
||||||
// the PPU
|
// the PPU
|
||||||
// ...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SNES::BootAPUWithIPL() {
|
void SNES::BootAPUWithIPL() {
|
||||||
|
|||||||
Reference in New Issue
Block a user