filename | src/sh4/sh4mem.c |
changeset | 100:995e42e96cc9 |
prev | 90:88e4872c2f58 |
next | 103:9b9cfc5855e0 |
author | nkeynes |
date | Wed Feb 15 13:11:50 2006 +0000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Split pvr2.c out to separate files for TA and renderer, minor renames change pvrdma to use mem_copy_to_sh4 |
view | annotate | diff | log | raw |
1 /**
2 * $Id: sh4mem.c,v 1.7 2006-02-15 13:11:50 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) )
57 extern struct mem_region mem_rgn[];
58 extern struct mmio_region *P4_io[];
60 int32_t sh4_read_p4( uint32_t addr )
61 {
62 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
63 if( !io ) {
64 ERROR( "Attempted read from unknown P4 region: %08X", addr );
65 return 0;
66 } else {
67 return io->io_read( addr&0xFFF );
68 }
69 }
71 void sh4_write_p4( uint32_t addr, int32_t val )
72 {
73 struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
74 if( !io ) {
75 if( (addr & 0xFC000000) == 0xE0000000 ) {
76 /* Store queue */
77 SH4_WRITE_STORE_QUEUE( addr, val );
78 } else if( (addr & 0xFF000000) != 0xF4000000 ) {
79 /* OC address cache isn't implemented, but don't complain about it.
80 * Complain about anything else though */
81 ERROR( "Attempted write to unknown P4 region: %08X", addr );
82 }
83 } else {
84 io->io_write( addr&0xFFF, val );
85 }
86 }
88 int32_t sh4_read_phys_word( uint32_t addr )
89 {
90 char *page;
91 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
92 return SIGNEXT16(sh4_read_p4( addr ));
94 if( (addr&0x1F800000) == 0x04000000 ) {
95 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
96 }
98 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
99 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
100 if( page == NULL ) {
101 ERROR( "Attempted word read to missing page: %08X",
102 addr );
103 return 0;
104 }
105 return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
106 } else {
107 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
108 }
109 }
111 int32_t sh4_read_long( uint32_t addr )
112 {
113 char *page;
115 CHECK_READ_WATCH(addr,4);
117 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
118 return sh4_read_p4( addr );
120 if( (addr&0x1F800000) == 0x04000000 ) {
121 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
122 }
124 if( IS_MMU_ENABLED() ) {
125 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
126 sh4_stop();
127 return 0;
128 }
130 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
131 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
132 int32_t val;
133 if( page == NULL ) {
134 ERROR( "Attempted long read to missing page: %08X", addr );
135 return 0;
136 }
137 val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
138 TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
139 return val;
140 } else {
141 return *(int32_t *)(page+(addr&0xFFF));
142 }
143 }
145 int32_t sh4_read_word( uint32_t addr )
146 {
147 char *page;
149 CHECK_READ_WATCH(addr,2);
151 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
152 return SIGNEXT16(sh4_read_p4( addr ));
154 if( (addr&0x1F800000) == 0x04000000 ) {
155 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
156 }
158 if( IS_MMU_ENABLED() ) {
159 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
160 sh4_stop();
161 return 0;
162 }
164 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
165 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
166 int32_t val;
167 if( page == NULL ) {
168 ERROR( "Attempted word read to missing page: %08X", addr );
169 return 0;
170 }
171 val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
172 TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
173 return val;
174 } else {
175 return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
176 }
177 }
179 int32_t sh4_read_byte( uint32_t addr )
180 {
181 char *page;
183 CHECK_READ_WATCH(addr,1);
185 if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
186 return SIGNEXT8(sh4_read_p4( addr ));
187 if( (addr&0x1F800000) == 0x04000000 ) {
188 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
189 }
191 if( IS_MMU_ENABLED() ) {
192 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
193 sh4_stop();
194 return 0;
195 }
197 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
198 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
199 int32_t val;
200 if( page == NULL ) {
201 ERROR( "Attempted byte read to missing page: %08X", addr );
202 return 0;
203 }
204 val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
205 TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
206 return val;
207 } else {
208 return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
209 }
210 }
212 void sh4_write_long( uint32_t addr, uint32_t val )
213 {
214 char *page;
216 CHECK_WRITE_WATCH(addr,4,val);
218 if( addr >= 0xE0000000 ) {
219 sh4_write_p4( addr, val );
220 return;
221 }
222 if( (addr&0x1F800000) == 0x04000000 ) {
223 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
224 }
226 if( IS_MMU_ENABLED() ) {
227 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
228 sh4_stop();
229 return;
230 }
231 if( (addr&0x1FFFFFFF) < 0x200000 ) {
232 ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
233 sh4_stop();
234 return;
235 }
236 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
237 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
238 if( page == NULL ) {
239 ERROR( "Long write to missing page: %08X => %08X", val, addr );
240 return;
241 }
242 TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
243 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
244 } else {
245 *(uint32_t *)(page+(addr&0xFFF)) = val;
246 }
247 }
249 void sh4_write_word( uint32_t addr, uint32_t val )
250 {
251 char *page;
253 CHECK_WRITE_WATCH(addr,2,val);
255 if( addr >= 0xE0000000 ) {
256 sh4_write_p4( addr, (int16_t)val );
257 return;
258 }
259 if( (addr&0x1F800000) == 0x04000000 ) {
260 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
261 }
262 if( IS_MMU_ENABLED() ) {
263 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
264 sh4_stop();
265 return;
266 }
267 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
268 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
269 if( page == NULL ) {
270 ERROR( "Attempted word write to missing page: %08X", addr );
271 return;
272 }
273 TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
274 io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
275 } else {
276 *(uint16_t *)(page+(addr&0xFFF)) = val;
277 }
278 }
280 void sh4_write_byte( uint32_t addr, uint32_t val )
281 {
282 char *page;
284 CHECK_WRITE_WATCH(addr,1,val);
286 if( addr >= 0xE0000000 ) {
287 sh4_write_p4( addr, (int8_t)val );
288 return;
289 }
290 if( (addr&0x1F800000) == 0x04000000 ) {
291 addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
292 }
294 if( IS_MMU_ENABLED() ) {
295 ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
296 sh4_stop();
297 return;
298 }
299 page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
300 if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
301 if( page == NULL ) {
302 ERROR( "Attempted byte write to missing page: %08X", addr );
303 return;
304 }
305 TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
306 io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
307 } else {
308 *(uint8_t *)(page+(addr&0xFFF)) = val;
309 }
310 }
314 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
315 * into the same memory black
316 */
317 void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
318 char *src = mem_get_region(srcaddr);
319 memcpy( dest, src, count );
320 }
322 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
323 if( destaddr >= 0x10000000 && destaddr < 0x20000000 ) {
324 pvr2_ta_write( src, count );
325 } else if( destaddr >= 04000000 && destaddr < 0x5000000 ) {
326 /* 64-bit video write. Oh. Yuck */
327 uint32_t *dest32[2];
328 uint32_t *src32 = (uint32_t *)src;
329 int flag = 0;
330 if( destaddr & 0x03 != 0 ) {
331 }
332 dest32[0] = (uint32_t *)mem_get_region(TRANSLATE_VIDEO_64BIT_ADDRESS(destaddr));
333 dest32[1] = (uint32_t *)mem_get_region(TRANSLATE_VIDEO_64BIT_ADDRESS(destaddr+4));
334 while( count >= 4 ) {
335 *dest32[flag]++ = *src32++;
336 flag = !flag;
337 count -=4;
338 }
339 if( count != 0 ) {
340 src = (char *)src32;
341 char *dest = dest32[flag];
342 do {
343 *dest++ = *src++;
344 count--;
345 } while( count > 0 );
346 }
347 } else {
348 char *dest = mem_get_region(destaddr);
349 if( dest == NULL )
350 ERROR( "Attempted block write to undefined region %08X", destaddr );
351 else
352 memcpy( dest, src, count );
353 }
354 }
.