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