nkeynes@31: /** nkeynes@502: * $Id: armmem.c,v 1.9 2007-11-08 11:54:16 nkeynes Exp $ nkeynes@31: * nkeynes@31: * Implements the ARM's memory map. nkeynes@31: * nkeynes@31: * Copyright (c) 2005 Nathan Keynes. nkeynes@31: * nkeynes@31: * This program is free software; you can redistribute it and/or modify nkeynes@31: * it under the terms of the GNU General Public License as published by nkeynes@31: * the Free Software Foundation; either version 2 of the License, or nkeynes@31: * (at your option) any later version. nkeynes@31: * nkeynes@31: * This program is distributed in the hope that it will be useful, nkeynes@31: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@31: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@31: * GNU General Public License for more details. nkeynes@31: */ nkeynes@31: nkeynes@11: #include nkeynes@11: #include "dream.h" nkeynes@7: #include "mem.h" nkeynes@66: #include "aica.h" nkeynes@7: nkeynes@502: unsigned char *arm_mem = NULL; nkeynes@502: unsigned char *arm_mem_scratch = NULL; nkeynes@11: nkeynes@7: void arm_mem_init() { nkeynes@11: arm_mem = mem_get_region_by_name( MEM_REGION_AUDIO ); nkeynes@40: arm_mem_scratch = mem_get_region_by_name( MEM_REGION_AUDIO_SCRATCH ); nkeynes@7: } nkeynes@7: nkeynes@14: int arm_has_page( uint32_t addr ) { nkeynes@14: return ( addr < 0x00200000 || nkeynes@14: (addr >= 0x00800000 && addr <= 0x00805000 ) ); nkeynes@14: } nkeynes@14: nkeynes@37: uint32_t arm_read_long( uint32_t addr ) { nkeynes@11: if( addr < 0x00200000 ) { nkeynes@11: return *(int32_t *)(arm_mem + addr); nkeynes@11: /* Main sound ram */ nkeynes@11: } else { nkeynes@66: uint32_t val; nkeynes@37: switch( addr & 0xFFFFF000 ) { nkeynes@37: case 0x00800000: nkeynes@66: val = mmio_region_AICA0_read(addr&0x0FFF); nkeynes@66: // DEBUG( "ARM long read from %08X => %08X", addr, val ); nkeynes@66: return val; nkeynes@37: case 0x00801000: nkeynes@66: val = mmio_region_AICA1_read(addr&0x0FFF); nkeynes@66: // DEBUG( "ARM long read from %08X => %08X", addr, val ); nkeynes@66: return val; nkeynes@37: case 0x00802000: nkeynes@66: val = mmio_region_AICA2_read(addr&0x0FFF); nkeynes@66: // DEBUG( "ARM long read from %08X => %08X", addr, val ); nkeynes@66: return val; nkeynes@37: case 0x00803000: nkeynes@37: case 0x00804000: nkeynes@40: return *(int32_t *)(arm_mem_scratch + addr - 0x00803000); nkeynes@37: } nkeynes@11: } nkeynes@37: ERROR( "Attempted long read to undefined page: %08X", nkeynes@37: addr ); nkeynes@37: /* Undefined memory */ nkeynes@37: return 0; nkeynes@7: } nkeynes@7: nkeynes@37: uint32_t arm_read_word( uint32_t addr ) { nkeynes@40: return (uint32_t)(uint16_t)arm_read_long( addr ); nkeynes@7: } nkeynes@7: nkeynes@37: uint32_t arm_read_byte( uint32_t addr ) { nkeynes@40: return (uint32_t)(uint8_t)arm_read_long( addr ); nkeynes@7: } nkeynes@7: nkeynes@37: void arm_write_long( uint32_t addr, uint32_t value ) nkeynes@37: { nkeynes@37: if( addr < 0x00200000 ) { nkeynes@40: /* Main sound ram */ nkeynes@37: *(uint32_t *)(arm_mem + addr) = value; nkeynes@37: } else { nkeynes@40: switch( addr & 0xFFFFF000 ) { nkeynes@40: case 0x00800000: nkeynes@66: // DEBUG( "ARM long write to %08X <= %08X", addr, value ); nkeynes@66: mmio_region_AICA0_write(addr&0x0FFF, value); nkeynes@40: break; nkeynes@40: case 0x00801000: nkeynes@66: // DEBUG( "ARM long write to %08X <= %08X", addr, value ); nkeynes@66: mmio_region_AICA1_write(addr&0x0FFF, value); nkeynes@40: break; nkeynes@40: case 0x00802000: nkeynes@66: // DEBUG( "ARM long write to %08X <= %08X", addr, value ); nkeynes@66: mmio_region_AICA2_write(addr&0x0FFF, value); nkeynes@40: break; nkeynes@40: case 0x00803000: nkeynes@40: case 0x00804000: nkeynes@40: *(uint32_t *)(arm_mem_scratch + addr - 0x00803000) = value; nkeynes@40: break; nkeynes@40: default: nkeynes@40: ERROR( "Attempted long write to undefined address: %08X", nkeynes@40: addr ); nkeynes@40: /* Undefined memory */ nkeynes@40: } nkeynes@37: } nkeynes@431: return; nkeynes@37: } nkeynes@37: nkeynes@66: uint32_t arm_combine_byte( uint32_t addr, uint32_t val, uint8_t byte ) nkeynes@66: { nkeynes@66: switch( addr & 0x03 ) { nkeynes@66: case 0: nkeynes@66: return (val & 0xFFFFFF00) | byte; nkeynes@66: case 1: nkeynes@66: return (val & 0xFFFF00FF) | (byte<<8); nkeynes@66: case 2: nkeynes@66: return (val & 0xFF00FFFF) | (byte<<16); nkeynes@66: case 3: nkeynes@66: return (val & 0x00FFFFFF) | (byte<<24); nkeynes@431: default: nkeynes@431: return val; // Can't happen, but make gcc happy nkeynes@66: } nkeynes@66: } nkeynes@66: nkeynes@37: void arm_write_byte( uint32_t addr, uint32_t value ) nkeynes@37: { nkeynes@37: if( addr < 0x00200000 ) { nkeynes@40: /* Main sound ram */ nkeynes@40: *(uint8_t *)(arm_mem + addr) = (uint8_t)value; nkeynes@37: } else { nkeynes@66: uint32_t tmp; nkeynes@40: switch( addr & 0xFFFFF000 ) { nkeynes@40: case 0x00800000: nkeynes@66: tmp = MMIO_READ( AICA0, addr & 0x0FFC ); nkeynes@66: value = arm_combine_byte( addr, tmp, value ); nkeynes@66: mmio_region_AICA0_write(addr&0x0FFC, value); nkeynes@40: break; nkeynes@40: case 0x00801000: nkeynes@66: tmp = MMIO_READ( AICA1, addr & 0x0FFC ); nkeynes@66: value = arm_combine_byte( addr, tmp, value ); nkeynes@66: mmio_region_AICA1_write(addr&0x0FFC, value); nkeynes@40: break; nkeynes@40: case 0x00802000: nkeynes@66: tmp = MMIO_READ( AICA2, addr & 0x0FFC ); nkeynes@66: value = arm_combine_byte( addr, tmp, value ); nkeynes@66: mmio_region_AICA2_write(addr&0x0FFC, value); nkeynes@40: break; nkeynes@40: case 0x00803000: nkeynes@40: case 0x00804000: nkeynes@40: *(uint8_t *)(arm_mem_scratch + addr - 0x00803000) = (uint8_t)value; nkeynes@40: break; nkeynes@40: default: nkeynes@40: ERROR( "Attempted byte write to undefined address: %08X", nkeynes@40: addr ); nkeynes@40: /* Undefined memory */ nkeynes@40: } nkeynes@37: } nkeynes@431: return; nkeynes@37: } nkeynes@37: nkeynes@37: /* User translations - TODO */ nkeynes@37: nkeynes@11: uint32_t arm_read_long_user( uint32_t addr ) { nkeynes@37: return arm_read_long( addr ); nkeynes@11: } nkeynes@11: nkeynes@11: uint32_t arm_read_byte_user( uint32_t addr ) { nkeynes@37: return arm_read_byte( addr ); nkeynes@37: } nkeynes@11: nkeynes@37: void arm_write_long_user( uint32_t addr, uint32_t val ) { nkeynes@37: arm_write_long( addr, val ); nkeynes@11: } nkeynes@37: nkeynes@37: void arm_write_byte_user( uint32_t addr, uint32_t val ) nkeynes@37: { nkeynes@37: arm_write_byte( addr, val ); nkeynes@37: }