formatting/readability
This commit is contained in:
parent
98076d286d
commit
567756d6cc
|
@ -61,6 +61,6 @@ $(TARGET) : $(OBJS)
|
|||
clean:
|
||||
$(RM) $(OBJS)
|
||||
$(RM) $(TARGET)
|
||||
|
||||
|
||||
install:
|
||||
$(CP) $(TARGET) $(DEST_$(ARCH))
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
GBA_CGB = 2, /**< Use GBA intial CPU register values when in CGB mode. */
|
||||
MULTICART_COMPAT = 4, /**< Use heuristics to detect and support some multicart MBCs disguised as MBC1. */
|
||||
};
|
||||
|
||||
|
||||
/** Load ROM image.
|
||||
*
|
||||
* @param romfile Path to rom image file. Typically a .gbc, .gb, or .zip-file (if zip-support is compiled in).
|
||||
|
@ -63,7 +63,7 @@ public:
|
|||
* @return 0 on success, negative value on failure.
|
||||
*/
|
||||
LoadRes load(const char *romfiledata, unsigned romfilelength, std::uint32_t now, unsigned flags, unsigned div);
|
||||
|
||||
|
||||
int loadGBCBios(const char* biosfiledata);
|
||||
int loadDMGBios(const char* biosfiledata);
|
||||
|
||||
|
@ -96,17 +96,17 @@ public:
|
|||
* Equivalent to reloading a ROM image, or turning a Game Boy Color off and on again.
|
||||
*/
|
||||
void reset(std::uint32_t now, unsigned div);
|
||||
|
||||
|
||||
/** @param palNum 0 <= palNum < 3. One of BG_PALETTE, SP1_PALETTE and SP2_PALETTE.
|
||||
* @param colorNum 0 <= colorNum < 4
|
||||
*/
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32);
|
||||
|
||||
|
||||
void setCgbPalette(unsigned *lut);
|
||||
|
||||
/** Sets the callback used for getting input state. */
|
||||
void setInputGetter(unsigned (*getInput)());
|
||||
|
||||
|
||||
void setReadCallback(MemoryCallback);
|
||||
void setWriteCallback(MemoryCallback);
|
||||
void setExecCallback(MemoryCallback);
|
||||
|
@ -118,7 +118,7 @@ public:
|
|||
|
||||
/** Returns true if the currently loaded ROM image is treated as having CGB support. */
|
||||
bool isCgb() const;
|
||||
|
||||
|
||||
/** Returns true if a ROM image is loaded. */
|
||||
bool isLoaded() const;
|
||||
|
||||
|
@ -126,10 +126,10 @@ public:
|
|||
void loadSavedata(const char *data);
|
||||
int saveSavedataLength();
|
||||
void saveSavedata(char *dest);
|
||||
|
||||
|
||||
// 0 = vram, 1 = rom, 2 = wram, 3 = cartram, 4 = oam, 5 = hram
|
||||
bool getMemoryArea(int which, unsigned char **data, int *length);
|
||||
|
||||
|
||||
/** ROM header title of currently loaded ROM image. */
|
||||
const std::string romTitle() const;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ template<typename T>
|
|||
class Array : Uncopyable {
|
||||
T *a;
|
||||
std::size_t sz;
|
||||
|
||||
|
||||
public:
|
||||
explicit Array(const std::size_t size = 0) : a(size ? new T[size] : 0), sz(size) {}
|
||||
~Array() { delete []a; }
|
||||
|
@ -39,7 +39,7 @@ public:
|
|||
template<typename T>
|
||||
class ScopedArray : Uncopyable {
|
||||
T *a_;
|
||||
|
||||
|
||||
public:
|
||||
explicit ScopedArray(T *a = 0) : a_(a) {}
|
||||
~ScopedArray() { delete []a_; }
|
||||
|
|
|
@ -47,12 +47,12 @@ CPU::CPU()
|
|||
long CPU::runFor(const unsigned long cycles) {
|
||||
memory.setBasetime(cycleCounter_);
|
||||
process(cycles/* << memory.isDoubleSpeed()*/);
|
||||
|
||||
|
||||
const long csb = memory.cyclesSinceBlit(cycleCounter_);
|
||||
|
||||
|
||||
if (cycleCounter_ & 0x80000000)
|
||||
cycleCounter_ = memory.resetCounters(cycleCounter_);
|
||||
|
||||
|
||||
return csb;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ long CPU::runFor(const unsigned long cycles) {
|
|||
static void calcHF(const unsigned HF1, unsigned& HF2) {
|
||||
unsigned arg1 = HF1 & 0xF;
|
||||
unsigned arg2 = (HF2 & 0xF) + (HF2 >> 8 & 1);
|
||||
|
||||
|
||||
if (HF2 & 0x800) {
|
||||
arg1 = arg2;
|
||||
arg2 = 1;
|
||||
|
@ -73,7 +73,7 @@ static void calcHF(const unsigned HF1, unsigned& HF2) {
|
|||
arg1 -= arg2;
|
||||
else
|
||||
arg1 = (arg1 + arg2) << 5;
|
||||
|
||||
|
||||
HF2 |= arg1 & 0x200;
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ void CPU::setStatePtrs(SaveState &state) {
|
|||
|
||||
void CPU::loadState(const SaveState &state) {
|
||||
memory.loadState(state/*, cycleCounter_*/);
|
||||
|
||||
|
||||
cycleCounter_ = state.cpu.cycleCounter;
|
||||
PC = state.cpu.PC & 0xFFFF;
|
||||
SP = state.cpu.SP & 0xFFFF;
|
||||
|
@ -497,10 +497,10 @@ void CPU::process(const unsigned long cycles) {
|
|||
|
||||
//unsigned char A = A_;
|
||||
unsigned long cycleCounter = cycleCounter_;
|
||||
|
||||
|
||||
while (memory.isActive()) {
|
||||
//unsigned short PC = PC_;
|
||||
|
||||
|
||||
if (memory.halted()) {
|
||||
if (cycleCounter < memory.nextEventTime()) {
|
||||
const unsigned long cycles = memory.nextEventTime() - cycleCounter;
|
||||
|
@ -508,7 +508,7 @@ void CPU::process(const unsigned long cycles) {
|
|||
}
|
||||
} else while (cycleCounter < memory.nextEventTime()) {
|
||||
unsigned char opcode = 0x00;
|
||||
|
||||
|
||||
int FullPC = PC;
|
||||
|
||||
if (PC >= 0x4000 && PC <= 0x7FFF)
|
||||
|
@ -552,7 +552,7 @@ void CPU::process(const unsigned long cycles) {
|
|||
skip = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (opcode) {
|
||||
//nop (4 cycles):
|
||||
//Do nothing for 4 cycles:
|
||||
|
@ -591,12 +591,12 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x08:
|
||||
{
|
||||
unsigned l, h;
|
||||
|
||||
|
||||
PC_READ(l);
|
||||
PC_READ(h);
|
||||
|
||||
|
||||
const unsigned addr = h << 8 | l;
|
||||
|
||||
|
||||
WRITE(addr, SP & 0xFF);
|
||||
WRITE((addr + 1) & 0xFFFF, SP >> 8);
|
||||
}
|
||||
|
@ -669,7 +669,7 @@ void CPU::process(const unsigned long cycles) {
|
|||
CF = A << 1;
|
||||
A = (CF | oldcf) & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
HF2 = 0;
|
||||
ZF = 1;
|
||||
break;
|
||||
|
@ -704,7 +704,7 @@ void CPU::process(const unsigned long cycles) {
|
|||
CF = A << 8;
|
||||
A = (A | oldcf) >> 1;
|
||||
}
|
||||
|
||||
|
||||
HF2 = 0;
|
||||
ZF = 1;
|
||||
break;
|
||||
|
@ -728,9 +728,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x22:
|
||||
{
|
||||
unsigned addr = HL();
|
||||
|
||||
|
||||
WRITE(addr, A);
|
||||
|
||||
|
||||
addr = (addr + 1) & 0xFFFF;
|
||||
L = addr;
|
||||
H = addr >> 8;
|
||||
|
@ -756,38 +756,38 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x27:
|
||||
/*{
|
||||
unsigned correction = ((A > 0x99) || (CF & 0x100)) ? 0x60 : 0x00;
|
||||
|
||||
|
||||
calcHF(HF1, HF2);
|
||||
|
||||
|
||||
if ((A & 0x0F) > 0x09 || (HF2 & 0x200))
|
||||
correction |= 0x06;
|
||||
|
||||
|
||||
HF1 = A;
|
||||
HF2 = (HF2 & 0x400) | correction;
|
||||
CF = (correction & 0x40) << 2;
|
||||
A = (HF2 & 0x400) ? A - correction : (A + correction);
|
||||
ZF = A;
|
||||
}*/
|
||||
|
||||
|
||||
calcHF(HF1, HF2);
|
||||
|
||||
|
||||
{
|
||||
unsigned correction = (CF & 0x100) ? 0x60 : 0x00;
|
||||
|
||||
|
||||
if (HF2 & 0x200)
|
||||
correction |= 0x06;
|
||||
|
||||
|
||||
if (!(HF2 &= 0x400)) {
|
||||
if ((A & 0x0F) > 0x09)
|
||||
correction |= 0x06;
|
||||
|
||||
|
||||
if (A > 0x99)
|
||||
correction |= 0x60;
|
||||
|
||||
|
||||
A += correction;
|
||||
} else
|
||||
A -= correction;
|
||||
|
||||
|
||||
CF = correction << 2 & 0x100;
|
||||
ZF = A;
|
||||
A &= 0xFF;
|
||||
|
@ -815,9 +815,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x2A:
|
||||
{
|
||||
unsigned addr = HL();
|
||||
|
||||
|
||||
READ(A, addr);
|
||||
|
||||
|
||||
addr = (addr + 1) & 0xFFFF;
|
||||
L = addr;
|
||||
H = addr >> 8;
|
||||
|
@ -859,10 +859,10 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x31:
|
||||
{
|
||||
unsigned l, h;
|
||||
|
||||
|
||||
PC_READ(l);
|
||||
PC_READ(h);
|
||||
|
||||
|
||||
SP = h << 8 | l;
|
||||
}
|
||||
break;
|
||||
|
@ -872,9 +872,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x32:
|
||||
{
|
||||
unsigned addr = HL();
|
||||
|
||||
|
||||
WRITE(addr, A);
|
||||
|
||||
|
||||
addr = (addr - 1) & 0xFFFF;
|
||||
L = addr;
|
||||
H = addr >> 8;
|
||||
|
@ -888,10 +888,10 @@ void CPU::process(const unsigned long cycles) {
|
|||
|
||||
//inc (hl) (12 cycles):
|
||||
//Increment value at address in hl, check flags except CF:
|
||||
case 0x34:
|
||||
case 0x34:
|
||||
{
|
||||
const unsigned addr = HL();
|
||||
|
||||
|
||||
READ(HF2, addr);
|
||||
ZF = HF2 + 1;
|
||||
WRITE(addr, ZF & 0xFF);
|
||||
|
@ -904,7 +904,7 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x35:
|
||||
{
|
||||
const unsigned addr = HL();
|
||||
|
||||
|
||||
READ(HF2, addr);
|
||||
ZF = HF2 - 1;
|
||||
WRITE(addr, ZF & 0xFF);
|
||||
|
@ -917,7 +917,7 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x36:
|
||||
{
|
||||
unsigned tmp;
|
||||
|
||||
|
||||
PC_READ(tmp);
|
||||
WRITE(HL(), tmp);
|
||||
}
|
||||
|
@ -958,10 +958,10 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x3A:
|
||||
{
|
||||
unsigned addr = HL();
|
||||
|
||||
|
||||
A = memory.read(addr, cycleCounter);
|
||||
cycleCounter += 4;
|
||||
|
||||
|
||||
addr = (addr - 1) & 0xFFFF;
|
||||
L = addr;
|
||||
H = addr >> 8;
|
||||
|
@ -1221,7 +1221,7 @@ void CPU::process(const unsigned long cycles) {
|
|||
unsigned data;
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
add_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1249,9 +1249,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x8E:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
adc_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1279,9 +1279,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x96:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
sub_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1311,9 +1311,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x9E:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
sbc_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1341,9 +1341,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xA6:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
and_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1374,9 +1374,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xAE:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
xor_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1405,9 +1405,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xB6:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
or_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1437,9 +1437,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xBE:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
cp_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1453,7 +1453,7 @@ void CPU::process(const unsigned long cycles) {
|
|||
//Pop two bytes from the stack and jump to that address, if ZF is unset:
|
||||
case 0xC0:
|
||||
cycleCounter += 4;
|
||||
|
||||
|
||||
if (ZF & 0xFF) {
|
||||
ret();
|
||||
}
|
||||
|
@ -1495,9 +1495,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xC6:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
PC_READ(data);
|
||||
|
||||
|
||||
add_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1509,11 +1509,11 @@ void CPU::process(const unsigned long cycles) {
|
|||
//Pop two bytes from the stack and jump to that address, if ZF is set:
|
||||
case 0xC8:
|
||||
cycleCounter += 4;
|
||||
|
||||
|
||||
if (!(ZF & 0xFF)) {
|
||||
ret();
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
//ret (16 cycles):
|
||||
|
@ -1537,7 +1537,7 @@ void CPU::process(const unsigned long cycles) {
|
|||
//CB OPCODES (Shifts, rotates and bits):
|
||||
case 0xCB:
|
||||
PC_READ(opcode);
|
||||
|
||||
|
||||
switch (opcode) {
|
||||
case 0x00:
|
||||
rlc_r(B);
|
||||
|
@ -1562,14 +1562,14 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x06:
|
||||
{
|
||||
const unsigned addr = HL();
|
||||
|
||||
|
||||
READ(CF, addr);
|
||||
CF <<= 1;
|
||||
|
||||
|
||||
ZF = CF | (CF >> 8);
|
||||
|
||||
WRITE(addr, ZF & 0xFF);
|
||||
|
||||
|
||||
HF2 = 0;
|
||||
}
|
||||
break;
|
||||
|
@ -1599,13 +1599,13 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x0E:
|
||||
{
|
||||
const unsigned addr = HL();
|
||||
|
||||
|
||||
READ(ZF, addr);
|
||||
|
||||
|
||||
CF = ZF << 8;
|
||||
|
||||
|
||||
WRITE(addr, (ZF | CF) >> 1 & 0xFF);
|
||||
|
||||
|
||||
HF2 = 0;
|
||||
}
|
||||
break;
|
||||
|
@ -1636,14 +1636,14 @@ void CPU::process(const unsigned long cycles) {
|
|||
{
|
||||
const unsigned addr = HL();
|
||||
const unsigned oldcf = CF >> 8 & 1;
|
||||
|
||||
|
||||
READ(CF, addr);
|
||||
CF <<= 1;
|
||||
|
||||
|
||||
ZF = CF | oldcf;
|
||||
|
||||
|
||||
WRITE(addr, ZF & 0xFF);
|
||||
|
||||
|
||||
HF2 = 0;
|
||||
}
|
||||
break;
|
||||
|
@ -1673,15 +1673,15 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x1E:
|
||||
{
|
||||
const unsigned addr = HL();
|
||||
|
||||
|
||||
READ(ZF, addr);
|
||||
|
||||
|
||||
const unsigned oldcf = CF & 0x100;
|
||||
CF = ZF << 8;
|
||||
ZF = (ZF | oldcf) >> 1;
|
||||
|
||||
|
||||
WRITE(addr, ZF);
|
||||
|
||||
|
||||
HF2 = 0;
|
||||
}
|
||||
break;
|
||||
|
@ -1711,14 +1711,14 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x26:
|
||||
{
|
||||
const unsigned addr = HL();
|
||||
|
||||
|
||||
READ(CF, addr);
|
||||
CF <<= 1;
|
||||
|
||||
|
||||
ZF = CF;
|
||||
|
||||
|
||||
WRITE(addr, ZF & 0xFF);
|
||||
|
||||
|
||||
HF2 = 0;
|
||||
}
|
||||
break;
|
||||
|
@ -1748,13 +1748,13 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x2E:
|
||||
{
|
||||
const unsigned addr = HL();
|
||||
|
||||
|
||||
READ(CF, addr);
|
||||
|
||||
|
||||
ZF = CF >> 1;
|
||||
|
||||
|
||||
WRITE(addr, ZF | (CF & 0x80));
|
||||
|
||||
|
||||
CF <<= 8;
|
||||
HF2 = 0;
|
||||
}
|
||||
|
@ -1785,11 +1785,11 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x36:
|
||||
{
|
||||
const unsigned addr = HL();
|
||||
|
||||
|
||||
READ(ZF, addr);
|
||||
|
||||
|
||||
WRITE(addr, (ZF << 4 | ZF >> 4) & 0xFF);
|
||||
|
||||
|
||||
CF = HF2 = 0;
|
||||
}
|
||||
break;
|
||||
|
@ -1819,13 +1819,13 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x3E:
|
||||
{
|
||||
const unsigned addr = HL();
|
||||
|
||||
|
||||
READ(CF, addr);
|
||||
|
||||
|
||||
ZF = CF >> 1;
|
||||
|
||||
|
||||
WRITE(addr, ZF);
|
||||
|
||||
|
||||
CF <<= 8;
|
||||
HF2 = 0;
|
||||
}
|
||||
|
@ -1854,9 +1854,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x46:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
bit0_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1884,9 +1884,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x4E:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
bit1_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1914,9 +1914,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x56:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
bit2_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1944,9 +1944,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x5E:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
bit3_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -1974,9 +1974,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x66:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
bit4_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -2004,9 +2004,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x6E:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
bit5_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -2034,9 +2034,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x76:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
bit6_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -2064,9 +2064,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0x7E:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
READ(data, HL());
|
||||
|
||||
|
||||
bit7_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -2479,9 +2479,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xCE:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
PC_READ(data);
|
||||
|
||||
|
||||
adc_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -2493,11 +2493,11 @@ void CPU::process(const unsigned long cycles) {
|
|||
//Pop two bytes from the stack and jump to that address, if CF is unset:
|
||||
case 0xD0:
|
||||
cycleCounter += 4;
|
||||
|
||||
|
||||
if (!(CF & 0x100)) {
|
||||
ret();
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case 0xD1:
|
||||
|
@ -2537,9 +2537,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xD6:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
PC_READ(data);
|
||||
|
||||
|
||||
sub_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -2551,11 +2551,11 @@ void CPU::process(const unsigned long cycles) {
|
|||
//Pop two bytes from the stack and jump to that address, if CF is set:
|
||||
case 0xD8:
|
||||
cycleCounter += 4;
|
||||
|
||||
|
||||
if (CF & 0x100) {
|
||||
ret();
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
//reti (16 cycles):
|
||||
|
@ -2563,11 +2563,11 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xD9:
|
||||
{
|
||||
unsigned l, h;
|
||||
|
||||
|
||||
pop_rr(h, l);
|
||||
|
||||
|
||||
memory.ei(cycleCounter);
|
||||
|
||||
|
||||
PC_MOD(h << 8 | l);
|
||||
}
|
||||
break;
|
||||
|
@ -2607,9 +2607,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xDE:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
PC_READ(data);
|
||||
|
||||
|
||||
sbc_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -2622,9 +2622,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xE0:
|
||||
{
|
||||
unsigned tmp;
|
||||
|
||||
|
||||
PC_READ(tmp);
|
||||
|
||||
|
||||
FF_WRITE(0xFF00 | tmp, A);
|
||||
}
|
||||
break;
|
||||
|
@ -2652,9 +2652,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xE6:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
PC_READ(data);
|
||||
|
||||
|
||||
and_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -2690,10 +2690,10 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xEA:
|
||||
{
|
||||
unsigned l, h;
|
||||
|
||||
|
||||
PC_READ(l);
|
||||
PC_READ(h);
|
||||
|
||||
|
||||
WRITE(h << 8 | l, A);
|
||||
}
|
||||
break;
|
||||
|
@ -2713,9 +2713,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xEE:
|
||||
{
|
||||
unsigned data;
|
||||
|
||||
|
||||
PC_READ(data);
|
||||
|
||||
|
||||
xor_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -2728,9 +2728,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xF0:
|
||||
{
|
||||
unsigned tmp;
|
||||
|
||||
|
||||
PC_READ(tmp);
|
||||
|
||||
|
||||
FF_READ(A, 0xFF00 | tmp);
|
||||
}
|
||||
break;
|
||||
|
@ -2738,9 +2738,9 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xF1: /*pop_rr(A, F); Cycles(12); break;*/
|
||||
{
|
||||
unsigned F;
|
||||
|
||||
|
||||
pop_rr(A, F);
|
||||
|
||||
|
||||
FROM_F(F);
|
||||
}
|
||||
break;
|
||||
|
@ -2762,10 +2762,10 @@ void CPU::process(const unsigned long cycles) {
|
|||
break;
|
||||
case 0xF5: /*push_rr(A, F); Cycles(16); break;*/
|
||||
calcHF(HF1, HF2);
|
||||
|
||||
|
||||
{
|
||||
unsigned F = F();
|
||||
|
||||
|
||||
push_rr(A, F);
|
||||
}
|
||||
break;
|
||||
|
@ -2775,7 +2775,7 @@ void CPU::process(const unsigned long cycles) {
|
|||
unsigned data;
|
||||
|
||||
PC_READ(data);
|
||||
|
||||
|
||||
or_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -2816,10 +2816,10 @@ void CPU::process(const unsigned long cycles) {
|
|||
case 0xFA:
|
||||
{
|
||||
unsigned l, h;
|
||||
|
||||
|
||||
PC_READ(l);
|
||||
PC_READ(h);
|
||||
|
||||
|
||||
READ(A, h << 8 | l);
|
||||
}
|
||||
break;
|
||||
|
@ -2843,7 +2843,7 @@ void CPU::process(const unsigned long cycles) {
|
|||
unsigned data;
|
||||
|
||||
PC_READ(data);
|
||||
|
||||
|
||||
cp_a_u8(data);
|
||||
}
|
||||
break;
|
||||
|
@ -2853,11 +2853,11 @@ void CPU::process(const unsigned long cycles) {
|
|||
// default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//PC_ = PC;
|
||||
cycleCounter = memory.event(cycleCounter);
|
||||
}
|
||||
|
||||
|
||||
//A_ = A;
|
||||
cycleCounter_ = cycleCounter;
|
||||
}
|
||||
|
|
|
@ -26,48 +26,48 @@ namespace gambatte {
|
|||
|
||||
class CPU {
|
||||
Memory memory;
|
||||
|
||||
|
||||
unsigned long cycleCounter_;
|
||||
|
||||
unsigned short PC;
|
||||
unsigned short SP;
|
||||
|
||||
|
||||
unsigned HF1, HF2, ZF, CF;
|
||||
|
||||
unsigned char A, B, C, D, E, /*F,*/ H, L;
|
||||
|
||||
bool skip;
|
||||
|
||||
|
||||
int *interruptAddresses;
|
||||
int numInterruptAddresses;
|
||||
int hitInterruptAddress;
|
||||
|
||||
void process(unsigned long cycles);
|
||||
|
||||
|
||||
void (*tracecallback)(void *);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
CPU();
|
||||
// void halt();
|
||||
|
||||
// unsigned interrupt(unsigned address, unsigned cycleCounter);
|
||||
|
||||
|
||||
long runFor(unsigned long cycles);
|
||||
void setStatePtrs(SaveState &state);
|
||||
void loadState(const SaveState &state);
|
||||
void setLayers(unsigned mask) { memory.setLayers(mask); }
|
||||
|
||||
|
||||
void loadSavedata(const char *data) { memory.loadSavedata(data); }
|
||||
int saveSavedataLength() {return memory.saveSavedataLength(); }
|
||||
void saveSavedata(char *dest) { memory.saveSavedata(dest); }
|
||||
|
||||
|
||||
bool getMemoryArea(int which, unsigned char **data, int *length) { return memory.getMemoryArea(which, data, length); }
|
||||
|
||||
void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
|
||||
memory.setVideoBuffer(videoBuf, pitch);
|
||||
}
|
||||
|
||||
|
||||
void setInputGetter(unsigned (*getInput)()) {
|
||||
memory.setInputGetter(getInput);
|
||||
}
|
||||
|
@ -103,19 +103,19 @@ public:
|
|||
void setLinkCallback(void(*callback)()) {
|
||||
memory.setLinkCallback(callback);
|
||||
}
|
||||
|
||||
|
||||
LoadRes load(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat) {
|
||||
return memory.loadROM(romfiledata, romfilelength, forceDmg, multicartCompat);
|
||||
}
|
||||
|
||||
|
||||
bool loaded() const { return memory.loaded(); }
|
||||
const char * romTitle() const { return memory.romTitle(); }
|
||||
|
||||
|
||||
void setSoundBuffer(uint_least32_t *const buf) { memory.setSoundBuffer(buf); }
|
||||
unsigned fillSoundBuffer() { return memory.fillSoundBuffer(cycleCounter_); }
|
||||
|
||||
|
||||
bool isCgb() const { return memory.isCgb(); }
|
||||
|
||||
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) {
|
||||
memory.setDmgPaletteColor(palNum, colorNum, rgb32);
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ public:
|
|||
void setCgbPalette(unsigned *lut) {
|
||||
memory.setCgbPalette(lut);
|
||||
}
|
||||
|
||||
|
||||
unsigned char* cgbBiosBuffer() { return memory.cgbBiosBuffer(); }
|
||||
unsigned char* dmgBiosBuffer() { return memory.dmgBiosBuffer(); }
|
||||
bool gbIsCgb() { return memory.gbIsCgb(); }
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
stream.seekg(0, std::ios::beg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void rewind() { stream.seekg(0, std::ios::beg); }
|
||||
virtual std::size_t size() const { return fsize; };
|
||||
virtual void read(char *buffer, std::size_t amount) { stream.read(buffer, amount); }
|
||||
|
|
|
@ -30,7 +30,7 @@ struct GB::Priv {
|
|||
unsigned layersMask;
|
||||
|
||||
uint_least32_t vbuff[160*144];
|
||||
|
||||
|
||||
Priv() : loadflags(0), layersMask(LAYER_MASK_BG | LAYER_MASK_OBJ)
|
||||
{
|
||||
}
|
||||
|
@ -39,13 +39,13 @@ struct GB::Priv {
|
|||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
GB::GB() : p_(new Priv) {}
|
||||
|
||||
GB::~GB() {
|
||||
//if (p_->cpu.loaded())
|
||||
// p_->cpu.saveSavedata();
|
||||
|
||||
|
||||
delete p_;
|
||||
}
|
||||
|
||||
|
@ -54,12 +54,12 @@ long GB::runFor(gambatte::uint_least32_t *const soundBuf, unsigned &samples) {
|
|||
samples = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
p_->cpu.setVideoBuffer(p_->vbuff, 160);
|
||||
p_->cpu.setSoundBuffer(soundBuf);
|
||||
const long cyclesSinceBlit = p_->cpu.runFor(samples * 2);
|
||||
samples = p_->cpu.fillSoundBuffer();
|
||||
|
||||
|
||||
return cyclesSinceBlit < 0 ? cyclesSinceBlit : static_cast<long>(samples) - (cyclesSinceBlit >> 1);
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ void GB::blitTo(gambatte::uint_least32_t *videoBuf, int pitch)
|
|||
|
||||
void GB::reset(const std::uint32_t now, const unsigned div) {
|
||||
if (p_->cpu.loaded()) {
|
||||
|
||||
|
||||
int length = p_->cpu.saveSavedataLength();
|
||||
char *s;
|
||||
if (length > 0)
|
||||
|
@ -91,7 +91,7 @@ void GB::reset(const std::uint32_t now, const unsigned div) {
|
|||
s = (char *) std::malloc(length);
|
||||
p_->cpu.saveSavedata(s);
|
||||
}
|
||||
|
||||
|
||||
SaveState state;
|
||||
p_->cpu.setStatePtrs(state);
|
||||
setInitState(state, !(p_->loadflags & FORCE_DMG), p_->loadflags & GBA_CGB, now, div);
|
||||
|
@ -143,9 +143,9 @@ void GB::setLinkCallback(void(*callback)()) {
|
|||
LoadRes GB::load(const char *romfiledata, unsigned romfilelength, const std::uint32_t now, unsigned const flags, const unsigned div) {
|
||||
//if (p_->cpu.loaded())
|
||||
// p_->cpu.saveSavedata();
|
||||
|
||||
|
||||
LoadRes const loadres = p_->cpu.load(romfiledata, romfilelength, flags & FORCE_DMG, flags & MULTICART_COMPAT);
|
||||
|
||||
|
||||
if (loadres == LOADRES_OK) {
|
||||
SaveState state;
|
||||
p_->cpu.setStatePtrs(state);
|
||||
|
@ -154,7 +154,7 @@ LoadRes GB::load(const char *romfiledata, unsigned romfilelength, const std::uin
|
|||
p_->cpu.loadState(state);
|
||||
//p_->cpu.loadSavedata();
|
||||
}
|
||||
|
||||
|
||||
return loadres;
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ const std::string GB::romTitle() const {
|
|||
title[title[0xF] & 0x80 ? 0xF : 0x10] = '\0';
|
||||
return std::string(title);
|
||||
}
|
||||
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
|
|
@ -677,29 +677,29 @@ static void setInitialCgbWram(unsigned char *const wram) {
|
|||
{ 0x7FCD, 0xBF }, { 0x7FCE, 0x7F }, { 0x7FCF, 0xFB }, { 0x7FDB, 0xF7 },
|
||||
{ 0x7FDF, 0x7F }, { 0x7FE8, 0xDF }, { 0x7FEC, 0xFB }, { 0x7FF2, 0xF7 }
|
||||
};
|
||||
|
||||
|
||||
for (unsigned addr = 0x0000; addr < 0x0800; addr += 0x10) {
|
||||
std::memset(wram + addr + 0x00, 0xFF, 0x08);
|
||||
std::memset(wram + addr + 0x08, 0x00, 0x08);
|
||||
}
|
||||
|
||||
|
||||
for (unsigned addr = 0x0800; addr < 0x1000; addr += 0x10) {
|
||||
std::memset(wram + addr + 0x00, 0x00, 0x08);
|
||||
std::memset(wram + addr + 0x08, 0xFF, 0x08);
|
||||
}
|
||||
|
||||
|
||||
for (unsigned addr = 0x0E00; addr < 0x1000; addr += 0x10) {
|
||||
wram[addr + 0x02] = 0xFF;
|
||||
wram[addr + 0x0A] = 0x00;
|
||||
}
|
||||
|
||||
|
||||
for (unsigned addr = 0x1000; addr < 0x8000; addr += 0x1000) {
|
||||
if (0x2000 != addr)
|
||||
std::memcpy(wram + addr, wram, 0x1000);
|
||||
}
|
||||
|
||||
|
||||
std::memset(wram + 0x2000, 0, 0x1000);
|
||||
|
||||
|
||||
for (std::size_t i = 0; i < sizeof cgbWramDumpDiff / sizeof cgbWramDumpDiff[0]; ++i)
|
||||
wram[cgbWramDumpDiff[i].addr] = cgbWramDumpDiff[i].val;
|
||||
}
|
||||
|
@ -959,19 +959,19 @@ static void setInitialDmgWram(unsigned char *const wram) {
|
|||
{ 0x1FA2, 0x40 }, { 0x1FB6, 0x80 }, { 0x1FC6, 0x10 }, { 0x1FCC, 0x20 },
|
||||
{ 0x1FD2, 0x20 }, { 0x1FD8, 0x04 }, { 0x1FDC, 0x10 }, { 0x1FDE, 0x04 }
|
||||
};
|
||||
|
||||
|
||||
for (unsigned addr = 0x0000; addr < 0x0800; addr += 0x200) {
|
||||
std::memset(wram + addr , 0x00, 0x100);
|
||||
std::memset(wram + addr + 0x100, 0xFF, 0x100);
|
||||
}
|
||||
|
||||
|
||||
for (unsigned addr = 0x0800; addr < 0x1000; addr += 0x200) {
|
||||
std::memset(wram + addr , 0xFF, 0x100);
|
||||
std::memset(wram + addr + 0x100, 0x00, 0x100);
|
||||
}
|
||||
|
||||
|
||||
std::memcpy(wram + 0x1000, wram, 0x1000);
|
||||
|
||||
|
||||
for (std::size_t i = 0; i < sizeof dmgWramDumpDiff / sizeof dmgWramDumpDiff[0]; ++i)
|
||||
wram[dmgWramDumpDiff[i].addr] = dmgWramDumpDiff[i].val;
|
||||
}
|
||||
|
@ -1004,21 +1004,21 @@ static void setInitialVram(unsigned char *const vram, const bool cgb) {
|
|||
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFC, 0xFC,
|
||||
0x3C, 0x42, 0xB9, 0xA5, 0xB9, 0xA5, 0x42, 0x3C
|
||||
};
|
||||
|
||||
|
||||
std::memset(vram, 0, 0x4000);
|
||||
|
||||
|
||||
for (std::size_t i = 0; i < sizeof even_numbered_8010_to_81a0_dump; ++i) {
|
||||
vram[0x0010 + i * 2] = even_numbered_8010_to_81a0_dump[i];
|
||||
}
|
||||
|
||||
|
||||
if (!cgb) {
|
||||
unsigned i = 1;
|
||||
|
||||
|
||||
for (unsigned addr = 0x1904; addr < 0x1910; ++addr)
|
||||
vram[addr] = i++;
|
||||
|
||||
|
||||
vram[0x1910] = 0x19;
|
||||
|
||||
|
||||
for (unsigned addr = 0x1924; addr < 0x1930; ++addr)
|
||||
vram[addr] = i++;
|
||||
}
|
||||
|
@ -1039,7 +1039,7 @@ static void setInitialCgbIoamhram(unsigned char *const ioamhram) {
|
|||
0x24, 0x13, 0xFD, 0x3A, 0x10, 0x10, 0xAD, 0x45,
|
||||
0x24, 0x13, 0xFD, 0x3A, 0x10, 0x10, 0xAD, 0x45
|
||||
};
|
||||
|
||||
|
||||
static const unsigned char ffxxDump[0x100] = {
|
||||
0xCF, 0x00, 0x7C, 0xFF, 0x00, 0x00, 0x00, 0xF8,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1,
|
||||
|
@ -1074,7 +1074,7 @@ static void setInitialCgbIoamhram(unsigned char *const ioamhram) {
|
|||
0x98, 0xD1, 0x71, 0x02, 0x4D, 0x01, 0xC1, 0xFF,
|
||||
0x0D, 0x00, 0xD3, 0x05, 0xF9, 0x00, 0x0B, 0x00
|
||||
};
|
||||
|
||||
|
||||
std::memset(ioamhram, 0x00, 0x0A0);
|
||||
std::memcpy(ioamhram + 0x0A0, feaxDump, sizeof feaxDump);
|
||||
std::memcpy(ioamhram + 0x100, ffxxDump, sizeof ffxxDump);
|
||||
|
@ -1103,7 +1103,7 @@ static void setInitialDmgIoamhram(unsigned char *const ioamhram) {
|
|||
0x24, 0x40, 0x42, 0x05, 0x0E, 0x04, 0x20, 0xA6,
|
||||
0x5E, 0xC1, 0x97, 0x7E, 0x44, 0x05, 0x01, 0xA9
|
||||
};
|
||||
|
||||
|
||||
static const unsigned char ffxxDump[0x100] = {
|
||||
0xCF, 0x00, 0x7E, 0xFF, 0xD3, 0x00, 0x00, 0xF8,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1,
|
||||
|
@ -1138,7 +1138,7 @@ static void setInitialDmgIoamhram(unsigned char *const ioamhram) {
|
|||
0xBC, 0x7F, 0x7E, 0xD0, 0xC7, 0xC3, 0xBD, 0xCF,
|
||||
0x59, 0xEA, 0x39, 0x01, 0x2E, 0x00, 0x69, 0x00
|
||||
};
|
||||
|
||||
|
||||
std::memcpy(ioamhram , oamDump, sizeof oamDump);
|
||||
std::memset(ioamhram + 0x0A0, 0x00, 0x060);
|
||||
std::memcpy(ioamhram + 0x100, ffxxDump, sizeof ffxxDump);
|
||||
|
@ -1148,24 +1148,24 @@ static void setInitialDmgIoamhram(unsigned char *const ioamhram) {
|
|||
|
||||
void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbMode, const std::uint32_t now, const unsigned div) {
|
||||
static const unsigned char cgbObjpDump[0x40] = {
|
||||
0x00, 0x00, 0xF2, 0xAB,
|
||||
0x61, 0xC2, 0xD9, 0xBA,
|
||||
0x88, 0x6E, 0xDD, 0x63,
|
||||
0x28, 0x27, 0xFB, 0x9F,
|
||||
0x35, 0x42, 0xD6, 0xD4,
|
||||
0x50, 0x48, 0x57, 0x5E,
|
||||
0x23, 0x3E, 0x3D, 0xCA,
|
||||
0x71, 0x21, 0x37, 0xC0,
|
||||
0xC6, 0xB3, 0xFB, 0xF9,
|
||||
0x08, 0x00, 0x8D, 0x29,
|
||||
0xA3, 0x20, 0xDB, 0x87,
|
||||
0x62, 0x05, 0x5D, 0xD4,
|
||||
0x0E, 0x08, 0xFE, 0xAF,
|
||||
0x20, 0x02, 0xD7, 0xFF,
|
||||
0x07, 0x6A, 0x55, 0xEC,
|
||||
0x00, 0x00, 0xF2, 0xAB,
|
||||
0x61, 0xC2, 0xD9, 0xBA,
|
||||
0x88, 0x6E, 0xDD, 0x63,
|
||||
0x28, 0x27, 0xFB, 0x9F,
|
||||
0x35, 0x42, 0xD6, 0xD4,
|
||||
0x50, 0x48, 0x57, 0x5E,
|
||||
0x23, 0x3E, 0x3D, 0xCA,
|
||||
0x71, 0x21, 0x37, 0xC0,
|
||||
0xC6, 0xB3, 0xFB, 0xF9,
|
||||
0x08, 0x00, 0x8D, 0x29,
|
||||
0xA3, 0x20, 0xDB, 0x87,
|
||||
0x62, 0x05, 0x5D, 0xD4,
|
||||
0x0E, 0x08, 0xFE, 0xAF,
|
||||
0x20, 0x02, 0xD7, 0xFF,
|
||||
0x07, 0x6A, 0x55, 0xEC,
|
||||
0x83, 0x40, 0x0B, 0x77
|
||||
};
|
||||
|
||||
|
||||
state.cpu.cycleCounter = 8;
|
||||
state.cpu.PC = 0;
|
||||
state.cpu.SP = 0;
|
||||
|
@ -1183,7 +1183,7 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
state.mem.agbMode = gbaCgbMode;
|
||||
|
||||
std::memset(state.mem.sram.ptr, 0xFF, state.mem.sram.getSz());
|
||||
|
||||
|
||||
setInitialVram(state.mem.vram.ptr, cgb);
|
||||
|
||||
if (cgb) {
|
||||
|
@ -1193,11 +1193,11 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
setInitialDmgWram(state.mem.wram.ptr);
|
||||
setInitialDmgIoamhram(state.mem.ioamhram.ptr);
|
||||
}
|
||||
|
||||
|
||||
state.mem.ioamhram.ptr[0x104] = 0;
|
||||
state.mem.ioamhram.ptr[0x140] = 0;
|
||||
state.mem.ioamhram.ptr[0x144] = 0x00;
|
||||
|
||||
|
||||
state.mem.divLastUpdate = 0 - div;
|
||||
state.mem.timaLastUpdate = 0;
|
||||
state.mem.tmatime = DISABLED_TIME;
|
||||
|
@ -1217,23 +1217,23 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
state.mem.hdmaTransfer = false;
|
||||
state.mem.gbIsCgb = cgb;
|
||||
|
||||
|
||||
|
||||
for (unsigned i = 0x00; i < 0x40; i += 0x02) {
|
||||
state.ppu.bgpData.ptr[i ] = 0xFF;
|
||||
state.ppu.bgpData.ptr[i + 1] = 0x7F;
|
||||
}
|
||||
|
||||
|
||||
std::memcpy(state.ppu.objpData.ptr, cgbObjpDump, sizeof cgbObjpDump);
|
||||
|
||||
|
||||
if (!cgb) {
|
||||
state.ppu.bgpData.ptr[0] = state.mem.ioamhram.get()[0x147];
|
||||
state.ppu.objpData.ptr[0] = state.mem.ioamhram.get()[0x148];
|
||||
state.ppu.objpData.ptr[1] = state.mem.ioamhram.get()[0x149];
|
||||
}
|
||||
|
||||
|
||||
for (unsigned pos = 0; pos < 80; ++pos)
|
||||
state.ppu.oamReaderBuf.ptr[pos] = state.mem.ioamhram.ptr[(pos * 2 & ~3) | (pos & 1)];
|
||||
|
||||
|
||||
std::fill_n(state.ppu.oamReaderSzbuf.ptr, 40, false);
|
||||
std::memset(state.ppu.spAttribList, 0, sizeof state.ppu.spAttribList);
|
||||
std::memset(state.ppu.spByte0List, 0, sizeof state.ppu.spByte0List);
|
||||
|
@ -1263,9 +1263,9 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
state.ppu.pendingLcdstatIrq = false;
|
||||
state.ppu.isCgb = cgb;
|
||||
|
||||
|
||||
|
||||
state.spu.cycleCounter = 0; // spu.cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
|
||||
|
||||
state.spu.ch1.sweep.counter = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch1.sweep.shadow = 0;
|
||||
state.spu.ch1.sweep.nr0 = 0;
|
||||
|
@ -1279,7 +1279,7 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
state.spu.ch1.lcounter.lengthCounter = 0;
|
||||
state.spu.ch1.nr4 = 0;
|
||||
state.spu.ch1.master = false;
|
||||
|
||||
|
||||
state.spu.ch2.duty.nextPosUpdate = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch2.duty.nr3 = 0;
|
||||
state.spu.ch2.duty.pos = 0;
|
||||
|
@ -1289,10 +1289,10 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
state.spu.ch2.lcounter.lengthCounter = 0;
|
||||
state.spu.ch2.nr4 = 0;
|
||||
state.spu.ch2.master = false;
|
||||
|
||||
|
||||
for (unsigned i = 0; i < 0x10; ++i)
|
||||
state.spu.ch3.waveRam.ptr[i] = state.mem.ioamhram.get()[0x130 + i];
|
||||
|
||||
|
||||
state.spu.ch3.lcounter.counter = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch3.lcounter.lengthCounter = 0x100;
|
||||
state.spu.ch3.waveCounter = SoundUnit::COUNTER_DISABLED;
|
||||
|
@ -1302,7 +1302,7 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
state.spu.ch3.wavePos = 0;
|
||||
state.spu.ch3.sampleBuf = 0;
|
||||
state.spu.ch3.master = false;
|
||||
|
||||
|
||||
state.spu.ch4.lfsr.counter = state.spu.cycleCounter + 4;
|
||||
state.spu.ch4.lfsr.reg = 0xFF;
|
||||
state.spu.ch4.env.counter = SoundUnit::COUNTER_DISABLED;
|
||||
|
@ -1311,7 +1311,7 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
state.spu.ch4.lcounter.lengthCounter = 0;
|
||||
state.spu.ch4.nr4 = 0;
|
||||
state.spu.ch4.master = false;
|
||||
|
||||
|
||||
state.rtc.baseTime = now;
|
||||
state.rtc.haltTime = state.rtc.baseTime;
|
||||
state.rtc.dataDh = 0;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* Copyright (C) 2007 by Sindre Aam<EFBFBD>s *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
@ -26,19 +26,19 @@ template<typename T, class Less>
|
|||
void insertionSort(T *const start, T *const end, Less less) {
|
||||
if (start >= end)
|
||||
return;
|
||||
|
||||
|
||||
T *a = start;
|
||||
|
||||
|
||||
while (++a < end) {
|
||||
const T e = *a;
|
||||
|
||||
|
||||
T *b = a;
|
||||
|
||||
|
||||
while (b != start && less(e, *(b - 1))) {
|
||||
*b = *(b - 1);
|
||||
b = b - 1;
|
||||
}
|
||||
|
||||
|
||||
*b = e;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ unsigned long Interrupter::interrupt(const unsigned address, unsigned long cycle
|
|||
memory.write(SP, PC & 0xFF, cycleCounter);
|
||||
PC = address;
|
||||
cycleCounter += 8;
|
||||
|
||||
|
||||
return cycleCounter;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,13 +28,13 @@ void InterruptRequester::loadState(const SaveState &state) {
|
|||
ifreg_ = state.mem.ioamhram.get()[0x10F];
|
||||
iereg_ = state.mem.ioamhram.get()[0x1FF] & 0x1F;
|
||||
intFlags.set(state.mem.IME, state.mem.halted);
|
||||
|
||||
|
||||
eventTimes.setValue<INTERRUPTS>(intFlags.imeOrHalted() && pendingIrqs() ? minIntTime : static_cast<unsigned long>(DISABLED_TIME));
|
||||
}
|
||||
|
||||
void InterruptRequester::resetCc(const unsigned long oldCc, const unsigned long newCc) {
|
||||
minIntTime = minIntTime < oldCc ? 0 : minIntTime - (oldCc - newCc);
|
||||
|
||||
|
||||
if (eventTimes.value(INTERRUPTS) != DISABLED_TIME)
|
||||
eventTimes.setValue<INTERRUPTS>(minIntTime);
|
||||
}
|
||||
|
@ -42,35 +42,35 @@ void InterruptRequester::resetCc(const unsigned long oldCc, const unsigned long
|
|||
void InterruptRequester::ei(const unsigned long cc) {
|
||||
intFlags.setIme();
|
||||
minIntTime = cc + 1;
|
||||
|
||||
|
||||
if (pendingIrqs())
|
||||
eventTimes.setValue<INTERRUPTS>(minIntTime);
|
||||
}
|
||||
|
||||
void InterruptRequester::di() {
|
||||
intFlags.unsetIme();
|
||||
|
||||
|
||||
if (!intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(DISABLED_TIME);
|
||||
}
|
||||
|
||||
void InterruptRequester::halt() {
|
||||
intFlags.setHalted();
|
||||
|
||||
|
||||
if (pendingIrqs())
|
||||
eventTimes.setValue<INTERRUPTS>(minIntTime);
|
||||
}
|
||||
|
||||
void InterruptRequester::unhalt() {
|
||||
intFlags.unsetHalted();
|
||||
|
||||
|
||||
if (!intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(DISABLED_TIME);
|
||||
}
|
||||
|
||||
void InterruptRequester::flagIrq(const unsigned bit) {
|
||||
ifreg_ |= bit;
|
||||
|
||||
|
||||
if (intFlags.imeOrHalted() && pendingIrqs())
|
||||
eventTimes.setValue<INTERRUPTS>(minIntTime);
|
||||
}
|
||||
|
@ -82,14 +82,14 @@ void InterruptRequester::ackIrq(const unsigned bit) {
|
|||
|
||||
void InterruptRequester::setIereg(const unsigned iereg) {
|
||||
iereg_ = iereg & 0x1F;
|
||||
|
||||
|
||||
if (intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(pendingIrqs() ? minIntTime : static_cast<unsigned long>(DISABLED_TIME));
|
||||
}
|
||||
|
||||
void InterruptRequester::setIfreg(const unsigned ifreg) {
|
||||
ifreg_ = ifreg;
|
||||
|
||||
|
||||
if (intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(pendingIrqs() ? minIntTime : static_cast<unsigned long>(DISABLED_TIME));
|
||||
}
|
||||
|
|
|
@ -32,41 +32,41 @@ class InterruptRequester {
|
|||
unsigned long minIntTime;
|
||||
unsigned ifreg_;
|
||||
unsigned iereg_;
|
||||
|
||||
|
||||
class IntFlags {
|
||||
friend class InterruptRequester;
|
||||
unsigned char flags_;
|
||||
enum { IME_MASK = 1, HALTED_MASK = 2 };
|
||||
|
||||
|
||||
public:
|
||||
IntFlags() : flags_(0) {}
|
||||
|
||||
|
||||
bool ime() const { return flags_ & IME_MASK; }
|
||||
bool halted() const { return flags_ & HALTED_MASK; }
|
||||
bool imeOrHalted() const { return flags_; }
|
||||
|
||||
|
||||
void setIme() { flags_ |= IME_MASK; }
|
||||
void unsetIme() { flags_ &= ~IME_MASK; }
|
||||
|
||||
|
||||
void setHalted() { flags_ |= HALTED_MASK; }
|
||||
void unsetHalted() { flags_ &= ~HALTED_MASK; }
|
||||
|
||||
|
||||
void set(const bool ime, const bool halted) { flags_ = halted * HALTED_MASK + ime * IME_MASK; }
|
||||
} intFlags;
|
||||
|
||||
|
||||
public:
|
||||
InterruptRequester();
|
||||
|
||||
|
||||
void loadState(const SaveState &);
|
||||
|
||||
|
||||
void resetCc(unsigned long oldCc, unsigned long newCc);
|
||||
|
||||
|
||||
unsigned ifreg() const { return ifreg_; }
|
||||
unsigned iereg() const { return iereg_; }
|
||||
unsigned pendingIrqs() const { return ifreg_ & iereg_; }
|
||||
bool ime() const { return intFlags.ime(); }
|
||||
bool halted() const { return intFlags.halted(); }
|
||||
|
||||
|
||||
void ei(unsigned long cc);
|
||||
void di();
|
||||
void halt();
|
||||
|
@ -75,7 +75,7 @@ public:
|
|||
void ackIrq(unsigned bit);
|
||||
void setIereg(unsigned iereg);
|
||||
void setIfreg(unsigned ifreg);
|
||||
|
||||
|
||||
MemEventId minEventId() const { return static_cast<MemEventId>(eventTimes.min()); }
|
||||
unsigned long minEventTime() const { return eventTimes.minValue(); }
|
||||
template<MemEventId id> void setEventTime(unsigned long value) { eventTimes.setValue<id>(value); }
|
||||
|
|
|
@ -76,11 +76,11 @@ public:
|
|||
};
|
||||
|
||||
static inline unsigned rambanks(const MemPtrs &memptrs) {
|
||||
return static_cast<std::size_t>(memptrs.rambankdataend() - memptrs.rambankdata()) / 0x2000;
|
||||
return std::size_t(memptrs.rambankdataend() - memptrs.rambankdata()) / 0x2000;
|
||||
}
|
||||
|
||||
static inline unsigned rombanks(const MemPtrs &memptrs) {
|
||||
return static_cast<std::size_t>(memptrs.romdataend() - memptrs.romdata() ) / 0x4000;
|
||||
return std::size_t(memptrs.romdataend() - memptrs.romdata() ) / 0x4000;
|
||||
}
|
||||
|
||||
class Mbc1 : public DefaultMbc {
|
||||
|
@ -219,7 +219,7 @@ public:
|
|||
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
|
||||
setRombank();
|
||||
}
|
||||
|
||||
|
||||
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
|
||||
return (addr < 0x4000) == ((bank & 0xF) == 0);
|
||||
}
|
||||
|
@ -287,10 +287,10 @@ class Mbc3 : public DefaultMbc {
|
|||
static unsigned adjustedRombank(unsigned bank) { return bank & 0x7F ? bank : bank | 1; }
|
||||
void setRambank() const {
|
||||
unsigned flags = enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0;
|
||||
|
||||
|
||||
if (rtc) {
|
||||
rtc->set(enableRam, rambank);
|
||||
|
||||
|
||||
if (rtc->getActive())
|
||||
flags |= MemPtrs::RTC_EN;
|
||||
}
|
||||
|
@ -546,7 +546,7 @@ LoadRes Cartridge::loadROM(const char *romfiledata, unsigned romfilelength, bool
|
|||
|
||||
//if (rom->fail())
|
||||
// return -1;
|
||||
|
||||
|
||||
unsigned rambanks = 1;
|
||||
unsigned rombanks = 2;
|
||||
bool cgb = false;
|
||||
|
@ -609,8 +609,8 @@ LoadRes Cartridge::loadROM(const char *romfiledata, unsigned romfilelength, bool
|
|||
default: return -1;
|
||||
}*/
|
||||
|
||||
rambanks = numRambanksFromH14x(header[0x147], header[0x149]);
|
||||
|
||||
rambanks = numRambanksFromH14x(header[0x147], header[0x149]);
|
||||
|
||||
cgb = !forceDmg;
|
||||
}
|
||||
std::size_t const filesize = romfilelength; //rom->size();
|
||||
|
@ -625,10 +625,10 @@ LoadRes Cartridge::loadROM(const char *romfiledata, unsigned romfilelength, bool
|
|||
std::memcpy(memptrs.romdata(), romfiledata, (filesize / 0x4000) * 0x4000ul);
|
||||
std::memset(memptrs.romdata() + (filesize / 0x4000) * 0x4000ul, 0xFF, (rombanks - filesize / 0x4000) * 0x4000ul);
|
||||
enforce8bit(memptrs.romdata(), rombanks * 0x4000ul);
|
||||
|
||||
|
||||
//if (rom->fail())
|
||||
// return -1;
|
||||
|
||||
|
||||
switch (type) {
|
||||
case PLAIN: mbc.reset(new Mbc0(memptrs)); break;
|
||||
case MBC1:
|
||||
|
|
|
@ -63,13 +63,13 @@ class Cartridge {
|
|||
MemPtrs memptrs;
|
||||
Rtc rtc;
|
||||
std::auto_ptr<Mbc> mbc;
|
||||
|
||||
|
||||
public:
|
||||
void setStatePtrs(SaveState &);
|
||||
void loadState(const SaveState &);
|
||||
|
||||
|
||||
bool loaded() const { return mbc.get(); }
|
||||
|
||||
|
||||
const unsigned char * rmem(unsigned area) const { return memptrs.rmem(area); }
|
||||
unsigned char * wmem(unsigned area) const { return memptrs.wmem(area); }
|
||||
unsigned char * vramdata() const { return memptrs.vramdata(); }
|
||||
|
@ -85,14 +85,14 @@ public:
|
|||
void setVrambank(unsigned bank) { memptrs.setVrambank(bank); }
|
||||
void setWrambank(unsigned bank) { memptrs.setWrambank(bank); }
|
||||
void setOamDmaSrc(OamDmaSrc oamDmaSrc) { memptrs.setOamDmaSrc(oamDmaSrc); }
|
||||
|
||||
|
||||
void mbcWrite(unsigned addr, unsigned data) { mbc->romWrite(addr, data); }
|
||||
|
||||
bool isCgb() const { return gambatte::isCgb(memptrs); }
|
||||
|
||||
|
||||
void rtcWrite(unsigned data) { rtc.write(data); }
|
||||
unsigned char rtcRead() const { return *rtc.getActive(); }
|
||||
|
||||
|
||||
void loadSavedata(const char *data);
|
||||
int saveSavedataLength();
|
||||
void saveSavedata(char *dest);
|
||||
|
|
|
@ -45,7 +45,7 @@ void MemPtrs::reset(const unsigned rombanks, const unsigned rambanks, const unsi
|
|||
wramdataend_ = wramdata_[0] + wrambanks * 0x1000ul;
|
||||
|
||||
std::memset(rdisabledRamw(), 0xFF, 0x2000);
|
||||
|
||||
|
||||
oamDmaSrc_ = OAM_DMA_SRC_OFF;
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
|
||||
|
@ -87,7 +87,7 @@ void MemPtrs::setRambank(const unsigned flags, const unsigned rambank) {
|
|||
}
|
||||
|
||||
void MemPtrs::setWrambank(const unsigned bank) {
|
||||
wramdata_[1] = wramdata_[0] + ((bank & 0x07) ? (bank & 0x07) : 1) * 0x1000;
|
||||
wramdata_[1] = wramdata_[0] + (bank & 0x07 ? bank & 0x07 : 1) * 0x1000;
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ void MemPtrs::setOamDmaSrc(const OamDmaSrc oamDmaSrc) {
|
|||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
|
||||
rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
|
||||
|
||||
|
||||
oamDmaSrc_ = oamDmaSrc;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ enum OamDmaSrc { OAM_DMA_SRC_ROM, OAM_DMA_SRC_SRAM, OAM_DMA_SRC_VRAM,
|
|||
class MemPtrs {
|
||||
const unsigned char *rmem_[0x10];
|
||||
unsigned char *wmem_[0x10];
|
||||
|
||||
|
||||
unsigned char *romdata_[2];
|
||||
unsigned char *wramdata_[2];
|
||||
unsigned char *vrambankptr_;
|
||||
|
@ -38,7 +38,7 @@ class MemPtrs {
|
|||
unsigned char *memchunk_;
|
||||
unsigned char *rambankdata_;
|
||||
unsigned char *wramdataend_;
|
||||
|
||||
|
||||
OamDmaSrc oamDmaSrc_;
|
||||
|
||||
unsigned curRomBank_;
|
||||
|
@ -54,11 +54,11 @@ class MemPtrs {
|
|||
unsigned char * wdisabledRam() const { return wramdataend_ + 0x2000; }
|
||||
public:
|
||||
enum RamFlag { READ_EN = 1, WRITE_EN = 2, RTC_EN = 4 };
|
||||
|
||||
|
||||
MemPtrs();
|
||||
~MemPtrs();
|
||||
void reset(unsigned rombanks, unsigned rambanks, unsigned wrambanks);
|
||||
|
||||
|
||||
const unsigned char * rmem(unsigned area) const { return rmem_[area]; }
|
||||
unsigned char * wmem(unsigned area) const { return wmem_[area]; }
|
||||
unsigned char * vramdata() const { return rambankdata_ - 0x4000; }
|
||||
|
|
|
@ -41,24 +41,24 @@ Rtc::Rtc()
|
|||
|
||||
void Rtc::doLatch() {
|
||||
std::uint32_t tmp = ((dataDh & 0x40) ? haltTime : timeCB()) - baseTime;
|
||||
|
||||
|
||||
while (tmp > 0x1FF * 86400) {
|
||||
baseTime += 0x1FF * 86400;
|
||||
tmp -= 0x1FF * 86400;
|
||||
dataDh |= 0x80;
|
||||
}
|
||||
|
||||
|
||||
dataDl = (tmp / 86400) & 0xFF;
|
||||
dataDh &= 0xFE;
|
||||
dataDh |= ((tmp / 86400) & 0x100) >> 8;
|
||||
tmp %= 86400;
|
||||
|
||||
|
||||
dataH = tmp / 3600;
|
||||
tmp %= 3600;
|
||||
|
||||
|
||||
dataM = tmp / 60;
|
||||
tmp %= 60;
|
||||
|
||||
|
||||
dataS = tmp;
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ void Rtc::loadState(const SaveState &state) {
|
|||
dataM = state.rtc.dataM;
|
||||
dataS = state.rtc.dataS;
|
||||
lastLatchData = state.rtc.lastLatchData;
|
||||
|
||||
|
||||
doSwapActive();
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ void Rtc::setDh(const unsigned new_dh) {
|
|||
const std::uint32_t old_highdays = ((unixtime - baseTime) / 86400) & 0x100;
|
||||
baseTime += old_highdays * 86400;
|
||||
baseTime -= ((new_dh & 0x1) << 8) * 86400;
|
||||
|
||||
|
||||
if ((dataDh ^ new_dh) & 0x40) {
|
||||
if (new_dh & 0x40)
|
||||
haltTime = timeCB();
|
||||
|
|
|
@ -41,7 +41,7 @@ private:
|
|||
bool enabled;
|
||||
bool lastLatchData;
|
||||
std::uint32_t (*timeCB)();
|
||||
|
||||
|
||||
void doLatch();
|
||||
void doSwapActive();
|
||||
void setDh(unsigned new_dh);
|
||||
|
@ -49,37 +49,37 @@ private:
|
|||
void setH(unsigned new_hours);
|
||||
void setM(unsigned new_minutes);
|
||||
void setS(unsigned new_seconds);
|
||||
|
||||
|
||||
public:
|
||||
Rtc();
|
||||
|
||||
|
||||
const unsigned char* getActive() const { return activeData; }
|
||||
std::uint32_t getBaseTime() const { return baseTime; }
|
||||
|
||||
|
||||
void setBaseTime(const std::uint32_t baseTime) {
|
||||
this->baseTime = baseTime;
|
||||
// doLatch();
|
||||
}
|
||||
|
||||
|
||||
void latch(const unsigned data) {
|
||||
if (!lastLatchData && data == 1)
|
||||
doLatch();
|
||||
|
||||
|
||||
lastLatchData = data;
|
||||
}
|
||||
|
||||
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
|
||||
void set(const bool enabled, unsigned bank) {
|
||||
bank &= 0xF;
|
||||
bank -= 8;
|
||||
|
||||
|
||||
this->enabled = enabled;
|
||||
this->index = bank;
|
||||
|
||||
|
||||
doSwapActive();
|
||||
}
|
||||
|
||||
|
||||
void write(const unsigned data) {
|
||||
// if (activeSet)
|
||||
(this->*activeSet)(data);
|
||||
|
|
|
@ -98,7 +98,7 @@ void Memory::loadState(const SaveState &state) {
|
|||
|
||||
intreq.setEventTime<BLIT>((ioamhram[0x140] & 0x80) ? display.nextMode1IrqTime() : state.cpu.cycleCounter);
|
||||
blanklcd = false;
|
||||
|
||||
|
||||
if (!isCgb())
|
||||
std::memset(cart.vramdata() + 0x2000, 0, 0x2000);
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ void Memory::loadState(const SaveState &state) {
|
|||
void Memory::setEndtime(const unsigned long cycleCounter, const unsigned long inc) {
|
||||
if (intreq.eventTime(BLIT) <= cycleCounter)
|
||||
intreq.setEventTime<BLIT>(intreq.eventTime(BLIT) + (70224 << isDoubleSpeed()));
|
||||
|
||||
|
||||
intreq.setEventTime<END>(cycleCounter + (inc << isDoubleSpeed()));
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
|
||||
while (cycleCounter >= intreq.minEventTime() && intreq.eventTime(END) != DISABLED_TIME)
|
||||
cycleCounter = event(cycleCounter);
|
||||
|
||||
|
||||
intreq.setEventTime<END>(DISABLED_TIME);
|
||||
|
||||
break;
|
||||
|
@ -173,17 +173,17 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
{
|
||||
const bool lcden = ioamhram[0x140] >> 7 & 1;
|
||||
unsigned long blitTime = intreq.eventTime(BLIT);
|
||||
|
||||
|
||||
if (lcden | blanklcd) {
|
||||
display.updateScreen(blanklcd, cycleCounter);
|
||||
intreq.setEventTime<BLIT>(DISABLED_TIME);
|
||||
intreq.setEventTime<END>(DISABLED_TIME);
|
||||
|
||||
|
||||
while (cycleCounter >= intreq.minEventTime())
|
||||
cycleCounter = event(cycleCounter);
|
||||
} else
|
||||
blitTime += 70224 << isDoubleSpeed();
|
||||
|
||||
|
||||
blanklcd = lcden ^ 1;
|
||||
intreq.setEventTime<BLIT>(blitTime);
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
unsigned dmaDest = dmaDestination;
|
||||
unsigned dmaLength = ((ioamhram[0x155] & 0x7F) + 0x1) * 0x10;
|
||||
unsigned length = hdmaReqFlagged(intreq) ? 0x10 : dmaLength;
|
||||
|
||||
|
||||
ackDmaReq(&intreq);
|
||||
|
||||
if ((static_cast<unsigned long>(dmaDest) + length) & 0x10000) {
|
||||
|
@ -255,7 +255,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
if ((ioamhram[0x155] & 0x80) && display.hdmaIsEnabled()) {
|
||||
if (lastOamDmaUpdate != DISABLED_TIME)
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
|
||||
display.disableHdma(cycleCounter);
|
||||
}
|
||||
}
|
||||
|
@ -275,11 +275,11 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
if (halted()) {
|
||||
if (gbIsCgb_ || (!gbIsCgb_ && cycleCounter <= halttime + 4))
|
||||
cycleCounter += 4;
|
||||
|
||||
|
||||
intreq.unhalt();
|
||||
intreq.setEventTime<UNHALT>(DISABLED_TIME);
|
||||
}
|
||||
|
||||
|
||||
if (ime()) {
|
||||
unsigned address;
|
||||
|
||||
|
@ -297,7 +297,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
cycleCounter += 4;
|
||||
display.update(cycleCounter);
|
||||
const unsigned n = pendingIrqs & -pendingIrqs;
|
||||
|
||||
|
||||
if (n == 0) {
|
||||
address = 0;
|
||||
}
|
||||
|
@ -306,11 +306,11 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
address = lut[n-1];
|
||||
} else
|
||||
address = 0x50 + n;
|
||||
|
||||
|
||||
intreq.ackIrq(n);
|
||||
PC = address;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -319,15 +319,15 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
|
||||
unsigned long Memory::stop(unsigned long cycleCounter) {
|
||||
cycleCounter += 4;
|
||||
|
||||
|
||||
if (ioamhram[0x14D] & isCgb()) {
|
||||
sound.generate_samples(cycleCounter, isDoubleSpeed());
|
||||
|
||||
|
||||
display.speedChange(cycleCounter);
|
||||
ioamhram[0x14D] ^= 0x81;
|
||||
|
||||
intreq.setEventTime<BLIT>((ioamhram[0x140] & 0x80) ? display.nextMode1IrqTime() : cycleCounter + (70224 << isDoubleSpeed()));
|
||||
|
||||
|
||||
if (intreq.eventTime(END) > cycleCounter) {
|
||||
intreq.setEventTime<END>(cycleCounter + (isDoubleSpeed() ?
|
||||
(intreq.eventTime(END) - cycleCounter) << 1 : (intreq.eventTime(END) - cycleCounter) >> 1));
|
||||
|
@ -381,7 +381,7 @@ unsigned long Memory::resetCounters(unsigned long cycleCounter) {
|
|||
decEventCycles(UNHALT, dec);
|
||||
|
||||
cycleCounter -= dec;
|
||||
|
||||
|
||||
intreq.resetCc(oldCC, cycleCounter);
|
||||
tima.resetCc(oldCC, cycleCounter, TimaInterruptRequester(intreq));
|
||||
display.resetCc(oldCC, cycleCounter);
|
||||
|
@ -453,7 +453,7 @@ const unsigned char * Memory::oamDmaSrcPtr() const {
|
|||
case OAM_DMA_SRC_INVALID:
|
||||
case OAM_DMA_SRC_OFF: break;
|
||||
}
|
||||
|
||||
|
||||
return ioamhram[0x146] == 0xFF && !isCgb() ? oamDmaSrcZero() : cart.rdisabledRam();
|
||||
}
|
||||
|
||||
|
@ -536,7 +536,7 @@ unsigned Memory::nontrivial_ff_read(const unsigned P, const unsigned long cycleC
|
|||
|
||||
static bool isInOamDmaConflictArea(const OamDmaSrc oamDmaSrc, const unsigned addr, const bool cgb) {
|
||||
struct Area { unsigned short areaUpper, exceptAreaLower, exceptAreaWidth, pad; };
|
||||
|
||||
|
||||
static const Area cgbAreas[] = {
|
||||
{ 0xC000, 0x8000, 0x2000, 0 },
|
||||
{ 0xC000, 0x8000, 0x2000, 0 },
|
||||
|
@ -545,7 +545,7 @@ static bool isInOamDmaConflictArea(const OamDmaSrc oamDmaSrc, const unsigned add
|
|||
{ 0xC000, 0x8000, 0x2000, 0 },
|
||||
{ 0x0000, 0x0000, 0x0000, 0 }
|
||||
};
|
||||
|
||||
|
||||
static const Area dmgAreas[] = {
|
||||
{ 0xFE00, 0x8000, 0x2000, 0 },
|
||||
{ 0xFE00, 0x8000, 0x2000, 0 },
|
||||
|
@ -554,7 +554,7 @@ static bool isInOamDmaConflictArea(const OamDmaSrc oamDmaSrc, const unsigned add
|
|||
{ 0xFE00, 0x8000, 0x2000, 0 },
|
||||
{ 0x0000, 0x0000, 0x0000, 0 }
|
||||
};
|
||||
|
||||
|
||||
const Area *const a = cgb ? cgbAreas : dmgAreas;
|
||||
|
||||
return addr < a[oamDmaSrc].areaUpper && addr - a[oamDmaSrc].exceptAreaLower >= a[oamDmaSrc].exceptAreaWidth;
|
||||
|
@ -564,7 +564,7 @@ unsigned Memory::nontrivial_read(const unsigned P, const unsigned long cycleCoun
|
|||
if (P < 0xFF80) {
|
||||
if (lastOamDmaUpdate != DISABLED_TIME) {
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
|
||||
if (isInOamDmaConflictArea(cart.oamDmaSrc(), P, isCgb()) && oamDmaPos < 0xA0)
|
||||
return ioamhram[oamDmaPos];
|
||||
}
|
||||
|
@ -830,7 +830,7 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned
|
|||
if ((ioamhram[0x140] ^ data) & 0x80) {
|
||||
const unsigned lyc = display.getStat(ioamhram[0x145], cycleCounter) & 4;
|
||||
const bool hdmaEnabled = display.hdmaIsEnabled();
|
||||
|
||||
|
||||
display.lcdcChange(data, cycleCounter);
|
||||
ioamhram[0x144] = 0;
|
||||
ioamhram[0x141] &= 0xF8;
|
||||
|
@ -1022,7 +1022,7 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned
|
|||
void Memory::nontrivial_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (lastOamDmaUpdate != DISABLED_TIME) {
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
|
||||
if (isInOamDmaConflictArea(cart.oamDmaSrc(), P, isCgb()) && oamDmaPos < 0xA0) {
|
||||
ioamhram[oamDmaPos] = data;
|
||||
return;
|
||||
|
|
|
@ -57,13 +57,13 @@ class Memory {
|
|||
unsigned (*getInput)();
|
||||
unsigned long divLastUpdate;
|
||||
unsigned long lastOamDmaUpdate;
|
||||
|
||||
|
||||
InterruptRequester intreq;
|
||||
Tima tima;
|
||||
LCD display;
|
||||
PSG sound;
|
||||
Interrupter interrupter;
|
||||
|
||||
|
||||
unsigned short dmaSource;
|
||||
unsigned short dmaDestination;
|
||||
unsigned char oamDmaPos;
|
||||
|
@ -80,24 +80,24 @@ class Memory {
|
|||
void startOamDma(unsigned long cycleCounter);
|
||||
void endOamDma(unsigned long cycleCounter);
|
||||
const unsigned char * oamDmaSrcPtr() const;
|
||||
|
||||
|
||||
unsigned nontrivial_ff_read(unsigned P, unsigned long cycleCounter);
|
||||
unsigned nontrivial_read(unsigned P, unsigned long cycleCounter);
|
||||
void nontrivial_ff_write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
void nontrivial_write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
|
||||
|
||||
unsigned nontrivial_peek(unsigned P);
|
||||
unsigned nontrivial_ff_peek(unsigned P);
|
||||
|
||||
void updateSerial(unsigned long cc);
|
||||
void updateTimaIrq(unsigned long cc);
|
||||
void updateIrqs(unsigned long cc);
|
||||
|
||||
|
||||
bool isDoubleSpeed() const { return display.isDoubleSpeed(); }
|
||||
|
||||
public:
|
||||
explicit Memory(const Interrupter &interrupter, unsigned short &sp, unsigned short &pc);
|
||||
|
||||
|
||||
bool loaded() const { return cart.loaded(); }
|
||||
unsigned curRomBank() const { return cart.curRomBank(); }
|
||||
const char * romTitle() const { return cart.romTitle(); }
|
||||
|
@ -124,9 +124,9 @@ public:
|
|||
unsigned long nextEventTime() const { return intreq.minEventTime(); }
|
||||
|
||||
void setLayers(unsigned mask) { display.setLayers(mask); }
|
||||
|
||||
|
||||
bool isActive() const { return intreq.eventTime(END) != DISABLED_TIME; }
|
||||
|
||||
|
||||
long cyclesSinceBlit(const unsigned long cc) const {
|
||||
return cc < intreq.eventTime(BLIT) ? -1 : static_cast<long>((cc - intreq.eventTime(BLIT)) >> isDoubleSpeed());
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ public:
|
|||
CDMapResult ret = { eCDLog_AddrType_ROM, P };
|
||||
return ret;
|
||||
}
|
||||
else if(P<0x8000)
|
||||
else if(P<0x8000)
|
||||
{
|
||||
unsigned bank = cart.rmem(P>>12) - cart.rmem(0);
|
||||
unsigned addr = P+bank;
|
||||
|
@ -187,7 +187,7 @@ public:
|
|||
return ret;
|
||||
}
|
||||
else if(P<0xFF80) {}
|
||||
else
|
||||
else
|
||||
{
|
||||
////this is just for debugging, really, it's pretty useless
|
||||
//CDMapResult ret = { eCDLog_AddrType_HRAM, (P-0xFF80) };
|
||||
|
@ -262,7 +262,7 @@ public:
|
|||
} else
|
||||
nontrivial_write(P, data, cycleCounter);
|
||||
}
|
||||
|
||||
|
||||
void write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (cart.wmem(P >> 12)) {
|
||||
cart.wmem(P >> 12)[P] = data;
|
||||
|
@ -277,7 +277,7 @@ public:
|
|||
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ff_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (P - 0xFF80u < 0x7Fu) {
|
||||
ioamhram[P - 0xFE00] = data;
|
||||
|
@ -329,14 +329,14 @@ public:
|
|||
|
||||
void setBasetime(unsigned long cc) { basetime = cc; }
|
||||
void setEndtime(unsigned long cc, unsigned long inc);
|
||||
|
||||
|
||||
void setSoundBuffer(uint_least32_t *const buf) { sound.setBuffer(buf); }
|
||||
unsigned fillSoundBuffer(unsigned long cc);
|
||||
|
||||
|
||||
void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
|
||||
display.setVideoBuffer(videoBuf, pitch);
|
||||
}
|
||||
|
||||
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32);
|
||||
void setCgbPalette(unsigned *lut);
|
||||
|
||||
|
|
|
@ -42,26 +42,26 @@ class MinKeeper {
|
|||
enum { LEVELS = MinKeeperUtil::CeiledLog2<ids>::R };
|
||||
template<int l> struct Num { enum { R = MinKeeperUtil::RoundedDiv2n<ids, LEVELS + 1 - l>::R }; };
|
||||
template<int l> struct Sum { enum { R = MinKeeperUtil::Sum<Num, l>::R }; };
|
||||
|
||||
|
||||
template<int id, int level>
|
||||
struct UpdateValue {
|
||||
enum { P = Sum<level-1>::R + id };
|
||||
enum { C0 = Sum<level>::R + id * 2 };
|
||||
|
||||
|
||||
static void updateValue(MinKeeper<ids> &m) {
|
||||
// GCC 4.3 generates better code with the ternary operator on i386.
|
||||
m.a[P] = (id * 2 + 1 == Num<level>::R || m.values[m.a[C0]] < m.values[m.a[C0 + 1]]) ? m.a[C0] : m.a[C0 + 1];
|
||||
UpdateValue<id / 2, level - 1>::updateValue(m);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<int id>
|
||||
struct UpdateValue<id,0> {
|
||||
static void updateValue(MinKeeper<ids> &m) {
|
||||
m.minValue_ = m.values[m.a[0]];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class UpdateValueLut {
|
||||
template<int id, int dummy> struct FillLut {
|
||||
static void fillLut(UpdateValueLut & l) {
|
||||
|
@ -69,42 +69,42 @@ class MinKeeper {
|
|||
FillLut<id-1,dummy>::fillLut(l);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<int dummy> struct FillLut<-1,dummy> {
|
||||
static void fillLut(UpdateValueLut &) {}
|
||||
};
|
||||
|
||||
|
||||
void (*lut_[Num<LEVELS-1>::R])(MinKeeper<ids>&);
|
||||
|
||||
|
||||
public:
|
||||
UpdateValueLut() { FillLut<Num<LEVELS-1>::R-1,0>::fillLut(*this); }
|
||||
void call(int id, MinKeeper<ids> &mk) const { lut_[id](mk); }
|
||||
};
|
||||
|
||||
|
||||
static UpdateValueLut updateValueLut;
|
||||
unsigned long values[ids];
|
||||
unsigned long minValue_;
|
||||
int a[Sum<LEVELS>::R];
|
||||
|
||||
|
||||
template<int id> static void updateValue(MinKeeper<ids> &m);
|
||||
|
||||
|
||||
public:
|
||||
explicit MinKeeper(unsigned long initValue = 0xFFFFFFFF);
|
||||
|
||||
|
||||
int min() const { return a[0]; }
|
||||
unsigned long minValue() const { return minValue_; }
|
||||
|
||||
|
||||
template<int id>
|
||||
void setValue(const unsigned long cnt) {
|
||||
values[id] = cnt;
|
||||
updateValue<id / 2>(*this);
|
||||
}
|
||||
|
||||
|
||||
void setValue(const int id, const unsigned long cnt) {
|
||||
values[id] = cnt;
|
||||
updateValueLut.call(id >> 1, *this);
|
||||
}
|
||||
|
||||
|
||||
unsigned long value(const int id) const { return values[id]; }
|
||||
|
||||
// not sure if i understood everything in minkeeper correctly, so something might be missing here?
|
||||
|
@ -122,28 +122,28 @@ template<int ids> typename MinKeeper<ids>::UpdateValueLut MinKeeper<ids>::update
|
|||
template<int ids>
|
||||
MinKeeper<ids>::MinKeeper(const unsigned long initValue) {
|
||||
std::fill(values, values + ids, initValue);
|
||||
|
||||
|
||||
for (int i = 0; i < Num<LEVELS-1>::R; ++i) {
|
||||
a[Sum<LEVELS-1>::R + i] = (i * 2 + 1 == ids || values[i * 2] < values[i * 2 + 1]) ? i * 2 : i * 2 + 1;
|
||||
}
|
||||
|
||||
|
||||
int n = Num<LEVELS-1>::R;
|
||||
int off = Sum<LEVELS-1>::R;
|
||||
|
||||
|
||||
while (off) {
|
||||
const int pn = (n + 1) >> 1;
|
||||
const int poff = off - pn;
|
||||
|
||||
|
||||
for (int i = 0; i < pn; ++i) {
|
||||
a[poff + i] = (i * 2 + 1 == n ||
|
||||
values[a[off + i * 2]] < values[a[off + i * 2 + 1]]) ?
|
||||
a[off + i * 2] : a[off + i * 2 + 1];
|
||||
}
|
||||
|
||||
|
||||
off = poff;
|
||||
n = pn;
|
||||
}
|
||||
|
||||
|
||||
minValue_ = values[a[0]];
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ public:
|
|||
virtual void ExitSection(const char *name);
|
||||
};
|
||||
|
||||
// defines and explicitly instantiates
|
||||
// defines and explicitly instantiates
|
||||
#define SYNCFUNC(x)\
|
||||
template void x::SyncState<false>(NewState *ns);\
|
||||
template void x::SyncState<true>(NewState *ns);\
|
||||
|
|
|
@ -30,13 +30,13 @@ struct SaveState {
|
|||
class Ptr {
|
||||
T *ptr;
|
||||
unsigned long sz;
|
||||
|
||||
|
||||
public:
|
||||
Ptr() : ptr(0), sz(0) {}
|
||||
const T* get() const { return ptr; }
|
||||
unsigned long getSz() const { return sz; }
|
||||
void set(T *ptr, const unsigned long sz) { this->ptr = ptr; this->sz = sz; }
|
||||
|
||||
|
||||
friend class SaverList;
|
||||
friend void setInitState(SaveState &, bool, bool, std::uint32_t, unsigned);
|
||||
};
|
||||
|
@ -55,7 +55,7 @@ struct SaveState {
|
|||
unsigned char L;
|
||||
bool skip;
|
||||
} cpu;
|
||||
|
||||
|
||||
struct Mem {
|
||||
Ptr<unsigned char> vram;
|
||||
Ptr<unsigned char> sram;
|
||||
|
@ -83,14 +83,14 @@ struct SaveState {
|
|||
bool agbMode;
|
||||
bool gbIsCgb;
|
||||
} mem;
|
||||
|
||||
|
||||
struct PPU {
|
||||
Ptr<unsigned char> bgpData;
|
||||
Ptr<unsigned char> objpData;
|
||||
//SpriteMapper::OamReader
|
||||
Ptr<unsigned char> oamReaderBuf;
|
||||
Ptr<bool> oamReaderSzbuf;
|
||||
|
||||
|
||||
unsigned long videoCycles;
|
||||
unsigned long enableDisplayM0Time;
|
||||
unsigned short lastM0Time;
|
||||
|
@ -119,24 +119,24 @@ struct SaveState {
|
|||
bool pendingLcdstatIrq;
|
||||
bool isCgb;
|
||||
} ppu;
|
||||
|
||||
|
||||
struct SPU {
|
||||
struct Duty {
|
||||
unsigned long nextPosUpdate;
|
||||
unsigned char nr3;
|
||||
unsigned char pos;
|
||||
};
|
||||
|
||||
|
||||
struct Env {
|
||||
unsigned long counter;
|
||||
unsigned char volume;
|
||||
};
|
||||
|
||||
|
||||
struct LCounter {
|
||||
unsigned long counter;
|
||||
unsigned short lengthCounter;
|
||||
};
|
||||
|
||||
|
||||
struct {
|
||||
struct {
|
||||
unsigned long counter;
|
||||
|
@ -150,7 +150,7 @@ struct SaveState {
|
|||
unsigned char nr4;
|
||||
bool master;
|
||||
} ch1;
|
||||
|
||||
|
||||
struct {
|
||||
Duty duty;
|
||||
Env env;
|
||||
|
@ -158,7 +158,7 @@ struct SaveState {
|
|||
unsigned char nr4;
|
||||
bool master;
|
||||
} ch2;
|
||||
|
||||
|
||||
struct {
|
||||
Ptr<unsigned char> waveRam;
|
||||
LCounter lcounter;
|
||||
|
@ -170,7 +170,7 @@ struct SaveState {
|
|||
unsigned char sampleBuf;
|
||||
bool master;
|
||||
} ch3;
|
||||
|
||||
|
||||
struct {
|
||||
struct {
|
||||
unsigned long counter;
|
||||
|
@ -181,10 +181,10 @@ struct SaveState {
|
|||
unsigned char nr4;
|
||||
bool master;
|
||||
} ch4;
|
||||
|
||||
|
||||
unsigned long cycleCounter;
|
||||
} spu;
|
||||
|
||||
|
||||
struct RTC {
|
||||
unsigned long baseTime;
|
||||
unsigned long haltTime;
|
||||
|
|
|
@ -75,7 +75,7 @@ void PSG::loadState(const SaveState &state) {
|
|||
ch2.loadState(state);
|
||||
ch3.loadState(state);
|
||||
ch4.loadState(state);
|
||||
|
||||
|
||||
lastUpdate = state.cpu.cycleCounter;
|
||||
set_so_volume(state.mem.ioamhram.get()[0x124]);
|
||||
map_so(state.mem.ioamhram.get()[0x125]);
|
||||
|
@ -84,7 +84,7 @@ void PSG::loadState(const SaveState &state) {
|
|||
|
||||
void PSG::accumulate_channels(const unsigned long cycles) {
|
||||
uint_least32_t *const buf = buffer + bufferPos;
|
||||
|
||||
|
||||
std::memset(buf, 0, cycles * sizeof *buf);
|
||||
ch1.update(buf, soVol, cycles);
|
||||
ch2.update(buf, soVol, cycles);
|
||||
|
@ -98,7 +98,7 @@ void PSG::generate_samples(const unsigned long cycleCounter, const unsigned doub
|
|||
|
||||
if (cycles)
|
||||
accumulate_channels(cycles);
|
||||
|
||||
|
||||
bufferPos += cycles;
|
||||
}
|
||||
|
||||
|
@ -111,10 +111,10 @@ unsigned PSG::fillBuffer() {
|
|||
uint_least32_t sum = rsum;
|
||||
uint_least32_t *b = buffer;
|
||||
unsigned n = bufferPos;
|
||||
|
||||
|
||||
if (unsigned n2 = n >> 3) {
|
||||
n -= n2 << 3;
|
||||
|
||||
|
||||
do {
|
||||
sum += b[0];
|
||||
b[0] = sum ^ 0x8000;
|
||||
|
@ -132,18 +132,18 @@ unsigned PSG::fillBuffer() {
|
|||
b[6] = sum ^ 0x8000;
|
||||
sum += b[7];
|
||||
b[7] = sum ^ 0x8000;
|
||||
|
||||
|
||||
b += 8;
|
||||
} while (--n2);
|
||||
}
|
||||
|
||||
|
||||
while (n--) {
|
||||
sum += *b;
|
||||
*b++ = sum ^ 0x8000; // xor away the initial rsum value of 0x8000 (which prevents borrows from the high word) from the low word
|
||||
}
|
||||
|
||||
|
||||
rsum = sum;
|
||||
|
||||
|
||||
return bufferPos;
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ void PSG::set_so_volume(const unsigned nr50) {
|
|||
|
||||
void PSG::map_so(const unsigned nr51) {
|
||||
const unsigned long tmp = nr51 * so1Mul + (nr51 >> 4) * so2Mul;
|
||||
|
||||
|
||||
ch1.setSo((tmp & 0x00010001) * 0xFFFF);
|
||||
ch2.setSo((tmp >> 1 & 0x00010001) * 0xFFFF);
|
||||
ch3.setSo((tmp >> 2 & 0x00010001) * 0xFFFF);
|
||||
|
|
|
@ -32,16 +32,16 @@ class PSG {
|
|||
Channel2 ch2;
|
||||
Channel3 ch3;
|
||||
Channel4 ch4;
|
||||
|
||||
|
||||
uint_least32_t *buffer;
|
||||
|
||||
|
||||
unsigned long lastUpdate;
|
||||
unsigned long soVol;
|
||||
|
||||
|
||||
uint_least32_t rsum;
|
||||
|
||||
|
||||
unsigned bufferPos;
|
||||
|
||||
|
||||
bool enabled;
|
||||
|
||||
void accumulate_channels(unsigned long cycles);
|
||||
|
@ -57,7 +57,7 @@ public:
|
|||
void resetCounter(unsigned long newCc, unsigned long oldCc, unsigned doubleSpeed);
|
||||
unsigned fillBuffer();
|
||||
void setBuffer(uint_least32_t *const buf) { buffer = buf; bufferPos = 0; }
|
||||
|
||||
|
||||
bool isEnabled() const { return enabled; }
|
||||
void setEnabled(bool value) { enabled = value; }
|
||||
|
||||
|
|
|
@ -33,31 +33,31 @@ Channel1::SweepUnit::SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit) :
|
|||
|
||||
unsigned Channel1::SweepUnit::calcFreq() {
|
||||
unsigned freq = shadow >> (nr0 & 0x07);
|
||||
|
||||
|
||||
if (nr0 & 0x08) {
|
||||
freq = shadow - freq;
|
||||
negging = true;
|
||||
} else
|
||||
freq = shadow + freq;
|
||||
|
||||
|
||||
if (freq & 2048)
|
||||
disableMaster();
|
||||
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::event() {
|
||||
const unsigned long period = nr0 >> 4 & 0x07;
|
||||
|
||||
|
||||
if (period) {
|
||||
const unsigned freq = calcFreq();
|
||||
|
||||
|
||||
if (!(freq & 2048) && (nr0 & 0x07)) {
|
||||
shadow = freq;
|
||||
dutyUnit.setFreq(freq, counter);
|
||||
calcFreq();
|
||||
}
|
||||
|
||||
|
||||
counter += period << 14;
|
||||
} else
|
||||
counter += 8ul << 14;
|
||||
|
@ -66,22 +66,22 @@ void Channel1::SweepUnit::event() {
|
|||
void Channel1::SweepUnit::nr0Change(const unsigned newNr0) {
|
||||
if (negging && !(newNr0 & 0x08))
|
||||
disableMaster();
|
||||
|
||||
|
||||
nr0 = newNr0;
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::nr4Init(const unsigned long cc) {
|
||||
negging = false;
|
||||
shadow = dutyUnit.getFreq();
|
||||
|
||||
|
||||
const unsigned period = nr0 >> 4 & 0x07;
|
||||
const unsigned shift = nr0 & 0x07;
|
||||
|
||||
|
||||
if (period | shift)
|
||||
counter = ((cc >> 14) + (period ? period : 8)) << 14;
|
||||
else
|
||||
counter = COUNTER_DISABLED;
|
||||
|
||||
|
||||
if (shift)
|
||||
calcFreq();
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ void Channel1::setNr0(const unsigned data) {
|
|||
void Channel1::setNr1(const unsigned data) {
|
||||
lengthCounter.nr1Change(data, nr4, cycleCounter);
|
||||
dutyUnit.nr1Change(data, cycleCounter);
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ void Channel1::setNr2(const unsigned data) {
|
|||
disableMaster();
|
||||
else
|
||||
staticOutputTest(cycleCounter);
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
|
@ -159,18 +159,18 @@ void Channel1::setNr3(const unsigned data) {
|
|||
|
||||
void Channel1::setNr4(const unsigned data) {
|
||||
lengthCounter.nr4Change(nr4, data, cycleCounter);
|
||||
|
||||
|
||||
nr4 = data;
|
||||
|
||||
|
||||
dutyUnit.nr4Change(data, cycleCounter);
|
||||
|
||||
|
||||
if (data & 0x80) { //init-bit
|
||||
nr4 &= 0x7F;
|
||||
master = !envelopeUnit.nr4Init(cycleCounter);
|
||||
sweepUnit.nr4Init(cycleCounter);
|
||||
staticOutputTest(cycleCounter);
|
||||
}
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ void Channel1::reset() {
|
|||
dutyUnit.reset();
|
||||
envelopeUnit.reset();
|
||||
sweepUnit.reset();
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ void Channel1::loadState(const SaveState &state) {
|
|||
dutyUnit.loadState(state.spu.ch1.duty, state.mem.ioamhram.get()[0x111], state.spu.ch1.nr4, state.spu.cycleCounter);
|
||||
envelopeUnit.loadState(state.spu.ch1.env, state.mem.ioamhram.get()[0x112], state.spu.cycleCounter);
|
||||
lengthCounter.loadState(state.spu.ch1.lcounter, state.spu.cycleCounter);
|
||||
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
nr4 = state.spu.ch1.nr4;
|
||||
master = state.spu.ch1.master;
|
||||
|
@ -210,42 +210,42 @@ void Channel1::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign
|
|||
const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0;
|
||||
const unsigned long outLow = outBase * (0 - 15ul);
|
||||
const unsigned long endCycles = cycleCounter + cycles;
|
||||
|
||||
|
||||
for (;;) {
|
||||
const unsigned long outHigh = master ? outBase * (envelopeUnit.getVolume() * 2 - 15ul) : outLow;
|
||||
const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles;
|
||||
unsigned long out = dutyUnit.isHighState() ? outHigh : outLow;
|
||||
|
||||
|
||||
while (dutyUnit.getCounter() <= nextMajorEvent) {
|
||||
*buf = out - prevOut;
|
||||
prevOut = out;
|
||||
buf += dutyUnit.getCounter() - cycleCounter;
|
||||
cycleCounter = dutyUnit.getCounter();
|
||||
|
||||
|
||||
dutyUnit.event();
|
||||
out = dutyUnit.isHighState() ? outHigh : outLow;
|
||||
}
|
||||
|
||||
|
||||
if (cycleCounter < nextMajorEvent) {
|
||||
*buf = out - prevOut;
|
||||
prevOut = out;
|
||||
buf += nextMajorEvent - cycleCounter;
|
||||
cycleCounter = nextMajorEvent;
|
||||
}
|
||||
|
||||
|
||||
if (nextEventUnit->getCounter() == nextMajorEvent) {
|
||||
nextEventUnit->event();
|
||||
setEvent();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (cycleCounter & SoundUnit::COUNTER_MAX) {
|
||||
dutyUnit.resetCounters(cycleCounter);
|
||||
lengthCounter.resetCounters(cycleCounter);
|
||||
envelopeUnit.resetCounters(cycleCounter);
|
||||
sweepUnit.resetCounters(cycleCounter);
|
||||
|
||||
|
||||
cycleCounter -= SoundUnit::COUNTER_MAX;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,9 +38,9 @@ class Channel1 {
|
|||
unsigned short shadow;
|
||||
unsigned char nr0;
|
||||
bool negging;
|
||||
|
||||
|
||||
unsigned calcFreq();
|
||||
|
||||
|
||||
public:
|
||||
SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit);
|
||||
void event();
|
||||
|
@ -51,27 +51,27 @@ class Channel1 {
|
|||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
|
||||
friend class StaticOutputTester<Channel1,DutyUnit>;
|
||||
|
||||
|
||||
StaticOutputTester<Channel1,DutyUnit> staticOutputTest;
|
||||
DutyMasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
DutyUnit dutyUnit;
|
||||
EnvelopeUnit envelopeUnit;
|
||||
SweepUnit sweepUnit;
|
||||
|
||||
|
||||
SoundUnit *nextEventUnit;
|
||||
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
|
||||
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
|
||||
|
||||
void setEvent();
|
||||
|
||||
|
||||
public:
|
||||
Channel1();
|
||||
void setNr0(unsigned data);
|
||||
|
@ -79,12 +79,12 @@ public:
|
|||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data);
|
||||
void setNr4(unsigned data);
|
||||
|
||||
|
||||
void setSo(unsigned long soMask);
|
||||
bool isActive() const { return master; }
|
||||
|
||||
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void loadState(const SaveState &state);
|
||||
|
|
|
@ -46,7 +46,7 @@ void Channel2::setEvent() {
|
|||
void Channel2::setNr1(const unsigned data) {
|
||||
lengthCounter.nr1Change(data, nr4, cycleCounter);
|
||||
dutyUnit.nr1Change(data, cycleCounter);
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ void Channel2::setNr2(const unsigned data) {
|
|||
disableMaster();
|
||||
else
|
||||
staticOutputTest(cycleCounter);
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
|
@ -66,17 +66,17 @@ void Channel2::setNr3(const unsigned data) {
|
|||
|
||||
void Channel2::setNr4(const unsigned data) {
|
||||
lengthCounter.nr4Change(nr4, data, cycleCounter);
|
||||
|
||||
|
||||
nr4 = data;
|
||||
|
||||
|
||||
if (data & 0x80) { //init-bit
|
||||
nr4 &= 0x7F;
|
||||
master = !envelopeUnit.nr4Init(cycleCounter);
|
||||
staticOutputTest(cycleCounter);
|
||||
}
|
||||
|
||||
|
||||
dutyUnit.nr4Change(data, cycleCounter);
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
|
@ -88,11 +88,11 @@ void Channel2::setSo(const unsigned long soMask) {
|
|||
|
||||
void Channel2::reset() {
|
||||
cycleCounter = 0x1000 | (cycleCounter & 0xFFF); // cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
|
||||
|
||||
// lengthCounter.reset();
|
||||
dutyUnit.reset();
|
||||
envelopeUnit.reset();
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ void Channel2::loadState(const SaveState &state) {
|
|||
dutyUnit.loadState(state.spu.ch2.duty, state.mem.ioamhram.get()[0x116], state.spu.ch2.nr4,state.spu.cycleCounter);
|
||||
envelopeUnit.loadState(state.spu.ch2.env, state.mem.ioamhram.get()[0x117], state.spu.cycleCounter);
|
||||
lengthCounter.loadState(state.spu.ch2.lcounter, state.spu.cycleCounter);
|
||||
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
nr4 = state.spu.ch2.nr4;
|
||||
master = state.spu.ch2.master;
|
||||
|
@ -114,41 +114,41 @@ void Channel2::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign
|
|||
const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0;
|
||||
const unsigned long outLow = outBase * (0 - 15ul);
|
||||
const unsigned long endCycles = cycleCounter + cycles;
|
||||
|
||||
|
||||
for (;;) {
|
||||
const unsigned long outHigh = master ? outBase * (envelopeUnit.getVolume() * 2 - 15ul) : outLow;
|
||||
const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles;
|
||||
unsigned long out = dutyUnit.isHighState() ? outHigh : outLow;
|
||||
|
||||
|
||||
while (dutyUnit.getCounter() <= nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += dutyUnit.getCounter() - cycleCounter;
|
||||
cycleCounter = dutyUnit.getCounter();
|
||||
|
||||
|
||||
dutyUnit.event();
|
||||
out = dutyUnit.isHighState() ? outHigh : outLow;
|
||||
}
|
||||
|
||||
|
||||
if (cycleCounter < nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += nextMajorEvent - cycleCounter;
|
||||
cycleCounter = nextMajorEvent;
|
||||
}
|
||||
|
||||
|
||||
if (nextEventUnit->getCounter() == nextMajorEvent) {
|
||||
nextEventUnit->event();
|
||||
setEvent();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (cycleCounter & SoundUnit::COUNTER_MAX) {
|
||||
dutyUnit.resetCounters(cycleCounter);
|
||||
lengthCounter.resetCounters(cycleCounter);
|
||||
envelopeUnit.resetCounters(cycleCounter);
|
||||
|
||||
|
||||
cycleCounter -= SoundUnit::COUNTER_MAX;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,37 +32,37 @@ struct SaveState;
|
|||
|
||||
class Channel2 {
|
||||
friend class StaticOutputTester<Channel2,DutyUnit>;
|
||||
|
||||
|
||||
StaticOutputTester<Channel2,DutyUnit> staticOutputTest;
|
||||
DutyMasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
DutyUnit dutyUnit;
|
||||
EnvelopeUnit envelopeUnit;
|
||||
|
||||
|
||||
SoundUnit *nextEventUnit;
|
||||
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
|
||||
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
|
||||
|
||||
void setEvent();
|
||||
|
||||
|
||||
public:
|
||||
Channel2();
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data);
|
||||
void setNr4(unsigned data);
|
||||
|
||||
|
||||
void setSo(unsigned long soMask);
|
||||
// void deactivate() { disableMaster(); setEvent(); }
|
||||
bool isActive() const { return master; }
|
||||
|
||||
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void loadState(const SaveState &state);
|
||||
|
|
|
@ -47,33 +47,33 @@ Channel3::Channel3() :
|
|||
|
||||
void Channel3::setNr0(const unsigned data) {
|
||||
nr0 = data & 0x80;
|
||||
|
||||
|
||||
if (!(data & 0x80))
|
||||
disableMaster();
|
||||
}
|
||||
|
||||
void Channel3::setNr2(const unsigned data) {
|
||||
rShift = (data >> 5 & 3U) - 1;
|
||||
|
||||
|
||||
if (rShift > 3)
|
||||
rShift = 4;
|
||||
}
|
||||
|
||||
void Channel3::setNr4(const unsigned data) {
|
||||
lengthCounter.nr4Change(nr4, data, cycleCounter);
|
||||
|
||||
|
||||
nr4 = data & 0x7F;
|
||||
|
||||
|
||||
if (data & nr0/* & 0x80*/) {
|
||||
if (!cgb && waveCounter == cycleCounter + 1) {
|
||||
const unsigned pos = ((wavePos + 1) & 0x1F) >> 1;
|
||||
|
||||
|
||||
if (pos < 4)
|
||||
waveRam[0] = waveRam[pos];
|
||||
else
|
||||
std::memcpy(waveRam, waveRam + (pos & ~3), 4);
|
||||
}
|
||||
|
||||
|
||||
master = true;
|
||||
wavePos = 0;
|
||||
lastReadTime = waveCounter = cycleCounter + toPeriod(nr3, data) + 3;
|
||||
|
@ -102,7 +102,7 @@ void Channel3::setStatePtrs(SaveState &state) {
|
|||
|
||||
void Channel3::loadState(const SaveState &state) {
|
||||
lengthCounter.loadState(state.spu.ch3.lcounter, state.spu.cycleCounter);
|
||||
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
waveCounter = std::max(state.spu.ch3.waveCounter, state.spu.cycleCounter);
|
||||
lastReadTime = state.spu.ch3.lastReadTime;
|
||||
|
@ -111,7 +111,7 @@ void Channel3::loadState(const SaveState &state) {
|
|||
wavePos = state.spu.ch3.wavePos & 0x1F;
|
||||
sampleBuf = state.spu.ch3.sampleBuf;
|
||||
master = state.spu.ch3.master;
|
||||
|
||||
|
||||
nr0 = state.mem.ioamhram.get()[0x11A] & 0x80;
|
||||
setNr2(state.mem.ioamhram.get()[0x11C]);
|
||||
}
|
||||
|
@ -133,20 +133,20 @@ void Channel3::updateWaveCounter(const unsigned long cc) {
|
|||
|
||||
void Channel3::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) {
|
||||
const unsigned long outBase = (nr0/* & 0x80*/) ? soBaseVol & soMask : 0;
|
||||
|
||||
|
||||
if (outBase && rShift != 4) {
|
||||
const unsigned long endCycles = cycleCounter + cycles;
|
||||
|
||||
|
||||
for (;;) {
|
||||
const unsigned long nextMajorEvent = lengthCounter.getCounter() < endCycles ? lengthCounter.getCounter() : endCycles;
|
||||
unsigned long out = outBase * (master ? ((sampleBuf >> (~wavePos << 2 & 4) & 0xF) >> rShift) * 2 - 15ul : 0 - 15ul);
|
||||
|
||||
|
||||
while (waveCounter <= nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += waveCounter - cycleCounter;
|
||||
cycleCounter = waveCounter;
|
||||
|
||||
|
||||
lastReadTime = waveCounter;
|
||||
waveCounter += toPeriod(nr3, nr4);
|
||||
++wavePos;
|
||||
|
@ -154,14 +154,14 @@ void Channel3::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign
|
|||
sampleBuf = waveRam[wavePos >> 1];
|
||||
out = outBase * (/*master ? */((sampleBuf >> (~wavePos << 2 & 4) & 0xF) >> rShift) * 2 - 15ul/* : 0 - 15ul*/);
|
||||
}
|
||||
|
||||
|
||||
if (cycleCounter < nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += nextMajorEvent - cycleCounter;
|
||||
cycleCounter = nextMajorEvent;
|
||||
}
|
||||
|
||||
|
||||
if (lengthCounter.getCounter() == nextMajorEvent) {
|
||||
lengthCounter.event();
|
||||
} else
|
||||
|
@ -171,23 +171,23 @@ void Channel3::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign
|
|||
const unsigned long out = outBase * (0 - 15ul);
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
|
||||
|
||||
cycleCounter += cycles;
|
||||
|
||||
|
||||
while (lengthCounter.getCounter() <= cycleCounter) {
|
||||
updateWaveCounter(lengthCounter.getCounter());
|
||||
lengthCounter.event();
|
||||
}
|
||||
|
||||
|
||||
updateWaveCounter(cycleCounter);
|
||||
}
|
||||
|
||||
|
||||
if (cycleCounter & SoundUnit::COUNTER_MAX) {
|
||||
lengthCounter.resetCounters(cycleCounter);
|
||||
|
||||
|
||||
if (waveCounter != SoundUnit::COUNTER_DISABLED)
|
||||
waveCounter -= SoundUnit::COUNTER_MAX;
|
||||
|
||||
|
||||
lastReadTime -= SoundUnit::COUNTER_MAX;
|
||||
cycleCounter -= SoundUnit::COUNTER_MAX;
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ void Channel3::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign
|
|||
SYNCFUNC(Channel3)
|
||||
{
|
||||
NSS(waveRam);
|
||||
|
||||
|
||||
SSS(lengthCounter);
|
||||
|
||||
NSS(cycleCounter);
|
||||
|
|
|
@ -31,35 +31,35 @@ struct SaveState;
|
|||
class Channel3 {
|
||||
class Ch3MasterDisabler : public MasterDisabler {
|
||||
unsigned long &waveCounter;
|
||||
|
||||
|
||||
public:
|
||||
Ch3MasterDisabler(bool &m, unsigned long &wC) : MasterDisabler(m), waveCounter(wC) {}
|
||||
void operator()() { MasterDisabler::operator()(); waveCounter = SoundUnit::COUNTER_DISABLED; }
|
||||
};
|
||||
|
||||
|
||||
unsigned char waveRam[0x10];
|
||||
|
||||
|
||||
Ch3MasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
unsigned long waveCounter;
|
||||
unsigned long lastReadTime;
|
||||
|
||||
|
||||
unsigned char nr0;
|
||||
unsigned char nr3;
|
||||
unsigned char nr4;
|
||||
unsigned char wavePos;
|
||||
unsigned char rShift;
|
||||
unsigned char sampleBuf;
|
||||
|
||||
|
||||
bool master;
|
||||
bool cgb;
|
||||
|
||||
|
||||
void updateWaveCounter(unsigned long cc);
|
||||
|
||||
|
||||
public:
|
||||
Channel3();
|
||||
bool isActive() const { return master; }
|
||||
|
@ -74,26 +74,26 @@ public:
|
|||
void setNr4(unsigned data);
|
||||
void setSo(unsigned long soMask);
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
|
||||
unsigned waveRamRead(unsigned index) const {
|
||||
if (master) {
|
||||
if (!cgb && cycleCounter != lastReadTime)
|
||||
return 0xFF;
|
||||
|
||||
|
||||
index = wavePos >> 1;
|
||||
}
|
||||
|
||||
|
||||
return waveRam[index];
|
||||
}
|
||||
|
||||
|
||||
void waveRamWrite(unsigned index, unsigned data) {
|
||||
if (master) {
|
||||
if (!cgb && cycleCounter != lastReadTime)
|
||||
return;
|
||||
|
||||
|
||||
index = wavePos >> 1;
|
||||
}
|
||||
|
||||
|
||||
waveRam[index] = data;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
static unsigned long toPeriod(const unsigned nr3) {
|
||||
unsigned s = (nr3 >> 4) + 3;
|
||||
unsigned r = nr3 & 7;
|
||||
|
||||
|
||||
if (!r) {
|
||||
r = 1;
|
||||
--s;
|
||||
}
|
||||
|
||||
|
||||
return r << s;
|
||||
}
|
||||
|
||||
|
@ -46,13 +46,13 @@ void Channel4::Lfsr::updateBackupCounter(const unsigned long cc) {
|
|||
const unsigned long period = toPeriod(nr3);
|
||||
backupCounter = cc - (cc - backupCounter) % period + period;
|
||||
}*/
|
||||
|
||||
|
||||
if (backupCounter <= cc) {
|
||||
const unsigned long period = toPeriod(nr3);
|
||||
unsigned long periods = (cc - backupCounter) / period + 1;
|
||||
|
||||
|
||||
backupCounter += periods * period;
|
||||
|
||||
|
||||
if (master && nr3 < 0xE0) {
|
||||
if (nr3 & 8) {
|
||||
while (periods > 6) {
|
||||
|
@ -60,7 +60,7 @@ void Channel4::Lfsr::updateBackupCounter(const unsigned long cc) {
|
|||
reg = (reg >> 6 & ~0x7E) | xored | xored << 8;
|
||||
periods -= 6;
|
||||
}
|
||||
|
||||
|
||||
const unsigned xored = ((reg ^ reg >> 1) << (7 - periods)) & 0x7F;
|
||||
reg = (reg >> periods & ~(0x80 - (0x80 >> periods))) | xored | xored << 8;
|
||||
} else {
|
||||
|
@ -68,7 +68,7 @@ void Channel4::Lfsr::updateBackupCounter(const unsigned long cc) {
|
|||
reg = reg ^ reg >> 1;
|
||||
periods -= 15;
|
||||
}
|
||||
|
||||
|
||||
reg = reg >> periods | (((reg ^ reg >> 1) << (15 - periods)) & 0x7FFF);
|
||||
}
|
||||
}
|
||||
|
@ -95,27 +95,27 @@ inline void Channel4::Lfsr::event() {
|
|||
if (nr3 < 0xE0) {
|
||||
const unsigned shifted = reg >> 1;
|
||||
const unsigned xored = (reg ^ shifted) & 1;
|
||||
|
||||
|
||||
reg = shifted | xored << 14;
|
||||
|
||||
|
||||
if (nr3 & 8)
|
||||
reg = (reg & ~0x40) | xored << 6;
|
||||
}
|
||||
|
||||
|
||||
counter += toPeriod(nr3);
|
||||
backupCounter = counter;
|
||||
|
||||
|
||||
|
||||
|
||||
/*if (nr3 < 0xE0) {
|
||||
const unsigned periods = nextStateDistance[reg & 0x3F];
|
||||
const unsigned xored = ((reg ^ reg >> 1) << (7 - periods)) & 0x7F;
|
||||
|
||||
|
||||
reg = reg >> periods | xored << 8;
|
||||
|
||||
|
||||
if (nr3 & 8)
|
||||
reg = reg & ~(0x80 - (0x80 >> periods)) | xored;
|
||||
}
|
||||
|
||||
|
||||
const unsigned long period = toPeriod(nr3);
|
||||
backupCounter = counter + period;
|
||||
counter += period * nextStateDistance[reg & 0x3F];*/
|
||||
|
@ -124,7 +124,7 @@ inline void Channel4::Lfsr::event() {
|
|||
void Channel4::Lfsr::nr3Change(const unsigned newNr3, const unsigned long cc) {
|
||||
updateBackupCounter(cc);
|
||||
nr3 = newNr3;
|
||||
|
||||
|
||||
// if (counter != COUNTER_DISABLED)
|
||||
// counter = backupCounter + toPeriod(nr3) * (nextStateDistance[reg & 0x3F] - 1);
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ void Channel4::setEvent() {
|
|||
|
||||
void Channel4::setNr1(const unsigned data) {
|
||||
lengthCounter.nr1Change(data, nr4, cycleCounter);
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
|
@ -200,26 +200,26 @@ void Channel4::setNr2(const unsigned data) {
|
|||
disableMaster();
|
||||
else
|
||||
staticOutputTest(cycleCounter);
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::setNr4(const unsigned data) {
|
||||
lengthCounter.nr4Change(nr4, data, cycleCounter);
|
||||
|
||||
|
||||
nr4 = data;
|
||||
|
||||
|
||||
if (data & 0x80) { //init-bit
|
||||
nr4 &= 0x7F;
|
||||
|
||||
|
||||
master = !envelopeUnit.nr4Init(cycleCounter);
|
||||
|
||||
|
||||
if (master)
|
||||
lfsr.nr4Init(cycleCounter);
|
||||
|
||||
|
||||
staticOutputTest(cycleCounter);
|
||||
}
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,7 @@ void Channel4::reset() {
|
|||
// lengthCounter.reset();
|
||||
lfsr.reset(cycleCounter);
|
||||
envelopeUnit.reset();
|
||||
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
|
@ -247,7 +247,7 @@ void Channel4::loadState(const SaveState &state) {
|
|||
lfsr.loadState(state);
|
||||
envelopeUnit.loadState(state.spu.ch4.env, state.mem.ioamhram.get()[0x121], state.spu.cycleCounter);
|
||||
lengthCounter.loadState(state.spu.ch4.lcounter, state.spu.cycleCounter);
|
||||
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
nr4 = state.spu.ch4.nr4;
|
||||
master = state.spu.ch4.master;
|
||||
|
@ -257,41 +257,41 @@ void Channel4::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign
|
|||
const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0;
|
||||
const unsigned long outLow = outBase * (0 - 15ul);
|
||||
const unsigned long endCycles = cycleCounter + cycles;
|
||||
|
||||
|
||||
for (;;) {
|
||||
const unsigned long outHigh = /*master ? */outBase * (envelopeUnit.getVolume() * 2 - 15ul)/* : outLow*/;
|
||||
const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles;
|
||||
unsigned long out = lfsr.isHighState() ? outHigh : outLow;
|
||||
|
||||
|
||||
while (lfsr.getCounter() <= nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += lfsr.getCounter() - cycleCounter;
|
||||
cycleCounter = lfsr.getCounter();
|
||||
|
||||
|
||||
lfsr.event();
|
||||
out = lfsr.isHighState() ? outHigh : outLow;
|
||||
}
|
||||
|
||||
|
||||
if (cycleCounter < nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += nextMajorEvent - cycleCounter;
|
||||
cycleCounter = nextMajorEvent;
|
||||
}
|
||||
|
||||
|
||||
if (nextEventUnit->getCounter() == nextMajorEvent) {
|
||||
nextEventUnit->event();
|
||||
setEvent();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (cycleCounter & SoundUnit::COUNTER_MAX) {
|
||||
lengthCounter.resetCounters(cycleCounter);
|
||||
lfsr.resetCounters(cycleCounter);
|
||||
envelopeUnit.resetCounters(cycleCounter);
|
||||
|
||||
|
||||
cycleCounter -= SoundUnit::COUNTER_MAX;
|
||||
}
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ SYNCFUNC(Channel4)
|
|||
NSS(cycleCounter);
|
||||
NSS(soMask);
|
||||
NSS(prevOut);
|
||||
|
||||
|
||||
NSS(nr4);
|
||||
NSS(master);
|
||||
}
|
||||
|
|
|
@ -36,9 +36,9 @@ class Channel4 {
|
|||
unsigned short reg;
|
||||
unsigned char nr3;
|
||||
bool master;
|
||||
|
||||
|
||||
void updateBackupCounter(unsigned long cc);
|
||||
|
||||
|
||||
public:
|
||||
Lfsr();
|
||||
void event();
|
||||
|
@ -54,45 +54,45 @@ class Channel4 {
|
|||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
|
||||
class Ch4MasterDisabler : public MasterDisabler {
|
||||
Lfsr &lfsr;
|
||||
public:
|
||||
Ch4MasterDisabler(bool &m, Lfsr &lfsr) : MasterDisabler(m), lfsr(lfsr) {}
|
||||
void operator()() { MasterDisabler::operator()(); lfsr.disableMaster(); }
|
||||
};
|
||||
|
||||
|
||||
friend class StaticOutputTester<Channel4,Lfsr>;
|
||||
|
||||
|
||||
StaticOutputTester<Channel4,Lfsr> staticOutputTest;
|
||||
Ch4MasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
EnvelopeUnit envelopeUnit;
|
||||
Lfsr lfsr;
|
||||
|
||||
|
||||
SoundUnit *nextEventUnit;
|
||||
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
|
||||
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
|
||||
|
||||
void setEvent();
|
||||
|
||||
|
||||
public:
|
||||
Channel4();
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data) { lfsr.nr3Change(data, cycleCounter); /*setEvent();*/ }
|
||||
void setNr4(unsigned data);
|
||||
|
||||
|
||||
void setSo(unsigned long soMask);
|
||||
bool isActive() const { return master; }
|
||||
|
||||
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void loadState(const SaveState &state);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
static inline bool toOutState(const unsigned duty, const unsigned pos) {
|
||||
static const unsigned char duties[4] = { 0x80, 0x81, 0xE1, 0x7E };
|
||||
|
||||
|
||||
return duties[duty] >> pos & 1;
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ void DutyUnit::setCounter() {
|
|||
0, 3, 2, 1, 0, 3, 2, 1,
|
||||
0, 5, 4, 3, 2, 1, 0, 1
|
||||
};
|
||||
|
||||
|
||||
if (enableEvents && nextPosUpdate != COUNTER_DISABLED)
|
||||
counter = nextPosUpdate + period * nextStateDistance[(duty * 8) | pos];
|
||||
else
|
||||
|
@ -67,13 +67,13 @@ void DutyUnit::setFreq(const unsigned newFreq, const unsigned long cc) {
|
|||
|
||||
void DutyUnit::event() {
|
||||
unsigned inc = period << duty;
|
||||
|
||||
|
||||
if (duty == 3)
|
||||
inc -= period * 2;
|
||||
|
||||
|
||||
if (!(high ^= true))
|
||||
inc = period * 8 - inc;
|
||||
|
||||
|
||||
counter += inc;
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ void DutyUnit::nr3Change(const unsigned newNr3, const unsigned long cc) {
|
|||
|
||||
void DutyUnit::nr4Change(const unsigned newNr4, const unsigned long cc) {
|
||||
setFreq((newNr4 << 8 & 0x700) | (getFreq() & 0xFF), cc);
|
||||
|
||||
|
||||
if (newNr4 & 0x80) {
|
||||
nextPosUpdate = (cc & ~1) + period;
|
||||
setCounter();
|
||||
|
@ -124,7 +124,7 @@ void DutyUnit::loadState(const SaveState::SPU::Duty &dstate, const unsigned nr1,
|
|||
void DutyUnit::resetCounters(const unsigned long oldCc) {
|
||||
if (nextPosUpdate == COUNTER_DISABLED)
|
||||
return;
|
||||
|
||||
|
||||
updatePos(oldCc);
|
||||
nextPosUpdate -= COUNTER_MAX;
|
||||
SoundUnit::resetCounters(oldCc);
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
void resetCounters(unsigned long oldCc);
|
||||
void killCounter();
|
||||
void reviveCounter(unsigned long cc);
|
||||
|
||||
|
||||
//intended for use by SweepUnit only.
|
||||
unsigned getFreq() const { return 2048 - (period >> 1); }
|
||||
void setFreq(unsigned newFreq, unsigned long cc);
|
||||
|
|
|
@ -25,21 +25,21 @@ EnvelopeUnit::VolOnOffEvent EnvelopeUnit::nullEvent;
|
|||
|
||||
void EnvelopeUnit::event() {
|
||||
const unsigned long period = nr2 & 7;
|
||||
|
||||
|
||||
if (period) {
|
||||
unsigned newVol = volume;
|
||||
|
||||
|
||||
if (nr2 & 8)
|
||||
++newVol;
|
||||
else
|
||||
--newVol;
|
||||
|
||||
|
||||
if (newVol < 0x10U) {
|
||||
volume = newVol;
|
||||
|
||||
|
||||
if (volume < 2)
|
||||
volOnOffEvent(counter);
|
||||
|
||||
|
||||
counter += period << 15;
|
||||
} else
|
||||
counter = COUNTER_DISABLED;
|
||||
|
@ -52,32 +52,32 @@ bool EnvelopeUnit::nr2Change(const unsigned newNr2) {
|
|||
++volume;
|
||||
else if (!(nr2 & 8))
|
||||
volume += 2;
|
||||
|
||||
|
||||
if ((nr2 ^ newNr2) & 8)
|
||||
volume = 0x10 - volume;
|
||||
|
||||
|
||||
volume &= 0xF;
|
||||
|
||||
|
||||
nr2 = newNr2;
|
||||
|
||||
|
||||
return !(newNr2 & 0xF8);
|
||||
}
|
||||
|
||||
bool EnvelopeUnit::nr4Init(const unsigned long cc) {
|
||||
{
|
||||
unsigned long period = nr2 & 7;
|
||||
|
||||
|
||||
if (!period)
|
||||
period = 8;
|
||||
|
||||
|
||||
if (!(cc & 0x7000))
|
||||
++period;
|
||||
|
||||
|
||||
counter = cc - ((cc - 0x1000) & 0x7FFF) + period * 0x8000;
|
||||
}
|
||||
|
||||
|
||||
volume = nr2 >> 4;
|
||||
|
||||
|
||||
return !(nr2 & 0xF8);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,13 +31,13 @@ public:
|
|||
virtual ~VolOnOffEvent() {}
|
||||
virtual void operator()(unsigned long /*cc*/) {}
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
static VolOnOffEvent nullEvent;
|
||||
VolOnOffEvent &volOnOffEvent;
|
||||
unsigned char nr2;
|
||||
unsigned char volume;
|
||||
|
||||
|
||||
public:
|
||||
explicit EnvelopeUnit(VolOnOffEvent &volOnOffEvent = nullEvent);
|
||||
void event();
|
||||
|
|
|
@ -44,23 +44,23 @@ void LengthCounter::nr1Change(const unsigned newNr1, const unsigned nr4, const u
|
|||
void LengthCounter::nr4Change(const unsigned oldNr4, const unsigned newNr4, const unsigned long cycleCounter) {
|
||||
if (counter != COUNTER_DISABLED)
|
||||
lengthCounter = (counter >> 13) - (cycleCounter >> 13);
|
||||
|
||||
|
||||
{
|
||||
unsigned dec = 0;
|
||||
|
||||
|
||||
if (newNr4 & 0x40) {
|
||||
dec = ~cycleCounter >> 12 & 1;
|
||||
|
||||
|
||||
if (!(oldNr4 & 0x40) && lengthCounter) {
|
||||
if (!(lengthCounter -= dec))
|
||||
disableMaster();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((newNr4 & 0x80) && !lengthCounter)
|
||||
lengthCounter = lengthMask + 1 - dec;
|
||||
}
|
||||
|
||||
|
||||
if ((newNr4 & 0x40) && lengthCounter)
|
||||
counter = ((cycleCounter >> 13) + lengthCounter) << 13;
|
||||
else
|
||||
|
@ -69,7 +69,7 @@ void LengthCounter::nr4Change(const unsigned oldNr4, const unsigned newNr4, cons
|
|||
|
||||
/*void LengthCounter::reset() {
|
||||
counter = COUNTER_DISABLED;
|
||||
|
||||
|
||||
if (cgb)
|
||||
lengthCounter = lengthMask + 1;
|
||||
}*/
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
namespace gambatte {
|
||||
class MasterDisabler {
|
||||
bool &master;
|
||||
|
||||
|
||||
public:
|
||||
MasterDisabler(bool &m) : master(m) {}
|
||||
virtual ~MasterDisabler() {}
|
||||
|
|
|
@ -26,7 +26,7 @@ protected:
|
|||
unsigned long counter;
|
||||
public:
|
||||
enum { COUNTER_MAX = 0x80000000u, COUNTER_DISABLED = 0xFFFFFFFFu };
|
||||
|
||||
|
||||
SoundUnit() : counter(COUNTER_DISABLED) {}
|
||||
virtual ~SoundUnit() {}
|
||||
virtual void event() = 0;
|
||||
|
|
|
@ -34,11 +34,11 @@ tac_(0)
|
|||
void Tima::loadState(const SaveState &state, const TimaInterruptRequester timaIrq) {
|
||||
lastUpdate_ = state.mem.timaLastUpdate;
|
||||
tmatime_ = state.mem.tmatime;
|
||||
|
||||
|
||||
tima_ = state.mem.ioamhram.get()[0x105];
|
||||
tma_ = state.mem.ioamhram.get()[0x106];
|
||||
tac_ = state.mem.ioamhram.get()[0x107];
|
||||
|
||||
|
||||
timaIrq.setNextIrqEventTime((tac_ & 4)
|
||||
?
|
||||
(tmatime_ != DISABLED_TIME && tmatime_ > state.cpu.cycleCounter
|
||||
|
@ -51,14 +51,14 @@ void Tima::loadState(const SaveState &state, const TimaInterruptRequester timaIr
|
|||
|
||||
void Tima::resetCc(const unsigned long oldCc, const unsigned long newCc, const TimaInterruptRequester timaIrq) {
|
||||
const unsigned long dec = oldCc - newCc;
|
||||
|
||||
|
||||
if (tac_ & 0x04) {
|
||||
updateIrq(oldCc, timaIrq);
|
||||
updateTima(oldCc);
|
||||
|
||||
|
||||
lastUpdate_ -= dec;
|
||||
timaIrq.setNextIrqEventTime(timaIrq.nextIrqEventTime() - dec);
|
||||
|
||||
|
||||
if (tmatime_ != DISABLED_TIME)
|
||||
tmatime_ -= dec;
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ void Tima::setTima(const unsigned data, const unsigned long cycleCounter, const
|
|||
|
||||
timaIrq.setNextIrqEventTime(lastUpdate_ + ((256u - data) << timaClock[tac_ & 3]) + 3);
|
||||
}
|
||||
|
||||
|
||||
tima_ = data;
|
||||
}
|
||||
|
||||
|
@ -115,14 +115,14 @@ void Tima::setTma(const unsigned data, const unsigned long cycleCounter, const T
|
|||
updateIrq(cycleCounter, timaIrq);
|
||||
updateTima(cycleCounter);
|
||||
}
|
||||
|
||||
|
||||
tma_ = data;
|
||||
}
|
||||
|
||||
void Tima::setTac(const unsigned data, const unsigned long cycleCounter, const TimaInterruptRequester timaIrq, bool gbIsCgb) {
|
||||
if (tac_ ^ data) {
|
||||
unsigned long nextIrqEventTime = timaIrq.nextIrqEventTime();
|
||||
|
||||
|
||||
if (tac_ & 0x04) {
|
||||
updateIrq(cycleCounter, timaIrq);
|
||||
updateTima(cycleCounter);
|
||||
|
@ -130,10 +130,10 @@ void Tima::setTac(const unsigned data, const unsigned long cycleCounter, const T
|
|||
lastUpdate_ -= (1u << (timaClock[tac_ & 3] - 1)) + 3;
|
||||
tmatime_ -= (1u << (timaClock[tac_ & 3] - 1)) + 3;
|
||||
nextIrqEventTime -= (1u << (timaClock[tac_ & 3] - 1)) + 3;
|
||||
|
||||
|
||||
if (cycleCounter >= nextIrqEventTime)
|
||||
timaIrq.flagIrq();
|
||||
|
||||
|
||||
updateTima(cycleCounter);
|
||||
|
||||
tmatime_ = DISABLED_TIME;
|
||||
|
@ -143,18 +143,18 @@ void Tima::setTac(const unsigned data, const unsigned long cycleCounter, const T
|
|||
if (data & 4) {
|
||||
lastUpdate_ = (cycleCounter >> timaClock[data & 3]) << timaClock[data & 3];
|
||||
unsigned long diff = cycleCounter - basetime_;
|
||||
|
||||
|
||||
if (gbIsCgb) {
|
||||
if (((diff >> (timaClock[tac_ & 3] - 1)) & 1) == 1 && ((diff >> (timaClock[data & 3] - 1)) & 1) == 0)
|
||||
tima_++;
|
||||
}
|
||||
}
|
||||
lastUpdate_ = basetime_ + ((diff >> timaClock[data & 3]) << timaClock[data & 3]);
|
||||
nextIrqEventTime = lastUpdate_ + ((256u - tima_) << timaClock[data & 3]) + 3;
|
||||
}
|
||||
|
||||
|
||||
timaIrq.setNextIrqEventTime(nextIrqEventTime);
|
||||
}
|
||||
|
||||
|
||||
tac_ = data;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace gambatte {
|
|||
|
||||
class TimaInterruptRequester {
|
||||
InterruptRequester &intreq;
|
||||
|
||||
|
||||
public:
|
||||
explicit TimaInterruptRequester(InterruptRequester &intreq) : intreq(intreq) {}
|
||||
void flagIrq() const { intreq.flagIrq(4); }
|
||||
|
@ -37,29 +37,29 @@ class Tima {
|
|||
unsigned long basetime_;
|
||||
unsigned long lastUpdate_;
|
||||
unsigned long tmatime_;
|
||||
|
||||
|
||||
unsigned char tima_;
|
||||
unsigned char tma_;
|
||||
unsigned char tac_;
|
||||
|
||||
|
||||
void updateIrq(const unsigned long cc, const TimaInterruptRequester timaIrq) {
|
||||
while (cc >= timaIrq.nextIrqEventTime())
|
||||
doIrqEvent(timaIrq);
|
||||
}
|
||||
|
||||
|
||||
void updateTima(unsigned long cc);
|
||||
|
||||
|
||||
public:
|
||||
Tima();
|
||||
void loadState(const SaveState &, TimaInterruptRequester timaIrq);
|
||||
void resetCc(unsigned long oldCc, unsigned long newCc, TimaInterruptRequester timaIrq);
|
||||
|
||||
|
||||
void setTima(unsigned tima, unsigned long cc, TimaInterruptRequester timaIrq);
|
||||
void setTma(unsigned tma, unsigned long cc, TimaInterruptRequester timaIrq);
|
||||
void setTac(unsigned tac, unsigned long cc, TimaInterruptRequester timaIrq, bool gbIsCgb);
|
||||
void resTac(unsigned long cc, TimaInterruptRequester timaIrq);
|
||||
unsigned tima(unsigned long cc);
|
||||
|
||||
|
||||
void doIrqEvent(TimaInterruptRequester timaIrq);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
namespace gambatte {
|
||||
|
||||
void LCD::setDmgPalette(unsigned long *const palette, const unsigned long *const dmgColors, const unsigned data) {
|
||||
void LCD::setDmgPalette(unsigned long palette[], const unsigned long dmgColors[], unsigned data) {
|
||||
palette[0] = dmgColors[data & 3];
|
||||
palette[1] = dmgColors[data >> 2 & 3];
|
||||
palette[2] = dmgColors[data >> 4 & 3];
|
||||
|
@ -77,18 +77,18 @@ void LCD::setCgb(bool cgb) {
|
|||
static unsigned long mode2IrqSchedule(const unsigned statReg, const LyCounter &lyCounter, const unsigned long cycleCounter) {
|
||||
if (!(statReg & 0x20))
|
||||
return DISABLED_TIME;
|
||||
|
||||
|
||||
unsigned next = lyCounter.time() - cycleCounter;
|
||||
|
||||
|
||||
if (lyCounter.ly() >= 143 || (lyCounter.ly() == 142 && next <= 4) || (statReg & 0x08)) {
|
||||
next += (153u - lyCounter.ly()) * lyCounter.lineTime();
|
||||
} else {
|
||||
if (next <= 4)
|
||||
next += lyCounter.lineTime();
|
||||
|
||||
|
||||
next -= 4;
|
||||
}
|
||||
|
||||
|
||||
return cycleCounter + next;
|
||||
}
|
||||
|
||||
|
@ -96,12 +96,12 @@ static inline unsigned long m0IrqTimeFromXpos166Time(const unsigned long xpos166
|
|||
return xpos166Time + cgb - ds;
|
||||
}
|
||||
|
||||
static inline unsigned long hdmaTimeFromM0Time(const unsigned long m0Time, const bool ds) {
|
||||
static inline unsigned long hdmaTimeFromM0Time(unsigned long m0Time, bool ds) {
|
||||
return m0Time + 1 - ds;
|
||||
}
|
||||
|
||||
static unsigned long nextHdmaTime(const unsigned long lastM0Time,
|
||||
const unsigned long nextM0Time, const unsigned long cycleCounter, const bool ds) {
|
||||
static unsigned long nextHdmaTime(unsigned long lastM0Time,
|
||||
unsigned long nextM0Time, unsigned long cycleCounter, bool ds) {
|
||||
return cycleCounter < hdmaTimeFromM0Time(lastM0Time, ds)
|
||||
? hdmaTimeFromM0Time(lastM0Time, ds)
|
||||
: hdmaTimeFromM0Time(nextM0Time, ds);
|
||||
|
@ -125,7 +125,7 @@ void LCD::loadState(const SaveState &state, const unsigned char *const oamram) {
|
|||
if (ppu.lcdc() & 0x80) {
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
lycIrq.reschedule(ppu.lyCounter(), ppu.now());
|
||||
|
||||
|
||||
eventTimes_.setm<ONESHOT_LCDSTATIRQ>(state.ppu.pendingLcdstatIrq
|
||||
? ppu.now() + 1 : static_cast<unsigned long>(DISABLED_TIME));
|
||||
eventTimes_.setm<ONESHOT_UPDATEWY2>(state.ppu.oldWy != state.mem.ioamhram.get()[0x14A]
|
||||
|
@ -140,8 +140,8 @@ void LCD::loadState(const SaveState &state, const unsigned char *const oamram) {
|
|||
? nextHdmaTime(ppu.lastM0Time(), nextM0Time_.predictedNextM0Time(), ppu.now(), isDoubleSpeed())
|
||||
: static_cast<unsigned long>(DISABLED_TIME));
|
||||
} else for (int i = 0; i < NUM_MEM_EVENTS; ++i)
|
||||
eventTimes_.set(static_cast<MemEvent>(i), DISABLED_TIME);
|
||||
|
||||
eventTimes_.set(MemEvent(i), DISABLED_TIME);
|
||||
|
||||
refreshPalettes();
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ static void clear(T *buf, const unsigned long color, const int dpitch) {
|
|||
|
||||
void LCD::updateScreen(const bool blanklcd, const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
|
||||
|
||||
if (blanklcd && ppu.frameBuf().fb()) {
|
||||
const unsigned long color = ppu.cgb() ? gbcToRgb32(0xFFFF) : dmgColorsRgb32[0];
|
||||
clear(ppu.frameBuf().fb(), color, ppu.frameBuf().pitch());
|
||||
|
@ -210,18 +210,18 @@ void LCD::updateScreen(const bool blanklcd, const unsigned long cycleCounter) {
|
|||
void LCD::resetCc(const unsigned long oldCc, const unsigned long newCc) {
|
||||
update(oldCc);
|
||||
ppu.resetCc(oldCc, newCc);
|
||||
|
||||
|
||||
if (ppu.lcdc() & 0x80) {
|
||||
const unsigned long dec = oldCc - newCc;
|
||||
|
||||
|
||||
nextM0Time_.invalidatePredictedNextM0Time();
|
||||
lycIrq.reschedule(ppu.lyCounter(), newCc);
|
||||
|
||||
|
||||
for (int i = 0; i < NUM_MEM_EVENTS; ++i) {
|
||||
if (eventTimes_(static_cast<MemEvent>(i)) != DISABLED_TIME)
|
||||
eventTimes_.set(static_cast<MemEvent>(i), eventTimes_(static_cast<MemEvent>(i)) - dec);
|
||||
if (eventTimes_(MemEvent(i)) != DISABLED_TIME)
|
||||
eventTimes_.set(MemEvent(i), eventTimes_(MemEvent(i)) - dec);
|
||||
}
|
||||
|
||||
|
||||
eventTimes_.set<LY_COUNT>(ppu.lyCounter().time());
|
||||
}
|
||||
}
|
||||
|
@ -229,20 +229,20 @@ void LCD::resetCc(const unsigned long oldCc, const unsigned long newCc) {
|
|||
void LCD::speedChange(const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
ppu.speedChange(cycleCounter);
|
||||
|
||||
|
||||
if (ppu.lcdc() & 0x80) {
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
lycIrq.reschedule(ppu.lyCounter(), cycleCounter);
|
||||
|
||||
|
||||
eventTimes_.set<LY_COUNT>(ppu.lyCounter().time());
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter));
|
||||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
eventTimes_.setm<MODE1_IRQ>(ppu.lyCounter().nextFrameCycle(144 * 456, cycleCounter));
|
||||
eventTimes_.setm<MODE2_IRQ>(mode2IrqSchedule(statReg, ppu.lyCounter(), cycleCounter));
|
||||
|
||||
|
||||
if (eventTimes_(MODE0_IRQ) != DISABLED_TIME && eventTimes_(MODE0_IRQ) - cycleCounter > 1)
|
||||
eventTimes_.setm<MODE0_IRQ>(m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed()));
|
||||
|
||||
|
||||
if (hdmaIsEnabled() && eventTimes_(HDMA_REQ) - cycleCounter > 1) {
|
||||
eventTimes_.setm<HDMA_REQ>(nextHdmaTime(ppu.lastM0Time(),
|
||||
nextM0Time_.predictedNextM0Time(), cycleCounter, isDoubleSpeed()));
|
||||
|
@ -261,7 +261,7 @@ unsigned long LCD::m0TimeOfCurrentLine(const unsigned long cc) {
|
|||
update(cc);
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
}
|
||||
|
||||
|
||||
return gambatte::m0TimeOfCurrentLine(ppu.lyCounter().time(), ppu.lastM0Time(), nextM0Time_.predictedNextM0Time());
|
||||
}
|
||||
|
||||
|
@ -269,7 +269,7 @@ static bool isHdmaPeriod(const LyCounter &lyCounter,
|
|||
const unsigned long m0TimeOfCurrentLy, const unsigned long cycleCounter)
|
||||
{
|
||||
const unsigned timeToNextLy = lyCounter.time() - cycleCounter;
|
||||
|
||||
|
||||
return /*(ppu.lcdc & 0x80) && */lyCounter.ly() < 144 && timeToNextLy > 4
|
||||
&& cycleCounter >= hdmaTimeFromM0Time(m0TimeOfCurrentLy, lyCounter.isDoubleSpeed());
|
||||
}
|
||||
|
@ -280,27 +280,27 @@ void LCD::enableHdma(const unsigned long cycleCounter) {
|
|||
nextM0Time_.predictNextM0Time(ppu);
|
||||
} else if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
|
||||
if (isHdmaPeriod(ppu.lyCounter(),
|
||||
gambatte::m0TimeOfCurrentLine(ppu.lyCounter().time(),
|
||||
ppu.lastM0Time(), nextM0Time_.predictedNextM0Time()), cycleCounter)) {
|
||||
eventTimes_.flagHdmaReq();
|
||||
}
|
||||
|
||||
|
||||
eventTimes_.setm<HDMA_REQ>(nextHdmaTime(ppu.lastM0Time(), nextM0Time_.predictedNextM0Time(), cycleCounter, isDoubleSpeed()));
|
||||
}
|
||||
|
||||
void LCD::disableHdma(const unsigned long cycleCounter) {
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
|
||||
eventTimes_.setm<HDMA_REQ>(DISABLED_TIME);
|
||||
}
|
||||
|
||||
bool LCD::vramAccessible(const unsigned long cycleCounter) {
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
|
||||
return !(ppu.lcdc() & 0x80) || ppu.lyCounter().ly() >= 144
|
||||
|| ppu.lyCounter().lineCycles(cycleCounter) < 80U
|
||||
|| cycleCounter + isDoubleSpeed() - ppu.cgb() + 2 >= m0TimeOfCurrentLine(cycleCounter);
|
||||
|
@ -309,7 +309,7 @@ bool LCD::vramAccessible(const unsigned long cycleCounter) {
|
|||
bool LCD::cgbpAccessible(const unsigned long cycleCounter) {
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
|
||||
return !(ppu.lcdc() & 0x80) || ppu.lyCounter().ly() >= 144
|
||||
|| ppu.lyCounter().lineCycles(cycleCounter) < 80U + isDoubleSpeed()
|
||||
|| cycleCounter >= m0TimeOfCurrentLine(cycleCounter) + 3 - isDoubleSpeed();
|
||||
|
@ -319,17 +319,17 @@ void LCD::doCgbColorChange(unsigned char *const pdata,
|
|||
unsigned long *const palette, unsigned index, const unsigned data) {
|
||||
pdata[index] = data;
|
||||
index >>= 1;
|
||||
palette[index] = gbcToRgb32(pdata[index << 1] | pdata[(index << 1) + 1] << 8);
|
||||
palette[index] = gbcToRgb32(pdata[index * 2] | pdata[(index * 2) + 1] << 8);
|
||||
}
|
||||
|
||||
void LCD::doCgbBgColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) {
|
||||
void LCD::doCgbBgColorChange(unsigned index, unsigned data, unsigned long cycleCounter) {
|
||||
if (cgbpAccessible(cycleCounter)) {
|
||||
update(cycleCounter);
|
||||
doCgbColorChange(bgpData, ppu.bgPalette(), index, data);
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::doCgbSpColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) {
|
||||
void LCD::doCgbSpColorChange(unsigned index, unsigned data, unsigned long cycleCounter) {
|
||||
if (cgbpAccessible(cycleCounter)) {
|
||||
update(cycleCounter);
|
||||
doCgbColorChange(objpData, ppu.spPalette(), index, data);
|
||||
|
@ -339,7 +339,7 @@ void LCD::doCgbSpColorChange(unsigned index, const unsigned data, const unsigned
|
|||
bool LCD::oamReadable(const unsigned long cycleCounter) {
|
||||
if (!(ppu.lcdc() & 0x80) || ppu.inactivePeriodAfterDisplayEnable(cycleCounter))
|
||||
return true;
|
||||
|
||||
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
|
@ -352,7 +352,7 @@ bool LCD::oamReadable(const unsigned long cycleCounter) {
|
|||
bool LCD::oamWritable(const unsigned long cycleCounter) {
|
||||
if (!(ppu.lcdc() & 0x80) || ppu.inactivePeriodAfterDisplayEnable(cycleCounter))
|
||||
return true;
|
||||
|
||||
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
|
@ -387,7 +387,7 @@ void LCD::wyChange(const unsigned newValue, const unsigned long cycleCounter) {
|
|||
update(cycleCounter + 1);
|
||||
ppu.setWy(newValue);
|
||||
// mode3CyclesChange(); // should be safe to wait until after wy2 delay, because no mode3 events are close to when wy1 is read.
|
||||
|
||||
|
||||
// wy2 is a delayed version of wy. really just slowness of ly == wy comparison.
|
||||
if (ppu.cgb() && (ppu.lcdc() & 0x80)) {
|
||||
eventTimes_.setm<ONESHOT_UPDATEWY2>(cycleCounter + 5);
|
||||
|
@ -420,7 +420,7 @@ void LCD::oamChange(const unsigned long cycleCounter) {
|
|||
void LCD::oamChange(const unsigned char *const oamram, const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
ppu.oamChange(oamram, cycleCounter);
|
||||
|
||||
|
||||
if (ppu.lcdc() & 0x80)
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter));
|
||||
}
|
||||
|
@ -428,53 +428,53 @@ void LCD::oamChange(const unsigned char *const oamram, const unsigned long cycle
|
|||
void LCD::lcdcChange(const unsigned data, const unsigned long cycleCounter) {
|
||||
const unsigned oldLcdc = ppu.lcdc();
|
||||
update(cycleCounter);
|
||||
|
||||
|
||||
if ((oldLcdc ^ data) & 0x80) {
|
||||
ppu.setLcdc(data, cycleCounter);
|
||||
|
||||
|
||||
if (data & 0x80) {
|
||||
lycIrq.lcdReset();
|
||||
m0Irq_.lcdReset(statReg, lycIrq.lycReg());
|
||||
|
||||
|
||||
if (lycIrq.lycReg() == 0 && (statReg & 0x40))
|
||||
eventTimes_.flagIrq(2);
|
||||
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
lycIrq.reschedule(ppu.lyCounter(), cycleCounter);
|
||||
|
||||
|
||||
eventTimes_.set<LY_COUNT>(ppu.lyCounter().time());
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter));
|
||||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
eventTimes_.setm<MODE1_IRQ>(ppu.lyCounter().nextFrameCycle(144 * 456, cycleCounter));
|
||||
eventTimes_.setm<MODE2_IRQ>(mode2IrqSchedule(statReg, ppu.lyCounter(), cycleCounter));
|
||||
|
||||
|
||||
if (statReg & 0x08)
|
||||
eventTimes_.setm<MODE0_IRQ>(m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed()));
|
||||
|
||||
|
||||
if (hdmaIsEnabled()) {
|
||||
eventTimes_.setm<HDMA_REQ>(nextHdmaTime(ppu.lastM0Time(),
|
||||
nextM0Time_.predictedNextM0Time(), cycleCounter, isDoubleSpeed()));
|
||||
}
|
||||
} else for (int i = 0; i < NUM_MEM_EVENTS; ++i)
|
||||
eventTimes_.set(static_cast<MemEvent>(i), DISABLED_TIME);
|
||||
eventTimes_.set(MemEvent(i), DISABLED_TIME);
|
||||
} else if (data & 0x80) {
|
||||
if (ppu.cgb()) {
|
||||
ppu.setLcdc((oldLcdc & ~0x14) | (data & 0x14), cycleCounter);
|
||||
|
||||
|
||||
if ((oldLcdc ^ data) & 0x04)
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter));
|
||||
|
||||
|
||||
update(cycleCounter + isDoubleSpeed() + 1);
|
||||
ppu.setLcdc(data, cycleCounter + isDoubleSpeed() + 1);
|
||||
|
||||
|
||||
if ((oldLcdc ^ data) & 0x20)
|
||||
mode3CyclesChange();
|
||||
} else {
|
||||
ppu.setLcdc(data, cycleCounter);
|
||||
|
||||
|
||||
if ((oldLcdc ^ data) & 0x04)
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter));
|
||||
|
||||
|
||||
if ((oldLcdc ^ data) & 0x22)
|
||||
mode3CyclesChange();
|
||||
}
|
||||
|
@ -512,7 +512,7 @@ void LCD::lcdstatChange(unsigned const data, unsigned long const cycleCounter) {
|
|||
unsigned const old = statReg;
|
||||
statReg = data;
|
||||
lycIrq.statRegChange(data, ppu.lyCounter(), cycleCounter);
|
||||
|
||||
|
||||
if (ppu.lcdc() & 0x80) {
|
||||
int const timeToNextLy = ppu.lyCounter().time() - cycleCounter;
|
||||
LyCnt const lycCmp = getLycCmpLy(ppu.lyCounter(), cycleCounter);
|
||||
|
@ -565,12 +565,12 @@ void LCD::lcdstatChange(unsigned const data, unsigned long const cycleCounter) {
|
|||
eventTimes_.setm<MODE2_IRQ>(mode2IrqSchedule(data, ppu.lyCounter(), cycleCounter));
|
||||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
}
|
||||
|
||||
|
||||
m2IrqStatReg_ = eventTimes_(MODE2_IRQ) - cycleCounter > (ppu.cgb() - isDoubleSpeed()) * 4U
|
||||
? data : (m2IrqStatReg_ & 0x10) | (statReg & ~0x10);
|
||||
m1IrqStatReg_ = eventTimes_(MODE1_IRQ) - cycleCounter > (ppu.cgb() - isDoubleSpeed()) * 4U
|
||||
? data : (m1IrqStatReg_ & 0x08) | (statReg & ~0x08);
|
||||
|
||||
|
||||
m0Irq_.statRegChange(data, eventTimes_(MODE0_IRQ), cycleCounter, ppu.cgb());
|
||||
}
|
||||
|
||||
|
@ -583,16 +583,16 @@ void LCD::lycRegChange(unsigned const data, unsigned long const cycleCounter) {
|
|||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
m0Irq_.lycRegChange(data, eventTimes_(MODE0_IRQ), cycleCounter, isDoubleSpeed(), ppu.cgb());
|
||||
m0Irq_.lycRegChange(data, eventTimes_(MODE0_IRQ), cycleCounter, isDoubleSpeed(), ppu.cgb());
|
||||
lycIrq.lycRegChange(data, ppu.lyCounter(), cycleCounter);
|
||||
|
||||
|
||||
if (!(ppu.lcdc() & 0x80))
|
||||
return;
|
||||
|
||||
|
||||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
|
||||
int const timeToNextLy = ppu.lyCounter().time() - cycleCounter;
|
||||
|
||||
|
||||
if ((statReg & 0x40) && data < 154
|
||||
&& (ppu.lyCounter().ly() < 144
|
||||
? !(statReg & 0x08) || cycleCounter < m0TimeOfCurrentLine(cycleCounter) || timeToNextLy <= 4 << ppu.cgb()
|
||||
|
@ -649,22 +649,22 @@ inline void LCD::doMode2IrqEvent() {
|
|||
const unsigned ly = eventTimes_(LY_COUNT) - eventTimes_(MODE2_IRQ) < 8
|
||||
? (ppu.lyCounter().ly() == 153 ? 0 : ppu.lyCounter().ly() + 1)
|
||||
: ppu.lyCounter().ly();
|
||||
|
||||
|
||||
if ((ly != 0 || !(m2IrqStatReg_ & 0x10)) &&
|
||||
(!(m2IrqStatReg_ & 0x40) || (lycIrq.lycReg() != 0 ? ly != (lycIrq.lycReg() + 1U) : ly > 1))) {
|
||||
eventTimes_.flagIrq(2);
|
||||
}
|
||||
|
||||
|
||||
m2IrqStatReg_ = statReg;
|
||||
|
||||
|
||||
if (!(statReg & 0x08)) {
|
||||
unsigned long nextTime = eventTimes_(MODE2_IRQ) + ppu.lyCounter().lineTime();
|
||||
|
||||
|
||||
if (ly == 0) {
|
||||
nextTime -= 4;
|
||||
} else if (ly == 143)
|
||||
nextTime += ppu.lyCounter().lineTime() * 10 + 4;
|
||||
|
||||
|
||||
eventTimes_.setm<MODE2_IRQ>(nextTime);
|
||||
} else
|
||||
eventTimes_.setm<MODE2_IRQ>(eventTimes_(MODE2_IRQ) + (70224 << isDoubleSpeed()));
|
||||
|
@ -679,7 +679,7 @@ inline void LCD::event() {
|
|||
m1IrqStatReg_ = statReg;
|
||||
eventTimes_.setm<MODE1_IRQ>(eventTimes_(MODE1_IRQ) + (70224 << isDoubleSpeed()));
|
||||
break;
|
||||
|
||||
|
||||
case LYC_IRQ: {
|
||||
unsigned char ifreg = 0;
|
||||
lycIrq.doEvent(&ifreg, ppu.lyCounter());
|
||||
|
@ -687,48 +687,48 @@ inline void LCD::event() {
|
|||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case SPRITE_MAP:
|
||||
eventTimes_.setm<SPRITE_MAP>(ppu.doSpriteMapEvent(eventTimes_(SPRITE_MAP)));
|
||||
mode3CyclesChange();
|
||||
break;
|
||||
|
||||
|
||||
case HDMA_REQ:
|
||||
eventTimes_.flagHdmaReq();
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
eventTimes_.setm<HDMA_REQ>(hdmaTimeFromM0Time(nextM0Time_.predictedNextM0Time(), isDoubleSpeed()));
|
||||
break;
|
||||
|
||||
|
||||
case MODE2_IRQ:
|
||||
doMode2IrqEvent();
|
||||
break;
|
||||
|
||||
|
||||
case MODE0_IRQ:
|
||||
{
|
||||
unsigned char ifreg = 0;
|
||||
m0Irq_.doEvent(&ifreg, ppu.lyCounter().ly(), statReg, lycIrq.lycReg());
|
||||
eventTimes_.flagIrq(ifreg);
|
||||
}
|
||||
|
||||
eventTimes_.setm<MODE0_IRQ>((statReg & 0x08)
|
||||
|
||||
eventTimes_.setm<MODE0_IRQ>(statReg & 0x08
|
||||
? m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed())
|
||||
: static_cast<unsigned long>(DISABLED_TIME));
|
||||
break;
|
||||
|
||||
|
||||
case ONESHOT_LCDSTATIRQ:
|
||||
eventTimes_.flagIrq(2);
|
||||
eventTimes_.setm<ONESHOT_LCDSTATIRQ>(DISABLED_TIME);
|
||||
break;
|
||||
|
||||
|
||||
case ONESHOT_UPDATEWY2:
|
||||
ppu.updateWy2();
|
||||
mode3CyclesChange();
|
||||
eventTimes_.setm<ONESHOT_UPDATEWY2>(DISABLED_TIME);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case LY_COUNT:
|
||||
ppu.doLyCountEvent();
|
||||
eventTimes_.set<LY_COUNT>(ppu.lyCounter().time());
|
||||
|
@ -741,12 +741,12 @@ inline void LCD::event() {
|
|||
void LCD::update(const unsigned long cycleCounter) {
|
||||
if (!(ppu.lcdc() & 0x80))
|
||||
return;
|
||||
|
||||
|
||||
while (cycleCounter >= eventTimes_.nextEventTime()) {
|
||||
ppu.update(eventTimes_.nextEventTime());
|
||||
event();
|
||||
}
|
||||
|
||||
|
||||
ppu.update(cycleCounter);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace gambatte {
|
|||
|
||||
class VideoInterruptRequester {
|
||||
InterruptRequester * intreq;
|
||||
|
||||
|
||||
public:
|
||||
explicit VideoInterruptRequester(InterruptRequester * intreq) : intreq(intreq) {}
|
||||
void flagHdmaReq() const { gambatte::flagHdmaReq(intreq); }
|
||||
|
@ -42,40 +42,40 @@ public:
|
|||
class M0Irq {
|
||||
unsigned char statReg_;
|
||||
unsigned char lycReg_;
|
||||
|
||||
|
||||
public:
|
||||
M0Irq() : statReg_(0), lycReg_(0) {}
|
||||
|
||||
|
||||
void lcdReset(const unsigned statReg, const unsigned lycReg) {
|
||||
statReg_ = statReg;
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
|
||||
void statRegChange(const unsigned statReg,
|
||||
const unsigned long nextM0IrqTime, const unsigned long cc, const bool cgb) {
|
||||
if (nextM0IrqTime - cc > cgb * 2U)
|
||||
statReg_ = statReg;
|
||||
}
|
||||
|
||||
|
||||
void lycRegChange(const unsigned lycReg,
|
||||
const unsigned long nextM0IrqTime, const unsigned long cc, const bool ds, const bool cgb) {
|
||||
if (nextM0IrqTime - cc > cgb * 5 + 1U - ds)
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
|
||||
void doEvent(unsigned char *const ifreg, const unsigned ly, const unsigned statReg, const unsigned lycReg) {
|
||||
if (((statReg_ | statReg) & 0x08) && (!(statReg_ & 0x40) || ly != lycReg_))
|
||||
*ifreg |= 2;
|
||||
|
||||
|
||||
statReg_ = statReg;
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
|
||||
void loadState(const SaveState &state) {
|
||||
lycReg_ = state.ppu.m0lyc;
|
||||
statReg_ = state.mem.ioamhram.get()[0x141];
|
||||
}
|
||||
|
||||
|
||||
unsigned statReg() const { return statReg_; }
|
||||
|
||||
template<bool isReader>
|
||||
|
@ -90,33 +90,33 @@ class LCD {
|
|||
enum Event { MEM_EVENT, LY_COUNT }; enum { NUM_EVENTS = LY_COUNT + 1 };
|
||||
enum MemEvent { ONESHOT_LCDSTATIRQ, ONESHOT_UPDATEWY2, MODE1_IRQ, LYC_IRQ, SPRITE_MAP,
|
||||
HDMA_REQ, MODE2_IRQ, MODE0_IRQ }; enum { NUM_MEM_EVENTS = MODE0_IRQ + 1 };
|
||||
|
||||
|
||||
class EventTimes {
|
||||
MinKeeper<NUM_EVENTS> eventMin_;
|
||||
MinKeeper<NUM_MEM_EVENTS> memEventMin_;
|
||||
VideoInterruptRequester memEventRequester_;
|
||||
|
||||
|
||||
void setMemEvent() {
|
||||
const unsigned long nmet = nextMemEventTime();
|
||||
eventMin_.setValue<MEM_EVENT>(nmet);
|
||||
memEventRequester_.setNextEventTime(nmet);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
explicit EventTimes(const VideoInterruptRequester memEventRequester) : memEventRequester_(memEventRequester) {}
|
||||
|
||||
|
||||
Event nextEvent() const { return static_cast<Event>(eventMin_.min()); }
|
||||
unsigned long nextEventTime() const { return eventMin_.minValue(); }
|
||||
unsigned long operator()(const Event e) const { return eventMin_.value(e); }
|
||||
template<Event e> void set(const unsigned long time) { eventMin_.setValue<e>(time); }
|
||||
void set(const Event e, const unsigned long time) { eventMin_.setValue(e, time); }
|
||||
|
||||
|
||||
MemEvent nextMemEvent() const { return static_cast<MemEvent>(memEventMin_.min()); }
|
||||
unsigned long nextMemEventTime() const { return memEventMin_.minValue(); }
|
||||
unsigned long operator()(const MemEvent e) const { return memEventMin_.value(e); }
|
||||
template<MemEvent e> void setm(const unsigned long time) { memEventMin_.setValue<e>(time); setMemEvent(); }
|
||||
void set(const MemEvent e, const unsigned long time) { memEventMin_.setValue(e, time); setMemEvent(); }
|
||||
|
||||
|
||||
void flagIrq(const unsigned bit) { memEventRequester_.flagIrq(bit); }
|
||||
void flagHdmaReq() { memEventRequester_.flagHdmaReq(); }
|
||||
|
||||
|
@ -128,7 +128,7 @@ class LCD {
|
|||
//SSS(memEventRequester_); // not needed
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
PPU ppu;
|
||||
unsigned long dmgColorsRgb32[3 * 4];
|
||||
unsigned long cgbColorsRgb32[32768];
|
||||
|
@ -144,7 +144,7 @@ class LCD {
|
|||
unsigned char m2IrqStatReg_;
|
||||
unsigned char m1IrqStatReg_;
|
||||
|
||||
static void setDmgPalette(unsigned long *palette, const unsigned long *dmgColors, unsigned data);
|
||||
static void setDmgPalette(unsigned long palette[], const unsigned long dmgColors[], unsigned data);
|
||||
void setDmgPaletteColor(unsigned index, unsigned long rgb32);
|
||||
|
||||
unsigned long gbcToRgb32(const unsigned bgr15);
|
||||
|
@ -158,7 +158,7 @@ class LCD {
|
|||
|
||||
unsigned long m0TimeOfCurrentLine(unsigned long cc);
|
||||
bool cgbpAccessible(unsigned long cycleCounter);
|
||||
|
||||
|
||||
void mode3CyclesChange();
|
||||
void doCgbBgColorChange(unsigned index, unsigned data, unsigned long cycleCounter);
|
||||
void doCgbSpColorChange(unsigned index, unsigned data, unsigned long cycleCounter);
|
||||
|
@ -242,7 +242,7 @@ public:
|
|||
update(cycleCounter);
|
||||
|
||||
lyReg = ppu.lyCounter().ly();
|
||||
|
||||
|
||||
if (lyReg == 153) {
|
||||
if (isDoubleSpeed()) {
|
||||
if (ppu.lyCounter().time() - cycleCounter <= 456 * 2 - 8)
|
||||
|
@ -261,13 +261,13 @@ public:
|
|||
void lcdcChange(unsigned data, unsigned long cycleCounter);
|
||||
void lcdstatChange(unsigned data, unsigned long cycleCounter);
|
||||
void lycRegChange(unsigned data, unsigned long cycleCounter);
|
||||
|
||||
|
||||
void enableHdma(unsigned long cycleCounter);
|
||||
void disableHdma(unsigned long cycleCounter);
|
||||
bool hdmaIsEnabled() const { return eventTimes_(HDMA_REQ) != DISABLED_TIME; }
|
||||
|
||||
|
||||
void update(unsigned long cycleCounter);
|
||||
|
||||
|
||||
bool isCgb() const { return ppu.cgb(); }
|
||||
bool isDoubleSpeed() const { return ppu.lyCounter().isDoubleSpeed(); }
|
||||
|
||||
|
|
|
@ -30,28 +30,28 @@ LyCounter::LyCounter()
|
|||
|
||||
void LyCounter::doEvent() {
|
||||
++ly_;
|
||||
|
||||
|
||||
if (ly_ == 154)
|
||||
ly_ = 0;
|
||||
|
||||
|
||||
time_ = time_ + lineTime_;
|
||||
}
|
||||
|
||||
unsigned long LyCounter::nextLineCycle(const unsigned lineCycle, const unsigned long cycleCounter) const {
|
||||
unsigned long tmp = time_ + (lineCycle << ds);
|
||||
|
||||
|
||||
if (tmp - cycleCounter > lineTime_)
|
||||
tmp -= lineTime_;
|
||||
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
unsigned long LyCounter::nextFrameCycle(const unsigned long frameCycle, const unsigned long cycleCounter) const {
|
||||
unsigned long tmp = time_ + (((153U - ly()) * 456U + frameCycle) << ds);
|
||||
|
||||
|
||||
if (tmp - cycleCounter > 70224U << ds)
|
||||
tmp -= 70224U << ds;
|
||||
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,20 +30,20 @@ class LyCounter {
|
|||
unsigned short lineTime_;
|
||||
unsigned char ly_;
|
||||
bool ds;
|
||||
|
||||
|
||||
public:
|
||||
LyCounter();
|
||||
void doEvent();
|
||||
bool isDoubleSpeed() const { return ds; }
|
||||
|
||||
|
||||
unsigned long frameCycles(const unsigned long cc) const {
|
||||
return ly_ * 456ul + lineCycles(cc);
|
||||
}
|
||||
|
||||
|
||||
unsigned lineCycles(const unsigned long cc) const {
|
||||
return 456u - ((time_ - cc) >> isDoubleSpeed());
|
||||
}
|
||||
|
||||
|
||||
unsigned lineTime() const { return lineTime_; }
|
||||
unsigned ly() const { return ly_; }
|
||||
unsigned long nextLineCycle(unsigned lineCycle, unsigned long cycleCounter) const;
|
||||
|
|
|
@ -45,20 +45,20 @@ void LycIrq::regChange(const unsigned statReg, const unsigned lycReg, const LyCo
|
|||
statRegSrc_ = statReg;
|
||||
lycRegSrc_ = lycReg;
|
||||
time_ = std::min(time_, timeSrc);
|
||||
|
||||
|
||||
if (cgb_) {
|
||||
if (time_ - cc > 8 || (timeSrc != time_ && time_ - cc > 4U - lyCounter.isDoubleSpeed() * 4U))
|
||||
lycReg_ = lycReg;
|
||||
|
||||
|
||||
if (time_ - cc > 4U - lyCounter.isDoubleSpeed() * 4U)
|
||||
statReg_ = statReg;
|
||||
} else {
|
||||
if (time_ - cc > 4 || timeSrc != time_)
|
||||
lycReg_ = lycReg;
|
||||
|
||||
|
||||
if (time_ - cc > 4 || lycReg_ != 0)
|
||||
statReg_ = statReg;
|
||||
|
||||
|
||||
statReg_ = (statReg_ & 0x40) | (statReg & ~0x40);
|
||||
}
|
||||
}
|
||||
|
@ -66,13 +66,13 @@ void LycIrq::regChange(const unsigned statReg, const unsigned lycReg, const LyCo
|
|||
void LycIrq::doEvent(unsigned char *const ifreg, const LyCounter &lyCounter) {
|
||||
if ((statReg_ | statRegSrc_) & 0x40) {
|
||||
const unsigned cmpLy = lyCounter.time() - time_ < lyCounter.lineTime() ? 0 : lyCounter.ly();
|
||||
|
||||
|
||||
if (lycReg_ == cmpLy &&
|
||||
(lycReg_ - 1U < 144U - 1U ? !(statReg_ & 0x20) : !(statReg_ & 0x10))) {
|
||||
*ifreg |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lycReg_ = lycRegSrc_;
|
||||
statReg_ = statRegSrc_;
|
||||
time_ = schedule(statReg_, lycReg_, lyCounter, time_);
|
||||
|
|
|
@ -33,9 +33,9 @@ class LycIrq {
|
|||
unsigned char lycReg_;
|
||||
unsigned char statReg_;
|
||||
bool cgb_;
|
||||
|
||||
|
||||
void regChange(unsigned statReg, unsigned lycReg, const LyCounter &lyCounter, unsigned long cc);
|
||||
|
||||
|
||||
public:
|
||||
LycIrq();
|
||||
void doEvent(unsigned char *ifreg, const LyCounter &lyCounter);
|
||||
|
@ -45,11 +45,11 @@ public:
|
|||
void setCgb(const bool cgb) { cgb_ = cgb; }
|
||||
void lcdReset();
|
||||
void reschedule(const LyCounter & lyCounter, unsigned long cc);
|
||||
|
||||
|
||||
void statRegChange(unsigned statReg, const LyCounter &lyCounter, unsigned long cc) {
|
||||
regChange(statReg, lycRegSrc_, lyCounter, cc);
|
||||
}
|
||||
|
||||
|
||||
void lycRegChange(unsigned lycReg, const LyCounter &lyCounter, unsigned long cc) {
|
||||
regChange(statRegSrc_, lycReg, lyCounter, cc);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace gambatte {
|
|||
|
||||
class NextM0Time {
|
||||
unsigned predictedNextM0Time_;
|
||||
|
||||
|
||||
public:
|
||||
NextM0Time() : predictedNextM0Time_(0) {}
|
||||
void predictNextM0Time(const class PPU &v);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -33,9 +33,9 @@ class PPUFrameBuf {
|
|||
uint_least32_t *buf_;
|
||||
uint_least32_t *fbline_;
|
||||
int pitch_;
|
||||
|
||||
|
||||
static uint_least32_t * nullfbline() { static uint_least32_t nullfbline_[160]; return nullfbline_; }
|
||||
|
||||
|
||||
public:
|
||||
PPUFrameBuf() : buf_(0), fbline_(nullfbline()), pitch_(0) {}
|
||||
uint_least32_t * fb() const { return buf_; }
|
||||
|
@ -93,7 +93,7 @@ struct PPUPriv {
|
|||
|
||||
bool cgb;
|
||||
bool weMaster;
|
||||
|
||||
|
||||
PPUPriv(NextM0Time &nextM0Time, const unsigned char *oamram, const unsigned char *vram);
|
||||
};
|
||||
|
||||
|
@ -104,7 +104,7 @@ public:
|
|||
: p_(nextM0Time, oamram, vram)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unsigned long * bgPalette() { return p_.bgPalette; }
|
||||
bool cgb() const { return p_.cgb; }
|
||||
void doLyCountEvent() { p_.lyCounter.doEvent(); }
|
||||
|
|
|
@ -83,10 +83,10 @@ void SpriteMapper::OamReader::update(const unsigned long cc) {
|
|||
if (!(pos & 1)) {
|
||||
if (pos == 80)
|
||||
pos = 0;
|
||||
|
||||
|
||||
if (cgb_)
|
||||
szbuf[pos >> 1] = largeSpritesSrc;
|
||||
|
||||
|
||||
buf[pos ] = oamram[pos * 2 ];
|
||||
buf[pos + 1] = oamram[pos * 2 + 1];
|
||||
} else
|
||||
|
@ -194,7 +194,7 @@ SYNCFUNC(SpriteMapper)
|
|||
{
|
||||
NSS(spritemap);
|
||||
NSS(num);
|
||||
|
||||
|
||||
SSS(nextM0Time_);
|
||||
SSS(oamReader);
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
private:
|
||||
mutable unsigned char spritemap[144*10];
|
||||
mutable unsigned char num[144];
|
||||
|
||||
|
||||
NextM0Time &nextM0Time_;
|
||||
OamReader oamReader;
|
||||
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue