Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 100:995e42e96cc9
prev90:88e4872c2f58
next103:9b9cfc5855e0
author nkeynes
date Wed Feb 15 13:11:50 2006 +0000 (17 years ago)
permissions -rw-r--r--
last change Split pvr2.c out to separate files for TA and renderer, minor renames
change pvrdma to use mem_copy_to_sh4
file annotate diff log raw
nkeynes@10
     1
/**
nkeynes@100
     2
 * $Id: sh4mem.c,v 1.7 2006-02-15 13:11:50 nkeynes Exp $
nkeynes@10
     3
 * sh4mem.c is responsible for the SH4's access to memory (including memory
nkeynes@10
     4
 * mapped I/O), using the page maps created in mem.c
nkeynes@10
     5
 *
nkeynes@10
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@10
     7
 *
nkeynes@10
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@10
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@10
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@10
    11
 * (at your option) any later version.
nkeynes@10
    12
 *
nkeynes@10
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@10
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@10
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@10
    16
 * GNU General Public License for more details.
nkeynes@10
    17
 */
nkeynes@10
    18
nkeynes@35
    19
#define MODULE sh4_module
nkeynes@35
    20
nkeynes@10
    21
#include <string.h>
nkeynes@10
    22
#include <zlib.h>
nkeynes@10
    23
#include "dream.h"
nkeynes@10
    24
#include "mem.h"
nkeynes@10
    25
#include "mmio.h"
nkeynes@70
    26
#include "sh4core.h"
nkeynes@10
    27
#include "sh4mmio.h"
nkeynes@10
    28
#include "dreamcast.h"
nkeynes@100
    29
#include "pvr2/pvr2.h"
nkeynes@10
    30
nkeynes@10
    31
#define OC_BASE 0x1C000000
nkeynes@10
    32
#define OC_TOP  0x20000000
nkeynes@10
    33
nkeynes@90
    34
#define TRANSLATE_VIDEO_64BIT_ADDRESS(a)  ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 )
nkeynes@10
    35
nkeynes@10
    36
#ifdef ENABLE_WATCH
nkeynes@10
    37
#define CHECK_READ_WATCH( addr, size ) \
nkeynes@10
    38
    if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
nkeynes@10
    39
        WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
nkeynes@10
    40
        dreamcast_stop(); \
nkeynes@10
    41
    }
nkeynes@10
    42
#define CHECK_WRITE_WATCH( addr, size, val )                  \
nkeynes@10
    43
    if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
nkeynes@10
    44
        WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
nkeynes@10
    45
        dreamcast_stop(); \
nkeynes@10
    46
    }
nkeynes@10
    47
#else
nkeynes@10
    48
#define CHECK_READ_WATCH( addr, size )
nkeynes@10
    49
#define CHECK_WRITE_WATCH( addr, size )
nkeynes@10
    50
#endif
nkeynes@10
    51
nkeynes@10
    52
#define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag) \
nkeynes@10
    53
TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
nkeynes@10
    54
    MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
nkeynes@10
    55
    MMIO_REGDESC_BYNUM((uint32_t)p, r) )
nkeynes@10
    56
nkeynes@10
    57
extern struct mem_region mem_rgn[];
nkeynes@10
    58
extern struct mmio_region *P4_io[];
nkeynes@10
    59
nkeynes@10
    60
int32_t sh4_read_p4( uint32_t addr )
nkeynes@10
    61
{
nkeynes@10
    62
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@10
    63
    if( !io ) {
nkeynes@10
    64
        ERROR( "Attempted read from unknown P4 region: %08X", addr );
nkeynes@10
    65
        return 0;
nkeynes@10
    66
    } else {
nkeynes@10
    67
        return io->io_read( addr&0xFFF );
nkeynes@10
    68
    }    
nkeynes@10
    69
}
nkeynes@10
    70
nkeynes@10
    71
