Search
lxdream.org :: lxdream/src/sh4/sh4mem.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 10:c898b37506e0
next35:21a4be098304
author nkeynes
date Sun Dec 25 08:24:11 2005 +0000 (18 years ago)
permissions -rw-r--r--
last change Finish adding header blocks to all files
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/sh4/sh4mem.c Sun Dec 25 08:24:11 2005 +0000
1.3 @@ -0,0 +1,319 @@
1.4 +/**
1.5 + * $Id: sh4mem.c,v 1.1 2005-12-11 05:15:36 nkeynes Exp $
1.6 + * sh4mem.c is responsible for the SH4's access to memory (including memory
1.7 + * mapped I/O), using the page maps created in mem.c
1.8 + *
1.9 + * Copyright (c) 2005 Nathan Keynes.
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.15 + *
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.20 + */
1.21 +
1.22 +#include <string.h>
1.23 +#include <zlib.h>
1.24 +#include "dream.h"
1.25 +#include "mem.h"
1.26 +#include "mmio.h"
1.27 +#include "sh4mmio.h"
1.28 +#include "dreamcast.h"
1.29 +
1.30 +#define OC_BASE 0x1C000000
1.31 +#define OC_TOP 0x20000000
1.32 +
1.33 +#define TRANSLATE_VIDEO_64BIT_ADDRESS(a) ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 );
1.34 +
1.35 +#ifdef ENABLE_WATCH
1.36 +#define CHECK_READ_WATCH( addr, size ) \
1.37 + if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
1.38 + WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
1.39 + dreamcast_stop(); \
1.40 + }
1.41 +#define CHECK_WRITE_WATCH( addr, size, val ) \
1.42 + if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
1.43 + WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
1.44 + dreamcast_stop(); \
1.45 + }
1.46 +#else
1.47 +#define CHECK_READ_WATCH( addr, size )
1.48 +#define CHECK_WRITE_WATCH( addr, size )
1.49 +#endif
1.50 +
1.51 +#define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag) \
1.52 +TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
1.53 + MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
1.54 + MMIO_REGDESC_BYNUM((uint32_t)p, r) )
1.55 +
1.56 +extern struct mem_region mem_rgn[];
1.57 +extern struct mmio_region *P4_io[];
1.58 +
1.59 +int32_t sh4_read_p4( uint32_t addr )
1.60 +{
1.61 + struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
1.62 + if( !io ) {
1.63 + ERROR( "Attempted read from unknown P4 region: %08X", addr );
1.64 + return 0;
1.65 + } else {
1.66 + return io->io_read( addr&0xFFF );
1.67 + }
1.68 +}
1.69 +
1.70 +void sh4_write_p4( uint32_t addr, int32_t val )
1.71 +{
1.72 + struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
1.73 + if( !io ) {
1.74 + if( (addr & 0xFC000000) == 0xE0000000 ) {
1.75 + /* Store queue */
1.76 + SH4_WRITE_STORE_QUEUE( addr, val );
1.77 + } else {
1.78 + ERROR( "Attempted write to unknown P4 region: %08X", addr );
1.79 + }
1.80 + } else {
1.81 + io->io_write( addr&0xFFF, val );
1.82 + }
1.83 +}
1.84 +
1.85 +int32_t sh4_read_phys_word( uint32_t addr )
1.86 +{
1.87 + char *page;
1.88 + if( addr > 0xE0000000 ) /* P4 Area, handled specially */
1.89 + return SIGNEXT16(sh4_read_p4( addr ));
1.90 +
1.91 + if( (addr&0x1F800000) == 0x04000000 ) {
1.92 + addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
1.93 + }
1.94 +
1.95 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.96 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.97 + if( page == NULL ) {
1.98 + ERROR( "Attempted word read to missing page: %08X",
1.99 + addr );
1.100 + return 0;
1.101 + }
1.102 + return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
1.103 + } else {
1.104 + return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
1.105 + }
1.106 +}
1.107 +
1.108 +int32_t sh4_read_long( uint32_t addr )
1.109 +{
1.110 + char *page;
1.111 +
1.112 + CHECK_READ_WATCH(addr,4);
1.113 +
1.114 + if( addr > 0xE0000000 ) /* P4 Area, handled specially */
1.115 + return sh4_read_p4( addr );
1.116 +
1.117 + if( (addr&0x1F800000) == 0x04000000 ) {
1.118 + addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
1.119 + }
1.120 +
1.121 + if( IS_MMU_ENABLED() ) {
1.122 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.123 + sh4_stop();
1.124 + return 0;
1.125 + }
1.126 +
1.127 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.128 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.129 + int32_t val;
1.130 + if( page == NULL ) {
1.131 + ERROR( "Attempted long read to missing page: %08X", addr );
1.132 + return 0;
1.133 + }
1.134 + val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
1.135 + TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
1.136 + return val;
1.137 + } else {
1.138 + return *(int32_t *)(page+(addr&0xFFF));
1.139 + }
1.140 +}
1.141 +
1.142 +int32_t sh4_read_word( uint32_t addr )
1.143 +{
1.144 + char *page;
1.145 +
1.146 + CHECK_READ_WATCH(addr,2);
1.147 +
1.148 + if( addr > 0xE0000000 ) /* P4 Area, handled specially */
1.149 + return SIGNEXT16(sh4_read_p4( addr ));
1.150 +
1.151 + if( (addr&0x1F800000) == 0x04000000 ) {
1.152 + addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
1.153 + }
1.154 +
1.155 + if( IS_MMU_ENABLED() ) {
1.156 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.157 + sh4_stop();
1.158 + return 0;
1.159 + }
1.160 +
1.161 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.162 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.163 + int32_t val;
1.164 + if( page == NULL ) {
1.165 + ERROR( "Attempted word read to missing page: %08X", addr );
1.166 + return 0;
1.167 + }
1.168 + val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
1.169 + TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
1.170 + return val;
1.171 + } else {
1.172 + return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
1.173 + }
1.174 +}
1.175 +
1.176 +int32_t sh4_read_byte( uint32_t addr )
1.177 +{
1.178 + char *page;
1.179 +
1.180 + CHECK_READ_WATCH(addr,1);
1.181 +
1.182 + if( addr > 0xE0000000 ) /* P4 Area, handled specially */
1.183 + return SIGNEXT8(sh4_read_p4( addr ));
1.184 + if( (addr&0x1F800000) == 0x04000000 ) {
1.185 + addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
1.186 + }
1.187 +
1.188 + if( IS_MMU_ENABLED() ) {
1.189 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.190 + sh4_stop();
1.191 + return 0;
1.192 + }
1.193 +
1.194 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.195 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.196 + int32_t val;
1.197 + if( page == NULL ) {
1.198 + ERROR( "Attempted byte read to missing page: %08X", addr );
1.199 + return 0;
1.200 + }
1.201 + val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
1.202 + TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
1.203 + return val;
1.204 + } else {
1.205 + return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
1.206 + }
1.207 +}
1.208 +
1.209 +void sh4_write_long( uint32_t addr, uint32_t val )
1.210 +{
1.211 + char *page;
1.212 +
1.213 + CHECK_WRITE_WATCH(addr,4,val);
1.214 +
1.215 + if( addr > 0xE0000000 ) {
1.216 + sh4_write_p4( addr, val );
1.217 + return;
1.218 + }
1.219 + if( (addr&0x1F800000) == 0x04000000 ) {
1.220 + addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
1.221 + }
1.222 +
1.223 + if( IS_MMU_ENABLED() ) {
1.224 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.225 + sh4_stop();
1.226 + return;
1.227 + }
1.228 + if( (addr&0x1FFFFFFF) < 0x200000 ) {
1.229 + ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
1.230 + sh4_stop();
1.231 + return;
1.232 + }
1.233 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.234 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.235 + if( page == NULL ) {
1.236 + ERROR( "Long write to missing page: %08X => %08X", val, addr );
1.237 + return;
1.238 + }
1.239 + TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
1.240 + io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
1.241 + } else {
1.242 + *(uint32_t *)(page+(addr&0xFFF)) = val;
1.243 + }
1.244 +}
1.245 +
1.246 +void sh4_write_word( uint32_t addr, uint32_t val )
1.247 +{
1.248 + char *page;
1.249 +
1.250 + CHECK_WRITE_WATCH(addr,2,val);
1.251 +
1.252 + if( addr > 0xE0000000 ) {
1.253 + sh4_write_p4( addr, (int16_t)val );
1.254 + return;
1.255 + }
1.256 + if( (addr&0x1F800000) == 0x04000000 ) {
1.257 + addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
1.258 + }
1.259 + if( IS_MMU_ENABLED() ) {
1.260 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.261 + sh4_stop();
1.262 + return;
1.263 + }
1.264 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.265 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.266 + if( page == NULL ) {
1.267 + ERROR( "Attempted word write to missing page: %08X", addr );
1.268 + return;
1.269 + }
1.270 + TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
1.271 + io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
1.272 + } else {
1.273 + *(uint16_t *)(page+(addr&0xFFF)) = val;
1.274 + }
1.275 +}
1.276 +
1.277 +void sh4_write_byte( uint32_t addr, uint32_t val )
1.278 +{
1.279 + char *page;
1.280 +
1.281 + CHECK_WRITE_WATCH(addr,1,val);
1.282 +
1.283 + if( addr > 0xE0000000 ) {
1.284 + sh4_write_p4( addr, (int8_t)val );
1.285 + return;
1.286 + }
1.287 + if( (addr&0x1F800000) == 0x04000000 ) {
1.288 + addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
1.289 + }
1.290 +
1.291 + if( IS_MMU_ENABLED() ) {
1.292 + ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
1.293 + sh4_stop();
1.294 + return;
1.295 + }
1.296 + page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.297 + if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
1.298 + if( page == NULL ) {
1.299 + ERROR( "Attempted byte write to missing page: %08X", addr );
1.300 + return;
1.301 + }
1.302 + TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
1.303 + io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
1.304 + } else {
1.305 + *(uint8_t *)(page+(addr&0xFFF)) = val;
1.306 + }
1.307 +}
1.308 +
1.309 +
1.310 +
1.311 +/* FIXME: Handle all the many special cases when the range doesn't fall cleanly
1.312 + * into the same memory black
1.313 + */
1.314 +void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
1.315 + char *src = mem_get_region(srcaddr);
1.316 + memcpy( dest, src, count );
1.317 +}
1.318 +
1.319 +void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
1.320 + char *dest = mem_get_region(destaddr);
1.321 + memcpy( dest, src, count );
1.322 +}
.