filename | src/sh4/dmac.c |
changeset | 929:fd8cb0c82f5f |
prev | 736:a02d1475ccfd |
next | 975:007bf7eb944f |
author | nkeynes |
date | Sat Dec 27 02:18:17 2008 +0000 (15 years ago) |
branch | lxdream-mem |
permissions | -rw-r--r-- |
last change | Simplify xlat_lut slightly (cache now always initialized even if we're not translating, just for efficiency) |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * SH4 onboard DMA controller (DMAC) peripheral.
5 *
6 * Copyright (c) 2005 Nathan Keynes.
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.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18 #define MODULE sh4_module
20 #include "dream.h"
21 #include "mem.h"
22 #include "sh4/sh4core.h"
23 #include "sh4/sh4mmio.h"
24 #include "sh4/intc.h"
25 #include "sh4/dmac.h"
27 static int DMAC_xfer_size[8] = {8, 1, 2, 4, 32, 1, 1, 1};
29 /* Control flags */
30 #define CHCR_IE 0x04 /* Interrupt Enable */
31 #define CHCR_TE 0x02 /* Transfer End */
32 #define CHCR_DE 0x01 /* DMAC Enable */
34 #define IS_DMAC_ENABLED() ((MMIO_READ(DMAC,DMAOR)&0x07) == 0x01)
36 #define IS_AUTO_REQUEST(val) ((val & 0x0C00) == 0x0400)
37 #define CHANNEL_RESOURCE(val) ((val >> 8) & 0x0F)
39 #define DMA_SOURCE(chan) MMIO_READ(DMAC, SAR0 + (chan<<4))
40 #define DMA_DEST(chan) MMIO_READ(DMAC, DAR0 + (chan<<4))
41 #define DMA_COUNT(chan) (MMIO_READ(DMAC, DMATCR0 + (chan<<4)) & 0x00FFFFFF)
42 #define DMA_CONTROL(chan) MMIO_READ(DMAC, CHCR0 + (chan<<4))
43 #define IS_CHANNEL_ENABLED(ctrl) ((ctrl & 0x03) == 0x01)
44 #define IS_CHANNEL_IRQ_ENABLED(ctrl) (ctrl & CHCR_IE)
45 #define IS_CHANNEL_IRQ_ACTIVE(ctrl) ((ctrl & (CHCR_IE|CHCR_TE)) == (CHCR_IE|CHCR_TE))
47 #define DMARES_MEMORY_TO_MEMORY 0x00
48 #define DMARES_MEMORY_TO_DEVICE 0x02
49 #define DMARES_DEVICE_TO_MEMORY 0x03
50 #define DMARES_MEMORY_TO_MEMORY_AUTO 0x04
51 #define DMARES_MEMORY_TO_PERIPH_AUTO 0x05
52 #define DMARES_PERIPH_TO_MEMORY_AUTO 0x06
53 #define DMARES_SCI_TRANSMIT_EMPTY 0x08
54 #define DMARES_SCI_RECEIVE_FULL 0x09
55 #define DMARES_SCIF_TRANSMIT_EMPTY 0x0A
56 #define DMARES_SCIF_RECEIVE_FULL 0x0B
57 #define DMARES_MEMORY_TO_MEMORY_TMU 0x0C
58 #define DMARES_MEMORY_TO_PERIPH_TMU 0x0D
59 #define DMARES_PERIPH_TO_MEMORY_TMU 0x0E
61 void DMAC_set_control( uint32_t channel, uint32_t val )
62 {
63 uint32_t oldval = DMA_CONTROL(channel);
64 int resource;
65 MMIO_WRITE( DMAC, CHCR0 + (channel<<4), val );
67 /* If TE or IE are cleared, clear the interrupt request */
68 if( IS_CHANNEL_IRQ_ACTIVE(oldval) &&
69 !IS_CHANNEL_IRQ_ACTIVE(val) )
70 intc_clear_interrupt( INT_DMA_DMTE0+channel );
72 resource = CHANNEL_RESOURCE(val);
73 if( IS_CHANNEL_ENABLED(val) ) {
74 if( resource >= DMARES_MEMORY_TO_MEMORY_AUTO &&
75 resource < DMARES_SCI_TRANSMIT_EMPTY ) {
76 /* Autorun */
77 }
78 }
80 /* Everything else we don't need to care about until we actually try to
81 * run the channel
82 */
83 }
85 MMIO_REGION_READ_FN( DMAC, reg )
86 {
87 return MMIO_READ( DMAC, reg&0xFFF );
88 }
90 MMIO_REGION_WRITE_FN( DMAC, reg, val )
91 {
92 reg &= 0xFFF;
93 switch( reg ) {
94 case DMAOR:
95 MMIO_WRITE( DMAC, reg, val );
96 break;
97 case CHCR0: DMAC_set_control( 0, val ); break;
98 case CHCR1: DMAC_set_control( 1, val ); break;
99 case CHCR2: DMAC_set_control( 2, val ); break;
100 case CHCR3: DMAC_set_control( 3, val ); break;
101 default:
102 MMIO_WRITE( DMAC, reg, val );
103 }
104 }
106 /**
107 * Execute up to run_count transfers on the specified channel. Assumes the
108 * trigger for the channel has been received.
109 *
110 * @param channel Channel number (0-3) to run.
111 * @param run_count number of transfers to execute, or 0 to run to the
112 * end of the transfer count.
113 */
114 void DMAC_run_channel( uint32_t channel, uint32_t run_count )
115 {
117 #if 0 /* Should really finish this */
118 char burst[32]; /* Transfer burst */
119 uint32_t control = DMA_CONTROL(channel);
121 if( IS_CHANNEL_ENABLED(control) ) {
122 uint32_t source = DMA_SOURCE(channel);
123 uint32_t dest = DMA_DEST(channel);
124 uint32_t count = DMA_COUNT( channel );
125 if( count == 0 )
126 count = 0x01000000;
127 if( run_count == 0 || run_count > count )
128 run_count = count;
129 uint32_t xfersize = DMAC_xfer_size[ (control >> 4)&0x07 ];
130 int source_step, dest_step;
131 int resource = (control >> 8) & 0x0F;
132 switch( (control >> 14) & 0x03 ) {
133 case 0: dest_step = 0; break;
134 case 1: dest_step = xfersize; break;
135 case 2: dest_step = -xfersize; break;
136 case 3: dest_step = 0; break; /* Illegal */
137 }
138 switch( (control >> 12) & 0x03 ) {
139 case 0: source_step = 0; break;
140 case 1: source_step = xfersize; break;
141 case 2: source_step = -xfersize; break;
142 case 3: source_step = 0; break; /* Illegal */
143 }
145 while( run_count > 0 ) {
146 /* Origin */
147 if( (resource & 0x02) == 0 ) {
148 /* Source is a normal memory address */
150 } else {
151 /* Device */
152 }
154 /* Destination */
155 if( (resource & 0x01) == 0 ) {
156 /* Destination is a normal memory address */
157 } else {
158 }
159 run_count--;
160 count--;
161 }
162 }
163 #endif
164 }
166 /**
167 * Fetch a block of data by DMA from memory to an external device (ie the
168 * ASIC). The DMA channel must be configured for Mem=>dev or it will return
169 * no bytes and whinge mightily. Note this is NOT used for SH4 peripheral
170 * transfers.
171 *
172 * @return the number of bytes actually transferred.
173 */
174 uint32_t DMAC_get_buffer( int channel, sh4ptr_t buf, uint32_t numBytes )
175 {
176 uint32_t control = DMA_CONTROL(channel);
177 uint32_t source, count, run_count, size, i;
178 char tmp[32];
180 if( !IS_CHANNEL_ENABLED(control) || !IS_DMAC_ENABLED() )
181 return 0;
183 if( ((control >> 8) & 0x0F) != DMARES_MEMORY_TO_DEVICE ) {
184 /* Error? */
186 return 0;
187 }
189 source = DMA_SOURCE(channel);
190 count = DMA_COUNT(channel);
191 if( count == 0 ) count = 0x01000000;
193 size = DMAC_xfer_size[ (control >> 4)&0x07 ];
194 run_count = numBytes / size;
195 if( run_count > count || run_count == 0 )
196 run_count = count;
198 /* Do copy - FIXME: doesn't work when crossing regions */
199 sh4ptr_t region = mem_get_region( source );
200 switch( (control >> 12) & 0x03 ) {
201 case 0:
202 memcpy( tmp, region, size );
203 for( i=0; i<run_count; i++ ) {
204 memcpy( buf, tmp, size );
205 buf += size;
206 }
207 break;
208 case 1:
209 i = run_count * size;
210 memcpy( buf, region, i );
211 source += i;
212 break;
213 case 2:
214 for( i=0; i<run_count; i++ ) {
215 memcpy( buf, region, size );
216 buf += size;
217 region -= size;
218 }
219 source -= (run_count * size);
220 break;
221 default:
222 return 0; /* Illegal */
223 }
225 /* Update the channel registers */
226 count -= run_count;
227 MMIO_WRITE( DMAC, SAR0 + (channel<<4), source );
228 MMIO_WRITE( DMAC, DMATCR0 + (channel<<4), count );
229 if( count == 0 ) {
230 control |= CHCR_TE;
231 if( IS_CHANNEL_IRQ_ENABLED(control) )
232 intc_raise_interrupt( INT_DMA_DMTE0 + channel );
233 MMIO_WRITE( DMAC, CHCR0 + (channel<<4), control );
234 }
236 return run_count * size;
237 }
239 uint32_t DMAC_put_buffer( int channel, sh4ptr_t buf, uint32_t numBytes )
240 {
241 uint32_t control = DMA_CONTROL(channel);
242 uint32_t dest, count, run_count, size, i;
244 if( !IS_CHANNEL_ENABLED(control) || !IS_DMAC_ENABLED() )
245 return 0;
247 if( ((control >> 8) & 0x0F) != DMARES_DEVICE_TO_MEMORY ) {
248 /* Error? */
249 return 0;
250 }
252 dest = DMA_DEST(channel);
253 count = DMA_COUNT(channel);
254 if( count == 0 ) count = 0x01000000;
256 size = DMAC_xfer_size[ (control >> 4)&0x07 ];
257 run_count = numBytes / size;
258 if( run_count > count || run_count == 0 )
259 run_count = count;
261 /* Do copy - FIXME: doesn't work when crossing regions */
262 sh4ptr_t region = mem_get_region( dest );
263 switch( (control >> 12) & 0x03 ) {
264 case 0:
265 for( i=0; i<run_count; i++ ) {
266 /* Doesn't make a whole lot of sense, but hey... */
267 memcpy( region, buf, size );
268 buf += size;
269 }
270 break;
271 case 1:
272 i = run_count * size;
273 memcpy( region, buf, i );
274 dest += i;
275 break;
276 case 2:
277 for( i=0; i<run_count; i++ ) {
278 memcpy( region, buf, size );
279 buf += size;
280 region -= size;
281 }
282 dest -= (run_count * size);
283 break;
284 default:
285 return 0; /* Illegal */
286 }
288 /* Update the channel registers */
289 count -= run_count;
290 MMIO_WRITE( DMAC, DAR0 + (channel<<4), dest );
291 MMIO_WRITE( DMAC, DMATCR0 + (channel<<4), count );
292 if( count == 0 ) {
293 control |= CHCR_TE;
294 if( IS_CHANNEL_IRQ_ENABLED(control) )
295 intc_raise_interrupt( INT_DMA_DMTE0 + channel );
296 MMIO_WRITE( DMAC, CHCR0 + (channel<<4), control );
297 }
298 return run_count * size;
299 }
301 void DMAC_reset( void )
302 {
304 }
306 void DMAC_save_state( FILE *F )
307 {
309 }
311 int DMAC_load_state( FILE *f )
312 {
313 return 0;
314 }
316 void DMAC_trigger( int resource )
317 {
318 int i;
319 if( !IS_DMAC_ENABLED() )
320 return;
321 for( i=0; i<4; i++ ) {
322 uint32_t control = DMA_CONTROL(i);
323 if( IS_CHANNEL_ENABLED(control) ) {
324 uint32_t channel_res = CHANNEL_RESOURCE(control);
325 switch( resource ) {
326 case DMAC_EXTERNAL:
327 if( channel_res == DMARES_MEMORY_TO_MEMORY )
328 DMAC_run_channel(i,1);
329 break;
330 case DMAC_SCI_TDE:
331 if( channel_res == DMARES_SCI_TRANSMIT_EMPTY )
332 DMAC_run_channel(i,1);
333 break;
334 case DMAC_SCI_RDF:
335 if( channel_res == DMARES_SCI_RECEIVE_FULL )
336 DMAC_run_channel(i,1);
337 break;
338 case DMAC_SCIF_TDE:
339 if( channel_res == DMARES_SCIF_TRANSMIT_EMPTY )
340 DMAC_run_channel(i,1);
341 break;
342 case DMAC_SCIF_RDF:
343 if( channel_res == DMARES_SCIF_RECEIVE_FULL )
344 DMAC_run_channel(i,1);
345 break;
346 case DMAC_TMU_ICI:
347 if( channel_res >= DMARES_MEMORY_TO_MEMORY_TMU )
348 DMAC_run_channel(i,1);
349 break;
350 }
351 }
352 }
353 }
.