void sh4_write_p4( uint32_t addr, int32_t val )
nkeynes@10
    72
{
nkeynes@10
    73
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@10
    74
    if( !io ) {
nkeynes@10
    75
        if( (addr & 0xFC000000) == 0xE0000000 ) {
nkeynes@10
    76
            /* Store queue */
nkeynes@10
    77
            SH4_WRITE_STORE_QUEUE( addr, val );
nkeynes@38
    78
        } else if( (addr & 0xFF000000) != 0xF4000000 ) {
nkeynes@38
    79
	    /* OC address cache isn't implemented, but don't complain about it.
nkeynes@38
    80
	     * Complain about anything else though */
nkeynes@10
    81
            ERROR( "Attempted write to unknown P4 region: %08X", addr );
nkeynes@10
    82
        }
nkeynes@10
    83
    } else {
nkeynes@10
    84
        io->io_write( addr&0xFFF, val );
nkeynes@10
    85
    }
nkeynes@10
    86
}
nkeynes@10
    87
nkeynes@10
    88
int32_t sh4_read_phys_word( uint32_t addr )
nkeynes@10
    89
{
nkeynes@10
    90
    char *page;
nkeynes@83
    91
    if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@10
    92
        return SIGNEXT16(sh4_read_p4( addr ));
nkeynes@10
    93
    
nkeynes@10
    94
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
    95
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@10
    96
    }
nkeynes@10
    97
nkeynes@10
    98
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
    99
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   100
        if( page == NULL ) {
nkeynes@10
   101
            ERROR( "Attempted word read to missing page: %08X",
nkeynes@10
   102
                   addr );
nkeynes@10
   103
            return 0;
nkeynes@10
   104
        }
nkeynes@10
   105
        return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
nkeynes@10
   106
    } else {
nkeynes@10
   107
        return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
nkeynes@10
   108
    }
nkeynes@10
   109
}
nkeynes@10
   110
nkeynes@10
   111
int32_t sh4_read_long( uint32_t addr )
nkeynes@10
   112
{
nkeynes@10
   113
    char *page;
nkeynes@10
   114
    
nkeynes@10
   115
    CHECK_READ_WATCH(addr,4);
nkeynes@10
   116
nkeynes@83
   117
    if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@10
   118
        return sh4_read_p4( addr );
nkeynes@10
   119
    
nkeynes@10
   120
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   121
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@10
   122
    }
nkeynes@10
   123
nkeynes@10
   124
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   125
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   126
        sh4_stop();
nkeynes@10
   127
        return 0;
nkeynes@10
   128
    }
nkeynes@10
   129
nkeynes@10
   130
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   131
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   132
        int32_t val;
nkeynes@10
   133
        if( page == NULL ) {
nkeynes@10
   134
            ERROR( "Attempted long read to missing page: %08X", addr );
nkeynes@10
   135
            return 0;
nkeynes@10
   136
        }
nkeynes@10
   137
        val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
nkeynes@10
   138
        TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
nkeynes@10
   139
        return val;
nkeynes@10
   140
    } else {
nkeynes@10
   141
        return *(int32_t *)(page+(addr&0xFFF));
nkeynes@10
   142
    }
nkeynes@10
   143
}
nkeynes@10
   144
nkeynes@10
   145
int32_t sh4_read_word( uint32_t addr )
nkeynes@10
   146
{
nkeynes@10
   147
    char *page;
nkeynes@10
   148
nkeynes@10
   149
    CHECK_READ_WATCH(addr,2);
nkeynes@10
   150
nkeynes@83
   151
    if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@10
   152
        return SIGNEXT16(sh4_read_p4( addr ));
nkeynes@10
   153
    
nkeynes@10
   154
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   155
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@10
   156
    }
nkeynes@10
   157
nkeynes@10
   158
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   159
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   160
        sh4_stop();
nkeynes@10
   161
        return 0;
nkeynes@10
   162
    }
nkeynes@10
   163
nkeynes@10
   164
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   165
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   166
        int32_t val;
nkeynes@10
   167
        if( page == NULL ) {
nkeynes@10
   168
            ERROR( "Attempted word read to missing page: %08X", addr );
nkeynes@10
   169
            return 0;
nkeynes@10
   170
        }
