Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 10:c898b37506e0
next35:21a4be098304
author nkeynes
date Mon Dec 26 03:10:41 2005 +0000 (18 years ago)
permissions -rw-r--r--
last change Update inst counter when switching CPUs
view annotate diff log raw
     1 /**
     2  * $Id: sh4mem.c,v 1.1 2005-12-11 05:15:36 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 #include <string.h>
    20 #include <zlib.h>
    21 #include "dream.h"
    22 #include "mem.h"
    23 #include "mmio.h"
    24 #include "sh4mmio.h"
    25 #include "dreamcast.h"
    27 #define OC_BASE 0x1C000000
    28 #define OC_TOP  0x20000000
    30 #define TRANSLATE_VIDEO_64BIT_ADDRESS(a)  ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 );
    32 #ifdef ENABLE_WATCH
    33 #define CHECK_READ_WATCH( addr, size ) \
    34     if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
    35         WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
    36         dreamcast_stop(); \
    37     }
    38 #define CHECK_WRITE_WATCH( addr, size, val )                  \
    39     if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
    40         WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
    41         dreamcast_stop(); \
    42     }
    43 #else
    44 #define CHECK_READ_WATCH( addr, size )
    45 #define CHECK_WRITE_WATCH( addr, size )
    46 #endif
    48 #define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag) \
    49 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
    50     MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
    51     MMIO_REGDESC_BYNUM((uint32_t)p, r) )
    53 extern struct mem_region mem_rgn[];
    54 extern struct mmio_region *P4_io[];
    56 int32_t sh4_read_p4( uint32_t addr )
    57 {
    58     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    59     if( !io ) {
    60         ERROR( "Attempted read from unknown P4 region: %08X", addr );
    61         return 0;
    62     } else {
    63         return io->io_read( addr&0xFFF );
    64     }    
    65 }
    67 void sh4_write_p4( uint32_t addr, int32_t val )
    68 {
    69     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    70     if( !io ) {
    71         if( (addr & 0xFC000000) == 0xE0000000 ) {
    72             /* Store queue */
    73             SH4_WRITE_STORE_QUEUE( addr, val );
    74         } else {
    75             ERROR( "Attempted write to unknown P4 region: %08X", addr );
    76         }
    77     } else {
    78         io->io_write( addr&0xFFF, val );
    79     }
    80 }
    82 int32_t sh4_read_phys_word( uint32_t addr )
    83 {
    84     char *page;
    85     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
    86         return SIGNEXT16(sh4_read_p4( addr ));
    88     if( (addr&0x1F800000) == 0x04000000 ) {
    89         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
    90     }
    92     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
    93     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
    94         if( page == NULL ) {
    95             ERROR( "Attempted word read to missing page: %08X",
    96                    addr );
    97             return 0;
    98         }
    99         return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   100     } else {
   101         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   102     }
   103 }
   105 int32_t sh4_read_long( uint32_t addr )
   106 {
   107     char *page;
   109     CHECK_READ_WATCH(addr,4);
   111     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
   112         return sh4_read_p4( addr );
   114     if( (addr&0x1F800000) == 0x04000000 ) {
   115         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   116     }
   118     if( IS_MMU_ENABLED() ) {
   119         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   120         sh4_stop();
   121         return 0;
   122     }
   124     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   125     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   126         int32_t val;
   127         if( page == NULL ) {
   128             ERROR( "Attempted long read to missing page: %08X", addr );
   129             return 0;
   130         }
   131         val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
   132         TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
   133         return val;
   134     } else {
   135         return *(int32_t *)(page+(addr&0xFFF));
   136     }
   137 }
   139 int32_t sh4_read_word( uint32_t addr )
   140 {
   141     char *page;
   143     CHECK_READ_WATCH(addr,2);
   145     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
   146         return SIGNEXT16(sh4_read_p4( addr ));
   148     if( (addr&0x1F800000) == 0x04000000 ) {
   149         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   150     }
   152     if( IS_MMU_ENABLED() ) {
   153         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   154         sh4_stop();
   155         return 0;
   156     }
   158     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   159     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   160         int32_t val;
   161         if( page == NULL ) {
   162             ERROR( "Attempted word read to missing page: %08X", addr );
   163             return 0;
   164         }
   165         val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   166         TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   167         return val;
   168     } else {
   169         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   170     }
   171 }
   173 int32_t sh4_read_byte( uint32_t addr )
   174 {
   175     char *page;
   177     CHECK_READ_WATCH(addr,1);
   179     if( addr > 0xE0000000 ) /* P4 Area, handled specially */
   180         return SIGNEXT8(sh4_read_p4( addr ));
   181     if( (addr&0x1F800000) == 0x04000000 ) {
   182         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   183     }
   185     if( IS_MMU_ENABLED() ) {
   186         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   187         sh4_stop();
   188         return 0;
   189     }
   191     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   192     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   193         int32_t val;
   194         if( page == NULL ) {
   195             ERROR( "Attempted byte read to missing page: %08X", addr );
   196             return 0;
   197         }
   198         val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   199         TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
   200         return val;
   201     } else {
   202         return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
   203     }
   204 }
   206 void sh4_write_long( uint32_t addr, uint32_t val )
   207 {
   208     char *page;
   210     CHECK_WRITE_WATCH(addr,4,val);
   212     if( addr > 0xE0000000 ) {
   213         sh4_write_p4( addr, val );
   214         return;
   215     }
   216     if( (addr&0x1F800000) == 0x04000000 ) {
   217         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   218     }
   220     if( IS_MMU_ENABLED() ) {
   221         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   222         sh4_stop();
   223         return;
   224     }
   225     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   226         ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
   227         sh4_stop();
   228         return;
   229     }
   230     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   231     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   232         if( page == NULL ) {
   233             ERROR( "Long write to missing page: %08X => %08X", val, addr );
   234             return;
   235         }
   236         TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
   237         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   238     } else {
   239         *(uint32_t *)(page+(addr&0xFFF)) = val;
   240     }
   241 }
   243 void sh4_write_word( uint32_t addr, uint32_t val )
   244 {
   245     char *page;
   247     CHECK_WRITE_WATCH(addr,2,val);
   249     if( addr > 0xE0000000 ) {
   250         sh4_write_p4( addr, (int16_t)val );
   251         return;
   252     }
   253     if( (addr&0x1F800000) == 0x04000000 ) {
   254         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   255     }
   256     if( IS_MMU_ENABLED() ) {
   257         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   258         sh4_stop();
   259         return;
   260     }
   261     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   262     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   263         if( page == NULL ) {
   264             ERROR( "Attempted word write to missing page: %08X", addr );
   265             return;
   266         }
   267         TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   268         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   269     } else {
   270         *(uint16_t *)(page+(addr&0xFFF)) = val;
   271     }
   272 }
   274 void sh4_write_byte( uint32_t addr, uint32_t val )
   275 {
   276     char *page;
   278     CHECK_WRITE_WATCH(addr,1,val);
   280     if( addr > 0xE0000000 ) {
   281         sh4_write_p4( addr, (int8_t)val );
   282         return;
   283     }
   284     if( (addr&0x1F800000) == 0x04000000 ) {
   285         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   286     }
   288     if( IS_MMU_ENABLED() ) {
   289         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   290         sh4_stop();
   291         return;
   292     }
   293     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   294     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   295         if( page == NULL ) {
   296             ERROR( "Attempted byte write to missing page: %08X", addr );
   297             return;
   298         }
   299         TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
   300         io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
   301     } else {
   302         *(uint8_t *)(page+(addr&0xFFF)) = val;
   303     }
   304 }
   308 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
   309  * into the same memory black
   310  */
   311 void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
   312     char *src = mem_get_region(srcaddr);
   313     memcpy( dest, src, count );
   314 }
   316 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
   317     char *dest = mem_get_region(destaddr);
   318     memcpy( dest, src, count );
   319 }
.