filename | src/sh4/sh4mem.c |
changeset | 406:9289b62f8f33 |
prev | 400:049d72a7a229 |
next | 418:b9b14afa0959 |
author | nkeynes |
date | Thu Oct 04 08:47:27 2007 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Suppress redundant T flag loads Tweak run_slice for performance |
view | annotate | diff | log | raw |
1 /**
2 * $Id: sh4mem.c,v 1.24 2007-09-28 07:25:22 nkeynes Exp $
3 * sh4mem.c is responsible for the SH4's access to memory (including memory
4 * mapped I/O), using the page maps created in mem.c
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 */
19 #define MODULE sh4_module
21 #include <string.h>
22 #include <zlib.h>
23 #include "dream.h"
24 #include "mem.h"
25 #include "mmio.h"
26 #include "sh4core.h"
27 #include "sh4mmio.h"
28 #include "dreamcast.h"
29 #include "pvr2/pvr2.h"
31 #define OC_BASE 0x1C000000
32 #define OC_TOP 0x20000000
34 #define TRANSLATE_VIDEO_64BIT_ADDRESS(a) ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 )
36 #ifdef ENABLE_WATCH
37 #define CHECK_READ_WATCH( addr, size ) \
38 if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
39 WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
40 dreamcast_stop(); \
41 }
42 #define CHECK_WRITE_WATCH( addr, size, val ) \
43 if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
44 WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
45 dreamcast_stop(); \
46 }
47 #else
48 #define CHECK_READ_WATCH( addr, size )
49 #define CHECK_WRITE_WATCH( addr, size, val )
50 #endif
52 #ifdef ENABLE_TRACE_IO
53 #define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag && !MMIO_NOTRACE_BYNUM((uint32_t)p,r)) \
54 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
55 MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
56 MMIO_REGDESC_BYNUM((uint32_t)p, r) )
57 #define TRACE_P4IO( str, io, r, ... ) if(io->trace_flag && !MMIO_NOTRACE_IOBYNUM(io,r)) \
58 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
59 io->id, MMIO_REGID_IOBYNUM(io, r), \
60 MMIO_REGDESC_IOBYNUM(io, r) )
61 #else
62 #define TRACE_IO( str, p, r, ... )
63 #define TRACE_P4IO( str, io, r, ... )
64 #endif
66 extern struct mem_region mem_rgn[];
67 extern struct mmio_region *P4_io[];
69 int32_t sh4_read_p4( uint32_t addr )
70 {
71 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
72 if( !io ) {
73 if( (addr & 0xFF000000) != 0xF4000000 ) {
74 /* OC address cache isn't implemented, but don't complain about it.
75 * Complain about anything else though */
76 ERROR( "Attempted read from unknown P4 region: %08X", addr );
77 }
78 return 0;
79 } else {
80 int32_t val = io->io_read( addr&0xFFF );
81 TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
82 return val;
83 }
84 }
86 void sh4_write_p4( uint32_t addr, int32_t val )
87 {
88 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
89 if( !io ) {
90 if( (addr & 0xFC000000) == 0xE0000000 ) {
91 /* Store queue */
92 SH4_WRITE_STORE_QUEUE( addr, val );
93 } else if( (addr & 0xFF000000) != 0xF4000000 ) {
94 /* OC address cache isn't implemented, but don't complain about it.
95 * Complain about anything else though */
96 ERROR( "Attempted write to unknown P4 region: %08X", addr );
97 }
98 } else {
99 TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
100 io->io_write( addr&0xFFF, val );
101 }
102 }
104 int32_t sh4_read_phys_word( uint32_t addr )
105 {
106 char *page;
107 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
108 return SIGNEXT16(sh4_read_p4( addr ));
110 if( (addr&0x1F800000) == 0x04000000 ) {
111 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
112 }
114 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
115 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
116 if( page == NULL ) {
117 ERROR( "Attempted word read to missing page: %08X",
118 addr );
119 return 0;
120 }
121 return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
122 } else {
123 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
124 }
125 }
127 int32_t sh4_read_long( uint32_t addr )
128 {
129 char *page;
131 CHECK_READ_WATCH(addr,4);
133 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
134 return sh4_read_p4( addr );
136 if( (addr&0x1F800000) == 0x04000000 ) {
137 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
138 pvr2_render_buffer_invalidate(addr, FALSE);
139 } else if( (addr&0x1F800000) == 0x05000000 ) {
140 pvr2_render_buffer_invalidate(addr, FALSE);
141 }
143 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
144 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
145 int32_t val;
146 if( page == NULL ) {
147 ERROR( "Attempted long read to missing page: %08X", addr );
148 return 0;
149 }
150 val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
151 TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
152 return val;
153 } else {
154 return *(int32_t *)(page+(addr&0xFFF));
155 }
156 }
158 int32_t sh4_read_word( uint32_t addr )
159 {
160 char *page;
162 CHECK_READ_WATCH(addr,2);
164 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
165 return SIGNEXT16(sh4_read_p4( addr ));
167 if( (addr&0x1F800000) == 0x04000000 ) {
168 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
169 pvr2_render_buffer_invalidate(addr, FALSE);
170 } else if( (addr&0x1F800000) == 0x05000000 ) {
171 pvr2_render_buffer_invalidate(addr, FALSE);
172 }
174 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
175 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
176 int32_t val;
177 if( page == NULL ) {
178 ERROR( "Attempted word read to missing page: %08X", addr );
179 return 0;
180 }
181 val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
182 TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
183 return val;
184 } else {
185 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
186 }
187 }
189 int32_t sh4_read_byte( uint32_t addr )
190 {
191 char *page;
193 CHECK_READ_WATCH(addr,1);
195 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
196 return SIGNEXT8(sh4_read_p4( addr ));
197 if( (addr&0x1F800000) == 0x04000000 ) {
198 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
199 pvr2_render_buffer_invalidate(addr, FALSE);
200 } else if( (addr&0x1F800000) == 0x05000000 ) {
201 pvr2_render_buffer_invalidate(addr, FALSE);
202 }
205 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
206 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
207 int32_t val;
208 if( page == NULL ) {
209 ERROR( "Attempted byte read to missing page: %08X", addr );
210 return 0;
211 }
212 val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
213 TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
214 return val;
215 } else {
216 // fprintf( stderr, "MOV.B %02X <= %08X\n",(uint32_t)*(uint8_t *)(page+(addr&0xFFF)), addr );
217 return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
218 }
219 }
221 void sh4_write_long( uint32_t addr, uint32_t val )
222 {
223 char *page;
225 // fprintf( stderr, "MOV.L %08X => %08X\n", val, addr );
226 CHECK_WRITE_WATCH(addr,4,val);
228 if( addr >= 0xE0000000 ) {
229 sh4_write_p4( addr, val );
230 return;
231 }
232 if( (addr&0x1F800000) == 0x04000000 ||
233 (addr&0x1F800000) == 0x11000000 ) {
234 texcache_invalidate_page(addr& 0x7FFFFF);
235 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
236 pvr2_render_buffer_invalidate(addr, TRUE);
237 } else if( (addr&0x1F800000) == 0x05000000 ) {
238 pvr2_render_buffer_invalidate(addr, TRUE);
239 }
241 if( (addr&0x1FFFFFFF) < 0x200000 ) {
242 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
243 sh4_stop();
244 return;
245 }
246 if( (addr&0x1F800000) == 0x00800000 )
247 asic_g2_write_word();
249 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
250 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
251 if( page == NULL ) {
252 if( (addr & 0x1F000000) >= 0x04000000 &&
253 (addr & 0x1F000000) < 0x07000000 )
254 return;
255 ERROR( "Long write to missing page: %08X => %08X", val, addr );
256 return;
257 }
258 TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
259 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
260 } else {
261 xlat_invalidate_long(addr);
262 *(uint32_t *)(page+(addr&0xFFF)) = val;
263 }
264 }
266 void sh4_write_word( uint32_t addr, uint32_t val )
267 {
268 char *page;
270 // fprintf( stderr, "MOV.W %04X => %08X\n", val, addr );
271 CHECK_WRITE_WATCH(addr,2,val);
273 if( addr >= 0xE0000000 ) {
274 sh4_write_p4( addr, (int16_t)val );
275 return;
276 }
277 if( (addr&0x1F800000) == 0x04000000 ||
278 (addr&0x1F800000) == 0x11000000 ) {
279 texcache_invalidate_page(addr& 0x7FFFFF);
280 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
281 pvr2_render_buffer_invalidate(addr, TRUE);
282 } else if( (addr&0x1F800000) == 0x05000000 ) {
283 pvr2_render_buffer_invalidate(addr, TRUE);
284 }
286 if( (addr&0x1FFFFFFF) < 0x200000 ) {
287 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
288 sh4_stop();
289 return;
290 }
291 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
292 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
293 if( page == NULL ) {
294 ERROR( "Attempted word write to missing page: %08X", addr );
295 return;
296 }
297 TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
298 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
299 } else {
300 xlat_invalidate_word(addr);
301 *(uint16_t *)(page+(addr&0xFFF)) = val;
302 }
303 }
305 void sh4_write_byte( uint32_t addr, uint32_t val )
306 {
307 char *page;
309 // fprintf( stderr, "MOV.B %02X => %08X\n", val, addr );
310 CHECK_WRITE_WATCH(addr,1,val);
312 if( addr >= 0xE0000000 ) {
313 sh4_write_p4( addr, (int8_t)val );
314 return;
315 }
316 if( (addr&0x1F800000) == 0x04000000 ||
317 (addr&0x1F800000) == 0x11000000 ) {
318 texcache_invalidate_page(addr& 0x7FFFFF);
319 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
320 pvr2_render_buffer_invalidate(addr, TRUE);
321 } else if( (addr&0x1F800000) == 0x05000000 ) {
322 pvr2_render_buffer_invalidate(addr, TRUE);
323 }
325 if( (addr&0x1FFFFFFF) < 0x200000 ) {
326 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
327 sh4_stop();
328 return;
329 }
330 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
331 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
332 if( page == NULL ) {
333 ERROR( "Attempted byte write to missing page: %08X", addr );
334 return;
335 }
336 TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
337 io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
338 } else {
339 xlat_invalidate_word(addr);
340 *(uint8_t *)(page+(addr&0xFFF)) = val;
341 }
342 }
346 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
347 * into the same memory block
348 */
349 void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
350 if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
351 pvr2_vram64_read( dest, srcaddr, count );
352 } else {
353 char *src = mem_get_region(srcaddr);
354 if( src == NULL ) {
355 ERROR( "Attempted block read from unknown address %08X", srcaddr );
356 } else {
357 memcpy( dest, src, count );
358 }
359 }
360 }
362 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
363 int region;
365 if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
366 pvr2_dma_write( destaddr, src, count );
367 return;
368 } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
369 pvr2_render_buffer_invalidate( destaddr, TRUE );
370 } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
371 pvr2_vram64_write( destaddr, src, count );
372 return;
373 }
374 char *dest = mem_get_region(destaddr);
375 if( dest == NULL )
376 ERROR( "Attempted block write to unknown address %08X", destaddr );
377 else {
378 xlat_invalidate_block( destaddr, count );
379 memcpy( dest, src, count );
380 }
381 }
383 void sh4_flush_store_queue( uint32_t addr )
384 {
385 /* Store queue operation */
386 int queue = (addr&0x20)>>2;
387 char *src = (char *)&sh4r.store_queue[queue];
388 uint32_t hi = (MMIO_READ( MMU, (queue == 0 ? QACR0 : QACR1) ) & 0x1C) << 24;
389 uint32_t target = addr&0x03FFFFE0 | hi;
390 mem_copy_to_sh4( target, src, 32 );
391 }
.