1 //---------------------------------------------------------------------------
2 // NEOPOP : Emulator as in Dreamland
3 //
4 // Copyright (c) 2001-2002 by neopop_uk
5 //---------------------------------------------------------------------------
6 
7 //---------------------------------------------------------------------------
8 //	This program is free software; you can redistribute it and/or modify
9 //	it under the terms of the GNU General Public License as published by
10 //	the Free Software Foundation; either version 2 of the License, or
11 //	(at your option) any later version. See also the license.txt file for
12 //	additional informations.
13 //---------------------------------------------------------------------------
14 
15 #include <string.h>
16 
17 #include "neopop.h"
18 #include "dma.h"
19 #include "mem.h"
20 #include "interrupt.h"
21 #include "../state.h"
22 
23 static uint32_t dmaS[4], dmaD[4];
24 static uint16_t dmaC[4];
25 static uint8_t dmaM[4];
26 
reset_dma(void)27 void reset_dma(void)
28 {
29 	memset(dmaS, 0, sizeof(dmaS));
30 	memset(dmaD, 0, sizeof(dmaD));
31 	memset(dmaC, 0, sizeof(dmaC));
32 	memset(dmaM, 0, sizeof(dmaM));
33 }
34 
DMA_update(int channel)35 void DMA_update(int channel)
36 {
37 	uint8_t mode = (dmaM[channel] & 0x1C) >> 2;
38 	uint8_t size = (dmaM[channel] & 0x03);			/* byte, word or long */
39 
40 	/* Correct? */
41 	if (dmaC[channel] == 0)
42 		return;
43 
44 	switch (mode)
45    {
46       case 0:	/* Destination INC mode, I/O to Memory transfer */
47          switch(size)
48          {
49             case 0:
50                storeB(dmaD[channel], loadB(dmaS[channel]));
51                dmaD[channel] += 1; /* Byte increment */
52                break;
53             case 1:
54                storeW(dmaD[channel], loadW(dmaS[channel]));
55                dmaD[channel] += 2; /* Word increment */
56                break;
57             case 2:
58                storeL(dmaD[channel], loadL(dmaS[channel]));
59                dmaD[channel] += 4; /* Long increment */
60                break;
61          }
62          break;
63 
64       case 1:	/* Destination DEC mode, I/O to Memory transfer */
65          switch(size)
66          {
67             case 0:
68                storeB(dmaD[channel], loadB(dmaS[channel]));
69                dmaD[channel] -= 1; //Byte decrement
70                break;
71             case 1:
72                storeW(dmaD[channel], loadW(dmaS[channel]));
73                dmaD[channel] -= 2; //Word decrement
74                break;
75             case 2:
76                storeL(dmaD[channel], loadL(dmaS[channel]));
77                dmaD[channel] -= 4; //Long decrement
78                break;
79          }
80          break;
81 
82       case 2:	/* Source INC mode, Memory to I/O transfer */
83          switch(size)
84          {
85             case 0:
86                storeB(dmaD[channel], loadB(dmaS[channel]));
87                dmaS[channel] += 1; //Byte increment
88                break;
89             case 1:
90                storeW(dmaD[channel], loadW(dmaS[channel]));
91                dmaS[channel] += 2; //Word increment
92                break;
93             case 2:
94                storeL(dmaD[channel], loadL(dmaS[channel]));
95                dmaS[channel] += 4; //Long increment
96                break;
97          }
98          break;
99 
100       case 3:	/* Source DEC mode, Memory to I/O transfer */
101          switch(size)
102          {
103             case 0:
104                storeB(dmaD[channel], loadB(dmaS[channel]));
105                dmaS[channel] -= 1; //Byte decrement
106                break;
107             case 1:
108                storeW(dmaD[channel], loadW(dmaS[channel]));
109                dmaS[channel] -= 2; //Word decrement
110                break;
111             case 2:
112                storeL(dmaD[channel], loadL(dmaS[channel]));
113                dmaS[channel] -= 4; //Long decrement
114                break;
115          }
116          break;
117 
118       case 4:	/* Fixed Address Mode */
119          switch(size)
120          {
121             case 0:
122                storeB(dmaD[channel], loadB(dmaS[channel]));
123                break;
124             case 1:
125                storeW(dmaD[channel], loadW(dmaS[channel]));
126                break;
127             case 2:
128                storeL(dmaD[channel], loadL(dmaS[channel]));
129                break;
130          }
131          break;
132 
133       case 5: /* Counter Mode */
134          dmaS[channel] ++;
135          break;
136    }
137 
138 	/* Perform common counter decrement,
139     * vector clearing, and interrupt handling.
140     */
141 
142 	dmaC[channel] --;
143 	if (dmaC[channel] == 0)
144 	{
145 		interrupt(14 + channel, 7);
146 		storeB(0x7C + channel, 0);
147 	}
148 }
149 
dmaStoreB(uint8_t cr,uint8_t data)150 void dmaStoreB(uint8_t cr, uint8_t data)
151 {
152 	switch(cr)
153    {
154       case 0x22:
155          dmaM[0] = data;
156          break;
157       case 0x26:
158          dmaM[1] = data;
159          break;
160       case 0x2A:
161          dmaM[2] = data;
162          break;
163       case 0x2E:
164          dmaM[3] = data;
165          break;
166    }
167 }
168 
dmaStoreW(uint8_t cr,uint16_t data)169 void dmaStoreW(uint8_t cr, uint16_t data)
170 {
171    switch(cr)
172    {
173       case 0x20:
174          dmaC[0] = data;
175          break;
176       case 0x24:
177          dmaC[1] = data;
178          break;
179       case 0x28:
180          dmaC[2] = data;
181          break;
182       case 0x2C:
183          dmaC[3] = data;
184          break;
185    }
186 }
187 
dmaStoreL(uint8_t cr,uint32_t data)188 void dmaStoreL(uint8_t cr, uint32_t data)
189 {
190    switch(cr)
191    {
192       case 0x00:
193          dmaS[0] = data;
194          break;
195       case 0x04:
196          dmaS[1] = data;
197          break;
198       case 0x08:
199          dmaS[2] = data;
200          break;
201       case 0x0C:
202          dmaS[3] = data;
203          break;
204       case 0x10:
205          dmaD[0] = data;
206          break;
207       case 0x14:
208          dmaD[1] = data;
209          break;
210       case 0x18:
211          dmaD[2] = data;
212          break;
213       case 0x1C:
214          dmaD[3] = data;
215          break;
216    }
217 }
218 
dmaLoadB(uint8_t cr)219 uint8_t dmaLoadB(uint8_t cr)
220 {
221 
222    switch(cr)
223    {
224       case 0x22:
225          return dmaM[0];
226       case 0x26:
227          return dmaM[1];
228       case 0x2A:
229          return dmaM[2];
230       case 0x2E:
231          return dmaM[3];
232    }
233 
234    return 0;
235 }
236 
dmaLoadW(uint8_t cr)237 uint16_t dmaLoadW(uint8_t cr)
238 {
239    switch(cr)
240    {
241       case 0x20:
242          return dmaC[0];
243       case 0x24:
244          return dmaC[1];
245       case 0x28:
246          return dmaC[2];
247       case 0x2C:
248          return dmaC[3];
249    }
250 
251    return 0;
252 }
253 
dmaLoadL(uint8_t cr)254 uint32_t dmaLoadL(uint8_t cr)
255 {
256    switch(cr)
257    {
258       case 0x00:
259          return dmaS[0];
260       case 0x04:
261          return dmaS[1];
262       case 0x08:
263          return dmaS[2];
264       case 0x0C:
265          return dmaS[3];
266       case 0x10:
267          return dmaD[0];
268       case 0x14:
269          return dmaD[1];
270       case 0x18:
271          return dmaD[2];
272       case 0x1C:
273          return dmaD[3];
274    }
275 
276    return 0;
277 }
278 
MDFNNGPCDMA_StateAction(void * data,int load,int data_only)279 int MDFNNGPCDMA_StateAction(void *data, int load, int data_only)
280 {
281    SFORMAT StateRegs[] =
282    {
283       { dmaS, (uint32_t)((4) * sizeof(uint32_t)), 0x40000000, "DMAS" },
284       { dmaD, (uint32_t)((4) * sizeof(uint32_t)), 0x40000000, "DMAD" },
285       { dmaC, (uint32_t)((4) * sizeof(uint16_t)), 0x20000000, "DMAC" },
286       { dmaM, (uint32_t)(4), 0, "DMAM" },
287       { 0, 0, 0, 0 }
288    };
289 
290    if(!MDFNSS_StateAction(data, load, data_only, StateRegs, "DMA", false))
291       return 0;
292 
293    return 1;
294 }
295