Skip to content

Commit

Permalink
always init dma on hi write (fixes #7, fixes #8, fixes #15)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsmolka committed Mar 21, 2021
1 parent 8e41a29 commit 551edfc
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 108 deletions.
14 changes: 0 additions & 14 deletions eggvance/src/dma/dma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,6 @@
#include "arm/arm.h"
#include "arm/constants.h"

Dma::Dma()
{
for (auto& channel : channels)
{
channel.control.on_write = [&](bool init)
{
if (init)
channel.init();

emit(channel, Dma::Event::Immediate);
};
}
}

void Dma::run()
{
while (active && scheduler.now < arm.target)
Expand Down
7 changes: 2 additions & 5 deletions eggvance/src/dma/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@
class Dma
{
public:
enum class Event { Immediate, HBlank, VBlank, FifoA, FifoB, Hdma };

Dma();
enum class Event { Immediate, HBlank, VBlank, Hdma, FifoA, FifoB };

void run();
void emit(DmaChannel& channel, Event event);
void broadcast(Event event);

DmaChannel channels[4] = { 0, 1, 2, 3 };

private:
void emit(DmaChannel& channel, Event event);

DmaChannel* active = nullptr;
};

Expand Down
141 changes: 71 additions & 70 deletions eggvance/src/dma/dmachannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,78 @@ void DmaChannel::init()
&& control.repeat
&& dad.isFifo();

latch.sad = sad;
latch.dad = dad;
latch.sad = sad & ~((2 << control.word) - 1);
latch.dad = dad & ~((2 << control.word) - 1);
latch.count = fifo ? 4 : static_cast<uint>(count);

initTransfer();
}

bool DmaChannel::start()
{
if (fifo)
{
if (apu.fifo[latch.dad == 0x400'00A4].size() > 16)
return false;
}
else if (control.repeat)
{
latch.count = count;

if (control.dadcnt == DmaControl::kControlReload)
{
latch.dad = dad & ~((2 << control.word) - 1);

initTransfer();
}
}

running = true;
pending = latch.count;

return true;
}

void DmaChannel::run()
{
static constexpr int kDeltas[2][4] =
{
{ 2, -2, 0, 2 },
{ 4, -4, 0, 4 }
};

int sad_delta = kDeltas[control.word | fifo][control.sadcnt];
int dad_delta = kDeltas[control.word | fifo][fifo ? DmaControl::kControlFixed : control.dadcnt];

while (pending--)
{
if (pending == latch.count - 1)
{
if (!(latch.sad & latch.dad & 0x800'0000))
arm.idle(2);

transfer(Access::NonSequential);
}
else
{
transfer(Access::Sequential);
}

latch.sad += sad_delta;
latch.dad += dad_delta;

if (arm.target >= scheduler.now && pending)
return;
}

running = false;

if (control.irq)
arm.raise(kIrqDma0 << id);

control.setEnabled(control.repeat
&& !(control.timing == DmaControl::kTimingImmediate)
&& !(control.timing == DmaControl::kTimingSpecial && id == 3 && ppu.vcount >= 161));
}

void DmaChannel::initEeprom()
Expand Down Expand Up @@ -108,71 +177,3 @@ void DmaChannel::initTransfer()
}
}
}

bool DmaChannel::start()
{
if (fifo)
{
if (apu.fifo[latch.dad == 0x400'00A4].size() > 16)
return false;
}
else if (control.repeat)
{
latch.count = count;

if (control.dadcnt == DmaControl::Control::kControlReload)
latch.dad = dad;
}

latch.sad &= ~((2 << control.word) - 1);
latch.dad &= ~((2 << control.word) - 1);

running = true;
pending = latch.count;

initTransfer();

return true;
}

void DmaChannel::run()
{
static constexpr int kDeltas[2][4] =
{
{ 2, -2, 0, 2 },
{ 4, -4, 0, 4 }
};

int sad_delta = kDeltas[control.word | fifo][control.sadcnt];
int dad_delta = kDeltas[control.word | fifo][fifo ? DmaControl::Control::kControlFixed : control.dadcnt];

while (pending--)
{
if (pending == latch.count - 1)
{
if (!(latch.sad & latch.dad & 0x800'0000))
arm.idle(2);

transfer(Access::NonSequential);
}
else
{
transfer(Access::Sequential);
}

latch.sad += sad_delta;
latch.dad += dad_delta;

if (arm.target >= scheduler.now && pending)
return;
}

running = false;

if (control.irq)
arm.raise(kIrqDma0 << id);

control.setEnabled(control.repeat
&& !(control.timing == DmaControl::Timing::kTimingImmediate)
&& !(control.timing == DmaControl::Timing::kTimingSpecial && id == 3 && ppu.vcount >= 161));
}
8 changes: 4 additions & 4 deletions eggvance/src/dma/dmachannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ class DmaChannel

DmaChannel(uint id);

void init();
bool start();
void run();

const uint id;
DmaSource sad;
DmaDestination dad;
DmaCount count;
DmaControl control;

private:
void init();
void initEeprom();
void initTransfer();

bool start();
void run();

uint running = 0;
uint fifo = 0;
uint pending = 0;
Expand Down
24 changes: 16 additions & 8 deletions eggvance/src/dma/io.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "io.h"

#include "dma.h"

DmaSource::DmaSource(uint id)
: RegisterW(id == 0 ? 0x07FF'FFFF : 0x0FFF'FFFF)
{
Expand Down Expand Up @@ -43,6 +45,7 @@ DmaCount::operator uint() const

DmaControl::DmaControl(uint id)
: Register(id == 3 ? 0xFFE0 : 0xF7E0)
, id(id)
{

}
Expand All @@ -59,26 +62,31 @@ void DmaControl::write(uint index, u8 byte)
}
else
{
uint was_enable = enabled;
uint was_enabled = enabled;

repeat = bit::seq<1, 1>(byte);
word = bit::seq<2, 1>(byte);
timing = bit::seq<4, 2>(byte);
irq = bit::seq<6, 1>(byte);
repeat = bit::seq<1, 1>(byte);
word = bit::seq<2, 1>(byte);
timing = bit::seq<4, 2>(byte);
irq = bit::seq<6, 1>(byte);
enabled = bit::seq<7, 1>(byte);

on_write(!was_enable && enabled);
DmaChannel& channel = dma.channels[id];

channel.init();

if (!was_enabled && enabled)
dma.emit(channel, Dma::Event::Immediate);
}
}

void DmaControl::setEnabled(bool enabled)
{
constexpr auto kEnabled = 1 << 15;

this->enabled = enabled;

if (enabled)
data |= kEnabled;
else
data &= ~kEnabled;

this->enabled = enabled;
}
15 changes: 8 additions & 7 deletions eggvance/src/dma/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@ class DmaControl : public Register<u16>
void write(uint index, u8 byte);
void setEnabled(bool enabled);

uint dadcnt = 0;
uint sadcnt = 0;
uint repeat = 0;
uint word = 0;
uint timing = 0;
uint irq = 0;
uint dadcnt = 0;
uint sadcnt = 0;
uint repeat = 0;
uint word = 0;
uint timing = 0;
uint irq = 0;
uint enabled = 0;

std::function<void(bool)> on_write;
private:
const uint id;
};

0 comments on commit 551edfc

Please sign in to comment.