11static const int bAdrOffsets[8][4] = {{0, 0, 0, 0}, {0, 1, 0, 1}, {0, 0, 0, 0},
12 {0, 0, 1, 1}, {0, 1, 2, 3}, {0, 1, 0, 1},
13 {0, 0, 0, 0}, {0, 0, 1, 1}};
15static const int transferLength[8] = {1, 2, 2, 4, 4, 4, 2, 4};
19 for (
int i = 0; i < 8; i++) {
20 channel[i].b_addr = 0xff;
21 channel[i].a_addr = 0xffff;
22 channel[i].a_bank = 0xff;
23 channel[i].size = 0xffff;
24 channel[i].ind_bank = 0xff;
25 channel[i].table_addr = 0xffff;
26 channel[i].rep_count = 0xff;
27 channel[i].unusedByte = 0xff;
28 channel[i].dma_active =
false;
29 channel[i].hdma_active =
false;
31 channel[i].fixed =
true;
32 channel[i].decrement =
true;
33 channel[i].indirect =
true;
34 channel[i].from_b =
true;
35 channel[i].unusedBit =
true;
36 channel[i].do_transfer =
false;
37 channel[i].terminated =
false;
46 uint8_t c = (adr & 0x70) >> 4;
49 uint8_t val = channel[c].mode;
50 val |= channel[c].fixed << 3;
51 val |= channel[c].decrement << 4;
52 val |= channel[c].unusedBit << 5;
53 val |= channel[c].indirect << 6;
54 val |= channel[c].from_b << 7;
58 return channel[c].b_addr;
61 return channel[c].a_addr & 0xff;
64 return channel[c].a_addr >> 8;
67 return channel[c].a_bank;
70 return channel[c].size & 0xff;
73 return channel[c].size >> 8;
76 return channel[c].ind_bank;
79 return channel[c].table_addr & 0xff;
82 return channel[c].table_addr >> 8;
85 return channel[c].rep_count;
89 return channel[c].unusedByte;
99 uint8_t c = (adr & 0x70) >> 4;
102 channel[c].mode = val & 0x7;
103 channel[c].fixed = val & 0x8;
104 channel[c].decrement = val & 0x10;
105 channel[c].unusedBit = val & 0x20;
106 channel[c].indirect = val & 0x40;
107 channel[c].from_b = val & 0x80;
111 channel[c].b_addr = val;
115 channel[c].a_addr = (channel[c].a_addr & 0xff00) | val;
119 channel[c].a_addr = (channel[c].a_addr & 0xff) | (val << 8);
123 channel[c].a_bank = val;
127 channel[c].size = (channel[c].size & 0xff00) | val;
131 channel[c].size = (channel[c].size & 0xff) | (val << 8);
135 channel[c].ind_bank = val;
139 channel[c].table_addr = (channel[c].table_addr & 0xff00) | val;
143 channel[c].table_addr = (channel[c].table_addr & 0xff) | (val << 8);
147 channel[c].rep_count = val;
152 channel[c].unusedByte = val;
163 snes->
cpu().set_int_delay(
true);
170 for (
int i = 0; i < 8; i++) {
171 if (!channel[i].dma_active)
continue;
175 while (channel[i].dma_active) {
177 TransferByte(snes, memory, channel[i].a_addr, channel[i].a_bank,
178 channel[i].b_addr + bAdrOffsets[channel[i].mode][offIndex++],
181 if (!channel[i].fixed) {
182 channel[i].a_addr += channel[i].decrement ? -1 : 1;
185 if (channel[i].size == 0) {
186 channel[i].dma_active =
false;
199 InitHdma(snes, memory,
true, cpu_cycles);
201 DoHdma(snes, memory,
true, cpu_cycles);
208 DoDma(snes, memory, cpu_cycles);
224 bool hdmaEnabled =
false;
226 for (
int i = 0; i < 8; i++) {
227 if (channel[i].hdma_active) hdmaEnabled =
true;
228 channel[i].do_transfer =
false;
229 channel[i].terminated =
false;
231 if (!hdmaEnabled)
return;
232 snes->
cpu().set_int_delay(
true);
237 for (
int i = 0; i < 8; i++) {
238 if (channel[i].hdma_active) {
240 channel[i].dma_active =
false;
243 channel[i].table_addr = channel[i].a_addr;
244 channel[i].rep_count =
245 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr++);
246 if (channel[i].rep_count == 0) channel[i].terminated =
true;
247 if (channel[i].indirect) {
250 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr++);
253 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr++) << 8;
255 channel[i].do_transfer =
true;
258 if (do_sync) snes->
SyncCycles(
false, cpu_cycles);
264 bool hdmaActive =
false;
266 for (
int i = 0; i < 8; i++) {
267 if (channel[i].hdma_active) {
269 if (!channel[i].terminated) lastActive = i;
273 if (!hdmaActive)
return;
274 snes->
cpu().set_int_delay(
true);
281 for (
int i = 0; i < 8; i++) {
283 if (channel[i].hdma_active) channel[i].dma_active =
false;
284 if (channel[i].hdma_active && !channel[i].terminated) {
286 if (channel[i].do_transfer) {
287 for (
int j = 0; j < transferLength[channel[i].mode]; j++) {
289 if (channel[i].indirect) {
290 TransferByte(snes, memory, channel[i].size++, channel[i].ind_bank,
291 channel[i].b_addr + bAdrOffsets[channel[i].mode][j],
294 TransferByte(snes, memory, channel[i].table_addr++, channel[i].a_bank,
295 channel[i].b_addr + bAdrOffsets[channel[i].mode][j],
303 for (
int i = 0; i < 8; i++) {
304 if (channel[i].hdma_active && !channel[i].terminated) {
305 channel[i].rep_count--;
306 channel[i].do_transfer = channel[i].rep_count & 0x80;
308 uint8_t newRepCount =
309 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr);
310 if ((channel[i].rep_count & 0x7f) == 0) {
311 channel[i].rep_count = newRepCount;
312 channel[i].table_addr++;
313 if (channel[i].indirect) {
314 if (channel[i].rep_count == 0 && i == lastActive) {
321 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr++);
325 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr++) << 8;
327 if (channel[i].rep_count == 0) channel[i].terminated =
true;
328 channel[i].do_transfer =
true;
337 uint8_t bAdr,
bool fromB) {
341 (aBank == 0x7e || aBank == 0x7f ||
342 ((aBank < 0x40 || (aBank >= 0x80 && aBank < 0xc0)) && aAdr < 0x2000)));
344 bool validA = !((aBank < 0x40 || (aBank >= 0x80 && aBank < 0xc0)) &&
345 (aAdr == 0x420b || aAdr == 0x420c ||
346 (aAdr >= 0x4300 && aAdr < 0x4380) ||
347 (aAdr >= 0x2100 && aAdr < 0x2200)));
350 if (validA) snes->
Write((aBank << 16) | aAdr, val);
353 validA ? snes->
Read((aBank << 16) | aAdr) : memory->
open_bus();
360 for (
int i = 0; i < 8; i++) {
362 channel[i].hdma_active = val & (1 << i);
364 channel[i].dma_active = val & (1 << i);
void RunCycles(int cycles)
void SyncCycles(bool start, int sync_cycles)
void Write(uint32_t adr, uint8_t val)
void WriteBBus(uint8_t adr, uint8_t val)
uint8_t ReadBBus(uint8_t adr)
uint8_t Read(uint32_t adr)
Implementation of the Memory interface for emulating memory in a SNES system.
void set_dma_state(uint8_t value)
auto dma_channels() -> DmaChannel *
auto hdma_run_requested() const -> bool override
void set_hdma_run_requested(bool value) override
auto dma_state() -> uint8_t &
auto open_bus() const -> uint8_t override
void set_hdma_init_requested(bool value) override
auto hdma_init_requested() const -> bool override
void InitHdma(SNES *snes, MemoryImpl *memory, bool do_sync, int cpu_cycles)
void TransferByte(SNES *snes, MemoryImpl *memory, uint16_t aAdr, uint8_t aBank, uint8_t bAdr, bool fromB)
void DoHdma(SNES *snes, MemoryImpl *memory, bool do_sync, int cycles)
void DoDma(SNES *snes, MemoryImpl *memory, int cpuCycles)
void WaitCycle(SNES *snes, MemoryImpl *memory)
void Reset(MemoryImpl *memory)
void HandleDma(SNES *snes, MemoryImpl *memory, int cpu_cycles)
void Write(MemoryImpl *memory, uint16_t adr, uint8_t val)
uint8_t Read(MemoryImpl *memory, uint16_t adr)
void StartDma(MemoryImpl *memory, uint8_t val, bool hdma)