TPP1 support
This commit is contained in:
parent
44c75ae7be
commit
f24489b983
@ -441,10 +441,10 @@ struct GB_gameboy_internal_s {
|
|||||||
uint16_t mbc_rom0_bank; /* For some MBC1 wirings. */
|
uint16_t mbc_rom0_bank; /* For some MBC1 wirings. */
|
||||||
bool camera_registers_mapped;
|
bool camera_registers_mapped;
|
||||||
uint8_t camera_registers[0x36];
|
uint8_t camera_registers[0x36];
|
||||||
bool rumble_state;
|
uint8_t rumble_strength;
|
||||||
bool cart_ir;
|
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_mode;
|
||||||
uint8_t huc3_access_index;
|
uint8_t huc3_access_index;
|
||||||
uint16_t huc3_minutes, huc3_days;
|
uint16_t huc3_minutes, huc3_days;
|
||||||
@ -453,6 +453,9 @@ struct GB_gameboy_internal_s {
|
|||||||
uint8_t huc3_read;
|
uint8_t huc3_read;
|
||||||
uint8_t huc3_access_flags;
|
uint8_t huc3_access_flags;
|
||||||
bool mbc3_rtc_mapped;
|
bool mbc3_rtc_mapped;
|
||||||
|
uint16_t tpp1_rom_bank;
|
||||||
|
uint8_t tpp1_ram_bank;
|
||||||
|
uint8_t tpp1_mode;
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
17
Core/mbc.c
17
Core/mbc.c
@ -111,12 +111,24 @@ void GB_update_mbc_mappings(GB_gameboy_t *gb)
|
|||||||
gb->mbc_rom_bank = gb->huc3.rom_bank;
|
gb->mbc_rom_bank = gb->huc3.rom_bank;
|
||||||
gb->mbc_ram_bank = gb->huc3.ram_bank;
|
gb->mbc_ram_bank = gb->huc3.ram_bank;
|
||||||
break;
|
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)
|
void GB_configure_cart(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
gb->cartridge_type = &GB_cart_defs[gb->rom[0x147]];
|
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) {
|
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");
|
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) {
|
if (gb->cartridge_type->mbc_type == GB_MBC2) {
|
||||||
gb->mbc_ram_size = 0x200;
|
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 {
|
else {
|
||||||
static const unsigned ram_sizes[256] = {0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000};
|
static const unsigned ram_sizes[256] = {0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000};
|
||||||
gb->mbc_ram_size = ram_sizes[gb->rom[0x149]];
|
gb->mbc_ram_size = ram_sizes[gb->rom[0x149]];
|
||||||
|
@ -12,6 +12,7 @@ typedef struct {
|
|||||||
GB_MBC5,
|
GB_MBC5,
|
||||||
GB_HUC1,
|
GB_HUC1,
|
||||||
GB_HUC3,
|
GB_HUC3,
|
||||||
|
GB_TPP1,
|
||||||
} mbc_type;
|
} mbc_type;
|
||||||
enum {
|
enum {
|
||||||
GB_STANDARD_MBC,
|
GB_STANDARD_MBC,
|
||||||
|
105
Core/memory.c
105
Core/memory.c
@ -178,7 +178,31 @@ 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: return (((gb->rtc_latched.high & 7) << 8) + gb->rtc_latched.days) / 7; // Week count
|
||||||
|
case 1: return gb->rtc_latched.hours |
|
||||||
|
(((((gb->rtc_latched.high & 7) << 8) + gb->rtc_latched.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_subtype != GB_CAMERA &&
|
||||||
gb->cartridge_type->mbc_type != GB_HUC1 &&
|
gb->cartridge_type->mbc_type != GB_HUC1 &&
|
||||||
gb->cartridge_type->mbc_type != GB_HUC3) {
|
gb->cartridge_type->mbc_type != GB_HUC3) {
|
||||||
@ -335,9 +359,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (addr < 0xFF00) {
|
if (addr < 0xFF00) {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr < 0xFF80) {
|
if (addr < 0xFF80) {
|
||||||
@ -539,8 +561,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 0x3000: gb->mbc5.rom_bank_high = value; break;
|
||||||
case 0x4000: case 0x5000:
|
case 0x4000: case 0x5000:
|
||||||
if (gb->cartridge_type->has_rumble) {
|
if (gb->cartridge_type->has_rumble) {
|
||||||
if (!!(value & 8) != gb->rumble_state) {
|
if (!!(value & 8) != !!gb->rumble_strength) {
|
||||||
gb->rumble_state = !gb->rumble_state;
|
gb->rumble_strength = gb->rumble_strength? 0 : 3;
|
||||||
}
|
}
|
||||||
value &= 7;
|
value &= 7;
|
||||||
}
|
}
|
||||||
@ -567,6 +589,49 @@ static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
case 0x4000: case 0x5000: gb->huc3.ram_bank = value; break;
|
case 0x4000: case 0x5000: gb->huc3.ram_bank = value; break;
|
||||||
}
|
}
|
||||||
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 &= ~0xc0;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
GB_update_mbc_mappings(gb);
|
GB_update_mbc_mappings(gb);
|
||||||
}
|
}
|
||||||
@ -688,6 +753,36 @@ static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
return;
|
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;
|
||||||
|
gb->rtc_latched.days = total_days;
|
||||||
|
gb->rtc_latched.high = total_days >> 8;
|
||||||
|
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;
|
||||||
|
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)
|
if ((!gb->mbc_ram_enable)
|
||||||
&& gb->cartridge_type->mbc_type != GB_HUC1) return;
|
&& gb->cartridge_type->mbc_type != GB_HUC1) return;
|
||||||
|
|
||||||
|
@ -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) {
|
while (gb->last_rtc_second + 60 * 60 * 24 < current_time) {
|
||||||
gb->last_rtc_second += 60 * 60 * 24;
|
gb->last_rtc_second += 60 * 60 * 24;
|
||||||
if (++gb->rtc_real.days == 0) {
|
if (++gb->rtc_real.days == 0) {
|
||||||
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
|
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
||||||
gb->rtc_real.high |= 0x80; /* Overflow bit */
|
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.days != 0) continue;
|
||||||
|
|
||||||
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
|
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
||||||
gb->rtc_real.high |= 0x80; /* Overflow bit */
|
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_last_sync += cycles;
|
||||||
gb->cycles_since_run += cycles;
|
gb->cycles_since_run += cycles;
|
||||||
|
|
||||||
if (gb->rumble_state) {
|
gb->rumble_on_cycles += gb->rumble_strength & 3;
|
||||||
gb->rumble_on_cycles++;
|
gb->rumble_off_cycles += (gb->rumble_strength & 3) ^ 3;
|
||||||
}
|
|
||||||
else {
|
|
||||||
gb->rumble_off_cycles++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gb->stopped) { // TODO: Verify what happens in STOP mode
|
if (!gb->stopped) { // TODO: Verify what happens in STOP mode
|
||||||
GB_dma_run(gb);
|
GB_dma_run(gb);
|
||||||
GB_hdma_run(gb);
|
GB_hdma_run(gb);
|
||||||
|
Loading…
Reference in New Issue
Block a user