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
20 #define ENABLE_TRACE_IO 1
27 #include "dreamcast.h"
28 #include "sh4/sh4core.h"
29 #include "sh4/sh4mmio.h"
30 #include "sh4/xltcache.h"
31 #include "pvr2/pvr2.h"
34 #define OC_BASE 0x1C000000
35 #define OC_TOP 0x20000000
37 #define TRANSLATE_VIDEO_64BIT_ADDRESS(a) ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 )
40 #define CHECK_READ_WATCH( addr, size ) \
41 if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
42 WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
45 #define CHECK_WRITE_WATCH( addr, size, val ) \
46 if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
47 WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
51 #define CHECK_READ_WATCH( addr, size )
52 #define CHECK_WRITE_WATCH( addr, size, val )
55 #ifdef ENABLE_TRACE_IO
56 #define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag && !MMIO_NOTRACE_BYNUM((uint32_t)p,r)) \
57 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
58 MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
59 MMIO_REGDESC_BYNUM((uint32_t)p, r) )
60 #define TRACE_P4IO( str, io, r, ... ) if(io->trace_flag && !MMIO_NOTRACE_IOBYNUM(io,r)) \
61 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
62 io->id, MMIO_REGID_IOBYNUM(io, r), \
63 MMIO_REGDESC_IOBYNUM(io, r) )
65 #define TRACE_IO( str, p, r, ... )
66 #define TRACE_P4IO( str, io, r, ... )
69 extern struct mem_region mem_rgn[];
70 extern struct mmio_region *P4_io[];
71 sh4ptr_t sh4_main_ram;
73 int32_t sh4_read_p4( sh4addr_t addr )
75 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
77 switch( addr & 0x1F000000 ) {
78 case 0x00000000: case 0x01000000: case 0x02000000: case 0x03000000:
79 /* Store queue - readable? */
82 case 0x10000000: return mmu_icache_addr_read( addr );
83 case 0x11000000: return mmu_icache_data_read( addr );
84 case 0x12000000: return mmu_itlb_addr_read( addr );
85 case 0x13000000: return mmu_itlb_data_read( addr );
86 case 0x14000000: return mmu_ocache_addr_read( addr );
87 case 0x15000000: return mmu_ocache_data_read( addr );
88 case 0x16000000: return mmu_utlb_addr_read( addr );
89 case 0x17000000: return mmu_utlb_data_read( addr );
91 WARN( "Attempted read from unknown or invalid P4 region: %08X", addr );
95 int32_t val = io->io_read( addr&0xFFF );
96 TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
101 void sh4_write_p4( sh4addr_t addr, int32_t val )
103 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
105 switch( addr & 0x1F000000 ) {
106 case 0x00000000: case 0x01000000: case 0x02000000: case 0x03000000:
108 SH4_WRITE_STORE_QUEUE( addr, val );
110 case 0x10000000: mmu_icache_addr_write( addr, val ); break;
111 case 0x11000000: mmu_icache_data_write( addr, val ); break;
112 case 0x12000000: mmu_itlb_addr_write( addr, val ); break;
113 case 0x13000000: mmu_itlb_data_write( addr, val ); break;
114 case 0x14000000: mmu_ocache_addr_write( addr, val ); break;
115 case 0x15000000: mmu_ocache_data_write( addr, val ); break;
116 case 0x16000000: mmu_utlb_addr_write( addr, val ); break;
117 case 0x17000000: mmu_utlb_data_write( addr, val ); break;
119 WARN( "Attempted write to unknown P4 region: %08X", addr );
122 TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
123 io->io_write( addr&0xFFF, val );
127 int32_t sh4_read_phys_word( sh4addr_t addr )
130 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
131 return SIGNEXT16(sh4_read_p4( addr ));
133 if( (addr&0x1F800000) == 0x04000000 ) {
134 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
137 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
138 if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
140 WARN( "Attempted word read to missing page: %08X",
144 return SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
146 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
151 * Convenience function to read a quad-word (implemented as two long reads).
153 int64_t sh4_read_quad( sh4addr_t addr )
155 return ((int64_t)((uint32_t)sh4_read_long(addr))) |
156 (((int64_t)((uint32_t)sh4_read_long(addr+4))) << 32);
159 int64_t sh4_read_long( sh4addr_t vma )
163 CHECK_READ_WATCH(addr,4);
165 uint64_t ppa = mmu_vma_to_phys_read(vma);
169 sh4addr_t addr = (sh4addr_t)ppa;
171 if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
172 return ZEROEXT32(sh4_read_p4( addr ));
173 } else if( (addr&0x1C000000) == 0x0C000000 ) {
174 return ZEROEXT32(*(int32_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
175 } else if( (addr&0x1F800000) == 0x04000000 ) {
176 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
177 pvr2_render_buffer_invalidate(addr, FALSE);
178 } else if( (addr&0x1F800000) == 0x05000000 ) {
179 pvr2_render_buffer_invalidate(addr, FALSE);
182 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
183 if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
186 WARN( "Attempted long read to missing page: %08X", addr );
189 val = io_rgn[(uintptr_t)page]->io_read(addr&0xFFF);
190 TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
191 return ZEROEXT32(val);
193 return ZEROEXT32(*(int32_t *)(page+(addr&0xFFF)));
197 int64_t sh4_read_word( sh4addr_t vma )
201 CHECK_READ_WATCH(addr,2);
203 uint64_t ppa = mmu_vma_to_phys_read(vma);
207 sh4addr_t addr = (sh4addr_t)ppa;
209 if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
210 return ZEROEXT32(SIGNEXT16(sh4_read_p4( addr )));
211 } else if( (addr&0x1C000000) == 0x0C000000 ) {
212 return ZEROEXT32(SIGNEXT16(*(int16_t *)(sh4_main_ram + (addr&0x00FFFFFF))));
213 } else if( (addr&0x1F800000) == 0x04000000 ) {
214 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
215 pvr2_render_buffer_invalidate(addr, FALSE);
216 } else if( (addr&0x1F800000) == 0x05000000 ) {
217 pvr2_render_buffer_invalidate(addr, FALSE);
220 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
221 if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
224 WARN( "Attempted word read to missing page: %08X", addr );
227 val = SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
228 TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
229 return ZEROEXT32(val);
231 return ZEROEXT32(SIGNEXT16(*(int16_t *)(page+(addr&0xFFF))));
235 int64_t sh4_read_byte( sh4addr_t vma )
239 CHECK_READ_WATCH(addr,1);
241 uint64_t ppa = mmu_vma_to_phys_read(vma);
245 sh4addr_t addr = (sh4addr_t)ppa;
247 if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
248 return ZEROEXT32(SIGNEXT8(sh4_read_p4( addr )));
249 } else if( (addr&0x1C000000) == 0x0C000000 ) {
250 return ZEROEXT32(SIGNEXT8(*(int8_t *)(sh4_main_ram + (addr&0x00FFFFFF))));
251 } else if( (addr&0x1F800000) == 0x04000000 ) {
252 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
253 pvr2_render_buffer_invalidate(addr, FALSE);
254 } else if( (addr&0x1F800000) == 0x05000000 ) {
255 pvr2_render_buffer_invalidate(addr, FALSE);
259 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
260 if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
263 WARN( "Attempted byte read to missing page: %08X", addr );
266 val = SIGNEXT8(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
267 TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
268 return ZEROEXT32(val);
270 return ZEROEXT32(SIGNEXT8(*(int8_t *)(page+(addr&0xFFF))));
275 * Convenience function to write a quad-word (implemented as two long writes).
277 void sh4_write_quad( sh4addr_t addr, uint64_t val )
279 sh4_write_long( addr, (uint32_t)val );
280 sh4_write_long( addr+4, (uint32_t)(val>>32) );
283 int32_t sh4_write_long( sh4addr_t vma, uint32_t val )
287 uint64_t ppa = mmu_vma_to_phys_write(vma);
291 sh4addr_t addr = (sh4addr_t)ppa;
293 CHECK_WRITE_WATCH(addr,4,val);
295 if( addr >= 0xE0000000 ) {
296 sh4_write_p4( addr, val );
298 } else if( (addr&0x1C000000) == 0x0C000000 ) {
299 *(uint32_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
300 xlat_invalidate_long(addr);
302 } else if( (addr&0x1F800000) == 0x04000000 ||
303 (addr&0x1F800000) == 0x11000000 ) {
304 texcache_invalidate_page(addr& 0x7FFFFF);
305 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
306 pvr2_render_buffer_invalidate(addr, TRUE);
307 } else if( (addr&0x1F800000) == 0x05000000 ) {
308 pvr2_render_buffer_invalidate(addr, TRUE);
311 if( (addr&0x1FFFFFFF) < 0x200000 ) {
312 WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
316 if( (addr&0x1F800000) == 0x00800000 )
317 asic_g2_write_word();
319 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
320 if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
322 if( (addr & 0x1F000000) >= 0x04000000 &&
323 (addr & 0x1F000000) < 0x07000000 )
325 WARN( "Long write to missing page: %08X => %08X", val, addr );
328 TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
329 io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
331 *(uint32_t *)(page+(addr&0xFFF)) = val;
336 int32_t sh4_write_word( sh4addr_t vma, uint32_t val )
340 uint64_t ppa = mmu_vma_to_phys_write(vma);
344 sh4addr_t addr = (sh4addr_t)ppa;
346 CHECK_WRITE_WATCH(addr,2,val);
348 if( addr >= 0xE0000000 ) {
349 sh4_write_p4( addr, (int16_t)val );
351 } else if( (addr&0x1C000000) == 0x0C000000 ) {
352 *(uint16_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
353 xlat_invalidate_word(addr);
355 } else if( (addr&0x1F800000) == 0x04000000 ||
356 (addr&0x1F800000) == 0x11000000 ) {
357 texcache_invalidate_page(addr& 0x7FFFFF);
358 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
359 pvr2_render_buffer_invalidate(addr, TRUE);
360 } else if( (addr&0x1F800000) == 0x05000000 ) {
361 pvr2_render_buffer_invalidate(addr, TRUE);
364 if( (addr&0x1FFFFFFF) < 0x200000 ) {
365 WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
369 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
370 if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
372 WARN( "Attempted word write to missing page: %08X", addr );
375 TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
376 io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
378 *(uint16_t *)(page+(addr&0xFFF)) = val;
383 int32_t sh4_write_byte( sh4addr_t vma, uint32_t val )
387 uint64_t ppa = mmu_vma_to_phys_write(vma);
391 sh4addr_t addr = (sh4addr_t)ppa;
393 CHECK_WRITE_WATCH(addr,1,val);
395 if( addr >= 0xE0000000 ) {
396 sh4_write_p4( addr, (int8_t)val );
398 } else if( (addr&0x1C000000) == 0x0C000000 ) {
399 *(uint8_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
400 xlat_invalidate_word(addr);
402 } else if( (addr&0x1F800000) == 0x04000000 ||
403 (addr&0x1F800000) == 0x11000000 ) {
404 texcache_invalidate_page(addr& 0x7FFFFF);
405 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
406 pvr2_render_buffer_invalidate(addr, TRUE);
407 } else if( (addr&0x1F800000) == 0x05000000 ) {
408 pvr2_render_buffer_invalidate(addr, TRUE);
411 if( (addr&0x1FFFFFFF) < 0x200000 ) {
412 WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
416 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
417 if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
419 WARN( "Attempted byte write to missing page: %08X", addr );
422 TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
423 io_rgn[(uintptr_t)page]->io_write( (addr&0xFFF), val);
425 *(uint8_t *)(page+(addr&0xFFF)) = val;
432 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
433 * into the same memory block
435 void mem_copy_from_sh4( sh4ptr_t dest, sh4addr_t srcaddr, size_t count ) {
436 if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
437 pvr2_vram64_read( dest, srcaddr, count );
439 sh4ptr_t src = mem_get_region(srcaddr);
441 WARN( "Attempted block read from unknown address %08X", srcaddr );
443 memcpy( dest, src, count );
448 void mem_copy_to_sh4( sh4addr_t destaddr, sh4ptr_t src, size_t count ) {
449 if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
450 pvr2_dma_write( destaddr, src, count );
452 } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
453 pvr2_render_buffer_invalidate( destaddr, TRUE );
454 } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
455 pvr2_vram64_write( destaddr, src, count );
458 sh4ptr_t dest = mem_get_region(destaddr);
460 WARN( "Attempted block write to unknown address %08X", destaddr );
462 xlat_invalidate_block( destaddr, count );
463 memcpy( dest, src, count );
467 void sh4_flush_store_queue( sh4addr_t addr )
469 /* Store queue operation */
470 int queue = (addr&0x20)>>2;
471 sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
472 uint32_t hi = (MMIO_READ( MMU, (queue == 0 ? QACR0 : QACR1) ) & 0x1C) << 24;
473 uint32_t target = (addr&0x03FFFFE0) | hi;
474 mem_copy_to_sh4( target, src, 32 );
477 sh4ptr_t sh4_get_region_by_vma( sh4addr_t vma )
479 uint64_t ppa = mmu_vma_to_phys_read(vma);
484 sh4addr_t addr = (sh4addr_t)ppa;
485 sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
486 if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
489 return page+(addr&0xFFF);
.