nkeynes@10
   171
        val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
nkeynes@10
   172
        TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@10
   173
        return val;
nkeynes@10
   174
    } else {
nkeynes@10
   175
        return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
nkeynes@10
   176
    }
nkeynes@10
   177
}
nkeynes@10
   178
nkeynes@10
   179
int32_t sh4_read_byte( uint32_t addr )
nkeynes@10
   180
{
nkeynes@10
   181
    char *page;
nkeynes@10
   182
nkeynes@10
   183
    CHECK_READ_WATCH(addr,1);
nkeynes@10
   184
nkeynes@83
   185
    if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@10
   186
        return SIGNEXT8(sh4_read_p4( addr ));
nkeynes@10
   187
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   188
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@10
   189
    }
nkeynes@10
   190
    
nkeynes@10
   191
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   192
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   193
        sh4_stop();
nkeynes@10
   194
        return 0;
nkeynes@10
   195
    }
nkeynes@10
   196
nkeynes@10
   197
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   198
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   199
        int32_t val;
nkeynes@10
   200
        if( page == NULL ) {
nkeynes@10
   201
            ERROR( "Attempted byte read to missing page: %08X", addr );
nkeynes@10
   202
            return 0;
nkeynes@10
   203
        }
nkeynes@10
   204
        val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
nkeynes@10
   205
        TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@10
   206
        return val;
nkeynes@10
   207
    } else {
nkeynes@10
   208
        return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
nkeynes@10
   209
    }
nkeynes@10
   210
}
nkeynes@10
   211
nkeynes@10
   212
void sh4_write_long( uint32_t addr, uint32_t val )
nkeynes@10
   213
{
nkeynes@10
   214
    char *page;
nkeynes@10
   215
    
nkeynes@10
   216
    CHECK_WRITE_WATCH(addr,4,val);
nkeynes@10
   217
nkeynes@83
   218
    if( addr >= 0xE0000000 ) {
nkeynes@10
   219
        sh4_write_p4( addr, val );
nkeynes@10
   220
        return;
nkeynes@10
   221
    }
nkeynes@10
   222
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   223
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@10
   224
    }
nkeynes@10
   225
nkeynes@10
   226
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   227
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   228
        sh4_stop();
nkeynes@10
   229
        return;
nkeynes@10
   230
    }
nkeynes@10
   231
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@10
   232
        ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@10
   233
        sh4_stop();
nkeynes@10
   234
        return;
nkeynes@10
   235
    }
nkeynes@10
   236
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   237
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   238
        if( page == NULL ) {
nkeynes@10
   239
            ERROR( "Long write to missing page: %08X => %08X", val, addr );
nkeynes@10
   240
            return;
nkeynes@10
   241
        }
nkeynes@10
   242
        TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
nkeynes@10
   243
        io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
nkeynes@10
   244
    } else {
nkeynes@10
   245
        *(uint32_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   246
    }
nkeynes@10
   247
}
nkeynes@10
   248
nkeynes@10
   249
void sh4_write_word( uint32_t addr, uint32_t val )
nkeynes@10
   250
{
nkeynes@10
   251
    char *page;
nkeynes@10
   252
nkeynes@10
   253
    CHECK_WRITE_WATCH(addr,2,val);
nkeynes@10
   254
nkeynes@83
   255
    if( addr >= 0xE0000000 ) {
nkeynes@10
   256
        sh4_write_p4( addr, (int16_t)val );
nkeynes@10
   257
        return;
nkeynes@10
   258
    }
nkeynes@10
   259
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   260
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@10
   261
    }
nkeynes@10
   262
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   263
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   264
        sh4_stop();
nkeynes@10
   265
        return;
nkeynes@10
   266
    }
nkeynes@10
   267
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   268
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   269
        if( page == NULL ) {
nkeynes@10
   270
            ERROR( "Attempted word write to missing page: %08X", addr );
nkeynes@10
   271
            return;
nkeynes@10
   272
        }
nkeynes@10
   273
        TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@10
   274
        io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
