Search
lxdream.org :: lxdream/src/sh4/mem.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/mem.c
changeset 1:eea311cfd33e
next2:42349f6ea216
author nkeynes
date Sat Mar 13 00:03:32 2004 +0000 (15 years ago)
permissions -rw-r--r--
last change This commit was generated by cvs2svn to compensate for changes in r2,
which included commits to RCS files with non-trunk default branches.
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/sh4/mem.c Sat Mar 13 00:03:32 2004 +0000
1.3 @@ -0,0 +1,416 @@
1.4 +#include <sys/mman.h>
1.5 +#include <assert.h>
1.6 +#include <stdint.h>
1.7 +#include <stdlib.h>
1.8 +#include <stdio.h>
1.9 +#include <unistd.h>
1.10 +#include <fcntl.h>
1.11 +#include <errno.h>
1.12 +#include <string.h>
1.13 +#include <zlib.h>
1.14 +#include "dream.h"
1.15 +#include "sh4core.h"
1.16 +#include "mem.h"
1.17 +
1.18 +#define OC_BASE 0x1C000000
1.19 +#define OC_TOP 0x20000000
1.20 +
1.21 +static char **page_map = NULL;
1.22 +static char *cache = NULL;
1.23 +
1.24 +struct mem_region mem_rgn[MAX_MEM_REGIONS];
1.25 +struct mmio_region *io_rgn[MAX_IO_REGIONS];
1.26 +struct mmio_region *P4_io[4096];
1.27 +
1.28 +int num_io_rgns = 1, num_mem_rgns = 0;
1.29 +
1.30 +void *mem_alloc_pages( int n )
1.31 +{
1.32 + void *mem = mmap( NULL, n * 4096,
1.33 + PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0 );
1.34 + if( mem == MAP_FAILED ) {
1.35 + ERROR( "Memory allocation failure! (%s)", strerror(errno) );
1.36 + return NULL;
1.37 + }
1.38 + return mem;
1.39 +}
1.40 +
1.41 +
1.42 +void mem_init( void )
1.43 +{
1.44 + page_map = mmap( NULL, sizeof(char *) * PAGE_TABLE_ENTRIES,
1.45 + PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0 );
1.46 + if( page_map == MAP_FAILED ) {
1.47 + ERROR( "Unable to allocate page map! (%s)", strerror(errno) );
1.48 + page_map = NULL;
1.49 + return;
1.50 + }
1.51 +
1.52 + memset( page_map, 0, sizeof(uint32_t) * PAGE_TABLE_ENTRIES );
1.53 + cache = mem_alloc_pages(2);
1.54 +}
1.55 +
1.56 +void mem_reset( void )
1.57 +{
1.58 + /* Restore all mmio registers to their initial settings */
1.59 + int i, j;
1.60 + for( i=1; i<num_io_rgns; i++ ) {
1.61 + for( j=0; io_rgn[i]->ports[j].id != NULL; j++ ) {
1.62 + if( io_rgn[i]->ports[j].def_val != UNDEFINED &&
1.63 + io_rgn[i]->ports[j].def_val != *io_rgn[i]->ports[j].val ) {
1.64 + io_rgn[i]->io_write( io_rgn[i]->ports[j].offset,
1.65 + io_rgn[i]->ports[j].def_val );
1.66 + }
1.67 + }
1.68 + }
1.69 +}
1.70 +
1.71 +struct mem_region *mem_map_region( void *mem, uint32_t base, uint32_t size,
1.72 + char *name, int flags )
1.73 +{
1.74 + int i;
1.75 + mem_rgn[num_mem_rgns].base = base;
1.76 + mem_rgn[num_mem_rgns].size = size;
1.77 + mem_rgn[num_mem_rgns].flags = flags;
1.78 + mem_rgn[num_mem_rgns].name = name;
1.79 + mem_rgn[num_mem_rgns].mem = mem;
1.80 + num_mem_rgns++;
1.81 +
1.82 + for( i=0; i<size>>PAGE_BITS; i++ )
1.83 + page_map[(base>>PAGE_BITS)+i] = mem + (i<<PAGE_BITS);
1.84 +
1.85 + return &mem_rgn[num_mem_rgns-1];
1.86 +}
1.87 +
1.88 +void *mem_create_ram_region( uint32_t base, uint32_t size, char *name )
1.89 +{
1.90 + char *mem;
1.91 +
1.92 + assert( (base&0xFFFFF000) == base ); /* must be page aligned */
1.93 + assert( (size&0x00000FFF) == 0 );
1.94 + assert( num_mem_rgns < MAX_MEM_REGIONS );
1.95 + assert( page_map != NULL );
1.96 +
1.97 + mem = mem_alloc_pages( size>>PAGE_BITS );
1.98 +
1.99 + mem_map_region( mem, base, size, name, 6 );
1.100 + return mem;
1.101 +}
1.102 +
1.103 +void *mem_load_rom( char *file, uint32_t base, uint32_t size, uint32_t crc )
1.104 +{
1.105 + char buf[512], *mem;
1.106 + int fd;
1.107 + uint32_t calc_crc;
1.108 + snprintf( buf, 512, "%s/%s",BIOS_PATH, file );
1.109 + fd = open( buf, O_RDONLY );
1.110 + if( fd == -1 ) {
1.111 + ERROR( "Bios file not found: %s", buf );
1.112 + return NULL;
1.113 + }
1.114 + mem = mmap( NULL, size, PROT_READ, MAP_PRIVATE, fd, 0 );
1.115 + if( mem == MAP_FAILED ) {
1.116 + ERROR( "Unable to map bios file: %s (%s)", file, strerror(errno) );
1.117 + close(fd);
1.118 + return NULL;
1.119 + }
1.120 + mem_map_region( mem, base, size, file, 4 );
1.121 +
1.122 + /* CRC check */
1.123 + calc_crc = crc32(0L, mem, size);
1.124 + if( calc_crc != crc ) {
1.125 + WARN( "Bios CRC Mismatch in %s: %08X (expected %08X)",
1.126 + file, calc_crc, crc);
1.127 + }
1.128 + return mem;
1.129 +}
1.130 +
1.131 +char *mem_get_region_by_name( char *name )
1.132 +{
1.133 + int i;
1.134 + for( i=0; i<num_mem_rgns; i++ ) {
1.135 + if( strcmp( mem_rgn[i].name, name ) == 0 )
1.136 + return mem_rgn[i].mem;
1.137 + }
1.138 + return NULL;
1.139 +}
1.140 +
1.141 +#define OCRAM_START (0x1C000000>>PAGE_BITS)
1.142 +#define OCRAM_END (0x20000000>>PAGE_BITS)
1.143 +
1.144 +void mem_set_cache_mode( int mode )
1.145 +{
1.146 + uint32_t i;
1.147 + switch( mode ) {
1.148 + case MEM_OC_INDEX0: /* OIX=0 */
1.149 + for( i=OCRAM_START; i<OCRAM_END; i++ )
1.150 + page_map[i] = cache + ((i&0x02)<<(PAGE_BITS-1));
1.151 + break;
1.152 + case MEM_OC_INDEX1: /* OIX=1 */
1.153 + for( i=OCRAM_START; i<OCRAM_END; i++ )
1.154 + page_map[i] = cache + ((i&0x02000000)>>(25-PAGE_BITS));
1.155 + break;
1.156 + default: /* disabled */
1.157 + for( i=OCRAM_START; i<OCRAM_END; i++ )
1.158 + page_map[i] = NULL;
1.159 + break;
1.160 + }
1.161 +}
1.162 +
1.163 +void register_io_region( struct mmio_region *io )
1.164 +{
1.165 + int i;
1.166 +
1.167 + assert(io);
1.168 + io->mem = mem_alloc_pages(2);
1.169 + io->save_mem = io->mem + PAGE_SIZE;
1.170 + io->index = (struct mmio_port **)malloc(1024*sizeof(struct mmio_port *));
1.171 + io->trace_flag = 1;
1.172 + memset( io->index, 0, 1024*sizeof(struct mmio_port *) );
1.173 + for( i=0; io->ports[i].id != NULL; i++ ) {
1.174 + io->ports[i].val = (uint32_t *)(io->mem + io->ports[i].offset);
1.175 + *io->ports[i].val = io->ports[i].def_val;
1.176 + io->index[io->ports[i].offset>>2] = &io->ports[i];
1.177 + }
1.178 + memcpy( io->save_mem, io->mem, PAGE_SIZE );
1.179 + if( (io->base & 0xFF000000) == 0xFF000000 ) {
1.180 + /* P4 area (on-chip I/O channels */
1.181 + P4_io[(io->base&0x1FFFFFFF)>>19] = io;
1.182 + } else {
1.183 + page_map[io->base>>12] = (char *)num_io_rgns;
1.184 + }
1.185 + io_rgn[num_io_rgns] = io;
1.186 + num_io_rgns++;
1.187 +}
1.188 +
1.189 +void register_io_regions( struct mmio_region **io )
1.190 +{
1.191 + while( *io ) register_io_region( *io++ );
1.192 +}
1.193 +
1.194 +#define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag) \
1.195 +TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
1.196 + MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
1.197 + MMIO_REGDESC_BYNUM((uint32_t)p, r) )
1.198 +
1.199 +
1.200 +int32_t mem_read_p4( uint32_t addr )
1.201 +{
1.202 + struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
1.203 + if( !io ) {
1.204 + ERROR( "Attempted read from unknown P4 region: %08X", addr );
1.205 + return 0;
1.206 + } else {
1.207 + return io->io_read( addr&0xFFF );
1.208 + }
1.209 +}
1.210 +
1.211 +void mem_write_p4( uint32_t addr, int32_t val )
1.212 +{
1.213 + struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
1.214 + if( !io ) {
1.215 + ERROR( "Attempted write to unknown P4 region: %08X", addr );
1.216 + } else {
1.217 + io->io_write( addr&0xFFF, val );
1.218 + }
1.219 +}
1.220 +
1.221 +int mem_has_page( uint32_t addr )
1.222 +{
1.223 + char *page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.224 + return page != NULL;
1.225 +}
1.226 +
1.227 +int32_t mem_read_phys_word( uint32_t addr )
1.228 +{
1.229 + char *page;
1.230 + if( addr > 0xE0000000 ) /* P4 Area, handled specially */
1.231 + return SIGNEXT16(mem_read_p4( addr ));
1.232 +
1.233 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.234 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.235 + if( page == NULL ) {
1.236 + ERROR( "Attempted word read to missing page: %08X",
1.237 + addr );
1.238 + return 0;
1.239 + }
1.240 + return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
1.241 + } else {
1.242 + return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
1.243 + }
1.244 +}
1.245 +
1.246 +int32_t mem_read_long( uint32_t addr )
1.247 +{
1.248 + char *page;
1.249 + if( addr > 0xE0000000 ) /* P4 Area, handled specially */
1.250 + return mem_read_p4( addr );
1.251 +
1.252 + if( IS_MMU_ENABLED() ) {
1.253 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.254 + sh4_stop();
1.255 + return 0;
1.256 + }
1.257 +
1.258 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.259 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.260 + int32_t val;
1.261 + if( page == NULL ) {
1.262 + ERROR( "Attempted long read to missing page: %08X", addr );
1.263 + return 0;
1.264 + }
1.265 + val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
1.266 + TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
1.267 + return val;
1.268 + } else {
1.269 + return *(int32_t *)(page+(addr&0xFFF));
1.270 + }
1.271 +}
1.272 +
1.273 +int32_t mem_read_word( uint32_t addr )
1.274 +{
1.275 + char *page;
1.276 + if( addr > 0xE0000000 ) /* P4 Area, handled specially */
1.277 + return SIGNEXT16(mem_read_p4( addr ));
1.278 +
1.279 + if( IS_MMU_ENABLED() ) {
1.280 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.281 + sh4_stop();
1.282 + return 0;
1.283 + }
1.284 +
1.285 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.286 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.287 + int32_t val;
1.288 + if( page == NULL ) {
1.289 + ERROR( "Attempted word read to missing page: %08X", addr );
1.290 + return 0;
1.291 + }
1.292 + val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
1.293 + TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
1.294 + return val;
1.295 + } else {
1.296 + return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
1.297 + }
1.298 +}
1.299 +
1.300 +int32_t mem_read_byte( uint32_t addr )
1.301 +{
1.302 + char *page;
1.303 + if( addr > 0xE0000000 ) /* P4 Area, handled specially */
1.304 + return SIGNEXT8(mem_read_p4( addr ));
1.305 +
1.306 + if( IS_MMU_ENABLED() ) {
1.307 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.308 + sh4_stop();
1.309 + return 0;
1.310 + }
1.311 +
1.312 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.313 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.314 + int32_t val;
1.315 + if( page == NULL ) {
1.316 + ERROR( "Attempted byte read to missing page: %08X", addr );
1.317 + return 0;
1.318 + }
1.319 + val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
1.320 + TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
1.321 + return val;
1.322 + } else {
1.323 + return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
1.324 + }
1.325 +}
1.326 +
1.327 +void mem_write_long( uint32_t addr, uint32_t val )
1.328 +{
1.329 + char *page;
1.330 +
1.331 + if( addr > 0xE0000000 ) {
1.332 + mem_write_p4( addr, val );
1.333 + return;
1.334 + }
1.335 +
1.336 + if( addr & 0xFFFFF000 == 0x0CFF0000 ||
1.337 + addr & 0x0FFFF000 == 0x0C374000 ) {
1.338 + TRACE( "Long write to watched page: %08X => %08X", val, addr );
1.339 + }
1.340 +
1.341 + if( IS_MMU_ENABLED() ) {
1.342 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.343 + sh4_stop();
1.344 + return;
1.345 + }
1.346 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.347 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.348 + if( page == NULL ) {
1.349 + ERROR( "Long write to missing page: %08X => %08X", val, addr );
1.350 + return;
1.351 + }
1.352 + TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
1.353 + io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
1.354 + } else {
1.355 + *(uint32_t *)(page+(addr&0xFFF)) = val;
1.356 + }
1.357 +}
1.358 +
1.359 +void mem_write_word( uint32_t addr, uint32_t val )
1.360 +{
1.361 + char *page;
1.362 +
1.363 + if( addr > 0xE0000000 ) {
1.364 + mem_write_p4( addr, (int16_t)val );
1.365 + return;
1.366 + }
1.367 + if( IS_MMU_ENABLED() ) {
1.368 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.369 + sh4_stop();
1.370 + return;
1.371 + }
1.372 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.373 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.374 + if( page == NULL ) {
1.375 + ERROR( "Attempted word write to missing page: %08X", addr );
1.376 + return;
1.377 + }
1.378 + TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
1.379 + io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
1.380 + } else {
1.381 + *(uint16_t *)(page+(addr&0xFFF)) = val;
1.382 + }
1.383 +}
1.384 +
1.385 +void mem_write_byte( uint32_t addr, uint32_t val )
1.386 +{
1.387 + char *page;
1.388 +
1.389 + if( addr > 0xE0000000 ) {
1.390 + mem_write_p4( addr, (int8_t)val );
1.391 + return;
1.392 + }
1.393 + if( IS_MMU_ENABLED() ) {
1.394 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.395 + sh4_stop();
1.396 + return;
1.397 + }
1.398 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.399 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.400 + if( page == NULL ) {
1.401 + ERROR( "Attempted byte write to missing page: %08X", addr );
1.402 + return;
1.403 + }
1.404 + TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
1.405 + io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
1.406 + } else {
1.407 + *(uint8_t *)(page+(addr&0xFFF)) = val;
1.408 + }
1.409 +}
1.410 +
1.411 +char *mem_get_region( uint32_t addr )
1.412 +{
1.413 + char *page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.414 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.415 + return NULL;
1.416 + } else {
1.417 + return page+(addr&0xFFF);
1.418 + }
1.419 +}
.