diff --git a/libHawk/GBHawk/GBHawk/Core.h b/libHawk/GBHawk/GBHawk/Core.h index ccaebb7377..ce28e5c5c6 100644 --- a/libHawk/GBHawk/GBHawk/Core.h +++ b/libHawk/GBHawk/GBHawk/Core.h @@ -52,6 +52,14 @@ namespace GBHawk psg.is_GBC = &MemMap.is_GBC; psg.double_speed = &MemMap.double_speed; psg.timer_div_reg = &timer.divider_reg; + + mapper.addr_access = &MemMap.addr_access; + mapper.Acc_X_state = &MemMap.Acc_X_state; + mapper.Acc_Y_state = &MemMap.Acc_Y_state; + mapper.ROM_Length = &MemMap.ROM_Length; + mapper.Cart_RAM_Length = &MemMap.Cart_RAM_Length; + mapper.ROM = &MemMap.ROM[0]; + mapper.Cart_RAM = &MemMap.Cart_RAM[0]; }; PPU ppu; diff --git a/libHawk/GBHawk/GBHawk/GBHawk.cpp b/libHawk/GBHawk/GBHawk/GBHawk.cpp index 93edce0357..33660260d8 100644 --- a/libHawk/GBHawk/GBHawk/GBHawk.cpp +++ b/libHawk/GBHawk/GBHawk/GBHawk.cpp @@ -22,8 +22,7 @@ GBHawk_EXPORT GBCore* GB_create() GBHawk_EXPORT void GB_destroy(GBCore* p) { delete p->MemMap.bios_rom; - delete p->MemMap.rom_1; - delete p->MemMap.rom_2; + delete p->MemMap.ROM; std::free(p); } diff --git a/libHawk/GBHawk/GBHawk/Mapper_Base.h b/libHawk/GBHawk/GBHawk/Mapper_Base.h index 699f4f3f57..0d97efd88f 100644 --- a/libHawk/GBHawk/GBHawk/Mapper_Base.h +++ b/libHawk/GBHawk/GBHawk/Mapper_Base.h @@ -18,10 +18,13 @@ namespace GBHawk } + uint8_t* ROM = nullptr; + uint8_t* Cart_RAM = nullptr; uint32_t* ROM_Length = nullptr; uint32_t* Cart_RAM_Length = nullptr; - uint32_t* ROM = nullptr; - uint32_t* Cart_RAM = nullptr; + uint32_t* addr_access = nullptr; + uint32_t* Acc_X_state = nullptr; + uint32_t* Acc_Y_state = nullptr; // Generic Mapper Variables bool RAM_enable; @@ -51,7 +54,16 @@ namespace GBHawk bool RTC_regs_latch_wr; uint32_t RTC_offset; + // camera + bool regs_enable; + uint8_t regs_cam[0x80] = {}; + // sachen + bool locked, locked_GBC, finished, reg_access; + uint32_t ROM_bank_mask; + uint32_t BASE_ROM_Bank; + uint32_t addr_last; + uint32_t counter; // TAMA5 uint8_t RTC_regs_TAMA[10] = {}; @@ -63,6 +75,30 @@ namespace GBHawk uint8_t Chip_return_low; uint8_t Chip_return_high; + // MBC7 + bool RAM_enable_1, RAM_enable_2, is_erased; + uint8_t acc_x_low; + uint8_t acc_x_high; + uint8_t acc_y_low; + uint8_t acc_y_high; + // EEPROM related + bool CS_prev; + bool CLK_prev; + bool DI_prev; + bool DO; + bool instr_read; + bool perf_instr; + bool WR_EN; + bool countdown_start; + uint32_t instr_bit_counter; + uint32_t instr; + uint32_t EE_addr; + uint32_t instr_case; + uint32_t instr_clocks; + uint32_t EE_value; + uint32_t countdown; + + virtual uint8_t ReadMemory(uint32_t addr) { @@ -142,6 +178,18 @@ namespace GBHawk saver = bool_saver(RTC_regs_latch_wr, saver); saver = int_saver(RTC_offset, saver); + saver = bool_saver(regs_enable, saver); + for (int i = 0; i < 5; i++) { saver = byte_saver(regs_cam[i], saver); } + + saver = bool_saver(locked, saver); + saver = bool_saver(locked_GBC, saver); + saver = bool_saver(finished, saver); + saver = bool_saver(reg_access, saver); + saver = int_saver(ROM_bank_mask, saver); + saver = int_saver(BASE_ROM_Bank, saver); + saver = int_saver(addr_last, saver); + saver = int_saver(counter, saver); + for (int i = 0; i < 10; i++) { saver = byte_saver(RTC_regs_TAMA[i], saver); } saver = byte_saver(Chip_return_low, saver); saver = byte_saver(Chip_return_high, saver); @@ -151,11 +199,103 @@ namespace GBHawk saver = int_saver(RAM_val_low, saver); saver = int_saver(RAM_val_high, saver); + saver = bool_saver(RAM_enable_1, saver); + saver = bool_saver(RAM_enable_2, saver); + saver = bool_saver(is_erased, saver); + saver = byte_saver(acc_x_low, saver); + saver = byte_saver(acc_x_high, saver); + saver = byte_saver(acc_y_low, saver); + saver = byte_saver(acc_y_high, saver); + // EEPROM related + saver = bool_saver(CS_prev, saver); + saver = bool_saver(CLK_prev, saver); + saver = bool_saver(DI_prev, saver); + saver = bool_saver(DO, saver); + saver = bool_saver(instr_read, saver); + saver = bool_saver(perf_instr, saver); + saver = bool_saver(WR_EN, saver); + saver = bool_saver(countdown_start, saver); + saver = int_saver(instr_bit_counter, saver); + saver = int_saver(instr, saver); + saver = int_saver(EE_addr, saver); + saver = int_saver(instr_case, saver); + saver = int_saver(instr_clocks, saver); + saver = int_saver(EE_value, saver); + saver = int_saver(countdown, saver); + return saver; } uint8_t* LoadState(uint8_t* loader) { + loader = bool_loader(&RAM_enable, loader); + loader = bool_loader(&sel_mode, loader); + loader = bool_loader(&IR_signal, loader); + loader = int_loader(&ROM_bank, loader); + loader = int_loader(&RAM_bank, loader); + loader = int_loader(&ROM_mask, loader); + loader = int_loader(&RAM_mask, loader); + + loader = bool_loader(&halt, loader); + loader = int_loader(&RTC_timer, loader); + loader = int_loader(&RTC_low_clock, loader); + + loader = bool_loader(&timer_read, loader); + loader = byte_loader(&control, loader); + loader = byte_loader(&chip_read, loader); + loader = int_loader(&time_val_shift, loader); + loader = int_loader(&time, loader); + loader = int_loader(&RTC_seconds, loader); + + for (int i = 0; i < 5; i++) { loader = byte_loader(&RTC_regs[i], loader); } + for (int i = 0; i < 5; i++) { loader = byte_loader(&RTC_regs_latch[i], loader); } + loader = bool_loader(&RTC_regs_latch_wr, loader); + loader = int_loader(&RTC_offset, loader); + + loader = bool_loader(®s_enable, loader); + for (int i = 0; i < 5; i++) { loader = byte_loader(®s_cam[i], loader); } + + loader = bool_loader(&locked, loader); + loader = bool_loader(&locked_GBC, loader); + loader = bool_loader(&finished, loader); + loader = bool_loader(®_access, loader); + loader = int_loader(&ROM_bank_mask, loader); + loader = int_loader(&BASE_ROM_Bank, loader); + loader = int_loader(&addr_last, loader); + loader = int_loader(&counter, loader); + + for (int i = 0; i < 10; i++) { loader = byte_loader(&RTC_regs_TAMA[i], loader); } + loader = byte_loader(&Chip_return_low, loader); + loader = byte_loader(&Chip_return_high, loader); + loader = int_loader(&ctrl, loader); + loader = int_loader(&RAM_addr_low, loader); + loader = int_loader(&RAM_addr_high, loader); + loader = int_loader(&RAM_val_low, loader); + loader = int_loader(&RAM_val_high, loader); + + loader = bool_loader(&RAM_enable_1, loader); + loader = bool_loader(&RAM_enable_2, loader); + loader = bool_loader(&is_erased, loader); + loader = byte_loader(&acc_x_low, loader); + loader = byte_loader(&acc_x_high, loader); + loader = byte_loader(&acc_y_low, loader); + loader = byte_loader(&acc_y_high, loader); + // EEPROM related + loader = bool_loader(&CS_prev, loader); + loader = bool_loader(&CLK_prev, loader); + loader = bool_loader(&DI_prev, loader); + loader = bool_loader(&DO, loader); + loader = bool_loader(&instr_read, loader); + loader = bool_loader(&perf_instr, loader); + loader = bool_loader(&WR_EN, loader); + loader = bool_loader(&countdown_start, loader); + loader = int_loader(&instr_bit_counter, loader); + loader = int_loader(&instr, loader); + loader = int_loader(&EE_addr, loader); + loader = int_loader(&instr_case, loader); + loader = int_loader(&instr_clocks, loader); + loader = int_loader(&EE_value, loader); + loader = int_loader(&countdown, loader); return loader; } diff --git a/libHawk/GBHawk/GBHawk/Mapper_Camera.h b/libHawk/GBHawk/GBHawk/Mapper_Camera.h index 34b3acd0e2..683af45d2b 100644 --- a/libHawk/GBHawk/GBHawk/Mapper_Camera.h +++ b/libHawk/GBHawk/GBHawk/Mapper_Camera.h @@ -14,10 +14,6 @@ namespace GBHawk { public: - - bool regs_enable; - uint8_t regs[0x80] = {}; - void Reset() { ROM_bank = 1; @@ -132,7 +128,7 @@ namespace GBHawk { if (regs_enable) { - regs[(addr & 0x7F)] = (uint8_t)(value & 0x7); + regs_cam[(addr & 0x7F)] = (uint8_t)(value & 0x7); } else { diff --git a/libHawk/GBHawk/GBHawk/Mapper_MBC7.h b/libHawk/GBHawk/GBHawk/Mapper_MBC7.h index 532259dc40..972e41fdd6 100644 --- a/libHawk/GBHawk/GBHawk/Mapper_MBC7.h +++ b/libHawk/GBHawk/GBHawk/Mapper_MBC7.h @@ -14,31 +14,6 @@ namespace GBHawk { public: - bool RAM_enable_1, RAM_enable_2; - uint8_t acc_x_low; - uint8_t acc_x_high; - uint8_t acc_y_low; - uint8_t acc_y_high; - bool is_erased; - - // EEPROM related - bool CS_prev; - bool CLK_prev; - bool DI_prev; - bool DO; - bool instr_read; - bool perf_instr; - uint32_t instr_bit_counter; - uint32_t instr; - bool WR_EN; - uint32_t EE_addr; - uint32_t instr_case; - uint32_t instr_clocks; - uint32_t EE_value; - uint32_t countdown; - bool countdown_start; - - void Reset() { ROM_bank = 1; @@ -236,10 +211,10 @@ namespace GBHawk { // latch new accelerometer values //Console.WriteLine("Latching ACC"); - acc_x_low = (uint8_t)(Core.Acc_X_state & 0xFF); - acc_x_high = (uint8_t)((Core.Acc_X_state & 0xFF00) >> 8); - acc_y_low = (uint8_t)(Core.Acc_Y_state & 0xFF); - acc_y_high = (uint8_t)((Core.Acc_Y_state & 0xFF00) >> 8); + acc_x_low = (uint8_t)(Acc_X_state[0] & 0xFF); + acc_x_high = (uint8_t)((Acc_X_state[0] & 0xFF00) >> 8); + acc_y_low = (uint8_t)(Acc_Y_state[0] & 0xFF); + acc_y_high = (uint8_t)((Acc_Y_state[0] & 0xFF00) >> 8); } } else if ((addr & 0xA0F0) == 0xA080) @@ -251,9 +226,9 @@ namespace GBHawk void EEPROM_write(uint8_t value) { - bool CS = value.Bit(7); - bool CLK = value.Bit(6); - bool DI = value.Bit(1); + bool CS = (value & 0x80) > 0; + bool CLK = (value & 0x40) > 0; + bool DI = (value & 0x2) > 0; // if we deselect the chip, complete instructions or countdown and stop if (!CS) diff --git a/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC1.h b/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC1.h index 93568262e9..1e08fe778d 100644 --- a/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC1.h +++ b/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC1.h @@ -14,13 +14,6 @@ namespace GBHawk { public: - bool locked; - uint32_t ROM_bank_mask; - uint32_t BASE_ROM_Bank; - bool reg_access; - uint32_t addr_last; - uint32_t counter; - void Reset() { ROM_bank = 1; @@ -154,21 +147,19 @@ namespace GBHawk { if (locked) { - if (((Core.addr_access & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (Core.addr_access >= 0x100)) + if (((addr_access[0] & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (addr_access[0] >= 0x100)) { counter++; - Console.WriteLine(Core.cpu.TotalExecutedCycles); } - if (Core.addr_access >= 0x100) + if (addr_access[0] >= 0x100) { - addr_last = Core.addr_access; + addr_last = addr_access[0]; } if (counter == 0x30) { locked = false; - Console.WriteLine("Unlocked"); } } } diff --git a/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC2.h b/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC2.h index 20563cda43..9d688a86d3 100644 --- a/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC2.h +++ b/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC2.h @@ -14,13 +14,6 @@ namespace GBHawk { public: - bool locked, locked_GBC, finished; - uint32_t ROM_bank_mask; - uint32_t BASE_ROM_Bank; - bool reg_access; - uint32_t addr_last; - uint32_t counter; - void Reset() { ROM_bank = 1; @@ -158,14 +151,14 @@ namespace GBHawk { if (locked) { - if (((Core.addr_access & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (Core.addr_access >= 0x100)) + if (((addr_access[0] & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (addr_access[0] >= 0x100)) { counter++; } - if (Core.addr_access >= 0x100) + if (addr_access[0] >= 0x100) { - addr_last = Core.addr_access; + addr_last = addr_access[0]; } if (counter == 0x30) @@ -177,14 +170,14 @@ namespace GBHawk } else if (locked_GBC) { - if (((Core.addr_access & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (Core.addr_access >= 0x100)) + if (((addr_access[0] & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (addr_access[0] >= 0x100)) { counter++; } - if (Core.addr_access >= 0x100) + if (addr_access[0] >= 0x100) { - addr_last = Core.addr_access; + addr_last = addr_access[0]; } if (counter == 0x30) @@ -196,7 +189,7 @@ namespace GBHawk // The above condition seems to never be reached as described in the mapper notes // so for now add this one - if ((Core.addr_access == 0x133) && (counter == 1)) + if ((addr_access[0] == 0x133) && (counter == 1)) { locked_GBC = false; finished = true; diff --git a/libHawk/GBHawk/GBHawk/Memory.cpp b/libHawk/GBHawk/GBHawk/Memory.cpp index 3bf7fd7c92..a5fa665fb3 100644 --- a/libHawk/GBHawk/GBHawk/Memory.cpp +++ b/libHawk/GBHawk/GBHawk/Memory.cpp @@ -7,6 +7,9 @@ #include "LR35902.h" #include "PPU_Base.h" #include "GBAudio.h" +#include "Mapper_Base.h" +#include "SerialPort.h" +#include "Timer.h" using namespace std; @@ -59,7 +62,7 @@ namespace GBHawk } else { - return mapper.ReadMemory(addr); + return mapper_pntr->ReadMemory(addr); } } else if ((addr >= 0xE000) && (addr < 0xF000)) @@ -70,7 +73,7 @@ namespace GBHawk { return RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)]; } - else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu.DMA_OAM_access) + else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu_pntr->DMA_OAM_access) { return OAM[addr - 0xFE00]; } @@ -97,7 +100,7 @@ namespace GBHawk } else { - return mapper.ReadMemory(addr); + return mapper_pntr->ReadMemory(addr); } } else if (addr >= 0x200) @@ -109,17 +112,17 @@ namespace GBHawk } else { - return mapper.ReadMemory(addr); + return mapper_pntr->ReadMemory(addr); } } else { - return mapper.ReadMemory(addr); + return mapper_pntr->ReadMemory(addr); } } else if (addr < 0x8000) { - return mapper.ReadMemory(addr); + return mapper_pntr->ReadMemory(addr); } else if (addr < 0xA000) { @@ -128,7 +131,7 @@ namespace GBHawk } else if (addr < 0xC000) { - return mapper.ReadMemory(addr); + return mapper_pntr->ReadMemory(addr); } else if (addr < 0xD000) { @@ -188,7 +191,7 @@ namespace GBHawk { RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)] = value; } - else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu.DMA_OAM_access) + else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu_pntr->DMA_OAM_access) { OAM[addr - 0xFE00] = value; } @@ -213,7 +216,7 @@ namespace GBHawk } else { - mapper.WriteMemory(addr, value); + mapper_pntr->WriteMemory(addr, value); } } else if (addr >= 0x200) @@ -224,17 +227,17 @@ namespace GBHawk } else { - mapper.WriteMemory(addr, value); + mapper_pntr->WriteMemory(addr, value); } } else { - mapper.WriteMemory(addr, value); + mapper_pntr->WriteMemory(addr, value); } } else if (addr < 0x8000) { - mapper.WriteMemory(addr, value); + mapper_pntr->WriteMemory(addr, value); } else if (addr < 0xA000) { @@ -242,7 +245,7 @@ namespace GBHawk } else if (addr < 0xC000) { - mapper.WriteMemory(addr, value); + mapper_pntr->WriteMemory(addr, value); } else if (addr < 0xD000) { @@ -295,7 +298,7 @@ namespace GBHawk } else { - return mapper.ReadMemory(addr); + return mapper_pntr->ReadMemory(addr); } } else if ((addr >= 0xE000) && (addr < 0xF000)) @@ -306,7 +309,7 @@ namespace GBHawk { return RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)]; } - else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu.DMA_OAM_access) + else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu_pntr->DMA_OAM_access) { return OAM[addr - 0xFE00]; } @@ -333,7 +336,7 @@ namespace GBHawk } else { - return mapper.ReadMemory(addr); + return mapper_pntr->ReadMemory(addr); } } else if (addr >= 0x200) @@ -345,17 +348,17 @@ namespace GBHawk } else { - return mapper.ReadMemory(addr); + return mapper_pntr->ReadMemory(addr); } } else { - return mapper.ReadMemory(addr); + return mapper_pntr->ReadMemory(addr); } } else if (addr < 0x8000) { - return mapper.PeekMemory(addr); + return mapper_pntr->PeekMemory(addr); } else if (addr < 0xA000) { @@ -364,7 +367,7 @@ namespace GBHawk } else if (addr < 0xC000) { - return mapper.PeekMemory(addr); + return mapper_pntr->PeekMemory(addr); } else if (addr < 0xD000) { @@ -405,4 +408,507 @@ namespace GBHawk return Read_Registers(addr); } } + + uint8_t MemoryManager::Read_Registers(uint32_t addr) + { + uint8_t ret = 0; + + switch (addr) + { + // Read Input + case 0xFF00: + _islag = false; + ret = input_register; + break; + + // Serial data port + case 0xFF01: + ret = serialport_pntr->ReadReg(addr); + break; + + // Serial port control + case 0xFF02: + ret = serialport_pntr->ReadReg(addr); + break; + + // Timer Registers + case 0xFF04: + case 0xFF05: + case 0xFF06: + case 0xFF07: + ret = timer_pntr->ReadReg(addr); + break; + + // Interrupt flags + case 0xFF0F: + ret = REG_FF0F_OLD; + break; + + // audio regs + case 0xFF10: + case 0xFF11: + case 0xFF12: + case 0xFF13: + case 0xFF14: + case 0xFF16: + case 0xFF17: + case 0xFF18: + case 0xFF19: + case 0xFF1A: + case 0xFF1B: + case 0xFF1C: + case 0xFF1D: + case 0xFF1E: + case 0xFF20: + case 0xFF21: + case 0xFF22: + case 0xFF23: + case 0xFF24: + case 0xFF25: + case 0xFF26: + case 0xFF30: + case 0xFF31: + case 0xFF32: + case 0xFF33: + case 0xFF34: + case 0xFF35: + case 0xFF36: + case 0xFF37: + case 0xFF38: + case 0xFF39: + case 0xFF3A: + case 0xFF3B: + case 0xFF3C: + case 0xFF3D: + case 0xFF3E: + case 0xFF3F: + ret = psg_pntr->ReadReg(addr); + break; + + // PPU Regs + case 0xFF40: + case 0xFF41: + case 0xFF42: + case 0xFF43: + case 0xFF44: + case 0xFF45: + case 0xFF46: + case 0xFF47: + case 0xFF48: + case 0xFF49: + case 0xFF4A: + case 0xFF4B: + ret = ppu_pntr->ReadReg(addr); + break; + + // Speed Control for GBC + case 0xFF4D: + if (GBC_compat) + { + ret = (uint8_t)(((double_speed ? 1 : 0) << 7) + ((speed_switch ? 1 : 0))); + } + else + { + ret = 0xFF; + } + break; + + case 0xFF4F: // VBK + if (GBC_compat) + { + ret = (uint8_t)(0xFE | VRAM_Bank); + } + else + { + ret = 0xFF; + } + break; + + // Bios control register. Not sure if it is readable + case 0xFF50: + ret = 0xFF; + break; + + // PPU Regs for GBC + case 0xFF51: + case 0xFF52: + case 0xFF53: + case 0xFF54: + case 0xFF55: + if (GBC_compat) + { + ret = ppu_pntr->ReadReg(addr); + } + else + { + ret = 0xFF; + } + break; + + case 0xFF56: + if (GBC_compat) + { + // can receive data + if ((IR_reg & 0xC0) == 0xC0) + { + ret = IR_reg; + } + else + { + ret = (uint8_t)(IR_reg | 2); + } + } + else + { + ret = 0xFF; + } + break; + + case 0xFF68: + case 0xFF69: + case 0xFF6A: + case 0xFF6B: + if (GBC_compat) + { + ret = ppu_pntr->ReadReg(addr); + } + else + { + ret = 0xFF; + } + break; + + // Speed Control for GBC + case 0xFF70: + if (GBC_compat) + { + ret = (uint8_t)RAM_Bank; + } + else + { + ret = 0xFF; + } + break; + + case 0xFF6C: + if (GBC_compat) { ret = undoc_6C; } + else { ret = 0xFF; } + break; + + case 0xFF72: + if (is_GBC) { ret = undoc_72; } + else { ret = 0xFF; } + break; + + case 0xFF73: + if (is_GBC) { ret = undoc_73; } + else { ret = 0xFF; } + break; + + case 0xFF74: + if (GBC_compat) { ret = undoc_74; } + else { ret = 0xFF; } + break; + + case 0xFF75: + if (is_GBC) { ret = undoc_75; } + else { ret = 0xFF; } + break; + + case 0xFF76: + if (is_GBC) { ret = undoc_76; } + else { ret = 0xFF; } + break; + + case 0xFF77: + if (is_GBC) { ret = undoc_77; } + else { ret = 0xFF; } + break; + + // interrupt control register + case 0xFFFF: + ret = REG_FFFF; + break; + + default: + ret = 0xFF; + break; + + } + return ret; + } + + void MemoryManager::Write_Registers(uint32_t addr, uint8_t value) + { + // check for high to low transitions that trigger IRQs + uint8_t contr_prev = input_register; + + switch (addr) + { + // select input + case 0xFF00: + input_register &= 0xCF; + input_register |= (uint8_t)(value & 0x30); // top 2 bits always 1 + + input_register &= 0xF0; + if ((input_register & 0x30) == 0x20) + { + input_register |= (uint8_t)(controller_state & 0xF); + } + else if ((input_register & 0x30) == 0x10) + { + input_register |= (uint8_t)((controller_state & 0xF0) >> 4); + } + else if ((input_register & 0x30) == 0x00) + { + // if both polls are set, then a bit is zero if either or both pins are zero + uint8_t temp = (uint8_t)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4)); + input_register |= temp; + } + else + { + input_register |= 0xF; + } + + // check for interrupts + if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) || + ((contr_prev & 4) > 0) && ((input_register & 4) == 0) || + ((contr_prev & 2) > 0) && ((input_register & 2) == 0) || + ((contr_prev & 1) > 0) && ((input_register & 1) == 0)) + { + if (((REG_FFFF & 0x10) > 0)) { cpu_pntr->FlagI = true; } + REG_FF0F |= 0x10; + } + + break; + + // Serial data port + case 0xFF01: + serialport_pntr->WriteReg(addr, value); + break; + + // Serial port control + case 0xFF02: + serialport_pntr->WriteReg(addr, value); + break; + + // Timer Registers + case 0xFF04: + case 0xFF05: + case 0xFF06: + case 0xFF07: + timer_pntr->WriteReg(addr, value); + break; + + // Interrupt flags + case 0xFF0F: + REG_FF0F = (uint8_t)(0xE0 | value); + + // check if enabling any of the bits triggered an IRQ + for (int i = 0; i < 5; i++) + { + if (((REG_FFFF & (1 << i)) > 0) && ((REG_FF0F & (1 << i)) > 0)) + { + cpu_pntr->FlagI = true; + } + } + + // if no bits are in common between flags and enables, de-assert the IRQ + if (((REG_FF0F & 0x1F) & REG_FFFF) == 0) { cpu_pntr->FlagI = false; } + break; + + // audio regs + case 0xFF10: + case 0xFF11: + case 0xFF12: + case 0xFF13: + case 0xFF14: + case 0xFF16: + case 0xFF17: + case 0xFF18: + case 0xFF19: + case 0xFF1A: + case 0xFF1B: + case 0xFF1C: + case 0xFF1D: + case 0xFF1E: + case 0xFF20: + case 0xFF21: + case 0xFF22: + case 0xFF23: + case 0xFF24: + case 0xFF25: + case 0xFF26: + case 0xFF30: + case 0xFF31: + case 0xFF32: + case 0xFF33: + case 0xFF34: + case 0xFF35: + case 0xFF36: + case 0xFF37: + case 0xFF38: + case 0xFF39: + case 0xFF3A: + case 0xFF3B: + case 0xFF3C: + case 0xFF3D: + case 0xFF3E: + case 0xFF3F: + psg_pntr->WriteReg(addr, value); + break; + + // PPU Regs + case 0xFF40: + case 0xFF41: + case 0xFF42: + case 0xFF43: + case 0xFF44: + case 0xFF45: + case 0xFF46: + case 0xFF47: + case 0xFF48: + case 0xFF49: + case 0xFF4A: + case 0xFF4B: + ppu_pntr->WriteReg(addr, value); + break; + + // GBC compatibility register (I think) + case 0xFF4C: + if ((value != 0xC0) && (value != 0x80))// && (value != 0xFF) && (value != 0x04)) + { + GBC_compat = false; + + // cpu operation is a function of hardware only + //cpu.is_GBC = GBC_compat; + } + break; + + // Speed Control for GBC + case 0xFF4D: + if (GBC_compat) + { + speed_switch = (value & 1) > 0; + } + break; + + // VBK + case 0xFF4F: + if (GBC_compat && !ppu_pntr->HDMA_active) + { + VRAM_Bank = (uint8_t)(value & 1); + } + break; + + // Bios control register. Writing 1 permanently disables BIOS until a power cycle occurs + case 0xFF50: + // Console.WriteLine(value); + if (GB_bios_register == 0) + { + GB_bios_register = value; + } + break; + + // PPU Regs for GBC + case 0xFF51: + case 0xFF52: + case 0xFF53: + case 0xFF54: + case 0xFF55: + if (GBC_compat) + { + ppu_pntr->WriteReg(addr, value); + } + break; + + case 0xFF56: + if (is_GBC) + { + IR_reg = (uint8_t)((value & 0xC1) | (IR_reg & 0x3E)); + + // send IR signal out + if ((IR_reg & 0x1) == 0x1) { IR_signal = (uint8_t)(0 | IR_mask); } + else { IR_signal = 2; } + + // receive own signal if IR on and receive on + if ((IR_reg & 0xC1) == 0xC1) { IR_self = (uint8_t)(0 | IR_mask); } + else { IR_self = 2; } + + IR_write = 8; + } + break; + + case 0xFF68: + case 0xFF69: + case 0xFF6A: + case 0xFF6B: + //if (GBC_compat) + //{ + ppu_pntr->WriteReg(addr, value); + //} + break; + + // RAM Bank in GBC mode + case 0xFF70: + //Console.WriteLine(value); + if (GBC_compat) + { + RAM_Bank = value & 7; + if (RAM_Bank == 0) { RAM_Bank = 1; } + } + break; + + case 0xFF6C: + if (GBC_compat) { undoc_6C |= (uint8_t)(value & 1); } + break; + + case 0xFF72: + if (is_GBC) { undoc_72 = value; } + break; + + case 0xFF73: + if (is_GBC) { undoc_73 = value; } + break; + + case 0xFF74: + if (GBC_compat) { undoc_74 = value; } + break; + + case 0xFF75: + if (is_GBC) { undoc_75 |= (uint8_t)(value & 0x70); } + break; + + case 0xFF76: + // read only + break; + + case 0xFF77: + // read only + break; + + // interrupt control register + case 0xFFFF: + REG_FFFF = value; + + // check if enabling any of the bits triggered an IRQ + for (int i = 0; i < 5; i++) + { + if (((REG_FFFF & (1 << i)) > 0) && ((REG_FF0F & (1 << i)) > 0)) + { + cpu_pntr->FlagI = true; + } + } + + // if no bits are in common between flags and enables, de-assert the IRQ + if (((REG_FF0F & 0x1F) & REG_FFFF) == 0) { cpu_pntr->FlagI = false; } + break; + + default: + //Console.Write(addr); + //Console.Write(" "); + //Console.WriteLine(value); + break; + } + } } \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/Memory.h b/libHawk/GBHawk/GBHawk/Memory.h index 532b623fbb..69d3b9840d 100644 --- a/libHawk/GBHawk/GBHawk/Memory.h +++ b/libHawk/GBHawk/GBHawk/Memory.h @@ -26,6 +26,8 @@ namespace GBHawk uint8_t ReadMemory(uint32_t addr); uint8_t PeekMemory(uint32_t addr); void WriteMemory(uint32_t addr, uint8_t value); + uint8_t Read_Registers(uint32_t addr); + void Write_Registers(uint32_t addr, uint8_t value); #pragma region Declarations @@ -35,15 +37,14 @@ namespace GBHawk Timer* timer_pntr = nullptr; SerialPort* serialport_pntr = nullptr; Mapper* mapper_pntr = nullptr; - uint8_t* rom_1 = nullptr; - uint8_t* rom_2 = nullptr; + uint8_t* ROM = nullptr; + uint8_t* Cart_RAM = nullptr; uint8_t* bios_rom = nullptr; // initialized by core loading, not savestated - uint32_t rom_size_1; - uint32_t rom_mapper_1; - uint32_t rom_size_2; - uint32_t rom_mapper_2; + uint32_t ROM_Length; + uint32_t ROM_Mapper; + uint32_t Cart_RAM_Length; // controls are not stated uint8_t controller_byte_1, controller_byte_2; @@ -60,7 +61,7 @@ namespace GBHawk bool GB_bios_register; bool HDMA_transfer; bool _islag; - uint8_t addr_access; + uint8_t REG_FFFF, REG_FF0F, REG_FF0F_OLD; uint8_t _scanlineCallbackLine; uint8_t input_register; @@ -69,6 +70,9 @@ namespace GBHawk uint8_t IR_reg, IR_mask, IR_signal, IR_receive, IR_self; uint32_t IR_write; + uint32_t addr_access; + uint32_t Acc_X_state; + uint32_t Acc_Y_state; // several undocumented GBC Registers uint8_t undoc_6C, undoc_72, undoc_73, undoc_74, undoc_75, undoc_76, undoc_77; @@ -106,17 +110,12 @@ namespace GBHawk void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1, uint32_t ext_rom_mapper_1, uint8_t* ext_rom_2, uint32_t ext_rom_size_2, uint32_t ext_rom_mapper_2) { - rom_1 = new uint8_t[ext_rom_size_1]; - rom_2 = new uint8_t[ext_rom_size_2]; + ROM = new uint8_t[ext_rom_size_1]; - memcpy(rom_1, ext_rom_1, ext_rom_size_1); - memcpy(rom_2, ext_rom_2, ext_rom_size_2); + memcpy(ROM, ext_rom_1, ext_rom_size_1); - rom_size_1 = ext_rom_size_1 / 0x4000; - rom_mapper_1 = ext_rom_mapper_1; - - rom_size_2 = ext_rom_size_2 / 0x4000; - rom_mapper_2 = ext_rom_mapper_2; + ROM_Length = ext_rom_size_1; + ROM_Mapper = ext_rom_mapper_1; } // Switch Speed (GBC only) @@ -140,509 +139,6 @@ namespace GBHawk return 0; } - uint8_t Read_Registers(uint32_t addr) - { - uint8_t ret = 0; - - switch (addr) - { - // Read Input - case 0xFF00: - _islag = false; - ret = input_register; - break; - - // Serial data port - case 0xFF01: - ret = serialport_pntr->ReadReg(addr); - break; - - // Serial port control - case 0xFF02: - ret = serialport_pntr->ReadReg(addr); - break; - - // Timer Registers - case 0xFF04: - case 0xFF05: - case 0xFF06: - case 0xFF07: - ret = timer_pntr->ReadReg(addr); - break; - - // Interrupt flags - case 0xFF0F: - ret = REG_FF0F_OLD; - break; - - // audio regs - case 0xFF10: - case 0xFF11: - case 0xFF12: - case 0xFF13: - case 0xFF14: - case 0xFF16: - case 0xFF17: - case 0xFF18: - case 0xFF19: - case 0xFF1A: - case 0xFF1B: - case 0xFF1C: - case 0xFF1D: - case 0xFF1E: - case 0xFF20: - case 0xFF21: - case 0xFF22: - case 0xFF23: - case 0xFF24: - case 0xFF25: - case 0xFF26: - case 0xFF30: - case 0xFF31: - case 0xFF32: - case 0xFF33: - case 0xFF34: - case 0xFF35: - case 0xFF36: - case 0xFF37: - case 0xFF38: - case 0xFF39: - case 0xFF3A: - case 0xFF3B: - case 0xFF3C: - case 0xFF3D: - case 0xFF3E: - case 0xFF3F: - ret = psg_pntr->ReadReg(addr); - break; - - // PPU Regs - case 0xFF40: - case 0xFF41: - case 0xFF42: - case 0xFF43: - case 0xFF44: - case 0xFF45: - case 0xFF46: - case 0xFF47: - case 0xFF48: - case 0xFF49: - case 0xFF4A: - case 0xFF4B: - ret = ppu_pntr->ReadReg(addr); - break; - - // Speed Control for GBC - case 0xFF4D: - if (GBC_compat) - { - ret = (uint8_t)(((double_speed ? 1 : 0) << 7) + ((speed_switch ? 1 : 0))); - } - else - { - ret = 0xFF; - } - break; - - case 0xFF4F: // VBK - if (GBC_compat) - { - ret = (uint8_t)(0xFE | VRAM_Bank); - } - else - { - ret = 0xFF; - } - break; - - // Bios control register. Not sure if it is readable - case 0xFF50: - ret = 0xFF; - break; - - // PPU Regs for GBC - case 0xFF51: - case 0xFF52: - case 0xFF53: - case 0xFF54: - case 0xFF55: - if (GBC_compat) - { - ret = ppu_pntr->ReadReg(addr); - } - else - { - ret = 0xFF; - } - break; - - case 0xFF56: - if (GBC_compat) - { - // can receive data - if ((IR_reg & 0xC0) == 0xC0) - { - ret = IR_reg; - } - else - { - ret = (uint8_t)(IR_reg | 2); - } - } - else - { - ret = 0xFF; - } - break; - - case 0xFF68: - case 0xFF69: - case 0xFF6A: - case 0xFF6B: - if (GBC_compat) - { - ret = ppu_pntr->ReadReg(addr); - } - else - { - ret = 0xFF; - } - break; - - // Speed Control for GBC - case 0xFF70: - if (GBC_compat) - { - ret = (uint8_t)RAM_Bank; - } - else - { - ret = 0xFF; - } - break; - - case 0xFF6C: - if (GBC_compat) { ret = undoc_6C; } - else { ret = 0xFF; } - break; - - case 0xFF72: - if (is_GBC) { ret = undoc_72; } - else { ret = 0xFF; } - break; - - case 0xFF73: - if (is_GBC) { ret = undoc_73; } - else { ret = 0xFF; } - break; - - case 0xFF74: - if (GBC_compat) { ret = undoc_74; } - else { ret = 0xFF; } - break; - - case 0xFF75: - if (is_GBC) { ret = undoc_75; } - else { ret = 0xFF; } - break; - - case 0xFF76: - if (is_GBC) { ret = undoc_76; } - else { ret = 0xFF; } - break; - - case 0xFF77: - if (is_GBC) { ret = undoc_77; } - else { ret = 0xFF; } - break; - - // interrupt control register - case 0xFFFF: - ret = REG_FFFF; - break; - - default: - ret = 0xFF; - break; - - } - return ret; - } - - void Write_Registers(int addr, uint8_t value) - { - switch (addr) - { - // select input - case 0xFF00: - input_register &= 0xCF; - input_register |= (uint8_t)(value & 0x30); // top 2 bits always 1 - - // check for high to low transitions that trigger IRQs - uint8_t contr_prev = input_register; - - input_register &= 0xF0; - if ((input_register & 0x30) == 0x20) - { - input_register |= (uint8_t)(controller_state & 0xF); - } - else if ((input_register & 0x30) == 0x10) - { - input_register |= (uint8_t)((controller_state & 0xF0) >> 4); - } - else if ((input_register & 0x30) == 0x00) - { - // if both polls are set, then a bit is zero if either or both pins are zero - uint8_t temp = (uint8_t)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4)); - input_register |= temp; - } - else - { - input_register |= 0xF; - } - - // check for interrupts - if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) || - ((contr_prev & 4) > 0) && ((input_register & 4) == 0) || - ((contr_prev & 2) > 0) && ((input_register & 2) == 0) || - ((contr_prev & 1) > 0) && ((input_register & 1) == 0)) - { - if (((REG_FFFF & 0x10) > 0)) { cpu_pntr->FlagI = true; } - REG_FF0F |= 0x10; - } - - break; - - // Serial data port - case 0xFF01: - serialport_pntr->WriteReg(addr, value); - break; - - // Serial port control - case 0xFF02: - serialport_pntr->WriteReg(addr, value); - break; - - // Timer Registers - case 0xFF04: - case 0xFF05: - case 0xFF06: - case 0xFF07: - timer_pntr->WriteReg(addr, value); - break; - - // Interrupt flags - case 0xFF0F: - REG_FF0F = (uint8_t)(0xE0 | value); - - // check if enabling any of the bits triggered an IRQ - for (int i = 0; i < 5; i++) - { - if (((REG_FFFF & (1 < 0) && ((REG_FF0F & (1 << i)) > 0)) - { - cpu_pntr->FlagI = true; - } - } - - // if no bits are in common between flags and enables, de-assert the IRQ - if (((REG_FF0F & 0x1F) & REG_FFFF) == 0) { cpu_pntr->FlagI = false; } - break; - - // audio regs - case 0xFF10: - case 0xFF11: - case 0xFF12: - case 0xFF13: - case 0xFF14: - case 0xFF16: - case 0xFF17: - case 0xFF18: - case 0xFF19: - case 0xFF1A: - case 0xFF1B: - case 0xFF1C: - case 0xFF1D: - case 0xFF1E: - case 0xFF20: - case 0xFF21: - case 0xFF22: - case 0xFF23: - case 0xFF24: - case 0xFF25: - case 0xFF26: - case 0xFF30: - case 0xFF31: - case 0xFF32: - case 0xFF33: - case 0xFF34: - case 0xFF35: - case 0xFF36: - case 0xFF37: - case 0xFF38: - case 0xFF39: - case 0xFF3A: - case 0xFF3B: - case 0xFF3C: - case 0xFF3D: - case 0xFF3E: - case 0xFF3F: - psg_pntr->WriteReg(addr, value); - break; - - // PPU Regs - case 0xFF40: - case 0xFF41: - case 0xFF42: - case 0xFF43: - case 0xFF44: - case 0xFF45: - case 0xFF46: - case 0xFF47: - case 0xFF48: - case 0xFF49: - case 0xFF4A: - case 0xFF4B: - ppu_pntr->WriteReg(addr, value); - break; - - // GBC compatibility register (I think) - case 0xFF4C: - if ((value != 0xC0) && (value != 0x80))// && (value != 0xFF) && (value != 0x04)) - { - GBC_compat = false; - - // cpu operation is a function of hardware only - //cpu.is_GBC = GBC_compat; - } - break; - - // Speed Control for GBC - case 0xFF4D: - if (GBC_compat) - { - speed_switch = (value & 1) > 0; - } - break; - - // VBK - case 0xFF4F: - if (GBC_compat && !ppu_pntr->HDMA_active) - { - VRAM_Bank = (uint8_t)(value & 1); - } - break; - - // Bios control register. Writing 1 permanently disables BIOS until a power cycle occurs - case 0xFF50: - // Console.WriteLine(value); - if (GB_bios_register == 0) - { - GB_bios_register = value; - } - break; - - // PPU Regs for GBC - case 0xFF51: - case 0xFF52: - case 0xFF53: - case 0xFF54: - case 0xFF55: - if (GBC_compat) - { - ppu_pntr->WriteReg(addr, value); - } - break; - - case 0xFF56: - if (is_GBC) - { - IR_reg = (uint8_t)((value & 0xC1) | (IR_reg & 0x3E)); - - // send IR signal out - if ((IR_reg & 0x1) == 0x1) { IR_signal = (uint8_t)(0 | IR_mask); } - else { IR_signal = 2; } - - // receive own signal if IR on and receive on - if ((IR_reg & 0xC1) == 0xC1) { IR_self = (uint8_t)(0 | IR_mask); } - else { IR_self = 2; } - - IR_write = 8; - } - break; - - case 0xFF68: - case 0xFF69: - case 0xFF6A: - case 0xFF6B: - //if (GBC_compat) - //{ - ppu_pntr->WriteReg(addr, value); - //} - break; - - // RAM Bank in GBC mode - case 0xFF70: - //Console.WriteLine(value); - if (GBC_compat) - { - RAM_Bank = value & 7; - if (RAM_Bank == 0) { RAM_Bank = 1; } - } - break; - - case 0xFF6C: - if (GBC_compat) { undoc_6C |= (uint8_t)(value & 1); } - break; - - case 0xFF72: - if (is_GBC) { undoc_72 = value; } - break; - - case 0xFF73: - if (is_GBC) { undoc_73 = value; } - break; - - case 0xFF74: - if (GBC_compat) { undoc_74 = value; } - break; - - case 0xFF75: - if (is_GBC) { undoc_75 |= (uint8_t)(value & 0x70); } - break; - - case 0xFF76: - // read only - break; - - case 0xFF77: - // read only - break; - - // interrupt control register - case 0xFFFF: - REG_FFFF = value; - - // check if enabling any of the bits triggered an IRQ - for (int i = 0; i < 5; i++) - { - if (((REG_FFFF & (1 << i)) > 0) && ((REG_FF0F & (1 << i)) > 0)) - { - cpu_pntr->FlagI = true; - } - } - - // if no bits are in common between flags and enables, de-assert the IRQ - if (((REG_FF0F & 0x1F) & REG_FFFF) == 0) { cpu_pntr->FlagI = false; } - break; - - default: - //Console.Write(addr); - //Console.Write(" "); - //Console.WriteLine(value); - break; - } - } - void Register_Reset() { input_register = 0xCF; // not reading any input