filename | src/sh4/dmac.c |
changeset | 929:fd8cb0c82f5f |
prev | 736:a02d1475ccfd |
next | 975:007bf7eb944f |
author | nkeynes |
date | Sat Dec 27 02:59:35 2008 +0000 (15 years ago) |
branch | lxdream-mem |
permissions | -rw-r--r-- |
last change | Replace fpscr_mask/fpscr flags in xlat_cache_block with a single xlat_sh4_mode, which tracks the field of the same name in sh4r - actually a little faster this way. Now depends on SR.MD, FPSCR.PR and FPSCR.SZ (although it doesn't benefit from the SR flag yet). Also fixed the failure to check the flags in the common case (code address returned by previous block) which took away the performance benefits, but oh well. |
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 }
.