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
374
gba_memory.c
374
gba_memory.c
|
@ -1179,16 +1179,24 @@ typedef enum
|
|||
#define RTC_WRITE_TIME_FULL 1
|
||||
#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_write_mode;
|
||||
u8 rtc_registers[3];
|
||||
u32 rtc_command;
|
||||
u32 rtc_data[12];
|
||||
u64 rtc_data;
|
||||
u32 rtc_data_bits;
|
||||
u32 rtc_status = 0x40;
|
||||
u32 rtc_data_bytes;
|
||||
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 h = 0;
|
||||
|
@ -1200,224 +1208,189 @@ static u32 encode_bcd(u8 value)
|
|||
return h * 16 + l;
|
||||
}
|
||||
|
||||
// RTC writes need to reflect in the bytes [0xC4..0xC9] of the gamepak
|
||||
#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) { \
|
||||
address16(map, update_address & 0x7FFF) = eswap16(_value); \
|
||||
} \
|
||||
void update_gpio_romregs() {
|
||||
if (rtc_enabled || rumble_enabled) {
|
||||
// Update the registers in the ROM mapped buffer.
|
||||
u8 *map = memory_map_read[0x8000000 >> 15];
|
||||
if (map) {
|
||||
if (gpio_regs[2]) {
|
||||
// Registers are visible, readable:
|
||||
address16(map, 0xC4) = eswap16(gpio_regs[0]);
|
||||
address16(map, 0xC6) = eswap16(gpio_regs[1]);
|
||||
address16(map, 0xC8) = eswap16(gpio_regs[2]);
|
||||
} else {
|
||||
// Registers are write-only, just read out zero
|
||||
address16(map, 0xC4) = 0;
|
||||
address16(map, 0xC6) = 0;
|
||||
address16(map, 0xC8) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void function_cc write_rtc(u32 address, u32 value)
|
||||
#define GPIO_RTC_CLK 0x1
|
||||
#define GPIO_RTC_DAT 0x2
|
||||
#define GPIO_RTC_CSS 0x4
|
||||
|
||||
static void write_rtc(u8 old, u8 new)
|
||||
{
|
||||
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 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;
|
||||
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;
|
||||
rtc_bit_count = 0;
|
||||
return;
|
||||
}
|
||||
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.
|
||||
|
||||
// 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:
|
||||
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
|
||||
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:
|
||||
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_data = 0;
|
||||
rtc_data_bits = 8;
|
||||
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;
|
||||
rtc_data_bits = 8;
|
||||
rtc_data = 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;
|
||||
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);
|
||||
}
|
||||
|
||||
// Only outputs the current time of day.
|
||||
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_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);
|
||||
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;
|
||||
|
||||
// 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_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;
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
rtc_bit_count++;
|
||||
rtc_data >>= 1;
|
||||
rtc_data_bits--;
|
||||
|
||||
if (!rtc_data_bits)
|
||||
rtc_state = RTC_IDLE; // Finish transmission!
|
||||
|
||||
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() \
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#define write_rtc16() \
|
||||
write_rtc(address & 0xFF, value) \
|
||||
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;
|
||||
}
|
||||
|
||||
#define write_rtc32() \
|
||||
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) \
|
||||
switch(address >> 24) \
|
||||
|
@ -1460,7 +1433,7 @@ void function_cc write_rtc(u32 address, u32 value)
|
|||
\
|
||||
case 0x08: \
|
||||
/* gamepak ROM or RTC */ \
|
||||
write_rtc##type(); \
|
||||
write_gpio##type(); \
|
||||
break; \
|
||||
\
|
||||
case 0x09: \
|
||||
|
@ -1571,6 +1544,7 @@ typedef struct
|
|||
|
||||
#define FLAGS_FLASH_128KB 0x0001
|
||||
#define FLAGS_RUMBLE 0x0002
|
||||
#define FLAGS_RTC 0x0004
|
||||
|
||||
#include "gba_over.h"
|
||||
|
||||
|
@ -1602,6 +1576,12 @@ static void load_game_config_over(gamepak_info_t *gpinfo)
|
|||
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)
|
||||
{
|
||||
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_rom_entry(read, physical_index, swap_location, gamepak_size >> 15);
|
||||
|
||||
// If RTC is active page the RTC register bytes so they can be read
|
||||
if ((rtc_state != RTC_DISABLED) && (physical_index == 0)) {
|
||||
address16(swap_location, 0xC4) = eswap16(rtc_registers[0]);
|
||||
address16(swap_location, 0xC6) = eswap16(rtc_registers[1]);
|
||||
address16(swap_location, 0xC8) = eswap16(rtc_registers[2]);
|
||||
}
|
||||
// When mapping page 0, we might need to reflect the GPIO regs.
|
||||
if (physical_index == 0)
|
||||
update_gpio_romregs();
|
||||
|
||||
return swap_location;
|
||||
}
|
||||
|
@ -2288,11 +2265,13 @@ void init_memory(void)
|
|||
eeprom_mode = EEPROM_BASE_MODE;
|
||||
eeprom_address = 0;
|
||||
eeprom_counter = 0;
|
||||
rumble_enable_tick = 0;
|
||||
rumble_ticks = 0;
|
||||
|
||||
flash_mode = FLASH_BASE_MODE;
|
||||
|
||||
rtc_state = RTC_DISABLED;
|
||||
memset(rtc_registers, 0, sizeof(rtc_registers));
|
||||
memset(gpio_regs, 0, sizeof(gpio_regs));
|
||||
reg[REG_BUS_VALUE] = 0xe129f000;
|
||||
}
|
||||
|
||||
|
@ -2315,7 +2294,7 @@ bool memory_check_savestate(const u8 *src)
|
|||
static const char *vars32[] = {
|
||||
"backup-type","flash-mode", "flash-cmd-pos", "flash-bank-num", "flash-dev-id",
|
||||
"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[] = {
|
||||
"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))
|
||||
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))
|
||||
return false;
|
||||
|
||||
|
@ -2364,6 +2343,7 @@ bool memory_check_savestate(const u8 *src)
|
|||
bool memory_read_savestate(const u8 *src)
|
||||
{
|
||||
int i;
|
||||
u32 rtc_data_array[2];
|
||||
const u8 *memdoc = bson_find_key(src, "memory");
|
||||
const u8 *bakdoc = bson_find_key(src, "backup");
|
||||
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-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-write-mode", &rtc_write_mode) &&
|
||||
bson_read_int32(bakdoc, "rtc-cmd", &rtc_command) &&
|
||||
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_bytes(bakdoc, "rtc-regs", rtc_registers, sizeof(rtc_registers)) &&
|
||||
bson_read_int32_array(bakdoc, "rtc-data-words", rtc_data,
|
||||
sizeof(rtc_data)/sizeof(rtc_data[0]))))
|
||||
bson_read_int32_array(bakdoc, "rtc-data-words", rtc_data_array, 2)))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < DMA_CHAN_CNT; i++)
|
||||
|
@ -2420,6 +2400,8 @@ bool memory_read_savestate(const u8 *src)
|
|||
return false;
|
||||
}
|
||||
|
||||
rtc_data = rtc_data_array[0] | (((u64)rtc_data_array[1]) << 32);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2427,6 +2409,8 @@ unsigned memory_write_savestate(u8 *dst)
|
|||
{
|
||||
int i;
|
||||
u8 *wbptr, *wbptr2, *startp = dst;
|
||||
u32 rtc_data_array[2] = { (u32)rtc_data, (u32)(rtc_data >> 32) };
|
||||
|
||||
bson_start_document(dst, "memory", wbptr);
|
||||
bson_write_bytes(dst, "iwram", &iwram[0x8000], 0x8000);
|
||||
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-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-write-mode", rtc_write_mode);
|
||||
bson_write_int32(dst, "rtc-cmd", rtc_command);
|
||||
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_bytes(dst, "rtc-regs", rtc_registers, sizeof(rtc_registers));
|
||||
bson_write_int32array(dst, "rtc-data-words", rtc_data,
|
||||
sizeof(rtc_data)/sizeof(rtc_data[0]));
|
||||
bson_write_int32array(dst, "rtc-data-words", rtc_data_array, 2);
|
||||
bson_finish_document(dst, wbptr);
|
||||
|
||||
bson_start_document(dst, "dma", wbptr);
|
||||
|
@ -2525,7 +2508,8 @@ static s32 load_gamepak_raw(const char *name)
|
|||
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;
|
||||
|
||||
|
@ -2542,9 +2526,17 @@ u32 load_gamepak(const struct retro_game_info* info, const char *name)
|
|||
translation_gate_targets = 0;
|
||||
flash_device_id = FLASH_DEVICE_MACRONIX_64KB;
|
||||
flash_bank_cnt = FLASH_SIZE_64KB;
|
||||
rtc_enabled = false;
|
||||
rumble_enabled = false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
12
gba_memory.h
12
gba_memory.h
|
@ -22,6 +22,10 @@
|
|||
|
||||
#include "libretro.h"
|
||||
|
||||
#define FEAT_AUTODETECT -1
|
||||
#define FEAT_DISABLE 0
|
||||
#define FEAT_ENABLE 1
|
||||
|
||||
#define DMA_CHAN_CNT 4
|
||||
|
||||
#define DMA_START_IMMEDIATELY 0
|
||||
|
@ -221,7 +225,10 @@ u32 function_cc read_eeprom(void);
|
|||
void function_cc write_eeprom(u32 address, u32 value);
|
||||
u8 read_backup(u32 address);
|
||||
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 ?! */
|
||||
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);
|
||||
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);
|
||||
void init_memory(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_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)
|
||||
"BOMBERMANJGC", /* gamepak_title */
|
||||
|
@ -498,6 +509,39 @@ static const ini_t gbaover[] = {
|
|||
0, /* translation_gate_target_2 */
|
||||
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)
|
||||
"M HOUSHIN", /* gamepak_title */
|
||||
|
@ -976,7 +1020,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON EMER", /* gamepak_title */
|
||||
"BPEE", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0x80008ce, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -987,7 +1031,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON EMER", /* gamepak_title */
|
||||
"BPEJ", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0x80008ce, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -998,7 +1042,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON EMER", /* gamepak_title */
|
||||
"BPED", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0x80008ce, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1009,7 +1053,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON EMER", /* gamepak_title */
|
||||
"BPEF", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0x80008ce, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1020,7 +1064,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON EMER", /* gamepak_title */
|
||||
"BPES", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0x80008ce, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1031,7 +1075,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON EMER", /* gamepak_title */
|
||||
"BPEI", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0x80008ce, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1042,7 +1086,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON SAPP", /* gamepak_title */
|
||||
"AXPE", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1053,7 +1097,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON SAPP", /* gamepak_title */
|
||||
"AXPJ", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1064,7 +1108,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON SAPP", /* gamepak_title */
|
||||
"AXPD", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1075,7 +1119,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON SAPP", /* gamepak_title */
|
||||
"AXPI", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1086,7 +1130,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON SAPP", /* gamepak_title */
|
||||
"AXPS", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1097,7 +1141,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON SAPP", /* gamepak_title */
|
||||
"AXPF", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1108,7 +1152,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON RUBY", /* gamepak_title */
|
||||
"AXVE", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1119,7 +1163,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON RUBY", /* gamepak_title */
|
||||
"AXVJ", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1130,7 +1174,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON RUBY", /* gamepak_title */
|
||||
"AXVD", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1141,7 +1185,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON RUBY", /* gamepak_title */
|
||||
"AXVI", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1152,7 +1196,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON RUBY", /* gamepak_title */
|
||||
"AXVS", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1163,7 +1207,7 @@ static const ini_t gbaover[] = {
|
|||
"POKEMON RUBY", /* gamepak_title */
|
||||
"AXVF", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1452,12 +1496,23 @@ static const ini_t gbaover[] = {
|
|||
0, /* translation_gate_target_2 */
|
||||
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)
|
||||
"SENNENKAZOKU", /* gamepak_title */
|
||||
"BKAJ", /* gamepak_code */
|
||||
"01", /* gamepak_maker */
|
||||
FLAGS_FLASH_128KB, /* flags */
|
||||
FLAGS_FLASH_128KB | FLAGS_RTC, /* flags */
|
||||
0, /* idle_loop_target_pc */
|
||||
0, /* translation_gate_target_1 */
|
||||
0, /* translation_gate_target_2 */
|
||||
|
@ -1782,6 +1837,39 @@ static const ini_t gbaover[] = {
|
|||
0, /* translation_gate_target_2 */
|
||||
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 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_input_poll_t input_poll_cb;
|
||||
static retro_environment_t environ_cb;
|
||||
static retro_set_rumble_state_t rumble_cb;
|
||||
|
||||
struct retro_perf_callback perf_cb;
|
||||
|
||||
|
@ -91,6 +92,8 @@ int dynarec_enable;
|
|||
boot_mode selected_boot_mode = boot_game;
|
||||
int sprite_limit = 1;
|
||||
|
||||
static int rtc_mode = FEAT_AUTODETECT, rumble_mode = FEAT_AUTODETECT;
|
||||
|
||||
u32 idle_loop_target_pc = 0xFFFFFFFF;
|
||||
u32 translation_gate_target_pc[MAX_TRANSLATION_GATES];
|
||||
u32 translation_gate_targets = 0;
|
||||
|
@ -744,7 +747,7 @@ static void extract_directory(char* buf, const char* path, size_t size)
|
|||
strncpy(buf, ".", size);
|
||||
}
|
||||
|
||||
static void check_variables(int started_from_load)
|
||||
static void check_variables(bool started_from_load)
|
||||
{
|
||||
struct retro_variable var;
|
||||
bool frameskip_type_prev;
|
||||
|
@ -776,7 +779,6 @@ static void check_variables(int started_from_load)
|
|||
if (started_from_load) {
|
||||
var.key = "gpsp_bios";
|
||||
var.value = 0;
|
||||
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||
{
|
||||
if (!strcmp(var.value, "auto"))
|
||||
|
@ -789,7 +791,6 @@ static void check_variables(int started_from_load)
|
|||
|
||||
var.key = "gpsp_boot_mode";
|
||||
var.value = 0;
|
||||
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||
{
|
||||
if (!strcmp(var.value, "game"))
|
||||
|
@ -797,6 +798,30 @@ static void check_variables(int started_from_load)
|
|||
else if (!strcmp(var.value, "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";
|
||||
|
@ -956,7 +981,7 @@ bool retro_load_game(const struct retro_game_info* info)
|
|||
if (!info)
|
||||
return false;
|
||||
|
||||
check_variables(1);
|
||||
check_variables(true);
|
||||
set_input_descriptors();
|
||||
|
||||
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));
|
||||
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.");
|
||||
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();
|
||||
|
||||
set_memory_descriptors();
|
||||
|
@ -1063,6 +1094,8 @@ void retro_run(void)
|
|||
input_poll_cb();
|
||||
update_input();
|
||||
|
||||
rumble_frame_reset();
|
||||
|
||||
/* Check whether current frame should
|
||||
* be skipped */
|
||||
skip_next_frame = 0;
|
||||
|
@ -1145,11 +1178,18 @@ void retro_run(void)
|
|||
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();
|
||||
video_run();
|
||||
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
|
||||
check_variables(0);
|
||||
check_variables(false);
|
||||
}
|
||||
|
||||
unsigned retro_api_version(void)
|
||||
|
|
|
@ -87,6 +87,30 @@ struct retro_core_option_definition option_defs_us[] = {
|
|||
},
|
||||
"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",
|
||||
"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)
|
||||
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
|
||||
// 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_b(bne, reg_rv, reg_zero, st_phndlr_branch(strop));
|
||||
if (strop == 1) {
|
||||
emit_mem_call(&write_rtc, 0xFF); // Addr
|
||||
emit_mem_call(&write_gpio, 0xFF); // Addr
|
||||
} else {
|
||||
mips_emit_nop();
|
||||
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 */
|
||||
#define GBA_STATE_MEM_SIZE (416*1024)
|
||||
#define GBA_STATE_MAGIC 0x06BAC0DE
|
||||
#define GBA_STATE_VERSION 0x00010002
|
||||
#define GBA_STATE_VERSION 0x00010003
|
||||
|
||||
bool gba_load_state(const void *src);
|
||||
void gba_save_state(void *dst);
|
||||
|
|
|
@ -219,8 +219,8 @@ defsymbl(x86_indirect_branch_dual)
|
|||
|
||||
# General ext memory routines
|
||||
|
||||
ext_store_rtc8: # No RTC writes on byte or word access
|
||||
ext_store_rtc32:
|
||||
ext_store_gpio8: # No GPIO/RTC writes on byte or word access
|
||||
ext_store_gpio32:
|
||||
ext_store_backup16: # Backup (flash) accessed via byte writes
|
||||
ext_store_backup32:
|
||||
ext_store_eeprom8: # EEPROM accesses are performed using 16 bit DMA
|
||||
|
@ -228,11 +228,11 @@ ext_store_eeprom32:
|
|||
ext_store_ignore:
|
||||
ret # ignore these writes
|
||||
|
||||
ext_store_rtc16:
|
||||
ext_store_gpio16:
|
||||
and $0xFFFF, %edx # make value 16bit
|
||||
and $0xFF, %eax # mask address
|
||||
SETUP_ARGS # Setup addr, value
|
||||
CALL_FUNC(write_rtc) # write out RTC register
|
||||
CALL_FUNC(write_gpio) # write out RTC register
|
||||
ret
|
||||
|
||||
ext_store_backup8:
|
||||
|
@ -565,7 +565,7 @@ return_to_main:
|
|||
ADDR_TYPE ext_store_palette##asize /* 0x05 Palette RAM */;\
|
||||
ADDR_TYPE ext_store_vram##asize /* 0x06 VRAM */;\
|
||||
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 /* 0x0A gamepak, ignore */;\
|
||||
ADDR_TYPE ext_store_ignore /* 0x0B gamepak, ignore */;\
|
||||
|
|
Loading…
Reference in New Issue