nkeynes@934 | 1 | /*`*
|
nkeynes@561 | 2 | * $Id$
|
nkeynes@31 | 3 | *
|
nkeynes@31 | 4 | * Implements the ARM's memory map.
|
nkeynes@31 | 5 | *
|
nkeynes@31 | 6 | * Copyright (c) 2005 Nathan Keynes.
|
nkeynes@31 | 7 | *
|
nkeynes@31 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@31 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@31 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@31 | 11 | * (at your option) any later version.
|
nkeynes@31 | 12 | *
|
nkeynes@31 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@31 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@31 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@31 | 16 | * GNU General Public License for more details.
|
nkeynes@31 | 17 | */
|
nkeynes@31 | 18 |
|
nkeynes@11 | 19 | #include <stdlib.h>
|
nkeynes@11 | 20 | #include "dream.h"
|
nkeynes@7 | 21 | #include "mem.h"
|
nkeynes@66 | 22 | #include "aica.h"
|
nkeynes@811 | 23 | #include "armcore.h"
|
nkeynes@7 | 24 |
|
nkeynes@934 | 25 | unsigned char aica_main_ram[2 MB];
|
nkeynes@934 | 26 | unsigned char aica_scratch_ram[8 KB];
|
nkeynes@7 | 27 |
|
nkeynes@931 | 28 | /*************** ARM memory access function blocks **************/
|
nkeynes@931 | 29 |
|
nkeynes@931 | 30 | static int32_t FASTCALL ext_audioram_read_long( sh4addr_t addr )
|
nkeynes@931 | 31 | {
|
nkeynes@934 | 32 | return *((int32_t *)(aica_main_ram + (addr&0x001FFFFF)));
|
nkeynes@931 | 33 | }
|
nkeynes@931 | 34 | static int32_t FASTCALL ext_audioram_read_word( sh4addr_t addr )
|
nkeynes@931 | 35 | {
|
nkeynes@934 | 36 | return SIGNEXT16(*((int16_t *)(aica_main_ram + (addr&0x001FFFFF))));
|
nkeynes@931 | 37 | }
|
nkeynes@931 | 38 | static int32_t FASTCALL ext_audioram_read_byte( sh4addr_t addr )
|
nkeynes@931 | 39 | {
|
nkeynes@934 | 40 | return SIGNEXT8(*((int16_t *)(aica_main_ram + (addr&0x001FFFFF))));
|
nkeynes@931 | 41 | }
|
nkeynes@931 | 42 | static void FASTCALL ext_audioram_write_long( sh4addr_t addr, uint32_t val )
|
nkeynes@931 | 43 | {
|
nkeynes@934 | 44 | *(uint32_t *)(aica_main_ram + (addr&0x001FFFFF)) = val;
|
nkeynes@931 | 45 | asic_g2_write_word();
|
nkeynes@931 | 46 | }
|
nkeynes@931 | 47 | static void FASTCALL ext_audioram_write_word( sh4addr_t addr, uint32_t val )
|
nkeynes@931 | 48 | {
|
nkeynes@934 | 49 | *(uint16_t *)(aica_main_ram + (addr&0x001FFFFF)) = (uint16_t)val;
|
nkeynes@931 | 50 | asic_g2_write_word();
|
nkeynes@931 | 51 | }
|
nkeynes@931 | 52 | static void FASTCALL ext_audioram_write_byte( sh4addr_t addr, uint32_t val )
|
nkeynes@931 | 53 | {
|
nkeynes@934 | 54 | *(uint8_t *)(aica_main_ram + (addr&0x001FFFFF)) = (uint8_t)val;
|
nkeynes@931 | 55 | asic_g2_write_word();
|
nkeynes@931 | 56 | }
|
nkeynes@931 | 57 | static void FASTCALL ext_audioram_read_burst( unsigned char *dest, sh4addr_t addr )
|
nkeynes@931 | 58 | {
|
nkeynes@934 | 59 | memcpy( dest, aica_main_ram+(addr&0x001FFFFF), 32 );
|
nkeynes@931 | 60 | }
|
nkeynes@931 | 61 | static void FASTCALL ext_audioram_write_burst( sh4addr_t addr, unsigned char *src )
|
nkeynes@931 | 62 | {
|
nkeynes@934 | 63 | memcpy( aica_main_ram+(addr&0x001FFFFF), src, 32 );
|
nkeynes@931 | 64 | }
|
nkeynes@931 | 65 |
|
nkeynes@931 | 66 | struct mem_region_fn mem_region_audioram = { ext_audioram_read_long, ext_audioram_write_long,
|
nkeynes@931 | 67 | ext_audioram_read_word, ext_audioram_write_word,
|
nkeynes@931 | 68 | ext_audioram_read_byte, ext_audioram_write_byte,
|
nkeynes@931 | 69 | ext_audioram_read_burst, ext_audioram_write_burst };
|
nkeynes@931 | 70 |
|
nkeynes@931 | 71 |
|
nkeynes@931 | 72 | static int32_t FASTCALL ext_audioscratch_read_long( sh4addr_t addr )
|
nkeynes@931 | 73 | {
|
nkeynes@934 | 74 | return *((int32_t *)(aica_scratch_ram + (addr&0x00001FFF)));
|
nkeynes@931 | 75 | }
|
nkeynes@931 | 76 | static int32_t FASTCALL ext_audioscratch_read_word( sh4addr_t addr )
|
nkeynes@931 | 77 | {
|
nkeynes@934 | 78 | return SIGNEXT16(*((int16_t *)(aica_scratch_ram + (addr&0x00001FFF))));
|
nkeynes@931 | 79 | }
|
nkeynes@931 | 80 | static int32_t FASTCALL ext_audioscratch_read_byte( sh4addr_t addr )
|
nkeynes@931 | 81 | {
|
nkeynes@934 | 82 | return SIGNEXT8(*((int16_t *)(aica_scratch_ram + (addr&0x00001FFF))));
|
nkeynes@931 | 83 | }
|
nkeynes@931 | 84 | static void FASTCALL ext_audioscratch_write_long( sh4addr_t addr, uint32_t val )
|
nkeynes@931 | 85 | {
|
nkeynes@934 | 86 | *(uint32_t *)(aica_scratch_ram + (addr&0x00001FFF)) = val;
|
nkeynes@931 | 87 | asic_g2_write_word();
|
nkeynes@931 | 88 | }
|
nkeynes@931 | 89 | static void FASTCALL ext_audioscratch_write_word( sh4addr_t addr, uint32_t val )
|
nkeynes@931 | 90 | {
|
nkeynes@934 | 91 | *(uint16_t *)(aica_scratch_ram + (addr&0x00001FFF)) = (uint16_t)val;
|
nkeynes@931 | 92 | asic_g2_write_word();
|
nkeynes@931 | 93 | }
|
nkeynes@931 | 94 | static void FASTCALL ext_audioscratch_write_byte( sh4addr_t addr, uint32_t val )
|
nkeynes@931 | 95 | {
|
nkeynes@934 | 96 | *(uint8_t *)(aica_scratch_ram + (addr&0x00001FFF)) = (uint8_t)val;
|
nkeynes@931 | 97 | asic_g2_write_word();
|
nkeynes@931 | 98 | }
|
nkeynes@931 | 99 | static void FASTCALL ext_audioscratch_read_burst( unsigned char *dest, sh4addr_t addr )
|
nkeynes@931 | 100 | {
|
nkeynes@934 | 101 | memcpy( dest, aica_scratch_ram+(addr&0x00001FFF), 32 );
|
nkeynes@931 | 102 | }
|
nkeynes@931 | 103 | static void FASTCALL ext_audioscratch_write_burst( sh4addr_t addr, unsigned char *src )
|
nkeynes@931 | 104 | {
|
nkeynes@934 | 105 | memcpy( aica_scratch_ram+(addr&0x00001FFF), src, 32 );
|
nkeynes@931 | 106 | }
|
nkeynes@931 | 107 |
|
nkeynes@931 | 108 | struct mem_region_fn mem_region_audioscratch = { ext_audioscratch_read_long, ext_audioscratch_write_long,
|
nkeynes@931 | 109 | ext_audioscratch_read_word, ext_audioscratch_write_word,
|
nkeynes@931 | 110 | ext_audioscratch_read_byte, ext_audioscratch_write_byte,
|
nkeynes@931 | 111 | ext_audioscratch_read_burst, ext_audioscratch_write_burst };
|
nkeynes@931 | 112 |
|
nkeynes@931 | 113 | /************************** Local ARM support **************************/
|
nkeynes@14 | 114 | int arm_has_page( uint32_t addr ) {
|
nkeynes@14 | 115 | return ( addr < 0x00200000 ||
|
nkeynes@736 | 116 | (addr >= 0x00800000 && addr <= 0x00805000 ) );
|
nkeynes@14 | 117 | }
|
nkeynes@14 | 118 |
|
nkeynes@37 | 119 | uint32_t arm_read_long( uint32_t addr ) {
|
nkeynes@11 | 120 | if( addr < 0x00200000 ) {
|
nkeynes@934 | 121 | return *(int32_t *)(aica_main_ram + addr);
|
nkeynes@736 | 122 | /* Main sound ram */
|
nkeynes@11 | 123 | } else {
|
nkeynes@736 | 124 | uint32_t val;
|
nkeynes@736 | 125 | switch( addr & 0xFFFFF000 ) {
|
nkeynes@736 | 126 | case 0x00800000:
|
nkeynes@736 | 127 | val = mmio_region_AICA0_read(addr&0x0FFF);
|
nkeynes@736 | 128 | // DEBUG( "ARM long read from %08X => %08X", addr, val );
|
nkeynes@736 | 129 | return val;
|
nkeynes@736 | 130 | case 0x00801000:
|
nkeynes@736 | 131 | val = mmio_region_AICA1_read(addr&0x0FFF);
|
nkeynes@736 | 132 | // DEBUG( "ARM long read from %08X => %08X", addr, val );
|
nkeynes@736 | 133 | return val;
|
nkeynes@736 | 134 | case 0x00802000:
|
nkeynes@736 | 135 | val = mmio_region_AICA2_read(addr&0x0FFF);
|
nkeynes@736 | 136 | // DEBUG( "ARM long read from %08X => %08X", addr, val );
|
nkeynes@736 | 137 | return val;
|
nkeynes@736 | 138 | case 0x00803000:
|
nkeynes@736 | 139 | case 0x00804000:
|
nkeynes@934 | 140 | return *(int32_t *)(aica_scratch_ram + addr - 0x00803000);
|
nkeynes@736 | 141 | }
|
nkeynes@11 | 142 | }
|
nkeynes@811 | 143 | ERROR( "Attempted long read to undefined page: %08X at %08X",
|
nkeynes@811 | 144 | addr, armr.r[15] );
|
nkeynes@37 | 145 | /* Undefined memory */
|
nkeynes@37 | 146 | return 0;
|
nkeynes@7 | 147 | }
|
nkeynes@7 | 148 |
|
nkeynes@37 | 149 | uint32_t arm_read_word( uint32_t addr ) {
|
nkeynes@40 | 150 | return (uint32_t)(uint16_t)arm_read_long( addr );
|
nkeynes@7 | 151 | }
|
nkeynes@7 | 152 |
|
nkeynes@37 | 153 | uint32_t arm_read_byte( uint32_t addr ) {
|
nkeynes@40 | 154 | return (uint32_t)(uint8_t)arm_read_long( addr );
|
nkeynes@7 | 155 | }
|
nkeynes@7 | 156 |
|
nkeynes@37 | 157 | void arm_write_long( uint32_t addr, uint32_t value )
|
nkeynes@37 | 158 | {
|
nkeynes@37 | 159 | if( addr < 0x00200000 ) {
|
nkeynes@736 | 160 | /* Main sound ram */
|
nkeynes@934 | 161 | *(uint32_t *)(aica_main_ram + addr) = value;
|
nkeynes@37 | 162 | } else {
|
nkeynes@736 | 163 | switch( addr & 0xFFFFF000 ) {
|
nkeynes@736 | 164 | case 0x00800000:
|
nkeynes@736 | 165 | // DEBUG( "ARM long write to %08X <= %08X", addr, value );
|
nkeynes@736 | 166 | mmio_region_AICA0_write(addr&0x0FFF, value);
|
nkeynes@736 | 167 | break;
|
nkeynes@736 | 168 | case 0x00801000:
|
nkeynes@736 | 169 | // DEBUG( "ARM long write to %08X <= %08X", addr, value );
|
nkeynes@736 | 170 | mmio_region_AICA1_write(addr&0x0FFF, value);
|
nkeynes@736 | 171 | break;
|
nkeynes@736 | 172 | case 0x00802000:
|
nkeynes@736 | 173 | // DEBUG( "ARM long write to %08X <= %08X", addr, value );
|
nkeynes@736 | 174 | mmio_region_AICA2_write(addr&0x0FFF, value);
|
nkeynes@736 | 175 | break;
|
nkeynes@736 | 176 | case 0x00803000:
|
nkeynes@736 | 177 | case 0x00804000:
|
nkeynes@934 | 178 | *(uint32_t *)(aica_scratch_ram + addr - 0x00803000) = value;
|
nkeynes@736 | 179 | break;
|
nkeynes@736 | 180 | default:
|
nkeynes@736 | 181 | ERROR( "Attempted long write to undefined address: %08X",
|
nkeynes@736 | 182 | addr );
|
nkeynes@736 | 183 | /* Undefined memory */
|
nkeynes@736 | 184 | }
|
nkeynes@37 | 185 | }
|
nkeynes@431 | 186 | return;
|
nkeynes@37 | 187 | }
|
nkeynes@37 | 188 |
|
nkeynes@66 | 189 | uint32_t arm_combine_byte( uint32_t addr, uint32_t val, uint8_t byte )
|
nkeynes@66 | 190 | {
|
nkeynes@66 | 191 | switch( addr & 0x03 ) {
|
nkeynes@66 | 192 | case 0:
|
nkeynes@736 | 193 | return (val & 0xFFFFFF00) | byte;
|
nkeynes@66 | 194 | case 1:
|
nkeynes@736 | 195 | return (val & 0xFFFF00FF) | (byte<<8);
|
nkeynes@66 | 196 | case 2:
|
nkeynes@736 | 197 | return (val & 0xFF00FFFF) | (byte<<16);
|
nkeynes@66 | 198 | case 3:
|
nkeynes@736 | 199 | return (val & 0x00FFFFFF) | (byte<<24);
|
nkeynes@431 | 200 | default:
|
nkeynes@736 | 201 | return val; // Can't happen, but make gcc happy
|
nkeynes@66 | 202 | }
|
nkeynes@66 | 203 | }
|
nkeynes@811 | 204 | void arm_write_word( uint32_t addr, uint32_t value )
|
nkeynes@811 | 205 | {
|
nkeynes@811 | 206 | if( addr < 0x00200000 ) {
|
nkeynes@934 | 207 | *(uint16_t *)(aica_main_ram + addr) = (uint16_t)value;
|
nkeynes@811 | 208 | } else {
|
nkeynes@811 | 209 |
|
nkeynes@811 | 210 | }
|
nkeynes@811 | 211 | }
|
nkeynes@37 | 212 | void arm_write_byte( uint32_t addr, uint32_t value )
|
nkeynes@37 | 213 | {
|
nkeynes@37 | 214 | if( addr < 0x00200000 ) {
|
nkeynes@736 | 215 | /* Main sound ram */
|
nkeynes@934 | 216 | *(uint8_t *)(aica_main_ram + addr) = (uint8_t)value;
|
nkeynes@37 | 217 | } else {
|
nkeynes@736 | 218 | uint32_t tmp;
|
nkeynes@736 | 219 | switch( addr & 0xFFFFF000 ) {
|
nkeynes@736 | 220 | case 0x00800000:
|
nkeynes@736 | 221 | tmp = MMIO_READ( AICA0, addr & 0x0FFC );
|
nkeynes@736 | 222 | value = arm_combine_byte( addr, tmp, value );
|
nkeynes@736 | 223 | mmio_region_AICA0_write(addr&0x0FFC, value);
|
nkeynes@736 | 224 | break;
|
nkeynes@736 | 225 | case 0x00801000:
|
nkeynes@736 | 226 | tmp = MMIO_READ( AICA1, addr & 0x0FFC );
|
nkeynes@736 | 227 | value = arm_combine_byte( addr, tmp, value );
|
nkeynes@736 | 228 | mmio_region_AICA1_write(addr&0x0FFC, value);
|
nkeynes@736 | 229 | break;
|
nkeynes@736 | 230 | case 0x00802000:
|
nkeynes@736 | 231 | tmp = MMIO_READ( AICA2, addr & 0x0FFC );
|
nkeynes@736 | 232 | value = arm_combine_byte( addr, tmp, value );
|
nkeynes@736 | 233 | mmio_region_AICA2_write(addr&0x0FFC, value);
|
nkeynes@736 | 234 | break;
|
nkeynes@736 | 235 | case 0x00803000:
|
nkeynes@736 | 236 | case 0x00804000:
|
nkeynes@934 | 237 | *(uint8_t *)(aica_scratch_ram + addr - 0x00803000) = (uint8_t)value;
|
nkeynes@736 | 238 | break;
|
nkeynes@736 | 239 | default:
|
nkeynes@736 | 240 | ERROR( "Attempted byte write to undefined address: %08X",
|
nkeynes@736 | 241 | addr );
|
nkeynes@736 | 242 | /* Undefined memory */
|
nkeynes@736 | 243 | }
|
nkeynes@37 | 244 | }
|
nkeynes@431 | 245 | return;
|
nkeynes@37 | 246 | }
|
nkeynes@37 | 247 |
|
nkeynes@37 | 248 | /* User translations - TODO */
|
nkeynes@37 | 249 |
|
nkeynes@11 | 250 | uint32_t arm_read_long_user( uint32_t addr ) {
|
nkeynes@37 | 251 | return arm_read_long( addr );
|
nkeynes@11 | 252 | }
|
nkeynes@11 | 253 |
|
nkeynes@11 | 254 | uint32_t arm_read_byte_user( uint32_t addr ) {
|
nkeynes@37 | 255 | return arm_read_byte( addr );
|
nkeynes@37 | 256 | }
|
nkeynes@11 | 257 |
|
nkeynes@37 | 258 | void arm_write_long_user( uint32_t addr, uint32_t val ) {
|
nkeynes@37 | 259 | arm_write_long( addr, val );
|
nkeynes@11 | 260 | }
|
nkeynes@37 | 261 |
|
nkeynes@37 | 262 | void arm_write_byte_user( uint32_t addr, uint32_t val )
|
nkeynes@37 | 263 | {
|
nkeynes@37 | 264 | arm_write_byte( addr, val );
|
nkeynes@37 | 265 | }
|