filename | src/sh4/sh4mem.c |
changeset | 934:3acd3b3ee6d1 |
prev | 933:880c37bb1909 |
next | 939:6f2302afeb89 |
author | nkeynes |
date | Fri Dec 26 14:25:23 2008 +0000 (14 years ago) |
branch | lxdream-mem |
permissions | -rw-r--r-- |
last change | Change RAM regions to use static arrays rather than mmap regions, for a 2-3% performance gain. General mem cleanups, including some save state fixes that break states again. |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 * sh4mem.c is responsible for interfacing between the SH4's internal memory
4 *
5 * Copyright (c) 2005 Nathan Keynes.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
18 #define MODULE sh4_module
20 #include <string.h>
21 #include <zlib.h>
22 #include "dream.h"
23 #include "mem.h"
24 #include "mmio.h"
25 #include "dreamcast.h"
26 #include "sh4/sh4core.h"
27 #include "sh4/sh4mmio.h"
28 #include "sh4/xltcache.h"
29 #include "pvr2/pvr2.h"
31 /* System regions (probably should be defined elsewhere) */
32 extern struct mem_region_fn mem_region_unmapped;
33 extern struct mem_region_fn mem_region_sdram;
34 extern struct mem_region_fn mem_region_vram32;
35 extern struct mem_region_fn mem_region_vram64;
36 extern struct mem_region_fn mem_region_audioram;
37 extern struct mem_region_fn mem_region_flashram;
38 extern struct mem_region_fn mem_region_bootrom;
40 /* On-chip regions other than defined MMIO regions */
41 extern struct mem_region_fn p4_region_storequeue;
42 extern struct mem_region_fn p4_region_icache_addr;
43 extern struct mem_region_fn p4_region_icache_data;
44 extern struct mem_region_fn p4_region_ocache_addr;
45 extern struct mem_region_fn p4_region_ocache_data;
46 extern struct mem_region_fn p4_region_itlb_addr;
47 extern struct mem_region_fn p4_region_itlb_data;
48 extern struct mem_region_fn p4_region_utlb_addr;
49 extern struct mem_region_fn p4_region_utlb_data;
51 /********************* The main ram address space **********************/
52 static int32_t FASTCALL ext_sdram_read_long( sh4addr_t addr )
53 {
54 return *((int32_t *)(dc_main_ram + (addr&0x00FFFFFF)));
55 }
56 static int32_t FASTCALL ext_sdram_read_word( sh4addr_t addr )
57 {
58 return SIGNEXT16(*((int16_t *)(dc_main_ram + (addr&0x00FFFFFF))));
59 }
60 static int32_t FASTCALL ext_sdram_read_byte( sh4addr_t addr )
61 {
62 return SIGNEXT8(*((int16_t *)(dc_main_ram + (addr&0x00FFFFFF))));
63 }
64 static void FASTCALL ext_sdram_write_long( sh4addr_t addr, uint32_t val )
65 {
66 *(uint32_t *)(dc_main_ram + (addr&0x00FFFFFF)) = val;
67 xlat_invalidate_long(addr);
68 }
69 static void FASTCALL ext_sdram_write_word( sh4addr_t addr, uint32_t val )
70 {
71 *(uint16_t *)(dc_main_ram + (addr&0x00FFFFFF)) = (uint16_t)val;
72 xlat_invalidate_word(addr);
73 }
74 static void FASTCALL ext_sdram_write_byte( sh4addr_t addr, uint32_t val )
75 {
76 *(uint8_t *)(dc_main_ram + (addr&0x00FFFFFF)) = (uint8_t)val;
77 xlat_invalidate_word(addr);
78 }
79 static void FASTCALL ext_sdram_read_burst( unsigned char *dest, sh4addr_t addr )
80 {
81 memcpy( dest, dc_main_ram+(addr&0x00FFFFFF), 32 );
82 }
83 static void FASTCALL ext_sdram_write_burst( sh4addr_t addr, unsigned char *src )
84 {
85 memcpy( dc_main_ram+(addr&0x00FFFFFF), src, 32 );
86 }
88 struct mem_region_fn mem_region_sdram = { ext_sdram_read_long, ext_sdram_write_long,
89 ext_sdram_read_word, ext_sdram_write_word,
90 ext_sdram_read_byte, ext_sdram_write_byte,
91 ext_sdram_read_burst, ext_sdram_write_burst };
94 /***************************** P4 Regions ************************************/
96 /* Store-queue (long-write only?) */
97 static void FASTCALL p4_storequeue_write_long( sh4addr_t addr, uint32_t val )
98 {
99 sh4r.store_queue[(addr>>2)&0xF] = val;
100 }
101 static int32_t FASTCALL p4_storequeue_read_long( sh4addr_t addr )
102 {
103 return sh4r.store_queue[(addr>>2)&0xF];
104 }
106 struct mem_region_fn p4_region_storequeue = {
107 p4_storequeue_read_long, p4_storequeue_write_long,
108 p4_storequeue_read_long, p4_storequeue_write_long,
109 p4_storequeue_read_long, p4_storequeue_write_long,
110 unmapped_read_burst, unmapped_write_burst }; // No burst access.
112 /* TLB access */
113 struct mem_region_fn p4_region_itlb_addr = {
114 mmu_itlb_addr_read, mmu_itlb_addr_write,
115 mmu_itlb_addr_read, mmu_itlb_addr_write,
116 mmu_itlb_addr_read, mmu_itlb_addr_write,
117 unmapped_read_burst, unmapped_write_burst };
118 struct mem_region_fn p4_region_itlb_data = {
119 mmu_itlb_data_read, mmu_itlb_data_write,
120 mmu_itlb_data_read, mmu_itlb_data_write,
121 mmu_itlb_data_read, mmu_itlb_data_write,
122 unmapped_read_burst, unmapped_write_burst };
123 struct mem_region_fn p4_region_utlb_addr = {
124 mmu_utlb_addr_read, mmu_utlb_addr_write,
125 mmu_utlb_addr_read, mmu_utlb_addr_write,
126 mmu_utlb_addr_read, mmu_utlb_addr_write,
127 unmapped_read_burst, unmapped_write_burst };
128 struct mem_region_fn p4_region_utlb_data = {
129 mmu_utlb_data_read, mmu_utlb_data_write,
130 mmu_utlb_data_read, mmu_utlb_data_write,
131 mmu_utlb_data_read, mmu_utlb_data_write,
132 unmapped_read_burst, unmapped_write_burst };
134 /********************** Initialization *************************/
136 mem_region_fn_t *sh4_address_space;
138 static void sh4_register_mem_region( uint32_t start, uint32_t end, mem_region_fn_t fn )
139 {
140 int count = (end - start) >> 12;
141 mem_region_fn_t *ptr = &sh4_address_space[start>>12];
142 while( count-- > 0 ) {
143 *ptr++ = fn;
144 }
145 }
147 static gboolean sh4_ext_page_remapped( sh4addr_t page, mem_region_fn_t fn, void *user_data )
148 {
149 int i;
150 for( i=0; i<= 0xC0000000; i+= 0x20000000 ) {
151 sh4_address_space[(page|i)>>12] = fn;
152 }
153 }
156 void sh4_mem_init()
157 {
158 int i;
159 mem_region_fn_t *ptr;
160 sh4_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
161 for( i=0, ptr = sh4_address_space; i<7; i++, ptr += LXDREAM_PAGE_TABLE_ENTRIES ) {
162 memcpy( ptr, ext_address_space, sizeof(mem_region_fn_t) * LXDREAM_PAGE_TABLE_ENTRIES );
163 }
165 /* Setup main P4 regions */
166 sh4_register_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue );
167 sh4_register_mem_region( 0xE4000000, 0xF0000000, &mem_region_unmapped );
168 sh4_register_mem_region( 0xF0000000, 0xF1000000, &p4_region_icache_addr );
169 sh4_register_mem_region( 0xF1000000, 0xF2000000, &p4_region_icache_data );
170 sh4_register_mem_region( 0xF2000000, 0xF3000000, &p4_region_itlb_addr );
171 sh4_register_mem_region( 0xF3000000, 0xF4000000, &p4_region_itlb_data );
172 sh4_register_mem_region( 0xF4000000, 0xF5000000, &p4_region_ocache_addr );
173 sh4_register_mem_region( 0xF5000000, 0xF6000000, &p4_region_ocache_data );
174 sh4_register_mem_region( 0xF6000000, 0xF7000000, &p4_region_utlb_addr );
175 sh4_register_mem_region( 0xF7000000, 0xF8000000, &p4_region_utlb_data );
176 sh4_register_mem_region( 0xF8000000, 0x00000000, &mem_region_unmapped );
178 /* Setup P4 control region */
179 sh4_register_mem_region( 0xFF000000, 0xFF001000, &mmio_region_MMU.fn );
180 sh4_register_mem_region( 0xFF100000, 0xFF101000, &mmio_region_PMM.fn );
181 sh4_register_mem_region( 0xFF200000, 0xFF201000, &mmio_region_UBC.fn );
182 sh4_register_mem_region( 0xFF800000, 0xFF801000, &mmio_region_BSC.fn );
183 sh4_register_mem_region( 0xFF900000, 0xFFA00000, &mem_region_unmapped ); // SDMR2 + SDMR3
184 sh4_register_mem_region( 0xFFA00000, 0xFFA01000, &mmio_region_DMAC.fn );
185 sh4_register_mem_region( 0xFFC00000, 0xFFC01000, &mmio_region_CPG.fn );
186 sh4_register_mem_region( 0xFFC80000, 0xFFC81000, &mmio_region_RTC.fn );
187 sh4_register_mem_region( 0xFFD00000, 0xFFD01000, &mmio_region_INTC.fn );
188 sh4_register_mem_region( 0xFFD80000, 0xFFD81000, &mmio_region_TMU.fn );
189 sh4_register_mem_region( 0xFFE00000, 0xFFE01000, &mmio_region_SCI.fn );
190 sh4_register_mem_region( 0xFFE80000, 0xFFE81000, &mmio_region_SCIF.fn );
191 sh4_register_mem_region( 0xFFF00000, 0xFFF01000, &mem_region_unmapped ); // H-UDI
193 register_mem_page_remapped_hook( sh4_ext_page_remapped, NULL );
194 }
196 /************** Access methods ***************/
197 #ifdef HAVE_FRAME_ADDRESS
198 #define RETURN_VIA(exc) do{ *(((void **)__builtin_frame_address(0))+1) = exc; return; } while(0)
199 #else
200 #define RETURN_VIA(exc) return NULL
201 #endif
204 int32_t FASTCALL sh4_read_long( sh4addr_t addr )
205 {
206 return sh4_address_space[addr>>12]->read_long(addr);
207 }
209 int32_t FASTCALL sh4_read_word( sh4addr_t addr )
210 {
211 return sh4_address_space[addr>>12]->read_word(addr);
212 }
214 int32_t FASTCALL sh4_read_byte( sh4addr_t addr )
215 {
216 return sh4_address_space[addr>>12]->read_byte(addr);
217 }
219 void FASTCALL sh4_write_long( sh4addr_t addr, uint32_t val )
220 {
221 sh4_address_space[addr>>12]->write_long(addr, val);
222 }
224 void FASTCALL sh4_write_word( sh4addr_t addr, uint32_t val )
225 {
226 sh4_address_space[addr>>12]->write_word(addr,val);
227 }
229 void FASTCALL sh4_write_byte( sh4addr_t addr, uint32_t val )
230 {
231 sh4_address_space[addr>>12]->write_byte(addr, val);
232 }
234 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
235 * into the same memory block
236 */
237 void mem_copy_from_sh4( sh4ptr_t dest, sh4addr_t srcaddr, size_t count ) {
238 if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
239 pvr2_vram64_read( dest, srcaddr, count );
240 } else {
241 sh4ptr_t src = mem_get_region(srcaddr);
242 if( src == NULL ) {
243 WARN( "Attempted block read from unknown address %08X", srcaddr );
244 } else {
245 memcpy( dest, src, count );
246 }
247 }
248 }
250 void mem_copy_to_sh4( sh4addr_t destaddr, sh4ptr_t src, size_t count ) {
251 if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
252 pvr2_dma_write( destaddr, src, count );
253 return;
254 } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
255 pvr2_render_buffer_invalidate( destaddr, TRUE );
256 } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
257 pvr2_vram64_write( destaddr, src, count );
258 return;
259 }
260 sh4ptr_t dest = mem_get_region(destaddr);
261 if( dest == NULL )
262 WARN( "Attempted block write to unknown address %08X", destaddr );
263 else {
264 xlat_invalidate_block( destaddr, count );
265 memcpy( dest, src, count );
266 }
267 }
.