Merge branch 'master' into bess

This commit is contained in:
Lior Halphon 2021-04-13 20:50:29 +03:00
commit 976f5e4d02
11 changed files with 204 additions and 29 deletions

View File

@ -1523,7 +1523,9 @@ static bool mbc(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg
const GB_cartridge_t *cartridge = gb->cartridge_type;
if (cartridge->has_ram) {
GB_log(gb, "Cartridge includes%s RAM: $%x bytes\n", cartridge->has_battery? " battery-backed": "", gb->mbc_ram_size);
bool has_battery = gb->cartridge_type->has_battery &&
(gb->cartridge_type->mbc_type != GB_TPP1 || (gb->rom[0x153] & 8));
GB_log(gb, "Cartridge includes%s RAM: $%x bytes\n", has_battery? " battery-backed": "", gb->mbc_ram_size);
}
else {
GB_log(gb, "No cartridge RAM\n");
@ -1565,7 +1567,8 @@ static bool mbc(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg
GB_log(gb, "No MBC\n");
}
if (cartridge->has_rumble) {
if (gb->cartridge_type->has_rumble &&
(gb->cartridge_type->mbc_type != GB_TPP1 || (gb->rom[0x153] & 1))) {
GB_log(gb, "Cart contains a Rumble Pak\n");
}

View File

@ -579,7 +579,6 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
else if (gb->model & GB_MODEL_NO_SFC_BIT) {
if (gb->icd_pixel_callback) {
icd_pixel = pixel;
//gb->icd_pixel_callback(gb, pixel);
}
}
else if (gb->cgb_palettes_ppu_blocked) {

View File

@ -598,6 +598,8 @@ typedef union {
int GB_save_battery_size(GB_gameboy_t *gb)
{
if (!gb->cartridge_type->has_battery) return 0; // Nothing to save.
if (gb->cartridge_type->mbc_type == GB_TPP1 && !(gb->rom[0x153] & 8)) return 0; // Nothing to save.
if (gb->mbc_ram_size == 0 && !gb->cartridge_type->has_rtc) return 0; /* Claims to have battery, but has no RAM or RTC */
if (gb->cartridge_type->mbc_type == GB_HUC3) {
@ -610,6 +612,7 @@ int GB_save_battery_size(GB_gameboy_t *gb)
int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size)
{
if (!gb->cartridge_type->has_battery) return 0; // Nothing to save.
if (gb->cartridge_type->mbc_type == GB_TPP1 && !(gb->rom[0x153] & 8)) return 0; // Nothing to save.
if (gb->mbc_ram_size == 0 && !gb->cartridge_type->has_rtc) return 0; /* Claims to have battery, but has no RAM or RTC */
if (size < GB_save_battery_size(gb)) return EIO;
@ -667,6 +670,7 @@ int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size)
int GB_save_battery(GB_gameboy_t *gb, const char *path)
{
if (!gb->cartridge_type->has_battery) return 0; // Nothing to save.
if (gb->cartridge_type->mbc_type == GB_TPP1 && !(gb->rom[0x153] & 8)) return 0; // Nothing to save.
if (gb->mbc_ram_size == 0 && !gb->cartridge_type->has_rtc) return 0; /* Claims to have battery, but has no RAM or RTC */
FILE *f = fopen(path, "wb");
if (!f) {

View File

@ -468,10 +468,10 @@ struct GB_gameboy_internal_s {
uint16_t mbc_rom0_bank; /* For some MBC1 wirings. */
bool camera_registers_mapped;
uint8_t camera_registers[0x36];
bool rumble_state;
uint8_t rumble_strength;
bool cart_ir;
// TODO: move to huc3/mbc3 struct when breaking save compat
// TODO: move to huc3/mbc3/tpp1 struct when breaking save compat
uint8_t huc3_mode;
uint8_t huc3_access_index;
uint16_t huc3_minutes, huc3_days;
@ -480,6 +480,9 @@ struct GB_gameboy_internal_s {
uint8_t huc3_read;
uint8_t huc3_access_flags;
bool mbc3_rtc_mapped;
uint16_t tpp1_rom_bank;
uint8_t tpp1_ram_bank;
uint8_t tpp1_mode;
);

View File

@ -111,12 +111,24 @@ void GB_update_mbc_mappings(GB_gameboy_t *gb)
gb->mbc_rom_bank = gb->huc3.rom_bank;
gb->mbc_ram_bank = gb->huc3.ram_bank;
break;
case GB_TPP1:
gb->mbc_rom_bank = gb->tpp1_rom_bank;
gb->mbc_ram_bank = gb->tpp1_ram_bank;
gb->mbc_ram_enable = (gb->tpp1_mode == 2) || (gb->tpp1_mode == 3);
break;
}
}
void GB_configure_cart(GB_gameboy_t *gb)
{
gb->cartridge_type = &GB_cart_defs[gb->rom[0x147]];
if (gb->rom[0x147] == 0xbc &&
gb->rom[0x149] == 0xc1 &&
gb->rom[0x14a] == 0x65) {
static const GB_cartridge_t tpp1 = {GB_TPP1, GB_STANDARD_MBC, true, true, true, true};
gb->cartridge_type = &tpp1;
gb->tpp1_rom_bank = 1;
}
if (gb->rom[0x147] == 0 && gb->rom_size > 0x8000) {
GB_log(gb, "ROM header reports no MBC, but file size is over 32Kb. Assuming cartridge uses MBC3.\n");
@ -130,6 +142,11 @@ void GB_configure_cart(GB_gameboy_t *gb)
if (gb->cartridge_type->mbc_type == GB_MBC2) {
gb->mbc_ram_size = 0x200;
}
else if (gb->cartridge_type->mbc_type == GB_TPP1) {
if (gb->rom[0x152] >= 1 && gb->rom[0x152] <= 9) {
gb->mbc_ram_size = 0x2000 << (gb->rom[0x152] - 1);
}
}
else {
static const unsigned ram_sizes[256] = {0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000};
gb->mbc_ram_size = ram_sizes[gb->rom[0x149]];

View File

@ -12,6 +12,7 @@ typedef struct {
GB_MBC5,
GB_HUC1,
GB_HUC3,
GB_TPP1,
} mbc_type;
enum {
GB_STANDARD_MBC,

View File

@ -178,7 +178,42 @@ static uint8_t read_mbc_ram(GB_gameboy_t *gb, uint16_t addr)
}
}
if ((!gb->mbc_ram_enable) &&
if (gb->cartridge_type->mbc_type == GB_TPP1) {
switch (gb->tpp1_mode) {
case 0:
switch (addr & 3) {
case 0: return gb->tpp1_rom_bank;
case 1: return gb->tpp1_rom_bank >> 8;
case 2: return gb->tpp1_ram_bank;
case 3: return gb->rumble_strength | (((gb->rtc_real.high & 0xC0) ^ 0x40) >> 4);
}
case 2:
case 3:
break; // Read RAM
case 5:
switch (addr & 3) {
case 0: { // Week count
unsigned total_days = (((gb->rtc_latched.high & 7) << 8) + gb->rtc_latched.days);
if (gb->rtc_latched.high & 0x20) {
return total_days / 7 - 1;
}
return total_days / 7;
}
case 1: { // Week count
unsigned total_days = (((gb->rtc_latched.high & 7) << 8) + gb->rtc_latched.days);
if (gb->rtc_latched.high & 0x20) {
return gb->rtc_latched.hours | 0xe0; // Hours and weekday
}
return gb->rtc_latched.hours | ((total_days % 7) << 5); // Hours and weekday
}
case 2: return gb->rtc_latched.minutes;
case 3: return gb->rtc_latched.seconds;
}
default:
return 0xFF;
}
}
else if ((!gb->mbc_ram_enable) &&
gb->cartridge_type->mbc_subtype != GB_CAMERA &&
gb->cartridge_type->mbc_type != GB_HUC1 &&
gb->cartridge_type->mbc_type != GB_HUC3) {
@ -335,9 +370,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
}
if (addr < 0xFF00) {
return 0;
}
if (addr < 0xFF80) {
@ -539,8 +572,8 @@ static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
case 0x3000: gb->mbc5.rom_bank_high = value; break;
case 0x4000: case 0x5000:
if (gb->cartridge_type->has_rumble) {
if (!!(value & 8) != gb->rumble_state) {
gb->rumble_state = !gb->rumble_state;
if (!!(value & 8) != !!gb->rumble_strength) {
gb->rumble_strength = gb->rumble_strength? 0 : 3;
}
value &= 7;
}
@ -567,6 +600,56 @@ static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
case 0x4000: case 0x5000: gb->huc3.ram_bank = value; break;
}
break;
case GB_TPP1:
switch (addr & 3) {
case 0:
gb->tpp1_rom_bank &= 0xFF00;
gb->tpp1_rom_bank |= value;
break;
case 1:
gb->tpp1_rom_bank &= 0xFF;
gb->tpp1_rom_bank |= value << 8;
break;
case 2:
gb->tpp1_ram_bank = value;
break;
case 3:
switch (value) {
case 0:
case 2:
case 3:
case 5:
gb->tpp1_mode = value;
break;
case 0x10:
memcpy(&gb->rtc_latched, &gb->rtc_real, sizeof(gb->rtc_real));
break;
case 0x11: {
uint8_t flags = gb->rtc_real.high & 0xc0;
memcpy(&gb->rtc_real, &gb->rtc_latched, sizeof(gb->rtc_real));
gb->rtc_real.high &= ~0xe0;
gb->rtc_real.high |= flags;
break;
}
case 0x14:
gb->rtc_real.high &= ~0x80;
break;
case 0x18:
gb->rtc_real.high |= 0x40;
break;
case 0x19:
gb->rtc_real.high &= ~0x40;
break;
case 0x20:
case 0x21:
case 0x22:
case 0x23:
gb->rumble_strength = value & 3;
break;
}
}
break;
}
GB_update_mbc_mappings(gb);
}
@ -688,6 +771,43 @@ static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
return;
}
if (gb->cartridge_type->mbc_type == GB_TPP1) {
switch (gb->tpp1_mode) {
case 3:
break;
case 5:
switch (addr & 3) {
case 0: {
unsigned total_days = (((gb->rtc_latched.high & 7) << 8) + gb->rtc_latched.days);
total_days = total_days % 7 + value * 7;
bool had_illegal_weekday = gb->rtc_latched.high & 0x20;
gb->rtc_latched.days = total_days;
gb->rtc_latched.high = total_days >> 8;
if (had_illegal_weekday) {
gb->rtc_latched.high |= 0x20;
}
return;
}
case 1: {
unsigned total_days = (((gb->rtc_latched.high & 7) << 8) + gb->rtc_latched.days);
total_days = total_days / 7 * 7 + (value >> 5);
gb->rtc_latched.hours = value & 0x1F;
gb->rtc_latched.days = total_days;
gb->rtc_latched.high = total_days >> 8;
if ((value & 0xE0) == 0xE0) { // Illegal weekday
gb->rtc_latched.high |= 0x20;
}
return;
}
case 2: gb->rtc_latched.minutes = value; return;
case 3: gb->rtc_latched.seconds = value; return;
}
return;
default:
return;
}
}
if ((!gb->mbc_ram_enable)
&& gb->cartridge_type->mbc_type != GB_HUC1) return;

View File

@ -15,7 +15,8 @@ void GB_handle_rumble(GB_gameboy_t *gb)
if (gb->rumble_mode == GB_RUMBLE_DISABLED) {
return;
}
if (gb->cartridge_type->has_rumble) {
if (gb->cartridge_type->has_rumble &&
(gb->cartridge_type->mbc_type != GB_TPP1 || (gb->rom[0x153] & 1))) {
if (gb->rumble_on_cycles + gb->rumble_off_cycles) {
gb->rumble_callback(gb, gb->rumble_on_cycles / (double)(gb->rumble_on_cycles + gb->rumble_off_cycles));
gb->rumble_on_cycles = gb->rumble_off_cycles = 0;

View File

@ -267,7 +267,8 @@ static void command_ready(GB_gameboy_t *gb)
#endif
uint8_t x = command->x;
uint8_t y = command->y;
if (x >= 20 || y >= 18 || (count + 3) / 4 > sizeof(gb->sgb->command) - sizeof(*command) - 1) {
count = MIN(count, 20 * 18);
if (x >= 20 || y >= 18) {
/* TODO: Verify with the SFC BIOS */
break;
}

View File

@ -288,10 +288,22 @@ static void GB_rtc_run(GB_gameboy_t *gb, uint8_t cycles)
while (gb->last_rtc_second + 60 * 60 * 24 < current_time) {
gb->last_rtc_second += 60 * 60 * 24;
if (++gb->rtc_real.days == 0) {
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
gb->rtc_real.high |= 0x80; /* Overflow bit */
if (gb->cartridge_type->mbc_type == GB_TPP1) {
if ((gb->rtc_real.high & 7) >= 6) { /* Bit 8 of days*/
gb->rtc_real.high &= 0x40;
gb->rtc_real.high |= 0x80; /* Overflow bit */
}
else {
gb->rtc_real.high++;
}
}
else {
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
gb->rtc_real.high |= 0x80; /* Overflow bit */
}
gb->rtc_real.high ^= 1;
}
gb->rtc_real.high ^= 1;
}
}
@ -308,11 +320,22 @@ static void GB_rtc_run(GB_gameboy_t *gb, uint8_t cycles)
if (++gb->rtc_real.days != 0) continue;
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
gb->rtc_real.high |= 0x80; /* Overflow bit */
if (gb->cartridge_type->mbc_type == GB_TPP1) {
if ((gb->rtc_real.high & 7) >= 6) { /* Bit 8 of days*/
gb->rtc_real.high &= 0x40;
gb->rtc_real.high |= 0x80; /* Overflow bit */
}
else {
gb->rtc_real.high++;
}
}
else {
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
gb->rtc_real.high |= 0x80; /* Overflow bit */
}
gb->rtc_real.high ^= 1;
}
gb->rtc_real.high ^= 1;
}
}
}
@ -344,13 +367,9 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
gb->cycles_since_last_sync += cycles;
gb->cycles_since_run += cycles;
if (gb->rumble_state) {
gb->rumble_on_cycles++;
}
else {
gb->rumble_off_cycles++;
}
gb->rumble_on_cycles += gb->rumble_strength & 3;
gb->rumble_off_cycles += (gb->rumble_strength & 3) ^ 3;
if (!gb->stopped) { // TODO: Verify what happens in STOP mode
GB_dma_run(gb);
GB_hdma_run(gb);

View File

@ -166,6 +166,7 @@ typedef union {
double _sentRumbleAmp;
unsigned _rumbleCounter;
bool _deviceCantSendReports;
dispatch_queue_t _rumbleQueue;
}
- (instancetype)initWithDevice:(IOHIDDeviceRef) device hacks:(NSDictionary *)hacks
@ -490,9 +491,11 @@ typedef union {
{.timeEnabled = 0, .dutyLength = 0, .enabled = 0, .dutyOff = 0, .dutyOn = 0},
}
};
}
_rumbleQueue = dispatch_queue_create([NSString stringWithFormat:@"Rumble Queue for %@", self.deviceName].UTF8String,
NULL);
return self;
}
@ -564,7 +567,9 @@ typedef union {
}
}
}
[self updateRumble];
dispatch_async(_rumbleQueue, ^{
[self updateRumble];
});
}
- (void)elementChanged:(IOHIDElementRef)element
@ -699,7 +704,9 @@ typedef union {
_physicallyConnected = false;
[exposedControllers removeObject:self];
[self setRumbleAmplitude:0];
[self updateRumble];
dispatch_sync(_rumbleQueue, ^{
[self updateRumble];
});
_device = nil;
}