Search
lxdream.org :: lxdream/src/sh4/mem.c
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 (18 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.
view annotate diff log raw
     1 #include <sys/mman.h>
     2 #include <assert.h>
     3 #include <stdint.h>
     4 #include <stdlib.h>
     5 #include <stdio.h>
     6 #include <unistd.h>
     7 #include <fcntl.h>
     8 #include <errno.h>
     9 #include <string.h>
    10 #include <zlib.h>
    11 #include "dream.h"
    12 #include "sh4core.h"
    13 #include "mem.h"
    15 #define OC_BASE 0x1C000000
    16 #define OC_TOP  0x20000000
    18 static char **page_map = NULL;
    19 static char *cache = NULL;
    21 struct mem_region mem_rgn[MAX_MEM_REGIONS];
    22 struct mmio_region *io_rgn[MAX_IO_REGIONS];
    23 struct mmio_region *P4_io[4096];
    25 int num_io_rgns = 1, num_mem_rgns = 0;
    27 void *mem_alloc_pages( int n )
    28 {
    29     void *mem = mmap( NULL, n * 4096,
    30                       PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0 );
    31     if( mem == MAP_FAILED ) {
    32         ERROR( "Memory allocation failure! (%s)", strerror(errno) );
    33         return NULL;
    34     }
    35     return mem;
    36 }
    39 void mem_init( void )
    40 {
    41     page_map = mmap( NULL, sizeof(char *) * PAGE_TABLE_ENTRIES,
    42                      PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0 );
    43     if( page_map == MAP_FAILED ) {
    44         ERROR( "Unable to allocate page map! (%s)", strerror(errno) );
    45         page_map = NULL;
    46         return;
    47     }
    49     memset( page_map, 0, sizeof(uint32_t) * PAGE_TABLE_ENTRIES );
    50     cache = mem_alloc_pages(2);
    51 }
    53 void mem_reset( void )
    54 {
    55     /* Restore all mmio registers to their initial settings */
    56     int i, j;
    57     for( i=1; i<num_io_rgns; i++ ) {
    58         for( j=0; io_rgn[i]->ports[j].id != NULL; j++ ) {
    59             if( io_rgn[i]->ports[j].def_val != UNDEFINED &&
    60                 io_rgn[i]->ports[j].def_val != *io_rgn[i]->ports[j].val ) {
    61                 io_rgn[i]->io_write( io_rgn[i]->ports[j].offset,
    62                                     io_rgn[i]->ports[j].def_val );
    63             }
    64         }
    65     }
    66 }
    68 struct mem_region *mem_map_region( void *mem, uint32_t base, uint32_t size,
    69                                    char *name, int flags )
    70 {
    71     int i;
    72     mem_rgn[num_mem_rgns].base = base;
    73     mem_rgn[num_mem_rgns].size = size;
    74     mem_rgn[num_mem_rgns].flags = flags;
    75     mem_rgn[num_mem_rgns].name = name;
    76     mem_rgn[num_mem_rgns].mem = mem;
    77     num_mem_rgns++;
    79     for( i=0; i<size>>PAGE_BITS; i++ )
    80         page_map[(base>>PAGE_BITS)+i] = mem + (i<<PAGE_BITS);
    82     return &mem_rgn[num_mem_rgns-1];
    83 }
    85 void *mem_create_ram_region( uint32_t base, uint32_t size, char *name )
    86 {
    87     char *mem;
    89     assert( (base&0xFFFFF000) == base ); /* must be page aligned */
    90     assert( (size&0x00000FFF) == 0 );
    91     assert( num_mem_rgns < MAX_MEM_REGIONS );
    92     assert( page_map != NULL );
    94     mem = mem_alloc_pages( size>>PAGE_BITS );
    96     mem_map_region( mem, base, size, name, 6 );
    97     return mem;
    98 }
   100 void *mem_load_rom( char *file, uint32_t base, uint32_t size, uint32_t crc )
   101 {
   102     char buf[512], *mem;
   103     int fd;
   104     uint32_t calc_crc;
   105     snprintf( buf, 512, "%s/%s",BIOS_PATH, file );
   106     fd = open( buf, O_RDONLY );
   107     if( fd == -1 ) {
   108         ERROR( "Bios file not found: %s", buf );
   109         return NULL;
   110     }
   111     mem = mmap( NULL, size, PROT_READ, MAP_PRIVATE, fd, 0 );
   112     if( mem == MAP_FAILED ) {
   113         ERROR( "Unable to map bios file: %s (%s)", file, strerror(errno) );
   114         close(fd);
   115         return NULL;
   116     }
   117     mem_map_region( mem, base, size, file, 4 );
   119     /* CRC check */
   120     calc_crc = crc32(0L, mem, size);
   121     if( calc_crc != crc ) {
   122         WARN( "Bios CRC Mismatch in %s: %08X (expected %08X)",
   123               file, calc_crc, crc);
   124     }
   125     return mem;
   126 }
   128 char *mem_get_region_by_name( char *name )
   129 {
   130     int i;
   131     for( i=0; i<num_mem_rgns; i++ ) {
   132         if( strcmp( mem_rgn[i].name, name ) == 0 )
   133             return mem_rgn[i].mem;
   134     }
   135     return NULL;
   136 }
   138 #define OCRAM_START (0x1C000000>>PAGE_BITS)
   139 #define OCRAM_END   (0x20000000>>PAGE_BITS)
   141 void mem_set_cache_mode( int mode )
   142 {
   143     uint32_t i;
   144     switch( mode ) {
   145         case MEM_OC_INDEX0: /* OIX=0 */
   146             for( i=OCRAM_START; i<OCRAM_END; i++ )
   147                 page_map[i] = cache + ((i&0x02)<<(PAGE_BITS-1));
   148             break;
   149         case MEM_OC_INDEX1: /* OIX=1 */
   150             for( i=OCRAM_START; i<OCRAM_END; i++ )
   151                 page_map[i] = cache + ((i&0x02000000)>>(25-PAGE_BITS));
   152             break;
   153         default: /* disabled */
   154             for( i=OCRAM_START; i<OCRAM_END; i++ )
   155                 page_map[i] = NULL;
   156             break;
   157     }
   158 }
   160 void register_io_region( struct mmio_region *io )
   161 {
   162     int i;
   164     assert(io);
   165     io->mem = mem_alloc_pages(2);
   166     io->save_mem = io->mem + PAGE_SIZE;
   167     io->index = (struct mmio_port **)malloc(1024*sizeof(struct mmio_port *));
   168     io->trace_flag = 1;
   169     memset( io->index, 0, 1024*sizeof(struct mmio_port *) );
   170     for( i=0; io->ports[i].id != NULL; i++ ) {
   171         io->ports[i].val = (uint32_t *)(io->mem + io->ports[i].offset);
   172         *io->ports[i].val = io->ports[i].def_val;
   173         io->index[io->ports[i].offset>>2] = &io->ports[i];
   174     }
   175     memcpy( io->save_mem, io->mem, PAGE_SIZE );
   176     if( (io->base & 0xFF000000) == 0xFF000000 ) {
   177         /* P4 area (on-chip I/O channels */
   178         P4_io[(io->base&0x1FFFFFFF)>>19] = io;
   179     } else {
   180         page_map[io->base>>12] = (char *)num_io_rgns;
   181     }
   182     io_rgn[num_io_rgns] = io;
   183     num_io_rgns++;
   184 }
   186 void register_io_regions( struct mmio_region **io )
   187 {
   188     while( *io ) register_io_region( *io++ );
   189 }
   191 #define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag) \
   192 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
   193     MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
   194     MMIO_REGDESC_BYNUM((uint32_t)p, r) )
   197 int32_t mem_read_p4( uint32_t addr )
   198 {
   199     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
   200     if( !io ) {
   201         ERROR( "Attempted read from unknown P4 region: %08X", addr );
   202         return 0;
   203     } else {
   204         return io->io_read( addr&0xFFF );
   205     }    
   206 }
   208 void mem_write_p4( uint32_t addr, int32_t val )
   209 {
   210     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
   211     if( !io ) {
   212         ERROR( "Attempted write to unknown P4 region: %08X", addr );
   213     } else {
   214         io->io_write( addr&0xFFF, val );
   215     }
   216 }
   218 int mem_has_page( uint32_t addr )
   219 {
   220     char *page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   221     return page != NULL;
   222 }
   224 int32_t mem_read_phys_word( uint32_t addr )
   225 {
   226     char *page;
   227     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
   228         return SIGNEXT16(mem_read_p4( addr ));
   230     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   231     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   232         if( page == NULL ) {
   233             ERROR( "Attempted word read to missing page: %08X",
   234                    addr );
   235             return 0;
   236         }
   237         return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   238     } else {
   239         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   240     }
   241 }
   243 int32_t mem_read_long( uint32_t addr )
   244 {
   245     char *page;
   246     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
   247         return mem_read_p4( addr );
   249     if( IS_MMU_ENABLED() ) {
   250         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   251         sh4_stop();
   252         return 0;
   253     }
   255     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   256     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   257         int32_t val;
   258         if( page == NULL ) {
   259             ERROR( "Attempted long read to missing page: %08X", addr );
   260             return 0;
   261         }
   262         val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
   263         TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
   264         return val;
   265     } else {
   266         return *(int32_t *)(page+(addr&0xFFF));
   267     }
   268 }
   270 int32_t mem_read_word( uint32_t addr )
   271 {
   272     char *page;
   273     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
   274         return SIGNEXT16(mem_read_p4( addr ));
   276     if( IS_MMU_ENABLED() ) {
   277         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   278         sh4_stop();
   279         return 0;
   280     }
   282     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   283     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   284         int32_t val;
   285         if( page == NULL ) {
   286             ERROR( "Attempted word read to missing page: %08X", addr );
   287             return 0;
   288         }
   289         val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   290         TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   291         return val;
   292     } else {
   293         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   294     }
   295 }
   297 int32_t mem_read_byte( uint32_t addr )
   298 {
   299     char *page;
   300     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
   301         return SIGNEXT8(mem_read_p4( addr ));
   303     if( IS_MMU_ENABLED() ) {
   304         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   305         sh4_stop();
   306         return 0;
   307     }
   309     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   310     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   311         int32_t val;
   312         if( page == NULL ) {
   313             ERROR( "Attempted byte read to missing page: %08X", addr );
   314             return 0;
   315         }
   316         val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   317         TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
   318         return val;
   319     } else {
   320         return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
   321     }
   322 }
   324 void mem_write_long( uint32_t addr, uint32_t val )
   325 {
   326     char *page;
   328     if( addr > 0xE0000000 ) {
   329         mem_write_p4( addr, val );
   330         return;
   331     }
   333     if( addr & 0xFFFFF000 == 0x0CFF0000 ||
   334         addr & 0x0FFFF000 == 0x0C374000 ) {
   335         TRACE( "Long write to watched page: %08X => %08X", val, addr );
   336     }
   338     if( IS_MMU_ENABLED() ) {
   339         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   340         sh4_stop();
   341         return;
   342     }
   343     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   344     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   345         if( page == NULL ) {
   346             ERROR( "Long write to missing page: %08X => %08X", val, addr );
   347             return;
   348         }
   349         TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
   350         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   351     } else {
   352         *(uint32_t *)(page+(addr&0xFFF)) = val;
   353     }
   354 }
   356 void mem_write_word( uint32_t addr, uint32_t val )
   357 {
   358     char *page;
   360     if( addr > 0xE0000000 ) {
   361         mem_write_p4( addr, (int16_t)val );
   362         return;
   363     }
   364     if( IS_MMU_ENABLED() ) {
   365         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   366         sh4_stop();
   367         return;
   368     }
   369     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   370     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   371         if( page == NULL ) {
   372             ERROR( "Attempted word write to missing page: %08X", addr );
   373             return;
   374         }
   375         TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   376         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   377     } else {
   378         *(uint16_t *)(page+(addr&0xFFF)) = val;
   379     }
   380 }
   382 void mem_write_byte( uint32_t addr, uint32_t val )
   383 {
   384     char *page;
   386     if( addr > 0xE0000000 ) {
   387         mem_write_p4( addr, (int8_t)val );
   388         return;
   389     }
   390     if( IS_MMU_ENABLED() ) {
   391         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   392         sh4_stop();
   393         return;
   394     }
   395     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   396     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   397         if( page == NULL ) {
   398             ERROR( "Attempted byte write to missing page: %08X", addr );
   399             return;
   400         }
   401         TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
   402         io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
   403     } else {
   404         *(uint8_t *)(page+(addr&0xFFF)) = val;
   405     }
   406 }
   408 char *mem_get_region( uint32_t addr )
   409 {
   410     char *page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   411     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   412         return NULL;
   413     } else {
   414         return page+(addr&0xFFF);
   415     }
   416 }
.