Rework RTC and break it into GPIO, with RTC and Rumble (GPIO3)
This adds Rumble support for GPIO3-enabled games (Drill Dozer).
This commit is contained in:
parent
f0bacff91a
commit
ae048beb9c
462
gba_memory.c
462
gba_memory.c
|
@ -1179,16 +1179,24 @@ typedef enum
|
||||||
#define RTC_WRITE_TIME_FULL 1
|
#define RTC_WRITE_TIME_FULL 1
|
||||||
#define RTC_WRITE_STATUS 2
|
#define RTC_WRITE_STATUS 2
|
||||||
|
|
||||||
|
static bool rtc_enabled = false, rumble_enabled = false;
|
||||||
|
|
||||||
|
// I/O registers (for RTC, rumble, etc)
|
||||||
|
u8 gpio_regs[3];
|
||||||
|
|
||||||
|
// RTC tracking variables
|
||||||
u32 rtc_state = RTC_DISABLED;
|
u32 rtc_state = RTC_DISABLED;
|
||||||
u32 rtc_write_mode;
|
u32 rtc_write_mode;
|
||||||
u8 rtc_registers[3];
|
|
||||||
u32 rtc_command;
|
u32 rtc_command;
|
||||||
u32 rtc_data[12];
|
u64 rtc_data;
|
||||||
|
u32 rtc_data_bits;
|
||||||
u32 rtc_status = 0x40;
|
u32 rtc_status = 0x40;
|
||||||
u32 rtc_data_bytes;
|
|
||||||
s32 rtc_bit_count;
|
s32 rtc_bit_count;
|
||||||
|
|
||||||
static u32 encode_bcd(u8 value)
|
// Rumble trackin vars, not really preserved (it's just aproximate)
|
||||||
|
static u32 rumble_enable_tick, rumble_ticks;
|
||||||
|
|
||||||
|
static u8 encode_bcd(u8 value)
|
||||||
{
|
{
|
||||||
int l = 0;
|
int l = 0;
|
||||||
int h = 0;
|
int h = 0;
|
||||||
|
@ -1200,224 +1208,189 @@ static u32 encode_bcd(u8 value)
|
||||||
return h * 16 + l;
|
return h * 16 + l;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RTC writes need to reflect in the bytes [0xC4..0xC9] of the gamepak
|
void update_gpio_romregs() {
|
||||||
#define write_rtc_register(index, _value) \
|
if (rtc_enabled || rumble_enabled) {
|
||||||
update_address = 0x80000C4 + (index * 2); \
|
// Update the registers in the ROM mapped buffer.
|
||||||
rtc_registers[index] = _value; \
|
u8 *map = memory_map_read[0x8000000 >> 15];
|
||||||
rtc_page_index = update_address >> 15; \
|
if (map) {
|
||||||
map = memory_map_read[rtc_page_index]; \
|
if (gpio_regs[2]) {
|
||||||
\
|
// Registers are visible, readable:
|
||||||
if(map) { \
|
address16(map, 0xC4) = eswap16(gpio_regs[0]);
|
||||||
address16(map, update_address & 0x7FFF) = eswap16(_value); \
|
address16(map, 0xC6) = eswap16(gpio_regs[1]);
|
||||||
} \
|
address16(map, 0xC8) = eswap16(gpio_regs[2]);
|
||||||
|
} else {
|
||||||
void function_cc write_rtc(u32 address, u32 value)
|
// Registers are write-only, just read out zero
|
||||||
{
|
address16(map, 0xC4) = 0;
|
||||||
u32 rtc_page_index;
|
address16(map, 0xC6) = 0;
|
||||||
u32 update_address;
|
address16(map, 0xC8) = 0;
|
||||||
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;
|
|
||||||
|
|
||||||
time(¤t_time_flat);
|
|
||||||
current_time = localtime(¤t_time_flat);
|
|
||||||
|
|
||||||
rtc_state = RTC_OUTPUT_DATA;
|
|
||||||
rtc_data_bytes = 7;
|
|
||||||
rtc_data[0] = encode_bcd(current_time->tm_year);
|
|
||||||
rtc_data[1] = encode_bcd(current_time->tm_mon + 1);
|
|
||||||
rtc_data[2] = encode_bcd(current_time->tm_mday);
|
|
||||||
rtc_data[3] = encode_bcd(current_time->tm_wday);
|
|
||||||
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 == (signed)(rtc_data_bytes * 8))
|
|
||||||
{
|
|
||||||
rtc_state = RTC_IDLE;
|
|
||||||
switch(rtc_write_mode)
|
|
||||||
{
|
|
||||||
case RTC_WRITE_STATUS:
|
|
||||||
rtc_status = rtc_data[0];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
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 == (signed)(rtc_data_bytes * 8))
|
|
||||||
{
|
|
||||||
rtc_state = RTC_IDLE;
|
|
||||||
memset(rtc_registers, 0, sizeof(rtc_registers));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
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 GPIO_RTC_CLK 0x1
|
||||||
|
#define GPIO_RTC_DAT 0x2
|
||||||
|
#define GPIO_RTC_CSS 0x4
|
||||||
|
|
||||||
#define write_rtc16() \
|
static void write_rtc(u8 old, u8 new)
|
||||||
write_rtc(address & 0xFF, value) \
|
{
|
||||||
|
// RTC works using a high CS and falling edge capture for the clock signal.
|
||||||
|
if (!(new & GPIO_RTC_CSS)) {
|
||||||
|
// Chip select is down, reset the RTC protocol. And do not process input.
|
||||||
|
rtc_state = RTC_IDLE;
|
||||||
|
rtc_command = 0;
|
||||||
|
rtc_bit_count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#define write_rtc32() \
|
// CS low to high transition!
|
||||||
|
if (!(old & GPIO_RTC_CSS))
|
||||||
|
rtc_state = RTC_COMMAND;
|
||||||
|
|
||||||
|
if ((old & GPIO_RTC_CLK) && !(new & GPIO_RTC_CLK)) {
|
||||||
|
// Advance clock state, input/ouput data.
|
||||||
|
switch (rtc_state) {
|
||||||
|
case RTC_COMMAND:
|
||||||
|
rtc_command <<= 1;
|
||||||
|
rtc_command |= ((new >> 1) & 1);
|
||||||
|
// 8 bit command read, process:
|
||||||
|
if (++rtc_bit_count == 8) {
|
||||||
|
switch (rtc_command) {
|
||||||
|
case RTC_COMMAND_RESET:
|
||||||
|
case RTC_COMMAND_WRITE_STATUS:
|
||||||
|
rtc_state = RTC_INPUT_DATA;
|
||||||
|
rtc_data = 0;
|
||||||
|
rtc_data_bits = 8;
|
||||||
|
rtc_write_mode = RTC_WRITE_STATUS;
|
||||||
|
break;
|
||||||
|
case RTC_COMMAND_READ_STATUS:
|
||||||
|
rtc_state = RTC_OUTPUT_DATA;
|
||||||
|
rtc_data_bits = 8;
|
||||||
|
rtc_data = rtc_status;
|
||||||
|
break;
|
||||||
|
case RTC_COMMAND_OUTPUT_TIME_FULL:
|
||||||
|
{
|
||||||
|
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_bits = 56;
|
||||||
|
rtc_data = ((u64)encode_bcd(current_time->tm_year)) |
|
||||||
|
((u64)encode_bcd(current_time->tm_mon+1)<< 8) |
|
||||||
|
((u64)encode_bcd(current_time->tm_mday) << 16) |
|
||||||
|
((u64)encode_bcd(current_time->tm_wday) << 24) |
|
||||||
|
((u64)encode_bcd(current_time->tm_hour) << 32) |
|
||||||
|
((u64)encode_bcd(current_time->tm_min) << 40) |
|
||||||
|
((u64)encode_bcd(current_time->tm_sec) << 48);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
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_bits = 24;
|
||||||
|
rtc_data = (encode_bcd(current_time->tm_hour)) |
|
||||||
|
(encode_bcd(current_time->tm_min) << 8) |
|
||||||
|
(encode_bcd(current_time->tm_sec) << 16);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
rtc_bit_count = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTC_INPUT_DATA:
|
||||||
|
rtc_data <<= 1;
|
||||||
|
rtc_data |= ((new >> 1) & 1);
|
||||||
|
rtc_data_bits--;
|
||||||
|
if (!rtc_data_bits) {
|
||||||
|
rtc_status = rtc_data; // HACK: assuming write status here.
|
||||||
|
rtc_state = RTC_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTC_OUTPUT_DATA:
|
||||||
|
// Output the next bit from rtc_data
|
||||||
|
if (!(gpio_regs[1] & 0x2)) {
|
||||||
|
// Only output if the port is set to OUT!
|
||||||
|
u32 bit = rtc_data & 1;
|
||||||
|
gpio_regs[0] = (new & ~0x2) | ((bit) << 1);
|
||||||
|
}
|
||||||
|
rtc_data >>= 1;
|
||||||
|
rtc_data_bits--;
|
||||||
|
|
||||||
|
if (!rtc_data_bits)
|
||||||
|
rtc_state = RTC_IDLE; // Finish transmission!
|
||||||
|
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_rumble(u8 old, u8 new) {
|
||||||
|
if (new && !old)
|
||||||
|
rumble_enable_tick = cpu_ticks;
|
||||||
|
else if (!new && old) {
|
||||||
|
rumble_ticks += (cpu_ticks - rumble_enable_tick);
|
||||||
|
rumble_enable_tick = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rumble_frame_reset() {
|
||||||
|
// Reset the tick initial value to frame start (only if active)
|
||||||
|
rumble_ticks = 0;
|
||||||
|
if (rumble_enable_tick)
|
||||||
|
rumble_enable_tick = cpu_ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rumble_active_pct() {
|
||||||
|
// Calculate the percentage of Rumble active for this frame.
|
||||||
|
u32 active_ticks = rumble_ticks;
|
||||||
|
// If the rumble is still active, account for the due cycles
|
||||||
|
if (rumble_enable_tick)
|
||||||
|
active_ticks += (cpu_ticks - rumble_enable_tick);
|
||||||
|
|
||||||
|
return active_ticks / (GBC_BASE_RATE / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
void function_cc write_gpio(u32 address, u32 value) {
|
||||||
|
u8 prev_value = gpio_regs[0];
|
||||||
|
switch(address) {
|
||||||
|
case 0xC4:
|
||||||
|
// Any writes do not affect input pins:
|
||||||
|
gpio_regs[0] = (gpio_regs[0] & ~gpio_regs[1]) | (value & gpio_regs[1]);
|
||||||
|
break;
|
||||||
|
case 0xC6:
|
||||||
|
gpio_regs[1] = value & 0xF;
|
||||||
|
break;
|
||||||
|
case 0xC8: /* I/O port control */
|
||||||
|
gpio_regs[2] = value & 1;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the game has an RTC, ensure it gets the data
|
||||||
|
if (rtc_enabled && (prev_value & 0x7) != (gpio_regs[0] & 0x7))
|
||||||
|
write_rtc(prev_value & 0x7, gpio_regs[0] & 0x7);
|
||||||
|
|
||||||
|
if (rumble_enabled && (prev_value & 0x8) != (gpio_regs[0] & 0x8))
|
||||||
|
write_rumble(prev_value & 0x8, gpio_regs[0] & 0x8);
|
||||||
|
|
||||||
|
// Reflect the values
|
||||||
|
update_gpio_romregs();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define write_gpio8() \
|
||||||
|
|
||||||
|
#define write_gpio16() \
|
||||||
|
write_gpio(address & 0xFF, value) \
|
||||||
|
|
||||||
|
#define write_gpio32() \
|
||||||
|
|
||||||
#define write_memory(type) \
|
#define write_memory(type) \
|
||||||
switch(address >> 24) \
|
switch(address >> 24) \
|
||||||
|
@ -1460,7 +1433,7 @@ void function_cc write_rtc(u32 address, u32 value)
|
||||||
\
|
\
|
||||||
case 0x08: \
|
case 0x08: \
|
||||||
/* gamepak ROM or RTC */ \
|
/* gamepak ROM or RTC */ \
|
||||||
write_rtc##type(); \
|
write_gpio##type(); \
|
||||||
break; \
|
break; \
|
||||||
\
|
\
|
||||||
case 0x09: \
|
case 0x09: \
|
||||||
|
@ -1571,6 +1544,7 @@ typedef struct
|
||||||
|
|
||||||
#define FLAGS_FLASH_128KB 0x0001
|
#define FLAGS_FLASH_128KB 0x0001
|
||||||
#define FLAGS_RUMBLE 0x0002
|
#define FLAGS_RUMBLE 0x0002
|
||||||
|
#define FLAGS_RTC 0x0004
|
||||||
|
|
||||||
#include "gba_over.h"
|
#include "gba_over.h"
|
||||||
|
|
||||||
|
@ -1602,6 +1576,12 @@ static void load_game_config_over(gamepak_info_t *gpinfo)
|
||||||
flash_bank_cnt = FLASH_SIZE_128KB;
|
flash_bank_cnt = FLASH_SIZE_128KB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gbaover[i].flags & FLAGS_RTC)
|
||||||
|
rtc_enabled = true;
|
||||||
|
|
||||||
|
if (gbaover[i].flags & FLAGS_RUMBLE)
|
||||||
|
rumble_enabled = true;
|
||||||
|
|
||||||
if (gbaover[i].translation_gate_target_1 != 0)
|
if (gbaover[i].translation_gate_target_1 != 0)
|
||||||
{
|
{
|
||||||
translation_gate_target_pc[translation_gate_targets] = gbaover[i].translation_gate_target_1;
|
translation_gate_target_pc[translation_gate_targets] = gbaover[i].translation_gate_target_1;
|
||||||
|
@ -2192,12 +2172,9 @@ u8 *load_gamepak_page(u32 physical_index)
|
||||||
// Map it to the read handlers now
|
// Map it to the read handlers now
|
||||||
map_rom_entry(read, physical_index, swap_location, gamepak_size >> 15);
|
map_rom_entry(read, physical_index, swap_location, gamepak_size >> 15);
|
||||||
|
|
||||||
// If RTC is active page the RTC register bytes so they can be read
|
// When mapping page 0, we might need to reflect the GPIO regs.
|
||||||
if ((rtc_state != RTC_DISABLED) && (physical_index == 0)) {
|
if (physical_index == 0)
|
||||||
address16(swap_location, 0xC4) = eswap16(rtc_registers[0]);
|
update_gpio_romregs();
|
||||||
address16(swap_location, 0xC6) = eswap16(rtc_registers[1]);
|
|
||||||
address16(swap_location, 0xC8) = eswap16(rtc_registers[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return swap_location;
|
return swap_location;
|
||||||
}
|
}
|
||||||
|
@ -2288,11 +2265,13 @@ void init_memory(void)
|
||||||
eeprom_mode = EEPROM_BASE_MODE;
|
eeprom_mode = EEPROM_BASE_MODE;
|
||||||
eeprom_address = 0;
|
eeprom_address = 0;
|
||||||
eeprom_counter = 0;
|
eeprom_counter = 0;
|
||||||
|
rumble_enable_tick = 0;
|
||||||
|
rumble_ticks = 0;
|
||||||
|
|
||||||
flash_mode = FLASH_BASE_MODE;
|
flash_mode = FLASH_BASE_MODE;
|
||||||
|
|
||||||
rtc_state = RTC_DISABLED;
|
rtc_state = RTC_DISABLED;
|
||||||
memset(rtc_registers, 0, sizeof(rtc_registers));
|
memset(gpio_regs, 0, sizeof(gpio_regs));
|
||||||
reg[REG_BUS_VALUE] = 0xe129f000;
|
reg[REG_BUS_VALUE] = 0xe129f000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2315,7 +2294,7 @@ bool memory_check_savestate(const u8 *src)
|
||||||
static const char *vars32[] = {
|
static const char *vars32[] = {
|
||||||
"backup-type","flash-mode", "flash-cmd-pos", "flash-bank-num", "flash-dev-id",
|
"backup-type","flash-mode", "flash-cmd-pos", "flash-bank-num", "flash-dev-id",
|
||||||
"flash-size", "eeprom-size", "eeprom-mode", "eeprom-addr", "eeprom-counter",
|
"flash-size", "eeprom-size", "eeprom-mode", "eeprom-addr", "eeprom-counter",
|
||||||
"rtc-state", "rtc-write-mode", "rtc-cmd", "rtc-status", "rtc-data-byte-cnt", "rtc-bit-cnt",
|
"rtc-state", "rtc-write-mode", "rtc-cmd", "rtc-status", "rtc-data-bit-cnt", "rtc-bit-cnt",
|
||||||
};
|
};
|
||||||
static const char *dmavars32[] = {
|
static const char *dmavars32[] = {
|
||||||
"src-addr", "dst-addr", "src-dir", "dst-dir",
|
"src-addr", "dst-addr", "src-dir", "dst-dir",
|
||||||
|
@ -2342,7 +2321,7 @@ bool memory_check_savestate(const u8 *src)
|
||||||
if (!bson_contains_key(bakdoc, vars32[i], BSON_TYPE_INT32))
|
if (!bson_contains_key(bakdoc, vars32[i], BSON_TYPE_INT32))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!bson_contains_key(bakdoc, "rtc-regs", BSON_TYPE_BIN) ||
|
if (!bson_contains_key(bakdoc, "gpio-regs", BSON_TYPE_BIN) ||
|
||||||
!bson_contains_key(bakdoc, "rtc-data-words", BSON_TYPE_ARR))
|
!bson_contains_key(bakdoc, "rtc-data-words", BSON_TYPE_ARR))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -2364,6 +2343,7 @@ bool memory_check_savestate(const u8 *src)
|
||||||
bool memory_read_savestate(const u8 *src)
|
bool memory_read_savestate(const u8 *src)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
u32 rtc_data_array[2];
|
||||||
const u8 *memdoc = bson_find_key(src, "memory");
|
const u8 *memdoc = bson_find_key(src, "memory");
|
||||||
const u8 *bakdoc = bson_find_key(src, "backup");
|
const u8 *bakdoc = bson_find_key(src, "backup");
|
||||||
const u8 *dmadoc = bson_find_key(src, "dma");
|
const u8 *dmadoc = bson_find_key(src, "dma");
|
||||||
|
@ -2391,15 +2371,15 @@ bool memory_read_savestate(const u8 *src)
|
||||||
bson_read_int32(bakdoc, "eeprom-addr", &eeprom_address) &&
|
bson_read_int32(bakdoc, "eeprom-addr", &eeprom_address) &&
|
||||||
bson_read_int32(bakdoc, "eeprom-counter", &eeprom_counter) &&
|
bson_read_int32(bakdoc, "eeprom-counter", &eeprom_counter) &&
|
||||||
|
|
||||||
|
bson_read_bytes(bakdoc, "gpio-regs", gpio_regs, sizeof(gpio_regs)) &&
|
||||||
|
|
||||||
bson_read_int32(bakdoc, "rtc-state", &rtc_state) &&
|
bson_read_int32(bakdoc, "rtc-state", &rtc_state) &&
|
||||||
bson_read_int32(bakdoc, "rtc-write-mode", &rtc_write_mode) &&
|
bson_read_int32(bakdoc, "rtc-write-mode", &rtc_write_mode) &&
|
||||||
bson_read_int32(bakdoc, "rtc-cmd", &rtc_command) &&
|
bson_read_int32(bakdoc, "rtc-cmd", &rtc_command) &&
|
||||||
bson_read_int32(bakdoc, "rtc-status", &rtc_status) &&
|
bson_read_int32(bakdoc, "rtc-status", &rtc_status) &&
|
||||||
bson_read_int32(bakdoc, "rtc-data-byte-cnt", &rtc_data_bytes) &&
|
bson_read_int32(bakdoc, "rtc-data-bit-cnt", &rtc_data_bits) &&
|
||||||
bson_read_int32(bakdoc, "rtc-bit-cnt", (u32*)&rtc_bit_count) &&
|
bson_read_int32(bakdoc, "rtc-bit-cnt", (u32*)&rtc_bit_count) &&
|
||||||
bson_read_bytes(bakdoc, "rtc-regs", rtc_registers, sizeof(rtc_registers)) &&
|
bson_read_int32_array(bakdoc, "rtc-data-words", rtc_data_array, 2)))
|
||||||
bson_read_int32_array(bakdoc, "rtc-data-words", rtc_data,
|
|
||||||
sizeof(rtc_data)/sizeof(rtc_data[0]))))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (i = 0; i < DMA_CHAN_CNT; i++)
|
for (i = 0; i < DMA_CHAN_CNT; i++)
|
||||||
|
@ -2420,6 +2400,8 @@ bool memory_read_savestate(const u8 *src)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtc_data = rtc_data_array[0] | (((u64)rtc_data_array[1]) << 32);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2427,6 +2409,8 @@ unsigned memory_write_savestate(u8 *dst)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u8 *wbptr, *wbptr2, *startp = dst;
|
u8 *wbptr, *wbptr2, *startp = dst;
|
||||||
|
u32 rtc_data_array[2] = { (u32)rtc_data, (u32)(rtc_data >> 32) };
|
||||||
|
|
||||||
bson_start_document(dst, "memory", wbptr);
|
bson_start_document(dst, "memory", wbptr);
|
||||||
bson_write_bytes(dst, "iwram", &iwram[0x8000], 0x8000);
|
bson_write_bytes(dst, "iwram", &iwram[0x8000], 0x8000);
|
||||||
bson_write_bytes(dst, "ewram", ewram, 0x40000);
|
bson_write_bytes(dst, "ewram", ewram, 0x40000);
|
||||||
|
@ -2450,15 +2434,14 @@ unsigned memory_write_savestate(u8 *dst)
|
||||||
bson_write_int32(dst, "eeprom-addr", eeprom_address);
|
bson_write_int32(dst, "eeprom-addr", eeprom_address);
|
||||||
bson_write_int32(dst, "eeprom-counter", eeprom_counter);
|
bson_write_int32(dst, "eeprom-counter", eeprom_counter);
|
||||||
|
|
||||||
|
bson_write_bytes(dst, "gpio-regs", gpio_regs, sizeof(gpio_regs));
|
||||||
bson_write_int32(dst, "rtc-state", rtc_state);
|
bson_write_int32(dst, "rtc-state", rtc_state);
|
||||||
bson_write_int32(dst, "rtc-write-mode", rtc_write_mode);
|
bson_write_int32(dst, "rtc-write-mode", rtc_write_mode);
|
||||||
bson_write_int32(dst, "rtc-cmd", rtc_command);
|
bson_write_int32(dst, "rtc-cmd", rtc_command);
|
||||||
bson_write_int32(dst, "rtc-status", rtc_status);
|
bson_write_int32(dst, "rtc-status", rtc_status);
|
||||||
bson_write_int32(dst, "rtc-data-byte-cnt", rtc_data_bytes);
|
bson_write_int32(dst, "rtc-data-bit-cnt", rtc_data_bits);
|
||||||
bson_write_int32(dst, "rtc-bit-cnt", rtc_bit_count);
|
bson_write_int32(dst, "rtc-bit-cnt", rtc_bit_count);
|
||||||
bson_write_bytes(dst, "rtc-regs", rtc_registers, sizeof(rtc_registers));
|
bson_write_int32array(dst, "rtc-data-words", rtc_data_array, 2);
|
||||||
bson_write_int32array(dst, "rtc-data-words", rtc_data,
|
|
||||||
sizeof(rtc_data)/sizeof(rtc_data[0]));
|
|
||||||
bson_finish_document(dst, wbptr);
|
bson_finish_document(dst, wbptr);
|
||||||
|
|
||||||
bson_start_document(dst, "dma", wbptr);
|
bson_start_document(dst, "dma", wbptr);
|
||||||
|
@ -2525,7 +2508,8 @@ static s32 load_gamepak_raw(const char *name)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 load_gamepak(const struct retro_game_info* info, const char *name)
|
u32 load_gamepak(const struct retro_game_info* info, const char *name,
|
||||||
|
int force_rtc, int force_rumble)
|
||||||
{
|
{
|
||||||
gamepak_info_t gpinfo;
|
gamepak_info_t gpinfo;
|
||||||
|
|
||||||
|
@ -2542,9 +2526,17 @@ u32 load_gamepak(const struct retro_game_info* info, const char *name)
|
||||||
translation_gate_targets = 0;
|
translation_gate_targets = 0;
|
||||||
flash_device_id = FLASH_DEVICE_MACRONIX_64KB;
|
flash_device_id = FLASH_DEVICE_MACRONIX_64KB;
|
||||||
flash_bank_cnt = FLASH_SIZE_64KB;
|
flash_bank_cnt = FLASH_SIZE_64KB;
|
||||||
|
rtc_enabled = false;
|
||||||
|
rumble_enabled = false;
|
||||||
|
|
||||||
load_game_config_over(&gpinfo);
|
load_game_config_over(&gpinfo);
|
||||||
|
|
||||||
|
// Forced RTC / Rumble modes, override the autodetect logic.
|
||||||
|
if (force_rtc != FEAT_AUTODETECT)
|
||||||
|
rtc_enabled = (force_rtc == FEAT_ENABLE);
|
||||||
|
if (force_rumble != FEAT_AUTODETECT)
|
||||||
|
rumble_enabled = (force_rumble == FEAT_ENABLE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
gba_memory.h
12
gba_memory.h
|
@ -22,6 +22,10 @@
|
||||||
|
|
||||||
#include "libretro.h"
|
#include "libretro.h"
|
||||||
|
|
||||||
|
#define FEAT_AUTODETECT -1
|
||||||
|
#define FEAT_DISABLE 0
|
||||||
|
#define FEAT_ENABLE 1
|
||||||
|
|
||||||
#define DMA_CHAN_CNT 4
|
#define DMA_CHAN_CNT 4
|
||||||
|
|
||||||
#define DMA_START_IMMEDIATELY 0
|
#define DMA_START_IMMEDIATELY 0
|
||||||
|
@ -221,7 +225,10 @@ u32 function_cc read_eeprom(void);
|
||||||
void function_cc write_eeprom(u32 address, u32 value);
|
void function_cc write_eeprom(u32 address, u32 value);
|
||||||
u8 read_backup(u32 address);
|
u8 read_backup(u32 address);
|
||||||
void function_cc write_backup(u32 address, u32 value);
|
void function_cc write_backup(u32 address, u32 value);
|
||||||
void function_cc write_rtc(u32 address, u32 value);
|
void function_cc write_gpio(u32 address, u32 value);
|
||||||
|
|
||||||
|
void rumble_frame_reset();
|
||||||
|
float rumble_active_pct();
|
||||||
|
|
||||||
/* EDIT: Shouldn't this be extern ?! */
|
/* EDIT: Shouldn't this be extern ?! */
|
||||||
extern const u32 def_seq_cycles[16][2];
|
extern const u32 def_seq_cycles[16][2];
|
||||||
|
@ -237,7 +244,8 @@ extern char gamepak_filename[512];
|
||||||
|
|
||||||
cpu_alert_type dma_transfer(unsigned dma_chan, int *cycles);
|
cpu_alert_type dma_transfer(unsigned dma_chan, int *cycles);
|
||||||
u8 *memory_region(u32 address, u32 *memory_limit);
|
u8 *memory_region(u32 address, u32 *memory_limit);
|
||||||
u32 load_gamepak(const struct retro_game_info* info, const char *name);
|
u32 load_gamepak(const struct retro_game_info* info, const char *name,
|
||||||
|
int force_rtc, int force_rumble);
|
||||||
s32 load_bios(char *name);
|
s32 load_bios(char *name);
|
||||||
void init_memory(void);
|
void init_memory(void);
|
||||||
void init_gamepak_buffer(void);
|
void init_gamepak_buffer(void);
|
||||||
|
|
126
gba_over.h
126
gba_over.h
|
@ -109,6 +109,17 @@ static const ini_t gbaover[] = {
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
0, /* translation_gate_target_3 */
|
0, /* translation_gate_target_3 */
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Shin Bokura no Taiyou: Gyakushuu no Sabata (J)
|
||||||
|
"BOKTAI3", /* gamepak_title */
|
||||||
|
"U33J", /* gamepak_code */
|
||||||
|
"A4", /* gamepak_maker */
|
||||||
|
FLAGS_RTC, /* flags */
|
||||||
|
0, /* idle_loop_target_pc */
|
||||||
|
0, /* translation_gate_target_1 */
|
||||||
|
0, /* translation_gate_target_2 */
|
||||||
|
0, /* translation_gate_target_3 */
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Bomberman Jetters Game Collection (J)
|
// Bomberman Jetters Game Collection (J)
|
||||||
"BOMBERMANJGC", /* gamepak_title */
|
"BOMBERMANJGC", /* gamepak_title */
|
||||||
|
@ -498,6 +509,39 @@ static const ini_t gbaover[] = {
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
0, /* translation_gate_target_3 */
|
0, /* translation_gate_target_3 */
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Legendz - Sign of Nekuromu (J)
|
||||||
|
"LEGENDZSON__", /* gamepak_title */
|
||||||
|
"BLVJ", /* gamepak_code */
|
||||||
|
"B2", /* gamepak_maker */
|
||||||
|
FLAGS_RTC, /* flags */
|
||||||
|
0, /* idle_loop_target_pc */
|
||||||
|
0, /* translation_gate_target_1 */
|
||||||
|
0, /* translation_gate_target_2 */
|
||||||
|
0, /* translation_gate_target_3 */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Legendz - Yomigaeru Shiren no Shima (J)
|
||||||
|
"LEGENDZSHIMA", /* gamepak_title */
|
||||||
|
"BLJJ", /* gamepak_code */
|
||||||
|
"B2", /* gamepak_maker */
|
||||||
|
FLAGS_RTC, /* flags */
|
||||||
|
0, /* idle_loop_target_pc */
|
||||||
|
0, /* translation_gate_target_1 */
|
||||||
|
0, /* translation_gate_target_2 */
|
||||||
|
0, /* translation_gate_target_3 */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Legendz - Buhwarhaneun Siryeonyi Seom (K)
|
||||||
|
"LEGENDZSHIMA", /* gamepak_title */
|
||||||
|
"BLJK", /* gamepak_code */
|
||||||
|
"B2", /* gamepak_maker */
|
||||||
|
FLAGS_RTC, /* flags */
|
||||||
|
0, /* idle_loop_target_pc */
|
||||||
|
0, /* translation_gate_target_1 */
|
||||||
|
0, /* translation_gate_target_2 */
|
||||||
|
0, /* translation_gate_target_3 */
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Magical Houshin (J)
|
// Magical Houshin (J)
|
||||||
"M HOUSHIN", /* gamepak_title */
|
"M HOUSHIN", /* gamepak_title */
|
||||||
|
@ -976,7 +1020,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON EMER", /* gamepak_title */
|
"POKEMON EMER", /* gamepak_title */
|
||||||
"BPEE", /* gamepak_code */
|
"BPEE", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0x80008ce, /* idle_loop_target_pc */
|
0x80008ce, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -987,7 +1031,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON EMER", /* gamepak_title */
|
"POKEMON EMER", /* gamepak_title */
|
||||||
"BPEJ", /* gamepak_code */
|
"BPEJ", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0x80008ce, /* idle_loop_target_pc */
|
0x80008ce, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -998,7 +1042,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON EMER", /* gamepak_title */
|
"POKEMON EMER", /* gamepak_title */
|
||||||
"BPED", /* gamepak_code */
|
"BPED", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0x80008ce, /* idle_loop_target_pc */
|
0x80008ce, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1009,7 +1053,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON EMER", /* gamepak_title */
|
"POKEMON EMER", /* gamepak_title */
|
||||||
"BPEF", /* gamepak_code */
|
"BPEF", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0x80008ce, /* idle_loop_target_pc */
|
0x80008ce, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1020,7 +1064,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON EMER", /* gamepak_title */
|
"POKEMON EMER", /* gamepak_title */
|
||||||
"BPES", /* gamepak_code */
|
"BPES", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0x80008ce, /* idle_loop_target_pc */
|
0x80008ce, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1031,7 +1075,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON EMER", /* gamepak_title */
|
"POKEMON EMER", /* gamepak_title */
|
||||||
"BPEI", /* gamepak_code */
|
"BPEI", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0x80008ce, /* idle_loop_target_pc */
|
0x80008ce, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1042,7 +1086,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON SAPP", /* gamepak_title */
|
"POKEMON SAPP", /* gamepak_title */
|
||||||
"AXPE", /* gamepak_code */
|
"AXPE", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1053,7 +1097,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON SAPP", /* gamepak_title */
|
"POKEMON SAPP", /* gamepak_title */
|
||||||
"AXPJ", /* gamepak_code */
|
"AXPJ", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1064,7 +1108,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON SAPP", /* gamepak_title */
|
"POKEMON SAPP", /* gamepak_title */
|
||||||
"AXPD", /* gamepak_code */
|
"AXPD", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1075,7 +1119,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON SAPP", /* gamepak_title */
|
"POKEMON SAPP", /* gamepak_title */
|
||||||
"AXPI", /* gamepak_code */
|
"AXPI", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1086,7 +1130,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON SAPP", /* gamepak_title */
|
"POKEMON SAPP", /* gamepak_title */
|
||||||
"AXPS", /* gamepak_code */
|
"AXPS", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1097,7 +1141,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON SAPP", /* gamepak_title */
|
"POKEMON SAPP", /* gamepak_title */
|
||||||
"AXPF", /* gamepak_code */
|
"AXPF", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1108,7 +1152,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON RUBY", /* gamepak_title */
|
"POKEMON RUBY", /* gamepak_title */
|
||||||
"AXVE", /* gamepak_code */
|
"AXVE", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1119,7 +1163,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON RUBY", /* gamepak_title */
|
"POKEMON RUBY", /* gamepak_title */
|
||||||
"AXVJ", /* gamepak_code */
|
"AXVJ", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1130,7 +1174,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON RUBY", /* gamepak_title */
|
"POKEMON RUBY", /* gamepak_title */
|
||||||
"AXVD", /* gamepak_code */
|
"AXVD", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1141,7 +1185,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON RUBY", /* gamepak_title */
|
"POKEMON RUBY", /* gamepak_title */
|
||||||
"AXVI", /* gamepak_code */
|
"AXVI", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1152,7 +1196,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON RUBY", /* gamepak_title */
|
"POKEMON RUBY", /* gamepak_title */
|
||||||
"AXVS", /* gamepak_code */
|
"AXVS", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1163,7 +1207,7 @@ static const ini_t gbaover[] = {
|
||||||
"POKEMON RUBY", /* gamepak_title */
|
"POKEMON RUBY", /* gamepak_title */
|
||||||
"AXVF", /* gamepak_code */
|
"AXVF", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1452,12 +1496,23 @@ static const ini_t gbaover[] = {
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
0, /* translation_gate_target_3 */
|
0, /* translation_gate_target_3 */
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// RockMan EXE 4.5 - Real Operation (J)
|
||||||
|
"ROCKEXE4.5RO", /* gamepak_title */
|
||||||
|
"BR4J", /* gamepak_code */
|
||||||
|
"08", /* gamepak_maker */
|
||||||
|
FLAGS_RTC, /* flags */
|
||||||
|
0, /* idle_loop_target_pc */
|
||||||
|
0, /* translation_gate_target_1 */
|
||||||
|
0, /* translation_gate_target_2 */
|
||||||
|
0, /* translation_gate_target_3 */
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Sennen Kazoku (J)
|
// Sennen Kazoku (J)
|
||||||
"SENNENKAZOKU", /* gamepak_title */
|
"SENNENKAZOKU", /* gamepak_title */
|
||||||
"BKAJ", /* gamepak_code */
|
"BKAJ", /* gamepak_code */
|
||||||
"01", /* gamepak_maker */
|
"01", /* gamepak_maker */
|
||||||
FLAGS_FLASH_128KB, /* flags */
|
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||||
0, /* idle_loop_target_pc */
|
0, /* idle_loop_target_pc */
|
||||||
0, /* translation_gate_target_1 */
|
0, /* translation_gate_target_1 */
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
|
@ -1782,6 +1837,39 @@ static const ini_t gbaover[] = {
|
||||||
0, /* translation_gate_target_2 */
|
0, /* translation_gate_target_2 */
|
||||||
0, /* translation_gate_target_3 */
|
0, /* translation_gate_target_3 */
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Wario Ware, Twisted (U)
|
||||||
|
"WARIOTWISTED", /* gamepak_title */
|
||||||
|
"RZWE", /* gamepak_code */
|
||||||
|
"01", /* gamepak_maker */
|
||||||
|
FLAGS_RUMBLE, /* flags */
|
||||||
|
0, /* idle_loop_target_pc */
|
||||||
|
0, /* translation_gate_target_1 */
|
||||||
|
0, /* translation_gate_target_2 */
|
||||||
|
0, /* translation_gate_target_3 */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Wario Ware, Twisted (E)
|
||||||
|
"WARIOTWISTED", /* gamepak_title */
|
||||||
|
"RZWP", /* gamepak_code */
|
||||||
|
"01", /* gamepak_maker */
|
||||||
|
FLAGS_RUMBLE, /* flags */
|
||||||
|
0, /* idle_loop_target_pc */
|
||||||
|
0, /* translation_gate_target_1 */
|
||||||
|
0, /* translation_gate_target_2 */
|
||||||
|
0, /* translation_gate_target_3 */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Wario Ware, Twisted (J)
|
||||||
|
"MAWARUWARIO", /* gamepak_title */
|
||||||
|
"RZWJ", /* gamepak_code */
|
||||||
|
"01", /* gamepak_maker */
|
||||||
|
FLAGS_RUMBLE, /* flags */
|
||||||
|
0, /* idle_loop_target_pc */
|
||||||
|
0, /* translation_gate_target_1 */
|
||||||
|
0, /* translation_gate_target_2 */
|
||||||
|
0, /* translation_gate_target_3 */
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Yu-Gi-Oh! - Dungeon Dice Monsters (U)
|
// Yu-Gi-Oh! - Dungeon Dice Monsters (U)
|
||||||
"YU-GI-OH DDM", /* gamepak_title */
|
"YU-GI-OH DDM", /* gamepak_title */
|
||||||
|
|
|
@ -84,6 +84,7 @@ static retro_video_refresh_t video_cb;
|
||||||
static retro_audio_sample_batch_t audio_batch_cb;
|
static retro_audio_sample_batch_t audio_batch_cb;
|
||||||
static retro_input_poll_t input_poll_cb;
|
static retro_input_poll_t input_poll_cb;
|
||||||
static retro_environment_t environ_cb;
|
static retro_environment_t environ_cb;
|
||||||
|
static retro_set_rumble_state_t rumble_cb;
|
||||||
|
|
||||||
struct retro_perf_callback perf_cb;
|
struct retro_perf_callback perf_cb;
|
||||||
|
|
||||||
|
@ -91,6 +92,8 @@ int dynarec_enable;
|
||||||
boot_mode selected_boot_mode = boot_game;
|
boot_mode selected_boot_mode = boot_game;
|
||||||
int sprite_limit = 1;
|
int sprite_limit = 1;
|
||||||
|
|
||||||
|
static int rtc_mode = FEAT_AUTODETECT, rumble_mode = FEAT_AUTODETECT;
|
||||||
|
|
||||||
u32 idle_loop_target_pc = 0xFFFFFFFF;
|
u32 idle_loop_target_pc = 0xFFFFFFFF;
|
||||||
u32 translation_gate_target_pc[MAX_TRANSLATION_GATES];
|
u32 translation_gate_target_pc[MAX_TRANSLATION_GATES];
|
||||||
u32 translation_gate_targets = 0;
|
u32 translation_gate_targets = 0;
|
||||||
|
@ -744,7 +747,7 @@ static void extract_directory(char* buf, const char* path, size_t size)
|
||||||
strncpy(buf, ".", size);
|
strncpy(buf, ".", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_variables(int started_from_load)
|
static void check_variables(bool started_from_load)
|
||||||
{
|
{
|
||||||
struct retro_variable var;
|
struct retro_variable var;
|
||||||
bool frameskip_type_prev;
|
bool frameskip_type_prev;
|
||||||
|
@ -776,7 +779,6 @@ static void check_variables(int started_from_load)
|
||||||
if (started_from_load) {
|
if (started_from_load) {
|
||||||
var.key = "gpsp_bios";
|
var.key = "gpsp_bios";
|
||||||
var.value = 0;
|
var.value = 0;
|
||||||
|
|
||||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||||
{
|
{
|
||||||
if (!strcmp(var.value, "auto"))
|
if (!strcmp(var.value, "auto"))
|
||||||
|
@ -789,7 +791,6 @@ static void check_variables(int started_from_load)
|
||||||
|
|
||||||
var.key = "gpsp_boot_mode";
|
var.key = "gpsp_boot_mode";
|
||||||
var.value = 0;
|
var.value = 0;
|
||||||
|
|
||||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||||
{
|
{
|
||||||
if (!strcmp(var.value, "game"))
|
if (!strcmp(var.value, "game"))
|
||||||
|
@ -797,6 +798,30 @@ static void check_variables(int started_from_load)
|
||||||
else if (!strcmp(var.value, "bios"))
|
else if (!strcmp(var.value, "bios"))
|
||||||
selected_boot_mode = boot_bios;
|
selected_boot_mode = boot_bios;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var.key = "gpsp_rtc";
|
||||||
|
var.value = 0;
|
||||||
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||||
|
{
|
||||||
|
if (!strcmp(var.value, "disabled"))
|
||||||
|
rtc_mode = FEAT_DISABLE;
|
||||||
|
else if (!strcmp(var.value, "enabled"))
|
||||||
|
rtc_mode = FEAT_ENABLE;
|
||||||
|
else
|
||||||
|
rtc_mode = FEAT_AUTODETECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
var.key = "gpsp_rumble";
|
||||||
|
var.value = 0;
|
||||||
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||||
|
{
|
||||||
|
if (!strcmp(var.value, "disabled"))
|
||||||
|
rumble_mode = FEAT_DISABLE;
|
||||||
|
else if (!strcmp(var.value, "enabled"))
|
||||||
|
rumble_mode = FEAT_ENABLE;
|
||||||
|
else
|
||||||
|
rumble_mode = FEAT_AUTODETECT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var.key = "gpsp_sprlim";
|
var.key = "gpsp_sprlim";
|
||||||
|
@ -956,7 +981,7 @@ bool retro_load_game(const struct retro_game_info* info)
|
||||||
if (!info)
|
if (!info)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
check_variables(1);
|
check_variables(true);
|
||||||
set_input_descriptors();
|
set_input_descriptors();
|
||||||
|
|
||||||
char filename_bios[MAX_PATH];
|
char filename_bios[MAX_PATH];
|
||||||
|
@ -1000,12 +1025,18 @@ bool retro_load_game(const struct retro_game_info* info)
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(gamepak_backup, 0xff, sizeof(gamepak_backup));
|
memset(gamepak_backup, 0xff, sizeof(gamepak_backup));
|
||||||
if (load_gamepak(info, info->path) != 0)
|
if (load_gamepak(info, info->path, rtc_mode, rumble_mode) != 0)
|
||||||
{
|
{
|
||||||
error_msg("Could not load the game file.");
|
error_msg("Could not load the game file.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct retro_rumble_interface rumbleif;
|
||||||
|
if (environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumbleif))
|
||||||
|
rumble_cb = rumbleif.set_rumble_state;
|
||||||
|
else
|
||||||
|
rumble_cb = NULL;
|
||||||
|
|
||||||
reset_gba();
|
reset_gba();
|
||||||
|
|
||||||
set_memory_descriptors();
|
set_memory_descriptors();
|
||||||
|
@ -1063,6 +1094,8 @@ void retro_run(void)
|
||||||
input_poll_cb();
|
input_poll_cb();
|
||||||
update_input();
|
update_input();
|
||||||
|
|
||||||
|
rumble_frame_reset();
|
||||||
|
|
||||||
/* Check whether current frame should
|
/* Check whether current frame should
|
||||||
* be skipped */
|
* be skipped */
|
||||||
skip_next_frame = 0;
|
skip_next_frame = 0;
|
||||||
|
@ -1145,11 +1178,18 @@ void retro_run(void)
|
||||||
execute_arm(execute_cycles);
|
execute_arm(execute_cycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rumble_cb) {
|
||||||
|
// TODO: Add some user-option to select a rumble policy
|
||||||
|
u32 strength = 0xffff * rumble_active_pct();
|
||||||
|
rumble_cb(0, RETRO_RUMBLE_WEAK, MIN(strength, 0xffff));
|
||||||
|
rumble_cb(0, RETRO_RUMBLE_STRONG, MIN(strength, 0xffff) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
audio_run();
|
audio_run();
|
||||||
video_run();
|
video_run();
|
||||||
|
|
||||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
|
||||||
check_variables(0);
|
check_variables(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned retro_api_version(void)
|
unsigned retro_api_version(void)
|
||||||
|
|
|
@ -87,6 +87,30 @@ struct retro_core_option_definition option_defs_us[] = {
|
||||||
},
|
},
|
||||||
"disabled"
|
"disabled"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"gpsp_rtc",
|
||||||
|
"RTC support",
|
||||||
|
"Sets the RTC support for the emulated cartridge. Autodetect uses a ROM database that works with most commercial titles. You might need to force RTC when using homebrew or ROM hacks.",
|
||||||
|
{
|
||||||
|
{ "auto", NULL },
|
||||||
|
{ "enabled", NULL },
|
||||||
|
{ "disabled", NULL },
|
||||||
|
{ NULL, NULL },
|
||||||
|
},
|
||||||
|
"auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"gpsp_rumble",
|
||||||
|
"Rumble support",
|
||||||
|
"Sets the Rumble support for the emulated cartridge. Autodetect uses a ROM database that works with most commercial titles. You might want to force Rumble when using homebrew or ROM hacks that support it. You can also force-disable it if you don't like it.",
|
||||||
|
{
|
||||||
|
{ "auto", NULL },
|
||||||
|
{ "enabled", NULL },
|
||||||
|
{ "disabled", NULL },
|
||||||
|
{ NULL, NULL },
|
||||||
|
},
|
||||||
|
"auto"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"gpsp_frameskip",
|
"gpsp_frameskip",
|
||||||
"Frameskip",
|
"Frameskip",
|
||||||
|
|
|
@ -2471,7 +2471,7 @@ static void emit_saveaccess_stub(u8 **tr_ptr) {
|
||||||
|
|
||||||
// Writes to region 8 are directed to RTC (only 16 bit ones though)
|
// Writes to region 8 are directed to RTC (only 16 bit ones though)
|
||||||
tmemld[1][8] = (u32)translation_ptr;
|
tmemld[1][8] = (u32)translation_ptr;
|
||||||
emit_mem_call(&write_rtc, 0xFE);
|
emit_mem_call(&write_gpio, 0xFE);
|
||||||
|
|
||||||
// These are for region 0xD where EEPROM is mapped. Addr is ignored
|
// These are for region 0xD where EEPROM is mapped. Addr is ignored
|
||||||
// Value is limited to one bit (both reading and writing!)
|
// Value is limited to one bit (both reading and writing!)
|
||||||
|
@ -2524,7 +2524,7 @@ static void emit_saveaccess_stub(u8 **tr_ptr) {
|
||||||
mips_emit_xori(reg_rv, reg_temp, 0x08);
|
mips_emit_xori(reg_rv, reg_temp, 0x08);
|
||||||
mips_emit_b(bne, reg_rv, reg_zero, st_phndlr_branch(strop));
|
mips_emit_b(bne, reg_rv, reg_zero, st_phndlr_branch(strop));
|
||||||
if (strop == 1) {
|
if (strop == 1) {
|
||||||
emit_mem_call(&write_rtc, 0xFF); // Addr
|
emit_mem_call(&write_gpio, 0xFF); // Addr
|
||||||
} else {
|
} else {
|
||||||
mips_emit_nop();
|
mips_emit_nop();
|
||||||
mips_emit_jr(mips_reg_ra); // Do nothing
|
mips_emit_jr(mips_reg_ra); // Do nothing
|
||||||
|
|
|
@ -92,7 +92,7 @@ bool bson_read_bytes(const u8 *srcp, const char *key, void* buffer, unsigned cnt
|
||||||
/* this is an upper limit, leave room for future (?) stuff */
|
/* this is an upper limit, leave room for future (?) stuff */
|
||||||
#define GBA_STATE_MEM_SIZE (416*1024)
|
#define GBA_STATE_MEM_SIZE (416*1024)
|
||||||
#define GBA_STATE_MAGIC 0x06BAC0DE
|
#define GBA_STATE_MAGIC 0x06BAC0DE
|
||||||
#define GBA_STATE_VERSION 0x00010002
|
#define GBA_STATE_VERSION 0x00010003
|
||||||
|
|
||||||
bool gba_load_state(const void *src);
|
bool gba_load_state(const void *src);
|
||||||
void gba_save_state(void *dst);
|
void gba_save_state(void *dst);
|
||||||
|
|
|
@ -219,8 +219,8 @@ defsymbl(x86_indirect_branch_dual)
|
||||||
|
|
||||||
# General ext memory routines
|
# General ext memory routines
|
||||||
|
|
||||||
ext_store_rtc8: # No RTC writes on byte or word access
|
ext_store_gpio8: # No GPIO/RTC writes on byte or word access
|
||||||
ext_store_rtc32:
|
ext_store_gpio32:
|
||||||
ext_store_backup16: # Backup (flash) accessed via byte writes
|
ext_store_backup16: # Backup (flash) accessed via byte writes
|
||||||
ext_store_backup32:
|
ext_store_backup32:
|
||||||
ext_store_eeprom8: # EEPROM accesses are performed using 16 bit DMA
|
ext_store_eeprom8: # EEPROM accesses are performed using 16 bit DMA
|
||||||
|
@ -228,11 +228,11 @@ ext_store_eeprom32:
|
||||||
ext_store_ignore:
|
ext_store_ignore:
|
||||||
ret # ignore these writes
|
ret # ignore these writes
|
||||||
|
|
||||||
ext_store_rtc16:
|
ext_store_gpio16:
|
||||||
and $0xFFFF, %edx # make value 16bit
|
and $0xFFFF, %edx # make value 16bit
|
||||||
and $0xFF, %eax # mask address
|
and $0xFF, %eax # mask address
|
||||||
SETUP_ARGS # Setup addr, value
|
SETUP_ARGS # Setup addr, value
|
||||||
CALL_FUNC(write_rtc) # write out RTC register
|
CALL_FUNC(write_gpio) # write out RTC register
|
||||||
ret
|
ret
|
||||||
|
|
||||||
ext_store_backup8:
|
ext_store_backup8:
|
||||||
|
@ -565,7 +565,7 @@ return_to_main:
|
||||||
ADDR_TYPE ext_store_palette##asize /* 0x05 Palette RAM */;\
|
ADDR_TYPE ext_store_palette##asize /* 0x05 Palette RAM */;\
|
||||||
ADDR_TYPE ext_store_vram##asize /* 0x06 VRAM */;\
|
ADDR_TYPE ext_store_vram##asize /* 0x06 VRAM */;\
|
||||||
ADDR_TYPE ext_store_oam##asize /* 0x07 OAM RAM */;\
|
ADDR_TYPE ext_store_oam##asize /* 0x07 OAM RAM */;\
|
||||||
ADDR_TYPE ext_store_rtc##asize /* 0x08 gamepak (RTC or ignore) */;\
|
ADDR_TYPE ext_store_gpio##asize /* 0x08 gamepak (RTC or ignore) */;\
|
||||||
ADDR_TYPE ext_store_ignore /* 0x09 gamepak, ignore */;\
|
ADDR_TYPE ext_store_ignore /* 0x09 gamepak, ignore */;\
|
||||||
ADDR_TYPE ext_store_ignore /* 0x0A gamepak, ignore */;\
|
ADDR_TYPE ext_store_ignore /* 0x0A gamepak, ignore */;\
|
||||||
ADDR_TYPE ext_store_ignore /* 0x0B gamepak, ignore */;\
|
ADDR_TYPE ext_store_ignore /* 0x0B gamepak, ignore */;\
|
||||||
|
|
Loading…
Reference in New Issue