filename | src/sh4/sh4mem.c |
changeset | 156:3b93648a3b07 |
prev | 150:c728a442b43f |
next | 165:126794f2ea6d |
author | nkeynes |
date | Thu Jun 15 10:25:45 2006 +0000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Add P4 I/O tracing Add ability to set I/O trace by region address |
view | annotate | diff | log | raw |
1 /**
2 * $Id: sh4mem.c,v 1.12 2006-06-15 10:25:45 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 )
50 #endif
52 #define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag) \
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) \
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 ERROR( "Attempted read from unknown P4 region: %08X", addr );
69 return 0;
70 } else {
71 int32_t val = io->io_read( addr&0xFFF );
72 TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
73 return val;
74 }
75 }
77 void sh4_write_p4( uint32_t addr, int32_t val )
78 {
79 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
80 if( !io ) {
81 if( (addr & 0xFC000000) == 0xE0000000 ) {
82 /* Store queue */
83 SH4_WRITE_STORE_QUEUE( addr, val );
84 } else if( (addr & 0xFF000000) != 0xF4000000 ) {
85 /* OC address cache isn't implemented, but don't complain about it.
86 * Complain about anything else though */
87 ERROR( "Attempted write to unknown P4 region: %08X", addr );
88 }
89 } else {
90 TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
91 io->io_write( addr&0xFFF, val );
92 }
93 }
95 int32_t sh4_read_phys_word( uint32_t addr )
96 {
97 char *page;
98 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
99 return SIGNEXT16(sh4_read_p4( addr ));
101 if( (addr&0x1F800000) == 0x04000000 ) {
102 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
103 }
105 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
106 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
107 if( page == NULL ) {
108 ERROR( "Attempted word read to missing page: %08X",
109 addr );
110 return 0;
111 }
112 return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
113 } else {
114 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
115 }
116 }
118 int32_t sh4_read_long( uint32_t addr )
119 {
120 char *page;
122 CHECK_READ_WATCH(addr,4);
124 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
125 return sh4_read_p4( addr );
127 if( (addr&0x1F800000) == 0x04000000 ) {
128 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
129 }
131 if( IS_MMU_ENABLED() ) {
132 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
133 sh4_stop();
134 return 0;
135 }
137 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
138 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
139 int32_t val;
140 if( page == NULL ) {
141 ERROR( "Attempted long read to missing page: %08X", addr );
142 return 0;
143 }
144 val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
145 TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
146 return val;
147 } else {
148 return *(int32_t *)(page+(addr&0xFFF));
149 }
150 }
152 int32_t sh4_read_word( uint32_t addr )
153 {
154 char *page;
156 CHECK_READ_WATCH(addr,2);
158 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
159 return SIGNEXT16(sh4_read_p4( addr ));
161 if( (addr&0x1F800000) == 0x04000000 ) {
162 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
163 }
165 if( IS_MMU_ENABLED() ) {
166 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
167 sh4_stop();
168 return 0;
169 }
171 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
172 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
173 int32_t val;
174 if( page == NULL ) {
175 ERROR( "Attempted word read to missing page: %08X", addr );
176 return 0;
177 }
178 val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
179 TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
180 return val;
181 } else {
182 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
183 }
184 }
186 int32_t sh4_read_byte( uint32_t addr )
187 {
188 char *page;
190 CHECK_READ_WATCH(addr,1);
192 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
193 return SIGNEXT8(sh4_read_p4( addr ));
194 if( (addr&0x1F800000) == 0x04000000 ) {
195 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
196 }
198 if( IS_MMU_ENABLED() ) {
199 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
200 sh4_stop();
201 return 0;
202 }
204 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
205 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
206 int32_t val;
207 if( page == NULL ) {
208 ERROR( "Attempted byte read to missing page: %08X", addr );
209 return 0;
210 }
211 val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
212 TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
213 return val;
214 } else {
215 return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
216 }
217 }
219 void sh4_write_long( uint32_t addr, uint32_t val )
220 {
221 char *page;
223 CHECK_WRITE_WATCH(addr,4,val);
225 if( addr >= 0xE0000000 ) {
226 sh4_write_p4( addr, val );
227 return;
228 }
229 if( (addr&0x1F800000) == 0x04000000 ||
230 (addr&0x1F800000) == 0x11000000 ) {
231 texcache_invalidate_page(addr& 0x7FFFFF);
232 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
233 }
235 if( IS_MMU_ENABLED() ) {
236 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
237 sh4_stop();
238 return;
239 }
240 if( (addr&0x1FFFFFFF) < 0x200000 ) {
241 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
242 sh4_stop();
243 return;
244 }
245 if( (addr&0x1F800000) == 0x00800000 )
246 asic_g2_write_word();
248 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
249 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
250 if( page == NULL ) {
251 if( (addr & 0x1F000000) >= 0x04000000 &&
252 (addr & 0x1F000000) < 0x07000000 )
253 return;
254 ERROR( "Long write to missing page: %08X => %08X", val, addr );
255 return;
256 }
257 TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
258 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
259 } else {
260 *(uint32_t *)(page+(addr&0xFFF)) = val;
261 }
262 }
264 void sh4_write_word( uint32_t addr, uint32_t val )
265 {
266 char *page;
268 CHECK_WRITE_WATCH(addr,2,val);
270 if( addr >= 0xE0000000 ) {
271 sh4_write_p4( addr, (int16_t)val );
272 return;
273 }
274 if( (addr&0x1F800000) == 0x04000000 ||
275 (addr&0x1F800000) == 0x11000000 ) {
276 texcache_invalidate_page(addr& 0x7FFFFF);
277 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
278 }
279 if( IS_MMU_ENABLED() ) {
280 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
281 sh4_stop();
282 return;
283 }
284 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
285 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
286 if( page == NULL ) {
287 ERROR( "Attempted word write to missing page: %08X", addr );
288 return;
289 }
290 TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
291 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
292 } else {
293 *(uint16_t *)(page+(addr&0xFFF)) = val;
294 }
295 }
297 void sh4_write_byte( uint32_t addr, uint32_t val )
298 {
299 char *page;
301 CHECK_WRITE_WATCH(addr,1,val);
303 if( addr >= 0xE0000000 ) {
304 sh4_write_p4( addr, (int8_t)val );
305 return;
306 }
307 if( (addr&0x1F800000) == 0x04000000 ||
308 (addr&0x1F800000) == 0x11000000 ) {
309 texcache_invalidate_page(addr& 0x7FFFFF);
310 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
311 }
313 if( IS_MMU_ENABLED() ) {
314 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
315 sh4_stop();
316 return;
317 }
318 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
319 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
320 if( page == NULL ) {
321 ERROR( "Attempted byte write to missing page: %08X", addr );
322 return;
323 }
324 TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
325 io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
326 } else {
327 *(uint8_t *)(page+(addr&0xFFF)) = val;
328 }
329 }
333 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
334 * into the same memory black
335 */
336 void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
337 if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
338 pvr2_vram64_read( dest, srcaddr, count );
339 } else {
340 char *src = mem_get_region(srcaddr);
341 if( src == NULL ) {
342 ERROR( "Attempted block read from unknown address %08X", srcaddr );
343 } else {
344 memcpy( dest, src, count );
345 }
346 }
347 }
349 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
350 if( destaddr >= 0x10000000 && destaddr < 0x11000000 ) {
351 pvr2_ta_write( src, count );
352 } else if( destaddr >= 0x04000000 && destaddr < 0x05000000 ||
353 destaddr >= 0x11000000 && destaddr < 0x12000000 ) {
354 pvr2_vram64_write( destaddr, src, count );
355 } else {
356 char *dest = mem_get_region(destaddr);
357 if( dest == NULL )
358 ERROR( "Attempted block write to unknown address %08X", destaddr );
359 else {
360 memcpy( dest, src, count );
361 }
362 }
363 }
.