nkeynes@10
   275
    } else {
nkeynes@10
   276
        *(uint16_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   277
    }
nkeynes@10
   278
}
nkeynes@10
   279
nkeynes@10
   280
void sh4_write_byte( uint32_t addr, uint32_t val )
nkeynes@10
   281
{
nkeynes@10
   282
    char *page;
nkeynes@10
   283
    
nkeynes@10
   284
    CHECK_WRITE_WATCH(addr,1,val);
nkeynes@10
   285
nkeynes@83
   286
    if( addr >= 0xE0000000 ) {
nkeynes@10
   287
        sh4_write_p4( addr, (int8_t)val );
nkeynes@10
   288
        return;
nkeynes@10
   289
    }
nkeynes@10
   290
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   291
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@10
   292
    }
nkeynes@10
   293
    
nkeynes@10
   294
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   295
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   296
        sh4_stop();
nkeynes@10
   297
        return;
nkeynes@10
   298
    }
nkeynes@10
   299
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   300
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   301
        if( page == NULL ) {
nkeynes@10
   302
            ERROR( "Attempted byte write to missing page: %08X", addr );
nkeynes@10
   303
            return;
nkeynes@10
   304
        }
nkeynes@10
   305
        TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@10
   306
        io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
nkeynes@10
   307
    } else {
nkeynes@10
   308
        *(uint8_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   309
    }
nkeynes@10
   310
}
nkeynes@10
   311
nkeynes@10
   312
nkeynes@10
   313
nkeynes@10
   314
/* FIXME: Handle all the many special cases when the range doesn't fall cleanly
nkeynes@10
   315
 * into the same memory black
nkeynes@10
   316
 */
nkeynes@10
   317
void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
nkeynes@10
   318
    char *src = mem_get_region(srcaddr);
nkeynes@10
   319
    memcpy( dest, src, count );
nkeynes@10
   320
}
nkeynes@10
   321
nkeynes@10
   322
void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
nkeynes@90
   323
    if( destaddr >= 0x10000000 && destaddr < 0x20000000 ) {
nkeynes@100
   324
	pvr2_ta_write( src, count );
nkeynes@90
   325
    } else if( destaddr >= 04000000 && destaddr < 0x5000000 ) {
nkeynes@90
   326
	/* 64-bit video write. Oh. Yuck */
nkeynes@90
   327
	uint32_t *dest32[2];
nkeynes@90
   328
	uint32_t *src32 = (uint32_t *)src;
nkeynes@90
   329
	int flag = 0;
nkeynes@90
   330
	if( destaddr & 0x03 != 0 ) {
nkeynes@90
   331
	}
nkeynes@90
   332
	dest32[0] = (uint32_t *)mem_get_region(TRANSLATE_VIDEO_64BIT_ADDRESS(destaddr));
nkeynes@90
   333
	dest32[1] = (uint32_t *)mem_get_region(TRANSLATE_VIDEO_64BIT_ADDRESS(destaddr+4));
nkeynes@90
   334
	while( count >= 4 ) {
nkeynes@90
   335
	    *dest32[flag]++ = *src32++;
nkeynes@90
   336
	    flag = !flag;
nkeynes@90
   337
	    count -=4;
nkeynes@90
   338
	}
nkeynes@90
   339
	if( count != 0 ) {
nkeynes@90
   340
	    src = (char *)src32;
nkeynes@90
   341
	    char *dest = dest32[flag];
nkeynes@90
   342
	    do {
nkeynes@90
   343
		*dest++ = *src++;
nkeynes@90
   344
		count--;
nkeynes@90
   345
	    } while( count > 0 );
nkeynes@90
   346
	}
nkeynes@90
   347
    } else {
nkeynes@90
   348
	char *dest = mem_get_region(destaddr);
nkeynes@90
   349
	if( dest == NULL )
nkeynes@90
   350
	    ERROR( "Attempted block write to undefined region %08X", destaddr );
nkeynes@90
   351
	else 
nkeynes@90
   352
	    memcpy( dest, src, count );
nkeynes@90
   353
    }
nkeynes@10
   354
}
.