nkeynes@953: /*`* nkeynes@561: * $Id$ 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@968: #include "asic.h" nkeynes@811: #include "armcore.h" nkeynes@7: nkeynes@953: unsigned char aica_main_ram[2 MB]; nkeynes@953: unsigned char aica_scratch_ram[8 KB]; nkeynes@11: nkeynes@953: /*************** ARM memory access function blocks **************/ nkeynes@953: nkeynes@953: static int32_t FASTCALL ext_audioram_read_long( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return *((int32_t *)(aica_main_ram + (addr&0x001FFFFF))); nkeynes@953: } nkeynes@953: static int32_t FASTCALL ext_audioram_read_word( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return SIGNEXT16(*((int16_t *)(aica_main_ram + (addr&0x001FFFFF)))); nkeynes@953: } nkeynes@953: static int32_t FASTCALL ext_audioram_read_byte( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return SIGNEXT8(*((int16_t *)(aica_main_ram + (addr&0x001FFFFF)))); nkeynes@953: } nkeynes@953: static void FASTCALL ext_audioram_write_long( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint32_t *)(aica_main_ram + (addr&0x001FFFFF)) = val; nkeynes@953: asic_g2_write_word(); nkeynes@953: } nkeynes@953: static void FASTCALL ext_audioram_write_word( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint16_t *)(aica_main_ram + (addr&0x001FFFFF)) = (uint16_t)val; nkeynes@953: asic_g2_write_word(); nkeynes@953: } nkeynes@953: static void FASTCALL ext_audioram_write_byte( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint8_t *)(aica_main_ram + (addr&0x001FFFFF)) = (uint8_t)val; nkeynes@953: asic_g2_write_word(); nkeynes@953: } nkeynes@953: static void FASTCALL ext_audioram_read_burst( unsigned char *dest, sh4addr_t addr ) nkeynes@953: { nkeynes@953: memcpy( dest, aica_main_ram+(addr&0x001FFFFF), 32 ); nkeynes@953: } nkeynes@953: static void FASTCALL ext_audioram_write_burst( sh4addr_t addr, unsigned char *src ) nkeynes@953: { nkeynes@953: memcpy( aica_main_ram+(addr&0x001FFFFF), src, 32 ); nkeynes@7: } nkeynes@7: nkeynes@953: struct mem_region_fn mem_region_audioram = { ext_audioram_read_long, ext_audioram_write_long, nkeynes@953: ext_audioram_read_word, ext_audioram_write_word, nkeynes@953: ext_audioram_read_byte, ext_audioram_write_byte, nkeynes@953: ext_audioram_read_burst, ext_audioram_write_burst }; nkeynes@953: nkeynes@953: nkeynes@953: static int32_t FASTCALL ext_audioscratch_read_long( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return *((int32_t *)(aica_scratch_ram + (addr&0x00001FFF))); nkeynes@953: } nkeynes@953: static int32_t FASTCALL ext_audioscratch_read_word( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return SIGNEXT16(*((int16_t *)(aica_scratch_ram + (addr&0x00001FFF)))); nkeynes@953: } nkeynes@953: static int32_t FASTCALL ext_audioscratch_read_byte( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return SIGNEXT8(*((int16_t *)(aica_scratch_ram + (addr&0x00001FFF)))); nkeynes@953: } nkeynes@953: static void FASTCALL ext_audioscratch_write_long( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint32_t *)(aica_scratch_ram + (addr&0x00001FFF)) = val; nkeynes@953: asic_g2_write_word(); nkeynes@953: } nkeynes@953: static void FASTCALL ext_audioscratch_write_word( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint16_t *)(aica_scratch_ram + (addr&0x00001FFF)) = (uint16_t)val; nkeynes@953: asic_g2_write_word(); nkeynes@953: } nkeynes@953: static void FASTCALL ext_audioscratch_write_byte( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint8_t *)(aica_scratch_ram + (addr&0x00001FFF)) = (uint8_t)val; nkeynes@953: asic_g2_write_word(); nkeynes@953: } nkeynes@953: static void FASTCALL ext_audioscratch_read_burst( unsigned char *dest, sh4addr_t addr ) nkeynes@953: { nkeynes@953: memcpy( dest, aica_scratch_ram+(addr&0x00001FFF), 32 ); nkeynes@953: } nkeynes@953: static void FASTCALL ext_audioscratch_write_burst( sh4addr_t addr, unsigned char *src ) nkeynes@953: { nkeynes@953: memcpy( aica_scratch_ram+(addr&0x00001FFF), src, 32 ); nkeynes@953: } nkeynes@953: nkeynes@953: struct mem_region_fn mem_region_audioscratch = { ext_audioscratch_read_long, ext_audioscratch_write_long, nkeynes@953: ext_audioscratch_read_word, ext_audioscratch_write_word, nkeynes@953: ext_audioscratch_read_byte, ext_audioscratch_write_byte, nkeynes@953: ext_audioscratch_read_burst, ext_audioscratch_write_burst }; nkeynes@953: nkeynes@953: /************************** Local ARM support **************************/ nkeynes@14: int arm_has_page( uint32_t addr ) { nkeynes@14: return ( addr < 0x00200000 || nkeynes@736: (addr >= 0x00800000 && addr <= 0x00805000 ) ); nkeynes@14: } nkeynes@14: nkeynes@37: uint32_t arm_read_long( uint32_t addr ) { nkeynes@11: if( addr < 0x00200000 ) { nkeynes@953: return *(int32_t *)(aica_main_ram + addr); nkeynes@736: /* Main sound ram */ nkeynes@11: } else { nkeynes@736: uint32_t val; nkeynes@736: switch( addr & 0xFFFFF000 ) { nkeynes@736: case 0x00800000: nkeynes@736: val = mmio_region_AICA0_read(addr&0x0FFF); nkeynes@736: // DEBUG( "ARM long read from %08X => %08X", addr, val ); nkeynes@736: return val; nkeynes@736: case 0x00801000: nkeynes@736: val = mmio_region_AICA1_read(addr&0x0FFF); nkeynes@736: // DEBUG( "ARM long read from %08X => %08X", addr, val ); nkeynes@736: return val; nkeynes@736: case 0x00802000: nkeynes@736: val = mmio_region_AICA2_read(addr&0x0FFF); nkeynes@736: // DEBUG( "ARM long read from %08X => %08X", addr, val ); nkeynes@736: return val; nkeynes@736: case 0x00803000: nkeynes@736: case 0x00804000: nkeynes@953: return *(int32_t *)(aica_scratch_ram + addr - 0x00803000); nkeynes@736: } nkeynes@11: } nkeynes@811: ERROR( "Attempted long read to undefined page: %08X at %08X", nkeynes@811: addr, armr.r[15] ); 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@736: /* Main sound ram */ nkeynes@953: *(uint32_t *)(aica_main_ram + addr) = value; nkeynes@37: } else { nkeynes@736: switch( addr & 0xFFFFF000 ) { nkeynes@736: case 0x00800000: nkeynes@736: // DEBUG( "ARM long write to %08X <= %08X", addr, value ); nkeynes@736: mmio_region_AICA0_write(addr&0x0FFF, value); nkeynes@736: break; nkeynes@736: case 0x00801000: nkeynes@736: // DEBUG( "ARM long write to %08X <= %08X", addr, value ); nkeynes@736: mmio_region_AICA1_write(addr&0x0FFF, value); nkeynes@736: break; nkeynes@736: case 0x00802000: nkeynes@736: // DEBUG( "ARM long write to %08X <= %08X", addr, value ); nkeynes@736: mmio_region_AICA2_write(addr&0x0FFF, value); nkeynes@736: break; nkeynes@736: case 0x00803000: nkeynes@736: case 0x00804000: nkeynes@953: *(uint32_t *)(aica_scratch_ram + addr - 0x00803000) = value; nkeynes@736: break; nkeynes@736: default: nkeynes@736: ERROR( "Attempted long write to undefined address: %08X", nkeynes@736: addr ); nkeynes@736: /* Undefined memory */ nkeynes@736: } 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@736: return (val & 0xFFFFFF00) | byte; nkeynes@66: case 1: nkeynes@736: return (val & 0xFFFF00FF) | (byte<<8); nkeynes@66: case 2: nkeynes@736: return (val & 0xFF00FFFF) | (byte<<16); nkeynes@66: case 3: nkeynes@736: return (val & 0x00FFFFFF) | (byte<<24); nkeynes@431: default: nkeynes@736: return val; // Can't happen, but make gcc happy nkeynes@66: } nkeynes@66: } nkeynes@811: void arm_write_word( uint32_t addr, uint32_t value ) nkeynes@811: { nkeynes@811: if( addr < 0x00200000 ) { nkeynes@953: *(uint16_t *)(aica_main_ram + addr) = (uint16_t)value; nkeynes@811: } else { nkeynes@811: nkeynes@811: } nkeynes@811: } nkeynes@37: void arm_write_byte( uint32_t addr, uint32_t value ) nkeynes@37: { nkeynes@37: if( addr < 0x00200000 ) { nkeynes@736: /* Main sound ram */ nkeynes@953: *(uint8_t *)(aica_main_ram + addr) = (uint8_t)value; nkeynes@37: } else { nkeynes@736: uint32_t tmp; nkeynes@736: switch( addr & 0xFFFFF000 ) { nkeynes@736: case 0x00800000: nkeynes@736: tmp = MMIO_READ( AICA0, addr & 0x0FFC ); nkeynes@736: value = arm_combine_byte( addr, tmp, value ); nkeynes@736: mmio_region_AICA0_write(addr&0x0FFC, value); nkeynes@736: break; nkeynes@736: case 0x00801000: nkeynes@736: tmp = MMIO_READ( AICA1, addr & 0x0FFC ); nkeynes@736: value = arm_combine_byte( addr, tmp, value ); nkeynes@736: mmio_region_AICA1_write(addr&0x0FFC, value); nkeynes@736: break; nkeynes@736: case 0x00802000: nkeynes@736: tmp = MMIO_READ( AICA2, addr & 0x0FFC ); nkeynes@736: value = arm_combine_byte( addr, tmp, value ); nkeynes@736: mmio_region_AICA2_write(addr&0x0FFC, value); nkeynes@736: break; nkeynes@736: case 0x00803000: nkeynes@736: case 0x00804000: nkeynes@953: *(uint8_t *)(aica_scratch_ram + addr - 0x00803000) = (uint8_t)value; nkeynes@736: break; nkeynes@736: default: nkeynes@736: ERROR( "Attempted byte write to undefined address: %08X", nkeynes@736: addr ); nkeynes@736: /* Undefined memory */ nkeynes@736: } 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: }