Skip to content

Commit

Permalink
Improve the accuracy of DMA open-bus.
Browse files Browse the repository at this point in the history
Fix #37.
  • Loading branch information
Arignir committed Mar 18, 2024
1 parent 046d753 commit b122bd3
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 18 deletions.
4 changes: 2 additions & 2 deletions include/gba/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,12 @@ enum io_regs {
IO_REG_IF = 0x04000202,
IO_REG_WAITCNT = 0x04000204,
IO_REG_IME = 0x04000208,
IO_REG_UNKNOWN_3 = 0x04000302,

/* System */

IO_REG_POSTFLG = 0x04000300,
IO_REG_HALTCNT = 0x04000301,
IO_REG_UNKNOWN_3 = 0x04000302,

IO_REG_END,
};
Expand Down Expand Up @@ -198,7 +198,7 @@ struct dma_channel {
uint32_t internal_dst;
uint32_t internal_count;

uint32_t bus;
uint32_t latch;

bool is_fifo;
bool is_video;
Expand Down
6 changes: 5 additions & 1 deletion include/gba/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,13 @@ struct memory {
// Prefetch buffer
struct prefetch_buffer pbuffer;

// Open Bus
// BIOS Open Bus
uint32_t bios_bus;

// DMA Open Bus
uint32_t dma_bus;
bool is_dma_bus_dirty;

// Set when the cartridge memory bus is in used
bool gamepak_bus_in_use;
};
Expand Down
19 changes: 9 additions & 10 deletions source/gba/memory/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,28 +152,26 @@ dma_run_channel(

if (unit_size == 4) {
if (likely(channel->internal_src >= EWRAM_START)) {
channel->bus = mem_read32(gba, channel->internal_src, access_src);
channel->latch = mem_read32(gba, channel->internal_src, access_src);
} else {
mem_read32(gba, channel->internal_src, access_src);
}
mem_write32(gba, channel->internal_dst, channel->bus, access_dst);
mem_write32(gba, channel->internal_dst, channel->latch, access_dst);
} else { // unit_size == 2
if (likely(channel->internal_src >= EWRAM_START)) {
/*
** Not sure what's the expected behaviour regarding the DMA's open bus behaviour/latch management,
** this is more or less random.
*/
channel->bus = mem_read16(gba, channel->internal_src, access_src);
channel->bus = ((channel->bus << 16) | channel->bus);
channel->latch = mem_read16(gba, channel->internal_src, access_src);
channel->latch = ((channel->latch << 16) | channel->latch);
} else {
mem_read16(gba, channel->internal_src, access_src);
channel->bus = ror32(channel->bus, 8 * (channel->internal_dst & 3));
channel->latch = ror32(channel->latch, 8 * (channel->internal_dst & 3));
}
mem_write16(gba, channel->internal_dst, channel->bus, access_dst);
mem_write16(gba, channel->internal_dst, channel->latch, access_dst);
}
channel->internal_src += src_step;
channel->internal_dst += dst_step;
channel->internal_count -= 1;
gba->memory.dma_bus = channel->latch;
gba->memory.is_dma_bus_dirty = true;
access_src = SEQUENTIAL;
access_dst = SEQUENTIAL;
}
Expand Down Expand Up @@ -230,6 +228,7 @@ mem_dma_do_all_pending_transfers(
}

gba->core.is_dma_running = true;
gba->memory.is_dma_bus_dirty = false;
core_idle(gba);

while (gba->core.pending_dma) {
Expand Down
10 changes: 5 additions & 5 deletions source/gba/memory/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,11 @@ mem_openbus_read(

shift = addr & 0x3;

if (gba->core.current_dma_idx != NO_CURRENT_DMA) {
struct dma_channel const *channel;

channel = &gba->io.dma[gba->core.current_dma_idx];
return (channel->bus >> (8 * shift));
// On first access, open-bus during DMA transfers returns the
// last prefetched instruction (as one would expect), but on
// subsequent transfers it returns the last transfered data.
if (gba->core.is_dma_running && gba->memory.is_dma_bus_dirty) {
return gba->memory.dma_bus >> (8 * shift);
}

if (gba->core.cpsr.thumb) {
Expand Down

0 comments on commit b122bd3

Please sign in to comment.