2 * $Id: sh4mem.c,v 1.25 2007-10-04 08:47:52 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
6 * Copyright (c) 2005 Nathan Keynes.
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.
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.
19 #define MODULE sh4_module
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 )
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 ); \
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 ); \
48 #define CHECK_READ_WATCH( addr, size )
49 #define CHECK_WRITE_WATCH( addr, size, val )
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) )
62 #define TRACE_IO( str, p, r, ... )
63 #define TRACE_P4IO( str, io, r, ... )
66 extern struct mem_region mem_rgn[];
67 extern struct mmio_region *P4_io[];
70 int32_t sh4_read_p4( uint32_t addr )
72 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
74 if( (addr & 0xFF000000) != 0xF4000000 ) {
75 /* OC address cache isn't implemented, but don't complain about it.
76 * Complain about anything else though */
77 ERROR( "Attempted read from unknown P4 region: %08X", addr );
81 int32_t val = io->io_read( addr&0xFFF );
82 TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
87 void sh4_write_p4( uint32_t addr, int32_t val )
89 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
91 if( (addr & 0xFC000000) == 0xE0000000 ) {
93 SH4_WRITE_STORE_QUEUE( addr, val );
94 } else if( (addr & 0xFF000000) != 0xF4000000 ) {
95 /* OC address cache isn't implemented, but don't complain about it.
96 * Complain about anything else though */
97 ERROR( "Attempted write to unknown P4 region: %08X", addr );
100 TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
101 io->io_write( addr&0xFFF, val );
105 int32_t sh4_read_phys_word( uint32_t addr )
108 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
109 return SIGNEXT16(sh4_read_p4( addr ));
111 if( (addr&0x1F800000) == 0x04000000 ) {
112 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
115 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
116 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
118 ERROR( "Attempted word read to missing page: %08X",
122 return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
124 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
128 int32_t sh4_read_long( uint32_t addr )
132 CHECK_READ_WATCH(addr,4);
134 if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
135 return sh4_read_p4( addr );
136 } else if( (addr&0x1C000000) == 0x0C000000 ) {
137 return *(int32_t *)(sh4_main_ram + (addr&0x00FFFFFF));
138 } else if( (addr&0x1F800000) == 0x04000000 ) {
139 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
140 pvr2_render_buffer_invalidate(addr, FALSE);
141 } else if( (addr&0x1F800000) == 0x05000000 ) {
142 pvr2_render_buffer_invalidate(addr, FALSE);
145 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
146 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
149 ERROR( "Attempted long read to missing page: %08X", addr );
152 val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
153 TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
156 return *(int32_t *)(page+(addr&0xFFF));
160 int32_t sh4_read_word( uint32_t addr )
164 CHECK_READ_WATCH(addr,2);
166 if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
167 return SIGNEXT16(sh4_read_p4( addr ));
168 } else if( (addr&0x1C000000) == 0x0C000000 ) {
169 return SIGNEXT16(*(int16_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
170 } else if( (addr&0x1F800000) == 0x04000000 ) {
171 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
172 pvr2_render_buffer_invalidate(addr, FALSE);
173 } else if( (addr&0x1F800000) == 0x05000000 ) {
174 pvr2_render_buffer_invalidate(addr, FALSE);
177 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
178 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
181 ERROR( "Attempted word read to missing page: %08X", addr );
184 val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
185 TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
188 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
192 int32_t sh4_read_byte( uint32_t addr )
196 CHECK_READ_WATCH(addr,1);
198 if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
199 return SIGNEXT8(sh4_read_p4( addr ));
200 } else if( (addr&0x1C000000) == 0x0C000000 ) {
201 return SIGNEXT8(*(int8_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
202 } else if( (addr&0x1F800000) == 0x04000000 ) {
203 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
204 pvr2_render_buffer_invalidate(addr, FALSE);
205 } else if( (addr&0x1F800000) == 0x05000000 ) {
206 pvr2_render_buffer_invalidate(addr, FALSE);
210 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
211 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
214 ERROR( "Attempted byte read to missing page: %08X", addr );
217 val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
218 TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
221 return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
225 void sh4_write_long( uint32_t addr, uint32_t val )
229 // fprintf( stderr, "MOV.L %08X => %08X\n", val, addr );
230 CHECK_WRITE_WATCH(addr,4,val);
232 if( addr >= 0xE0000000 ) {
233 sh4_write_p4( addr, val );
235 } else if( (addr&0x1C000000) == 0x0C000000 ) {
236 *(uint32_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
238 } else if( (addr&0x1F800000) == 0x04000000 ||
239 (addr&0x1F800000) == 0x11000000 ) {
240 texcache_invalidate_page(addr& 0x7FFFFF);
241 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
242 pvr2_render_buffer_invalidate(addr, TRUE);
243 } else if( (addr&0x1F800000) == 0x05000000 ) {
244 pvr2_render_buffer_invalidate(addr, TRUE);
247 if( (addr&0x1FFFFFFF) < 0x200000 ) {
248 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
252 if( (addr&0x1F800000) == 0x00800000 )
253 asic_g2_write_word();
255 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
256 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
258 if( (addr & 0x1F000000) >= 0x04000000 &&
259 (addr & 0x1F000000) < 0x07000000 )
261 ERROR( "Long write to missing page: %08X => %08X", val, addr );
264 TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
265 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
267 xlat_invalidate_long(addr);
268 *(uint32_t *)(page+(addr&0xFFF)) = val;
272 void sh4_write_word( uint32_t addr, uint32_t val )
276 // fprintf( stderr, "MOV.W %04X => %08X\n", val, addr );
277 CHECK_WRITE_WATCH(addr,2,val);
279 if( addr >= 0xE0000000 ) {
280 sh4_write_p4( addr, (int16_t)val );
282 } else if( (addr&0x1C000000) == 0x0C000000 ) {
283 *(uint16_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
285 } else if( (addr&0x1F800000) == 0x04000000 ||
286 (addr&0x1F800000) == 0x11000000 ) {
287 texcache_invalidate_page(addr& 0x7FFFFF);
288 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
289 pvr2_render_buffer_invalidate(addr, TRUE);
290 } else if( (addr&0x1F800000) == 0x05000000 ) {
291 pvr2_render_buffer_invalidate(addr, TRUE);
294 if( (addr&0x1FFFFFFF) < 0x200000 ) {
295 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
299 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
300 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
302 ERROR( "Attempted word write to missing page: %08X", addr );
305 TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
306 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
308 xlat_invalidate_word(addr);
309 *(uint16_t *)(page+(addr&0xFFF)) = val;
313 void sh4_write_byte( uint32_t addr, uint32_t val )
317 // fprintf( stderr, "MOV.B %02X => %08X\n", val, addr );
318 CHECK_WRITE_WATCH(addr,1,val);
320 if( addr >= 0xE0000000 ) {
321 sh4_write_p4( addr, (int8_t)val );
323 } else if( (addr&0x1C000000) == 0x0C000000 ) {
324 *(uint8_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
326 } else if( (addr&0x1F800000) == 0x04000000 ||
327 (addr&0x1F800000) == 0x11000000 ) {
328 texcache_invalidate_page(addr& 0x7FFFFF);
329 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
330 pvr2_render_buffer_invalidate(addr, TRUE);
331 } else if( (addr&0x1F800000) == 0x05000000 ) {
332 pvr2_render_buffer_invalidate(addr, TRUE);
335 if( (addr&0x1FFFFFFF) < 0x200000 ) {
336 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
340 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
341 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
343 ERROR( "Attempted byte write to missing page: %08X", addr );
346 TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
347 io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
349 xlat_invalidate_word(addr);
350 *(uint8_t *)(page+(addr&0xFFF)) = val;
356 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
357 * into the same memory block
359 void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
360 if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
361 pvr2_vram64_read( dest, srcaddr, count );
363 char *src = mem_get_region(srcaddr);
365 ERROR( "Attempted block read from unknown address %08X", srcaddr );
367 memcpy( dest, src, count );
372 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
375 if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
376 pvr2_dma_write( destaddr, src, count );
378 } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
379 pvr2_render_buffer_invalidate( destaddr, TRUE );
380 } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
381 pvr2_vram64_write( destaddr, src, count );
384 char *dest = mem_get_region(destaddr);
386 ERROR( "Attempted block write to unknown address %08X", destaddr );
388 xlat_invalidate_block( destaddr, count );
389 memcpy( dest, src, count );
393 void sh4_flush_store_queue( uint32_t addr )
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 );
.