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
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[];
69 int32_t sh4_read_p4( uint32_t addr )
71 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
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 );
80 int32_t val = io->io_read( addr&0xFFF );
81 TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
86 void sh4_write_p4( uint32_t addr, int32_t val )
88 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
90 if( (addr & 0xFC000000) == 0xE0000000 ) {
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 );
99 TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
100 io->io_write( addr&0xFFF, val );
104 int32_t sh4_read_phys_word( uint32_t addr )
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);
114 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
115 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
117 ERROR( "Attempted word read to missing page: %08X",
121 return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
123 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
127 int32_t sh4_read_long( uint32_t addr )
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);
143 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
144 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
147 ERROR( "Attempted long read to missing page: %08X", addr );
150 val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
151 TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
154 return *(int32_t *)(page+(addr&0xFFF));
158 int32_t sh4_read_word( uint32_t addr )
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);
174 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
175 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
178 ERROR( "Attempted word read to missing page: %08X", addr );
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 );
185 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
189 int32_t sh4_read_byte( uint32_t addr )
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);
205 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
206 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
209 ERROR( "Attempted byte read to missing page: %08X", addr );
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 );
216 // fprintf( stderr, "MOV.B %02X <= %08X\n",(uint32_t)*(uint8_t *)(page+(addr&0xFFF)), addr );
217 return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
221 void sh4_write_long( uint32_t addr, uint32_t val )
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 );
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);
241 if( (addr&0x1FFFFFFF) < 0x200000 ) {
242 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
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 */
252 if( (addr & 0x1F000000) >= 0x04000000 &&
253 (addr & 0x1F000000) < 0x07000000 )
255 ERROR( "Long write to missing page: %08X => %08X", val, addr );
258 TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
259 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
261 xlat_invalidate_long(addr);
262 *(uint32_t *)(page+(addr&0xFFF)) = val;
266 void sh4_write_word( uint32_t addr, uint32_t val )
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 );
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);
286 if( (addr&0x1FFFFFFF) < 0x200000 ) {
287 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
291 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
292 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
294 ERROR( "Attempted word write to missing page: %08X", addr );
297 TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
298 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
300 xlat_invalidate_word(addr);
301 *(uint16_t *)(page+(addr&0xFFF)) = val;
305 void sh4_write_byte( uint32_t addr, uint32_t val )
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 );
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);
325 if( (addr&0x1FFFFFFF) < 0x200000 ) {
326 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
330 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
331 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
333 ERROR( "Attempted byte write to missing page: %08X", addr );
336 TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
337 io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
339 xlat_invalidate_word(addr);
340 *(uint8_t *)(page+(addr&0xFFF)) = val;
346 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
347 * into the same memory block
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 );
353 char *src = mem_get_region(srcaddr);
355 ERROR( "Attempted block read from unknown address %08X", srcaddr );
357 memcpy( dest, src, count );
362 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
365 if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
366 pvr2_dma_write( destaddr, src, count );
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 );
374 char *dest = mem_get_region(destaddr);
376 ERROR( "Attempted block write to unknown address %08X", destaddr );
378 xlat_invalidate_block( destaddr, count );
379 memcpy( dest, src, count );
383 void sh4_flush_store_queue( uint32_t addr )
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 );
.