6static const int bAdrOffsets[8][4] = {{0, 0, 0, 0}, {0, 1, 0, 1}, {0, 0, 0, 0},
7 {0, 0, 1, 1}, {0, 1, 2, 3}, {0, 1, 0, 1},
8 {0, 0, 0, 0}, {0, 0, 1, 1}};
10static const int transferLength[8] = {1, 2, 2, 4, 4, 4, 2, 4};
14 for (
int i = 0; i < 8; i++) {
15 channel[i].b_addr = 0xff;
16 channel[i].a_addr = 0xffff;
17 channel[i].a_bank = 0xff;
18 channel[i].size = 0xffff;
19 channel[i].ind_bank = 0xff;
20 channel[i].table_addr = 0xffff;
21 channel[i].rep_count = 0xff;
22 channel[i].unusedByte = 0xff;
23 channel[i].dma_active =
false;
24 channel[i].hdma_active =
false;
26 channel[i].fixed =
true;
27 channel[i].decrement =
true;
28 channel[i].indirect =
true;
29 channel[i].from_b =
true;
30 channel[i].unusedBit =
true;
31 channel[i].do_transfer =
false;
32 channel[i].terminated =
false;
41 uint8_t c = (adr & 0x70) >> 4;
44 uint8_t val = channel[c].mode;
45 val |= channel[c].fixed << 3;
46 val |= channel[c].decrement << 4;
47 val |= channel[c].unusedBit << 5;
48 val |= channel[c].indirect << 6;
49 val |= channel[c].from_b << 7;
53 return channel[c].b_addr;
56 return channel[c].a_addr & 0xff;
59 return channel[c].a_addr >> 8;
62 return channel[c].a_bank;
65 return channel[c].size & 0xff;
68 return channel[c].size >> 8;
71 return channel[c].ind_bank;
74 return channel[c].table_addr & 0xff;
77 return channel[c].table_addr >> 8;
80 return channel[c].rep_count;
84 return channel[c].unusedByte;
94 uint8_t c = (adr & 0x70) >> 4;
97 channel[c].mode = val & 0x7;
98 channel[c].fixed = val & 0x8;
99 channel[c].decrement = val & 0x10;
100 channel[c].unusedBit = val & 0x20;
101 channel[c].indirect = val & 0x40;
102 channel[c].from_b = val & 0x80;
106 channel[c].b_addr = val;
110 channel[c].a_addr = (channel[c].a_addr & 0xff00) | val;
114 channel[c].a_addr = (channel[c].a_addr & 0xff) | (val << 8);
118 channel[c].a_bank = val;
122 channel[c].size = (channel[c].size & 0xff00) | val;
126 channel[c].size = (channel[c].size & 0xff) | (val << 8);
130 channel[c].ind_bank = val;
134 channel[c].table_addr = (channel[c].table_addr & 0xff00) | val;
138 channel[c].table_addr = (channel[c].table_addr & 0xff) | (val << 8);
142 channel[c].rep_count = val;
147 channel[c].unusedByte = val;
158 snes->
cpu().set_int_delay(
true);
165 for (
int i = 0; i < 8; i++) {
166 if (!channel[i].dma_active)
172 while (channel[i].dma_active) {
174 TransferByte(snes, memory, channel[i].a_addr, channel[i].a_bank,
175 channel[i].b_addr + bAdrOffsets[channel[i].mode][offIndex++],
178 if (!channel[i].fixed) {
179 channel[i].a_addr += channel[i].decrement ? -1 : 1;
182 if (channel[i].size == 0) {
183 channel[i].dma_active =
false;
196 InitHdma(snes, memory,
true, cpu_cycles);
198 DoHdma(snes, memory,
true, cpu_cycles);
205 DoDma(snes, memory, cpu_cycles);
215 DoHdma(snes, memory,
false, 0);
223 bool hdmaEnabled =
false;
225 for (
int i = 0; i < 8; i++) {
226 if (channel[i].hdma_active)
228 channel[i].do_transfer =
false;
229 channel[i].terminated =
false;
233 snes->
cpu().set_int_delay(
true);
239 for (
int i = 0; i < 8; i++) {
240 if (channel[i].hdma_active) {
242 channel[i].dma_active =
false;
245 channel[i].table_addr = channel[i].a_addr;
246 channel[i].rep_count =
247 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr++);
248 if (channel[i].rep_count == 0)
249 channel[i].terminated =
true;
250 if (channel[i].indirect) {
253 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr++);
256 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr++)
259 channel[i].do_transfer =
true;
269 bool hdmaActive =
false;
271 for (
int i = 0; i < 8; i++) {
272 if (channel[i].hdma_active) {
274 if (!channel[i].terminated)
281 snes->
cpu().set_int_delay(
true);
289 for (
int i = 0; i < 8; i++) {
291 if (channel[i].hdma_active)
292 channel[i].dma_active =
false;
293 if (channel[i].hdma_active && !channel[i].terminated) {
295 if (channel[i].do_transfer) {
296 for (
int j = 0; j < transferLength[channel[i].mode]; j++) {
298 if (channel[i].indirect) {
299 TransferByte(snes, memory, channel[i].size++, channel[i].ind_bank,
300 channel[i].b_addr + bAdrOffsets[channel[i].mode][j],
305 channel[i].b_addr + bAdrOffsets[channel[i].mode][j],
313 for (
int i = 0; i < 8; i++) {
314 if (channel[i].hdma_active && !channel[i].terminated) {
315 channel[i].rep_count--;
316 channel[i].do_transfer = channel[i].rep_count & 0x80;
318 uint8_t newRepCount =
319 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr);
320 if ((channel[i].rep_count & 0x7f) == 0) {
321 channel[i].rep_count = newRepCount;
322 channel[i].table_addr++;
323 if (channel[i].indirect) {
324 if (channel[i].rep_count == 0 && i == lastActive) {
331 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr++);
335 snes->
Read((channel[i].a_bank << 16) | channel[i].table_addr++)
338 if (channel[i].rep_count == 0)
339 channel[i].terminated =
true;
340 channel[i].do_transfer =
true;
350 uint8_t bAdr,
bool fromB) {
354 (aBank == 0x7e || aBank == 0x7f ||
355 ((aBank < 0x40 || (aBank >= 0x80 && aBank < 0xc0)) && aAdr < 0x2000)));
357 bool validA = !((aBank < 0x40 || (aBank >= 0x80 && aBank < 0xc0)) &&
358 (aAdr == 0x420b || aAdr == 0x420c ||
359 (aAdr >= 0x4300 && aAdr < 0x4380) ||
360 (aAdr >= 0x2100 && aAdr < 0x2200)));
361 auto record_vram = [&](uint8_t b_addr) {
378 snes->
Write((aBank << 16) | aAdr, val);
382 validA ? snes->
Read((aBank << 16) | aAdr) : memory->
open_bus();
393 for (
int i = 0; i < 8; i++) {
395 channel[i].hdma_active = val & (1 << i);
397 channel[i].dma_active = val & (1 << i);
Implementation of the Memory interface for emulating memory in a SNES system.
auto open_bus() const -> uint8_t override
void set_dma_state(uint8_t value)
auto dma_state() -> uint8_t &
auto dma_channels() -> DmaChannel *
void set_hdma_run_requested(bool value) override
auto hdma_init_requested() const -> bool override
void set_hdma_init_requested(bool value) override
auto hdma_run_requested() const -> bool override
void RunCycles(int cycles)
void WriteBBus(uint8_t adr, uint8_t val)
uint8_t Read(uint32_t adr)
uint8_t ReadBBus(uint8_t adr)
void Write(uint32_t adr, uint8_t val)
void SyncCycles(bool start, int sync_cycles)
void AccumulateDmaBytes(uint32_t bytes)
void AccumulateVramBytes(uint32_t bytes)
void TransferByte(Snes *snes, MemoryImpl *memory, uint16_t aAdr, uint8_t aBank, uint8_t bAdr, bool fromB)
void ResetDma(MemoryImpl *memory)
void WriteDma(MemoryImpl *memory, uint16_t adr, uint8_t val)
void HandleDma(Snes *snes, MemoryImpl *memory, int cpu_cycles)
void WaitCycle(Snes *snes, MemoryImpl *memory)
uint8_t ReadDma(MemoryImpl *memory, uint16_t adr)
void DoDma(Snes *snes, MemoryImpl *memory, int cpuCycles)
void StartDma(MemoryImpl *memory, uint8_t val, bool hdma)
void InitHdma(Snes *snes, MemoryImpl *memory, bool do_sync, int cpu_cycles)
void DoHdma(Snes *snes, MemoryImpl *memory, bool do_sync, int cycles)