📄 memory.c
字号:
/* gameplaySP * * Copyright (C) 2006 Exophase <exophase@gmail.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */#include "common.h"// This table is configured for sequential access on system defaultsu32 waitstate_cycles_sequential[16][3] ={ { 1, 1, 1 }, // BIOS { 1, 1, 1 }, // Invalid { 3, 3, 6 }, // EWRAM (default settings) { 1, 1, 1 }, // IWRAM { 1, 1, 1 }, // IO Registers { 1, 1, 2 }, // Palette RAM { 1, 1, 2 }, // VRAM { 1, 1, 2 }, // OAM { 3, 3, 6 }, // Gamepak (wait 0) { 3, 3, 6 }, // Gamepak (wait 0) { 5, 5, 9 }, // Gamepak (wait 1) { 5, 5, 9 }, // Gamepak (wait 1) { 9, 9, 17 }, // Gamepak (wait 2) { 9, 9, 17 }, // Gamepak (wait 2)};// Different settings for gamepak ws0-2 sequential (2nd) accessu32 gamepak_waitstate_sequential[2][3][3] ={ { { 3, 3, 6 }, { 5, 5, 9 }, { 9, 9, 17 } }, { { 2, 2, 3 }, { 2, 2, 3 }, { 2, 2, 3 } }};#ifdef PSP_BUILD_VRAM_STORAGEu16 *palette_ram = (u16 *)(0x4000000 + (1024 * 32 * 15));u16 *palette_ram_converted = (u16 *)(0x4000000 + (1024 * 32 * 15) + 1024);u16 *oam_ram = (u16 *)(0x4000000 + (1024 * 32 * 15) + 1024 + 1024);u16 *io_registers = (u16 *)(0x4000000 + (1024 * 32 * 16));u8 *iwram = (u8 *)(0x4000000 + (1024 * 32 * 18));u8 *ewram = (u8 *)(0x4000000 + (1024 * 32 * 20));u8 *vram = (u8 *)(0x4000000 + (1024 * 32 * 36));#elseu16 palette_ram[512];u16 oam_ram[512];u16 palette_ram_converted[512];u16 io_registers[1024 * 16];u8 ewram[1024 * 256 * 2];u8 iwram[1024 * 32 * 2];u8 vram[1024 * 96 * 2];#endifu8 bios_rom[1024 * 32];u32 bios_read_protect;// Up to 128kb, store SRAM, flash ROM, or EEPROM here.u8 gamepak_backup[1024 * 128];// Keeps us knowing how much we have left.u8 *gamepak_rom;u32 gamepak_size;dma_transfer_type dma[4];u8 *memory_regions[16];u32 memory_limits[16];typedef struct{ u32 page_timestamp; u32 physical_index;} gamepak_swap_entry_type;u32 gamepak_ram_buffer_size;u32 gamepak_ram_pages;// Enough to map the gamepak RAM space.gamepak_swap_entry_type *gamepak_memory_map;// This is global so that it can be kept open for large ROMs to swap// pages from, so there's no slowdown with opening and closing the file// a lot.#ifdef PSP_BUILDfile_tag_type gamepak_file_large = -1;#elsefile_tag_type gamepak_file_large = NULL;#endifu32 direct_map_vram = 0;// Writes to these respective locations should trigger an update// so the related subsystem may react to it.// If OAM is written to:u32 oam_update = 1;// If GBC audio is written to:u32 gbc_sound_update = 0;// If the GBC audio waveform is modified:u32 gbc_sound_wave_update = 0;// If the backup space is written (only update once this hits 0)u32 backup_update = 0;// Write out backup file this many cycles after the most recent// backup write.const u32 write_backup_delay = 10;typedef enum{ BACKUP_SRAM, BACKUP_FLASH, BACKUP_EEPROM, BACKUP_NONE} backup_type_type;typedef enum{ SRAM_SIZE_32KB, SRAM_SIZE_64KB} sram_size_type;// Keep it 32KB until the upper 64KB is accessed, then make it 64KB.backup_type_type backup_type = BACKUP_NONE;sram_size_type sram_size = SRAM_SIZE_32KB;typedef enum{ FLASH_BASE_MODE, FLASH_ERASE_MODE, FLASH_ID_MODE, FLASH_WRITE_MODE, FLASH_BANKSWITCH_MODE} flash_mode_type;typedef enum{ FLASH_SIZE_64KB, FLASH_SIZE_128KB} flash_size_type;flash_mode_type flash_mode = FLASH_BASE_MODE;u32 flash_command_position = 0;u8 *flash_bank_ptr = gamepak_backup;flash_device_id_type flash_device_id = FLASH_DEVICE_MACRONIX_64KB;flash_manufacturer_id_type flash_manufacturer_id = FLASH_MANUFACTURER_MACRONIX;flash_size_type flash_size = FLASH_SIZE_64KB;u8 read_backup(u32 address){ u8 value; if(backup_type == BACKUP_NONE) backup_type = BACKUP_SRAM; if(backup_type == BACKUP_SRAM) { value = gamepak_backup[address]; } else if(flash_mode == FLASH_ID_MODE) { /* ID manufacturer type */ if(address == 0x0000) value = flash_manufacturer_id; else /* ID device type */ if(address == 0x0001) value = flash_device_id; } else { value = flash_bank_ptr[address]; } return value;}#define read_backup8() \ value = read_backup(address & 0xFFFF) \#define read_backup16() \ value = 0 \#define read_backup32() \ value = 0 \// EEPROM is 512 bytes by default; it is autodetecte as 8KB if// 14bit address DMAs are made (this is done in the DMA handler).typedef enum{ EEPROM_512_BYTE, EEPROM_8_KBYTE} eeprom_size_type;typedef enum{ EEPROM_BASE_MODE, EEPROM_READ_MODE, EEPROM_READ_HEADER_MODE, EEPROM_ADDRESS_MODE, EEPROM_WRITE_MODE, EEPROM_WRITE_ADDRESS_MODE, EEPROM_ADDRESS_FOOTER_MODE, EEPROM_WRITE_FOOTER_MODE} eeprom_mode_type;eeprom_size_type eeprom_size = EEPROM_512_BYTE;eeprom_mode_type eeprom_mode = EEPROM_BASE_MODE;u32 eeprom_address_length;u32 eeprom_address = 0;s32 eeprom_counter = 0;u8 eeprom_buffer[8];void function_cc write_eeprom(u32 address, u32 value){ switch(eeprom_mode) { case EEPROM_BASE_MODE: backup_type = BACKUP_EEPROM; eeprom_buffer[0] |= (value & 0x01) << (1 - eeprom_counter); eeprom_counter++; if(eeprom_counter == 2) { if(eeprom_size == EEPROM_512_BYTE) eeprom_address_length = 6; else eeprom_address_length = 14; eeprom_counter = 0; switch(eeprom_buffer[0] & 0x03) { case 0x02: eeprom_mode = EEPROM_WRITE_ADDRESS_MODE; break; case 0x03: eeprom_mode = EEPROM_ADDRESS_MODE; break; } address16(eeprom_buffer, 0) = 0; } break; case EEPROM_ADDRESS_MODE: case EEPROM_WRITE_ADDRESS_MODE: eeprom_buffer[eeprom_counter / 8] |= (value & 0x01) << (7 - (eeprom_counter % 8)); eeprom_counter++; if(eeprom_counter == eeprom_address_length) { if(eeprom_size == EEPROM_512_BYTE) { eeprom_address = (address16(eeprom_buffer, 0) >> 2) * 8; } else { eeprom_address = (((u32)eeprom_buffer[1] >> 2) | ((u32)eeprom_buffer[0] << 6)) * 8; } address16(eeprom_buffer, 0) = 0; eeprom_counter = 0; if(eeprom_mode == EEPROM_ADDRESS_MODE) { eeprom_mode = EEPROM_ADDRESS_FOOTER_MODE; } else { eeprom_mode = EEPROM_WRITE_MODE; memset(gamepak_backup + eeprom_address, 0, 8); } } break; case EEPROM_WRITE_MODE: gamepak_backup[eeprom_address + (eeprom_counter / 8)] |= (value & 0x01) << (7 - (eeprom_counter % 8)); eeprom_counter++; if(eeprom_counter == 64) { backup_update = write_backup_delay; eeprom_counter = 0; eeprom_mode = EEPROM_WRITE_FOOTER_MODE; } break; case EEPROM_ADDRESS_FOOTER_MODE: case EEPROM_WRITE_FOOTER_MODE: eeprom_counter = 0; if(eeprom_mode == EEPROM_ADDRESS_FOOTER_MODE) { eeprom_mode = EEPROM_READ_HEADER_MODE; } else { eeprom_mode = EEPROM_BASE_MODE; } break; }}#define read_memory_gamepak(type) \ u32 gamepak_index = address >> 15; \ u8 *map = memory_map_read[gamepak_index]; \ \ if(map == NULL) \ map = load_gamepak_page(gamepak_index & 0x3FF); \ \ value = address##type(map, address & 0x7FFF) \#define read_open8() \ if(!(reg[REG_CPSR] & 0x20)) \ value = read_memory8(reg[REG_PC] + 4 + (address & 0x03)); \ else \ value = read_memory8(reg[REG_PC] + 2 + (address & 0x01)) \#define read_open16() \ if(!(reg[REG_CPSR] & 0x20)) \ value = read_memory16(reg[REG_PC] + 4 + (address & 0x02)); \ else \ value = read_memory16(reg[REG_PC] + 2) \#define read_open32() \ if(!(reg[REG_CPSR] & 0x20)) \ { \ value = read_memory32(reg[REG_PC] + 4); \ } \ else \ { \ u32 current_instruction = read_memory16(reg[REG_PC] + 2); \ value = current_instruction | (current_instruction << 16); \ } \u32 function_cc read_eeprom(){ u32 value; switch(eeprom_mode) { case EEPROM_BASE_MODE: value = 1; break; case EEPROM_READ_MODE: value = (gamepak_backup[eeprom_address + (eeprom_counter / 8)] >> (7 - (eeprom_counter % 8))) & 0x01; eeprom_counter++; if(eeprom_counter == 64) { eeprom_counter = 0; eeprom_mode = EEPROM_BASE_MODE; } break; case EEPROM_READ_HEADER_MODE: value = 0; eeprom_counter++; if(eeprom_counter == 4) { eeprom_mode = EEPROM_READ_MODE; eeprom_counter = 0; } break; default: value = 0; break; } return value;}#define read_memory(type) \ switch(address >> 24) \ { \ case 0x00: \ /* BIOS */ \ if(reg[REG_PC] >= 0x4000) \ value = address##type(&bios_read_protect, address & 0x03); \ else \ value = address##type(bios_rom, address & 0x3FFF); \ break; \ \ case 0x02: \ /* external work RAM */ \ address = (address & 0x7FFF) + ((address & 0x38000) * 2) + 0x8000; \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -