Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 38:9ccc7ac66a9d
prev35:21a4be098304
next70:a5a5cef16deb
author nkeynes
date Mon Jan 02 14:48:29 2006 +0000 (18 years ago)
permissions -rw-r--r--
last change Commit in dmac.h (oops)
view annotate diff log raw
     1 /**
     2  * $Id: sh4mem.c,v 1.3 2005-12-26 10:47:10 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 "sh4mmio.h"
    27 #include "dreamcast.h"
    29 #define OC_BASE 0x1C000000
    30 #define OC_TOP  0x20000000
    32 #define TRANSLATE_VIDEO_64BIT_ADDRESS(a)  ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 );
    34 #ifdef ENABLE_WATCH
    35 #define CHECK_READ_WATCH( addr, size ) \
    36     if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
    37         WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
    38         dreamcast_stop(); \
    39     }
    40 #define CHECK_WRITE_WATCH( addr, size, val )                  \
    41     if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
    42         WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
    43         dreamcast_stop(); \
    44     }
    45 #else
    46 #define CHECK_READ_WATCH( addr, size )
    47 #define CHECK_WRITE_WATCH( addr, size )
    48 #endif
    50 #define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag) \
    51 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
    52     MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
    53     MMIO_REGDESC_BYNUM((uint32_t)p, r) )
    55 extern struct mem_region mem_rgn[];
    56 extern struct mmio_region *P4_io[];
    58 int32_t sh4_read_p4( uint32_t addr )
    59 {
    60     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    61     if( !io ) {
    62         ERROR( "Attempted read from unknown P4 region: %08X", addr );
    63         return 0;
    64     } else {
    65         return io->io_read( addr&0xFFF );
    66     }    
    67 }
    69 void sh4_write_p4( uint32_t addr, int32_t val )
    70 {
    71     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    72     if( !io ) {
    73         if( (addr & 0xFC000000) == 0xE0000000 ) {
    74             /* Store queue */
    75             SH4_WRITE_STORE_QUEUE( addr, val );
    76         } else if( (addr & 0xFF000000) != 0xF4000000 ) {
    77 	    /* OC address cache isn't implemented, but don't complain about it.
    78 	     * Complain about anything else though */
    79             ERROR( "Attempted write to unknown P4 region: %08X", addr );
    80         }
    81     } else {
    82         io->io_write( addr&0xFFF, val );
    83     }
    84 }
    86 int32_t sh4_read_phys_word( uint32_t addr )
    87 {
    88     char *page;
    89     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
    90         return SIGNEXT16(sh4_read_p4( addr ));
    92     if( (addr&0x1F800000) == 0x04000000 ) {
    93         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
    94     }
    96     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
    97     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
    98         if( page == NULL ) {
    99             ERROR( "Attempted word read to missing page: %08X",
   100                    addr );
   101             return 0;
   102         }
   103         return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   104     } else {
   105         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   106     }
   107 }
   109 int32_t sh4_read_long( uint32_t addr )
   110 {
   111     char *page;
   113     CHECK_READ_WATCH(addr,4);
   115     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
   116         return sh4_read_p4( addr );
   118     if( (addr&0x1F800000) == 0x04000000 ) {
   119         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   120     }
   122     if( IS_MMU_ENABLED() ) {
   123         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   124         sh4_stop();
   125         return 0;
   126     }
   128     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   129     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   130         int32_t val;
   131         if( page == NULL ) {
   132             ERROR( "Attempted long read to missing page: %08X", addr );
   133             return 0;
   134         }
   135         val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
   136         TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
   137         return val;
   138     } else {
   139         return *(int32_t *)(page+(addr&0xFFF));
   140     }
   141 }
   143 int32_t sh4_read_word( uint32_t addr )
   144 {
   145     char *page;
   147     CHECK_READ_WATCH(addr,2);
   149     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
   150         return SIGNEXT16(sh4_read_p4( addr ));
   152     if( (addr&0x1F800000) == 0x04000000 ) {
   153         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   154     }
   156     if( IS_MMU_ENABLED() ) {
   157         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   158         sh4_stop();
   159         return 0;
   160     }
   162     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   163     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   164         int32_t val;
   165         if( page == NULL ) {
   166             ERROR( "Attempted word read to missing page: %08X", addr );
   167             return 0;
   168         }
   169         val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   170         TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   171         return val;
   172     } else {
   173         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   174     }
   175 }
   177 int32_t sh4_read_byte( uint32_t addr )
   178 {
   179     char *page;
   181     CHECK_READ_WATCH(addr,1);
   183     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
   184         return SIGNEXT8(sh4_read_p4( addr ));
   185     if( (addr&0x1F800000) == 0x04000000 ) {
   186         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   187     }
   189     if( IS_MMU_ENABLED() ) {
   190         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   191         sh4_stop();
   192         return 0;
   193     }
   195     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   196     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   197         int32_t val;
   198         if( page == NULL ) {
   199             ERROR( "Attempted byte read to missing page: %08X", addr );
   200             return 0;
   201         }
   202         val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   203         TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
   204         return val;
   205     } else {
   206         return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
   207     }
   208 }
   210 void sh4_write_long( uint32_t addr, uint32_t val )
   211 {
   212     char *page;
   214     CHECK_WRITE_WATCH(addr,4,val);
   216     if( addr > 0xE0000000 ) {
   217         sh4_write_p4( addr, val );
   218         return;
   219     }
   220     if( (addr&0x1F800000) == 0x04000000 ) {
   221         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   222     }
   224     if( IS_MMU_ENABLED() ) {
   225         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   226         sh4_stop();
   227         return;
   228     }
   229     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   230         ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
   231         sh4_stop();
   232         return;
   233     }
   234     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   235     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   236         if( page == NULL ) {
   237             ERROR( "Long write to missing page: %08X => %08X", val, addr );
   238             return;
   239         }
   240         TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
   241         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   242     } else {
   243         *(uint32_t *)(page+(addr&0xFFF)) = val;
   244     }
   245 }
   247 void sh4_write_word( uint32_t addr, uint32_t val )
   248 {
   249     char *page;
   251     CHECK_WRITE_WATCH(addr,2,val);
   253     if( addr > 0xE0000000 ) {
   254         sh4_write_p4( addr, (int16_t)val );
   255         return;
   256     }
   257     if( (addr&0x1F800000) == 0x04000000 ) {
   258         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   259     }
   260     if( IS_MMU_ENABLED() ) {
   261         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   262         sh4_stop();
   263         return;
   264     }
   265     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   266     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   267         if( page == NULL ) {
   268             ERROR( "Attempted word write to missing page: %08X", addr );
   269             return;
   270         }
   271         TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   272         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   273     } else {
   274         *(uint16_t *)(page+(addr&0xFFF)) = val;
   275     }
   276 }
   278 void sh4_write_byte( uint32_t addr, uint32_t val )
   279 {
   280     char *page;
   282     CHECK_WRITE_WATCH(addr,1,val);
   284     if( addr > 0xE0000000 ) {
   285         sh4_write_p4( addr, (int8_t)val );
   286         return;
   287     }
   288     if( (addr&0x1F800000) == 0x04000000 ) {
   289         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   290     }
   292     if( IS_MMU_ENABLED() ) {
   293         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   294         sh4_stop();
   295         return;
   296     }
   297     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   298     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   299         if( page == NULL ) {
   300             ERROR( "Attempted byte write to missing page: %08X", addr );
   301             return;
   302         }
   303         TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
   304         io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
   305     } else {
   306         *(uint8_t *)(page+(addr&0xFFF)) = val;
   307     }
   308 }
   312 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
   313  * into the same memory black
   314  */
   315 void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
   316     char *src = mem_get_region(srcaddr);
   317     memcpy( dest, src, count );
   318 }
   320 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
   321     char *dest = mem_get_region(destaddr);
   322     memcpy( dest, src, count );
   323 }
.