GBHawk: finsih mappers start integration

This commit is contained in:
alyosha-tas 2020-03-27 16:44:45 -04:00
parent 03b83a1043
commit b8233666ac
9 changed files with 710 additions and 606 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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(&regs_enable, loader);
for (int i = 0; i < 5; i++) { loader = byte_loader(&regs_cam[i], loader); }
loader = bool_loader(&locked, loader);
loader = bool_loader(&locked_GBC, loader);
loader = bool_loader(&finished, loader);
loader = bool_loader(&reg_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;
}

View File

@ -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
{

View File

@ -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)

View File

@ -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");
}
}
}

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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 <<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;
}
}
void Register_Reset()
{
input_register = 0xCF; // not reading any input