📄 memory.c
字号:
address32(palette_ram, palette_address) = value; \ convert_palette(value_high); \ convert_palette(value_low); \ value = (value_high << 16) | value_low; \ address32(palette_ram_converted, palette_address) = value; \} \void function_cc write_backup(u32 address, u32 value){ value &= 0xFF; if(backup_type == BACKUP_NONE) backup_type = BACKUP_SRAM; // gamepak SRAM or Flash ROM if((address == 0x5555) && (flash_mode != FLASH_WRITE_MODE)) { if((flash_command_position == 0) && (value == 0xAA)) { backup_type = BACKUP_FLASH; flash_command_position = 1; } if(flash_command_position == 2) { switch(value) { case 0x90: // Enter ID mode, this also tells the emulator that we're using // flash, not SRAM if(flash_mode == FLASH_BASE_MODE) flash_mode = FLASH_ID_MODE; break; case 0x80: // Enter erase mode if(flash_mode == FLASH_BASE_MODE) flash_mode = FLASH_ERASE_MODE; break; case 0xF0: // Terminate ID mode if(flash_mode == FLASH_ID_MODE) flash_mode = FLASH_BASE_MODE; break; case 0xA0: // Write mode if(flash_mode == FLASH_BASE_MODE) flash_mode = FLASH_WRITE_MODE; break; case 0xB0: // Bank switch // Here the chip is now officially 128KB. flash_size = FLASH_SIZE_128KB; if(flash_mode == FLASH_BASE_MODE) flash_mode = FLASH_BANKSWITCH_MODE; break; case 0x10: // Erase chip if(flash_mode == FLASH_ERASE_MODE) { if(flash_size == FLASH_SIZE_64KB) memset(gamepak_backup, 0xFF, 1024 * 64); else memset(gamepak_backup, 0xFF, 1024 * 128); backup_update = write_backup_delay; flash_mode = FLASH_BASE_MODE; } break; default: break; } flash_command_position = 0; } if(backup_type == BACKUP_SRAM) gamepak_backup[0x5555] = value; } else if((address == 0x2AAA) && (value == 0x55) && (flash_command_position == 1)) { flash_command_position = 2; } else { if((flash_command_position == 2) && (flash_mode == FLASH_ERASE_MODE) && (value == 0x30)) { // Erase sector memset(flash_bank_ptr + (address & 0xF000), 0xFF, 1024 * 4); backup_update = write_backup_delay; flash_mode = FLASH_BASE_MODE; flash_command_position = 0; } else if((flash_command_position == 0) && (flash_mode == FLASH_BANKSWITCH_MODE) && (address == 0x0000)) { flash_bank_ptr = gamepak_backup + (value & 0x01) * (1024 * 64); flash_mode = FLASH_BASE_MODE; } else if((flash_command_position == 0) && (flash_mode == FLASH_WRITE_MODE)) { // Write value to flash ROM backup_update = write_backup_delay; flash_bank_ptr[address] = value; flash_mode = FLASH_BASE_MODE; } else if(backup_type == BACKUP_SRAM) { // Write value to SRAM backup_update = write_backup_delay; // Hit 64KB territory? if(address >= 0x8000) sram_size = SRAM_SIZE_64KB; gamepak_backup[address] = value; } }}#define write_backup8() \ write_backup(address & 0xFFFF, value) \#define write_backup16() \#define write_backup32() \#define write_vram8() \ address &= ~0x01; \ address16(vram, address) = ((value << 8) | value) \#define write_vram16() \ address16(vram, address) = value \#define write_vram32() \ address32(vram, address) = value \// RTC code derived from VBA's (due to lack of any real publically available// documentation...)typedef enum{ RTC_DISABLED, RTC_IDLE, RTC_COMMAND, RTC_OUTPUT_DATA, RTC_INPUT_DATA} rtc_state_type;typedef enum{ RTC_COMMAND_RESET = 0x60, RTC_COMMAND_WRITE_STATUS = 0x62, RTC_COMMAND_READ_STATUS = 0x63, RTC_COMMAND_OUTPUT_TIME_FULL = 0x65, RTC_COMMAND_OUTPUT_TIME = 0x67} rtc_command_type;typedef enum{ RTC_WRITE_TIME, RTC_WRITE_TIME_FULL, RTC_WRITE_STATUS} rtc_write_mode_type;rtc_state_type rtc_state = RTC_DISABLED;rtc_write_mode_type rtc_write_mode;u8 rtc_registers[3];u32 rtc_command;u32 rtc_data[12];u32 rtc_status = 0x40;u32 rtc_data_bytes;s32 rtc_bit_count;u32 encode_bcd(u8 value){ return ((value / 10) << 4) | (value % 10);}#define write_rtc_register(index, _value) \ update_address = 0x80000C4 + (index * 2); \ rtc_registers[index] = _value; \ rtc_page_index = update_address >> 15; \ map = memory_map_read[rtc_page_index]; \ \ if(map == NULL) \ map = load_gamepak_page(rtc_page_index & 0x3FF); \ \ address16(map, update_address & 0x7FFF) = _value \void function_cc write_rtc(u32 address, u32 value){ u32 rtc_page_index; u32 update_address; u8 *map; value &= 0xFFFF; switch(address) { // RTC command // Bit 0: SCHK, perform action // Bit 1: IO, input/output command data // Bit 2: CS, select input/output? If high make I/O write only case 0xC4: if(rtc_state == RTC_DISABLED) rtc_state = RTC_IDLE; if(!(rtc_registers[0] & 0x04)) value = (rtc_registers[0] & 0x02) | (value & ~0x02); if(rtc_registers[2] & 0x01) { // To begin writing a command 1, 5 must be written to the command // registers. if((rtc_state == RTC_IDLE) && (rtc_registers[0] == 0x01) && (value == 0x05)) { // We're now ready to begin receiving a command. write_rtc_register(0, value); rtc_state = RTC_COMMAND; rtc_command = 0; rtc_bit_count = 7; } else { write_rtc_register(0, value); switch(rtc_state) { // Accumulate RTC command by receiving the next bit, and if we // have accumulated enough bits to form a complete command // execute it. case RTC_COMMAND: if(rtc_registers[0] & 0x01) { rtc_command |= ((value & 0x02) >> 1) << rtc_bit_count; rtc_bit_count--; } // Have we received a full RTC command? If so execute it. if(rtc_bit_count < 0) { switch(rtc_command) { // Resets RTC case RTC_COMMAND_RESET: rtc_state = RTC_IDLE; memset(rtc_registers, 0, sizeof(rtc_registers)); break; // Sets status of RTC case RTC_COMMAND_WRITE_STATUS: rtc_state = RTC_INPUT_DATA; rtc_data_bytes = 1; rtc_write_mode = RTC_WRITE_STATUS; break; // Outputs current status of RTC case RTC_COMMAND_READ_STATUS: rtc_state = RTC_OUTPUT_DATA; rtc_data_bytes = 1; rtc_data[0] = rtc_status; break; // Actually outputs the time, all of it case RTC_COMMAND_OUTPUT_TIME_FULL: { struct tm *current_time; time_t current_time_flat; u32 day_of_week; time(¤t_time_flat); current_time = localtime(¤t_time_flat); day_of_week = current_time->tm_wday; if(day_of_week == 0) day_of_week = 6; else day_of_week--; rtc_state = RTC_OUTPUT_DATA; rtc_data_bytes = 7; rtc_data[0] = encode_bcd(current_time->tm_year % 100); rtc_data[1] = encode_bcd(current_time->tm_mon + 1); rtc_data[2] = encode_bcd(current_time->tm_mday); rtc_data[3] = encode_bcd(day_of_week); rtc_data[4] = encode_bcd(current_time->tm_hour); rtc_data[5] = encode_bcd(current_time->tm_min); rtc_data[6] = encode_bcd(current_time->tm_sec); break; } // Only outputs the current time of day. case RTC_COMMAND_OUTPUT_TIME: { struct tm *current_time; time_t current_time_flat; time(¤t_time_flat); current_time = localtime(¤t_time_flat); rtc_state = RTC_OUTPUT_DATA; rtc_data_bytes = 3; rtc_data[0] = encode_bcd(current_time->tm_hour); rtc_data[1] = encode_bcd(current_time->tm_min); rtc_data[2] = encode_bcd(current_time->tm_sec); break; } } rtc_bit_count = 0; } break; // Receive parameters from the game as input to the RTC // for a given command. Read one bit at a time. case RTC_INPUT_DATA: // Bit 1 of parameter A must be high for input if(rtc_registers[1] & 0x02) { // Read next bit for input if(!(value & 0x01)) { rtc_data[rtc_bit_count >> 3] |= ((value & 0x01) << (7 - (rtc_bit_count & 0x07))); } else { rtc_bit_count++; if(rtc_bit_count == (rtc_data_bytes * 8)) { rtc_state = RTC_IDLE; switch(rtc_write_mode) { case RTC_WRITE_STATUS: rtc_status = rtc_data[0]; break; } } } } break; case RTC_OUTPUT_DATA: // Bit 1 of parameter A must be low for output if(!(rtc_registers[1] & 0x02)) { // Write next bit to output, on bit 1 of parameter B if(!(value & 0x01)) { u8 current_output_byte = rtc_registers[2]; current_output_byte = (current_output_byte & ~0x02) | (((rtc_data[rtc_bit_count >> 3] >> (rtc_bit_count & 0x07)) & 0x01) << 1); write_rtc_register(0, current_output_byte); } else { rtc_bit_count++; if(rtc_bit_count == (rtc_data_bytes * 8)) { rtc_state = RTC_IDLE; memset(rtc_registers, 0, sizeof(rtc_registers)); } } } break; } } } else { write_rtc_register(2, value); } break; // Write parameter A case 0xC6: write_rtc_register(1, value); break; // Write parameter B case 0xC8: write_rtc_register(2, value); break; }}#define write_rtc8() \#define write_rtc16() \ write_rtc(address & 0xFF, value) \#define write_rtc32() \#define write_memory(type) \ switch(address >> 24) \ { \ case 0x02: \ /* external work RAM */ \ address = (address & 0x7FFF) + ((address & 0x38000) * 2) + 0x8000; \ address##type(ewram, address) = value; \ break; \ \ case 0x03: \ /* internal work RAM */ \ address##type(iwram, (address & 0x7FFF) + 0x8000) = value; \ break; \ \ case 0x04: \ /* I/O registers */ \ return write_io_register##type(address & 0x3FF, value); \ \ case 0x05: \ /* palette RAM */ \ write_palette##type(address & 0x3FF, value); \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -