filename | src/sh4/sh4mem.c |
changeset | 371:f2fe152cfc9b |
prev | 369:4b4223e7d720 |
next | 400:049d72a7a229 |
author | nkeynes |
date | Wed Sep 12 11:31:16 2007 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Fix load_spreg/store_spreg Fix PREF Add jump target debug checking |
view | annotate | diff | log | raw |
1 /**
2 * $Id: sh4mem.c,v 1.22 2007-09-08 04:38:11 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 #define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag && !MMIO_NOTRACE_BYNUM((uint32_t)p,r)) \
53 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
54 MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
55 MMIO_REGDESC_BYNUM((uint32_t)p, r) )
56 #define TRACE_P4IO( str, io, r, ... ) if(io->trace_flag && !MMIO_NOTRACE_IOBYNUM(io,r)) \
57 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
58 io->id, MMIO_REGID_IOBYNUM(io, r), \
59 MMIO_REGDESC_IOBYNUM(io, r) )
61 extern struct mem_region mem_rgn[];
62 extern struct mmio_region *P4_io[];
64 int32_t sh4_read_p4( uint32_t addr )
65 {
66 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
67 if( !io ) {
68 if( (addr & 0xFF000000) != 0xF4000000 ) {
69 /* OC address cache isn't implemented, but don't complain about it.
70 * Complain about anything else though */
71 ERROR( "Attempted read from unknown P4 region: %08X", addr );
72 }
73 return 0;
74 } else {
75 int32_t val = io->io_read( addr&0xFFF );
76 TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
77 return val;
78 }
79 }
81 void sh4_write_p4( uint32_t addr, int32_t val )
82 {
83 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
84 if( !io ) {
85 if( (addr & 0xFC000000) == 0xE0000000 ) {
86 /* Store queue */
87 SH4_WRITE_STORE_QUEUE( addr, val );
88 } else if( (addr & 0xFF000000) != 0xF4000000 ) {
89 /* OC address cache isn't implemented, but don't complain about it.
90 * Complain about anything else though */
91 ERROR( "Attempted write to unknown P4 region: %08X", addr );
92 }
93 } else {
94 TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
95 io->io_write( addr&0xFFF, val );
96 }
97 }
99 int32_t sh4_read_phys_word( uint32_t addr )
100 {
101 char *page;
102 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
103 return SIGNEXT16(sh4_read_p4( addr ));
105 if( (addr&0x1F800000) == 0x04000000 ) {
106 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
107 }
109 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
110 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
111 if( page == NULL ) {
112 ERROR( "Attempted word read to missing page: %08X",
113 addr );
114 return 0;
115 }
116 return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
117 } else {
118 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
119 }
120 }
122 int32_t sh4_read_long( uint32_t addr )
123 {
124 char *page;
126 CHECK_READ_WATCH(addr,4);
128 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
129 return sh4_read_p4( addr );
131 if( (addr&0x1F800000) == 0x04000000 ) {
132 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
133 pvr2_render_buffer_invalidate(addr, FALSE);
134 } else if( (addr&0x1F800000) == 0x05000000 ) {
135 pvr2_render_buffer_invalidate(addr, FALSE);
136 }
138 if( IS_MMU_ENABLED() ) {
139 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
140 sh4_stop();
141 return 0;
142 }
144 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
145 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
146 int32_t val;
147 if( page == NULL ) {
148 ERROR( "Attempted long read to missing page: %08X", addr );
149 return 0;
150 }
151 val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
152 TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
153 return val;
154 } else {
155 return *(int32_t *)(page+(addr&0xFFF));
156 }
157 }
159 int32_t sh4_read_word( uint32_t addr )
160 {
161 char *page;
163 CHECK_READ_WATCH(addr,2);
165 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
166 return SIGNEXT16(sh4_read_p4( addr ));
168 if( (addr&0x1F800000) == 0x04000000 ) {
169 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
170 pvr2_render_buffer_invalidate(addr, FALSE);
171 } else if( (addr&0x1F800000) == 0x05000000 ) {
172 pvr2_render_buffer_invalidate(addr, FALSE);
173 }
176 if( IS_MMU_ENABLED() ) {
177 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
178 sh4_stop();
179 return 0;
180 }
182 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
183 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
184 int32_t val;
185 if( page == NULL ) {
186 ERROR( "Attempted word read to missing page: %08X", addr );
187 return 0;
188 }
189 val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
190 TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
191 return val;
192 } else {
193 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
194 }
195 }
197 int32_t sh4_read_byte( uint32_t addr )
198 {
199 char *page;
201 CHECK_READ_WATCH(addr,1);
203 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
204 return SIGNEXT8(sh4_read_p4( addr ));
205 if( (addr&0x1F800000) == 0x04000000 ) {
206 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
207 pvr2_render_buffer_invalidate(addr, FALSE);
208 } else if( (addr&0x1F800000) == 0x05000000 ) {
209 pvr2_render_buffer_invalidate(addr, FALSE);
210 }
213 if( IS_MMU_ENABLED() ) {
214 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
215 sh4_stop();
216 return 0;
217 }
219 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
220 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
221 int32_t val;
222 if( page == NULL ) {
223 ERROR( "Attempted byte read to missing page: %08X", addr );
224 return 0;
225 }
226 val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
227 TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
228 return val;
229 } else {
230 return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
231 }
232 }
234 void sh4_write_long( uint32_t addr, uint32_t val )
235 {
236 char *page;
238 CHECK_WRITE_WATCH(addr,4,val);
240 if( addr >= 0xE0000000 ) {
241 sh4_write_p4( addr, val );
242 return;
243 }
244 if( (addr&0x1F800000) == 0x04000000 ||
245 (addr&0x1F800000) == 0x11000000 ) {
246 texcache_invalidate_page(addr& 0x7FFFFF);
247 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
248 pvr2_render_buffer_invalidate(addr, TRUE);
249 } else if( (addr&0x1F800000) == 0x05000000 ) {
250 pvr2_render_buffer_invalidate(addr, TRUE);
251 }
253 if( IS_MMU_ENABLED() ) {
254 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
255 sh4_stop();
256 return;
257 }
258 if( (addr&0x1FFFFFFF) < 0x200000 ) {
259 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
260 sh4_stop();
261 return;
262 }
263 if( (addr&0x1F800000) == 0x00800000 )
264 asic_g2_write_word();
266 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
267 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
268 if( page == NULL ) {
269 if( (addr & 0x1F000000) >= 0x04000000 &&
270 (addr & 0x1F000000) < 0x07000000 )
271 return;
272 ERROR( "Long write to missing page: %08X => %08X", val, addr );
273 return;
274 }
275 TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
276 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
277 } else {
278 *(uint32_t *)(page+(addr&0xFFF)) = val;
279 }
280 }
282 void sh4_write_word( uint32_t addr, uint32_t val )
283 {
284 char *page;
286 CHECK_WRITE_WATCH(addr,2,val);
288 if( addr >= 0xE0000000 ) {
289 sh4_write_p4( addr, (int16_t)val );
290 return;
291 }
292 if( (addr&0x1F800000) == 0x04000000 ||
293 (addr&0x1F800000) == 0x11000000 ) {
294 texcache_invalidate_page(addr& 0x7FFFFF);
295 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
296 pvr2_render_buffer_invalidate(addr, TRUE);
297 } else if( (addr&0x1F800000) == 0x05000000 ) {
298 pvr2_render_buffer_invalidate(addr, TRUE);
299 }
300 if( IS_MMU_ENABLED() ) {
301 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
302 sh4_stop();
303 return;
304 }
305 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
306 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
307 if( page == NULL ) {
308 ERROR( "Attempted word write to missing page: %08X", addr );
309 return;
310 }
311 TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
312 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
313 } else {
314 *(uint16_t *)(page+(addr&0xFFF)) = val;
315 }
316 }
318 void sh4_write_byte( uint32_t addr, uint32_t val )
319 {
320 char *page;
322 CHECK_WRITE_WATCH(addr,1,val);
324 if( addr >= 0xE0000000 ) {
325 sh4_write_p4( addr, (int8_t)val );
326 return;
327 }
328 if( (addr&0x1F800000) == 0x04000000 ||
329 (addr&0x1F800000) == 0x11000000 ) {
330 texcache_invalidate_page(addr& 0x7FFFFF);
331 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
332 pvr2_render_buffer_invalidate(addr, TRUE);
333 } else if( (addr&0x1F800000) == 0x05000000 ) {
334 pvr2_render_buffer_invalidate(addr, TRUE);
335 }
337 if( IS_MMU_ENABLED() ) {
338 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
339 sh4_stop();
340 return;
341 }
342 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
343 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
344 if( page == NULL ) {
345 ERROR( "Attempted byte write to missing page: %08X", addr );
346 return;
347 }
348 TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
349 io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
350 } else {
351 *(uint8_t *)(page+(addr&0xFFF)) = val;
352 }
353 }
357 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
358 * into the same memory black
359 */
360 void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
361 if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
362 pvr2_vram64_read( dest, srcaddr, count );
363 } else {
364 char *src = mem_get_region(srcaddr);
365 if( src == NULL ) {
366 ERROR( "Attempted block read from unknown address %08X", srcaddr );
367 } else {
368 memcpy( dest, src, count );
369 }
370 }
371 }
373 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
374 int region;
376 if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
377 pvr2_dma_write( destaddr, src, count );
378 return;
379 } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
380 pvr2_render_buffer_invalidate( destaddr, TRUE );
381 } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
382 pvr2_vram64_write( destaddr, src, count );
383 return;
384 }
385 char *dest = mem_get_region(destaddr);
386 if( dest == NULL )
387 ERROR( "Attempted block write to unknown address %08X", destaddr );
388 else {
389 memcpy( dest, src, count );
390 }
391 }
393 void sh4_flush_store_queue( uint32_t addr )
394 {
395 /* Store queue operation */
396 int queue = (addr&0x20)>>2;
397 char *src = (char *)&sh4r.store_queue[queue];
398 uint32_t hi = (MMIO_READ( MMU, (queue == 0 ? QACR0 : QACR1) ) & 0x1C) << 24;
399 uint32_t target = addr&0x03FFFFE0 | hi;
400 mem_copy_to_sh4( target, src, 32 );
401 }
.