Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmeteor/source/dma.cpp
2 views
1
// Meteor - A Nintendo Gameboy Advance emulator
2
// Copyright (C) 2009-2011 Philippe Daouadi
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
#include "ameteor/dma.hpp"
18
#include "ameteor/io.hpp"
19
#include "ameteor/memory.hpp"
20
#include "globals.hpp"
21
#include "ameteor.hpp"
22
23
#include "debug.hpp"
24
#include <sstream>
25
26
namespace AMeteor
27
{
28
void Dma::Reset ()
29
{
30
for (Channel* chan = m_chans; chan < m_chans+4; ++chan)
31
{
32
chan->src = 0;
33
chan->dest = 0;
34
chan->count = 0;
35
chan->control.w = 0;
36
}
37
m_graphic = 0;
38
}
39
40
void Dma::UpdateCnt (uint8_t channum)
41
{
42
Channel& chan = m_chans[channum];
43
44
if (chan.control.w !=
45
IO.DRead16(Io::DMA0CNT_H + channum * Io::DMA_CHANSIZE))
46
{
47
if (!chan.control.b.enable &&
48
(IO.DRead16(Io::DMA0CNT_H + channum * Io::DMA_CHANSIZE)
49
& (0x1 << 15)))
50
// if we changed enable from 0 to 1
51
{
52
chan.dest = IO.DRead32(Io::DMA0DAD + channum * Io::DMA_CHANSIZE);
53
if (channum == 3)
54
chan.dest &= 0x0FFFFFFF;
55
else
56
chan.dest &= 0x07FFFFFF;
57
58
chan.src = IO.DRead32(Io::DMA0SAD + channum * Io::DMA_CHANSIZE);
59
if (channum == 0)
60
chan.src &= 0x07FFFFFF;
61
else
62
chan.src &= 0x0FFFFFFF;
63
64
chan.count = chan.reload;
65
if (channum != 3)
66
chan.count &= 0x3FFF;
67
68
chan.control.w =
69
IO.DRead16(Io::DMA0CNT_H + channum * Io::DMA_CHANSIZE);
70
71
Check(channum, Immediately);
72
}
73
else
74
chan.control.w =
75
IO.DRead16(Io::DMA0CNT_H + channum * Io::DMA_CHANSIZE);
76
77
if (chan.control.b.start == Special)
78
{
79
switch (channum)
80
{
81
case 0:
82
met_abort("prohibited !");
83
break;
84
case 1:
85
case 2:
86
// sound dma
87
if (chan.dest != 0x040000A0 && chan.dest != 0x040000A4)
88
met_abort("Special DMA 1 or 2 with unauthorized address : "
89
<< IOS_ADD << chan.dest);
90
if (!chan.control.b.repeat)
91
met_abort("Special DMA 1 or 2 without repeat");
92
93
// 4 words of 32 bits
94
chan.count = 4;
95
chan.control.b.type = 1;
96
// no increment
97
chan.control.b.dest = 2;
98
break;
99
case 3:
100
met_abort("not implemented");
101
break;
102
}
103
}
104
}
105
}
106
107
void Dma::Check (uint8_t channum, uint8_t reason)
108
{
109
register Channel::Control cnt = m_chans[channum].control;
110
111
if (cnt.b.enable &&
112
cnt.b.start == reason)
113
Process(channum);
114
}
115
116
void Dma::Process (uint8_t channum)
117
{
118
Channel& chan = m_chans[channum];
119
120
int8_t s_inc, d_inc;
121
s_inc = d_inc = 2; // increment or increment reload
122
123
if (chan.control.b.src == 1) // decrement
124
s_inc = -2;
125
else if (chan.control.b.src == 2) // fixed
126
s_inc = 0;
127
else if (chan.control.b.src == 3)
128
met_abort("prohibited");
129
130
if (chan.control.b.dest == 1)
131
d_inc = -2;
132
else if (chan.control.b.dest == 2)
133
d_inc = 0;
134
//else if (chan.control.b.dest == 3)
135
// same as 0, but we do something at the end
136
137
if (chan.control.b.type) // 32 bits transfer
138
{
139
s_inc <<= 1;
140
d_inc <<= 1;
141
}
142
143
if (chan.count == 0)
144
{
145
if (channum != 3)
146
chan.count = 0x4000;
147
// 0x10000 doesn't fill in 16 bits, we treat this case in the Copy() call
148
}
149
150
//printf("DMA%hhu from %08X to %08X of %hu %s\n", channum, chan.src, chan.dest, chan.count, chan.control.b.type ? "words":"halfwords");
151
//if (i > debut)
152
debug ("DMA" << IOS_NOR << (int)channum << ", from " << IOS_ADD << chan.src
153
<< " to " << IOS_ADD << chan.dest
154
<< " of " << IOS_NOR << (chan.count ? chan.count : 0x10000)
155
<< (chan.control.b.type ? " words" : " halfwords"));
156
if (traceenabled)
157
{
158
std::stringstream ss;
159
ss << "DMA" << IOS_NOR << (int)channum << ", from " << IOS_ADD << chan.src
160
<< " to " << IOS_ADD << chan.dest
161
<< " of " << IOS_NOR << (chan.count ? chan.count : 0x10000)
162
<< (chan.control.b.type ? " words" : " halfwords");
163
trace_bizhawk(ss.str());
164
}
165
#if 0
166
if (channum == 3 && (chan.dest >> 24) == 0x0D || (chan.src >> 24) == 0x0D)
167
{
168
if (chan.control.b.type)
169
met_abort("Word copy for EEPROM DMA3");
170
if (d_inc != 2 || s_inc != 2)
171
met_abort("Source or destination not incremeting in EEPROM DMA3");
172
if ((chan.dest >> 24) == 0x0D)
173
MEM.WriteEepromDma(chan.src, chan.count ? chan.count : 0x10000);
174
else if ((chan.src >> 24) == 0x0D)
175
MEM.ReadEepromDma(chan.dest, chan.count ? chan.count : 0x10000);
176
chan.src += chan.count * 2;
177
chan.dest += chan.count * 2;
178
}
179
else
180
#endif
181
if (channum == 3 && (chan.dest >> 24) == 0x0D)
182
{
183
if (chan.control.b.type)
184
met_abort("Word copy for EEPROM DMA3");
185
if (d_inc != 2 || s_inc != 2)
186
met_abort("Source or destination not incremeting in EEPROM DMA3");
187
MEM.WriteEepromDma(chan.src, chan.count);
188
chan.src += chan.count * 2;
189
chan.dest += chan.count * 2;
190
}
191
else
192
Copy(chan.src, chan.dest, s_inc, d_inc,
193
chan.count ? chan.count : 0x10000, chan.control.b.type);
194
195
if (chan.control.b.type)
196
{
197
CYCLES32NSeq(chan.src, chan.count);
198
CYCLES32NSeq(chan.dest, chan.count);
199
ICYCLES(2);
200
}
201
else
202
{
203
CYCLES16NSeq(chan.src, chan.count);
204
CYCLES16NSeq(chan.dest, chan.count);
205
ICYCLES(2);
206
}
207
uint32_t d = chan.dest >> 24;
208
uint32_t s = chan.src >> 24;
209
if (d >= 0x08 && d <= 0x0D && s >= 0x08 && s <= 0x0D)
210
// if both source and destination are in GamePak
211
ICYCLES(2);
212
213
if (chan.control.b.irq)
214
CPU.SendInterrupt(0x1 << (8 + channum));
215
216
if (chan.control.b.dest == 3)
217
{
218
chan.dest = IO.DRead32(Io::DMA0DAD + channum * Io::DMA_CHANSIZE);
219
if (channum == 3)
220
chan.dest &= 0x0FFFFFFF;
221
else
222
chan.dest &= 0x07FFFFFF;
223
}
224
225
// if repeat but not sound dma
226
//if (!((channum == 1 || channum == 2) && chan.control.b.start == Special) && chan.control.b.repeat)
227
if (((channum != 1 && channum != 2) || chan.control.b.start != Special)
228
&& chan.control.b.repeat)
229
{
230
chan.count = chan.reload;
231
}
232
233
if (!chan.control.b.repeat || chan.control.b.start == Immediately)
234
{
235
chan.control.b.enable = 0;
236
IO.GetRef16(Io::DMA0CNT_H + channum * Io::DMA_CHANSIZE) &= 0x7FFF;
237
}
238
}
239
240
void Dma::Copy (uint32_t& src, uint32_t& dest, int8_t s_inc, int8_t d_inc,
241
uint32_t count, bool word)
242
{
243
uint32_t basedest = dest;
244
245
if (word)
246
{
247
src &= 0xFFFFFFFC;
248
dest &= 0xFFFFFFFC;
249
}
250
else
251
{
252
src &= 0xFFFFFFFE;
253
dest &= 0xFFFFFFFE;
254
}
255
256
// sound
257
if (dest == 0x040000A0)
258
{
259
SOUND.SendDigitalA((uint8_t*)MEM.GetRealAddress(src));
260
src += 4*4;
261
if (d_inc != 0)
262
met_abort("dinc != 0 on dma sound, should not happen");
263
return;
264
}
265
if (dest == 0x040000A4)
266
{
267
SOUND.SendDigitalB((uint8_t*)MEM.GetRealAddress(src));
268
src += 4*4;
269
if (d_inc != 0)
270
met_abort("dinc != 0 on dma sound, should not happen");
271
return;
272
}
273
274
if ((dest >> 24) >= 0x05 &&
275
(dest >> 24) <= 0x07)
276
m_graphic = true;
277
278
if (word)
279
{
280
for (uint32_t cur = 0; cur < count; ++cur)
281
{
282
MEM.Write32(dest, MEM.Read32(src));
283
src += s_inc;
284
dest += d_inc;
285
}
286
}
287
else
288
{
289
for (uint32_t cur = 0; cur < count; ++cur)
290
{
291
MEM.Write16(dest, MEM.Read16(src));
292
src += s_inc;
293
dest += d_inc;
294
}
295
}
296
297
m_graphic = false;
298
//if ((basedest >> 24) == 0x07)
299
// LCD.OamWrite(basedest, dest);
300
}
301
302
bool Dma::SaveState (std::ostream& stream)
303
{
304
SS_WRITE_ARRAY(m_chans);
305
// no need to save or load m_graphic since we shouldn't save or load during
306
// a dma
307
308
return true;
309
}
310
311
bool Dma::LoadState (std::istream& stream)
312
{
313
SS_READ_ARRAY(m_chans);
314
315
return true;
316
}
317
}
318
319