mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2024-11-27 01:40:23 +00:00
various oamdma accuracy. oamdma bus conflicts with cpu, ppu, cgbdma. rewritten memory read/write methods. accurate timing of ppu sprite mapping reads. fix recent cgb sprite cycles sorting slip up.
git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@118 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
This commit is contained in:
parent
7e6d5246da
commit
d7e9f01a3f
BIN
hwtests/oamdma/late_sp00y_1_out3.gbc
Normal file
BIN
hwtests/oamdma/late_sp00y_1_out3.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp00y_2_out0.gbc
Normal file
BIN
hwtests/oamdma/late_sp00y_2_out0.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp00y_ds_1_out3.gbc
Normal file
BIN
hwtests/oamdma/late_sp00y_ds_1_out3.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp00y_ds_2_out0.gbc
Normal file
BIN
hwtests/oamdma/late_sp00y_ds_2_out0.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp01x_1_out0.gbc
Normal file
BIN
hwtests/oamdma/late_sp01x_1_out0.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp01x_2_out3.gbc
Normal file
BIN
hwtests/oamdma/late_sp01x_2_out3.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp01x_ds_1_out0.gbc
Normal file
BIN
hwtests/oamdma/late_sp01x_ds_1_out0.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp01x_ds_2_out3.gbc
Normal file
BIN
hwtests/oamdma/late_sp01x_ds_2_out3.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp01y_1_out3.gbc
Normal file
BIN
hwtests/oamdma/late_sp01y_1_out3.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp01y_2_out0.gbc
Normal file
BIN
hwtests/oamdma/late_sp01y_2_out0.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp01y_ds_1_out3.gbc
Normal file
BIN
hwtests/oamdma/late_sp01y_ds_1_out3.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp01y_ds_2_out0.gbc
Normal file
BIN
hwtests/oamdma/late_sp01y_ds_2_out0.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp02x_1_out0.gbc
Normal file
BIN
hwtests/oamdma/late_sp02x_1_out0.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp02x_2_out3.gbc
Normal file
BIN
hwtests/oamdma/late_sp02x_2_out3.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp02y_1_out3.gbc
Normal file
BIN
hwtests/oamdma/late_sp02y_1_out3.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/late_sp02y_2_out0.gbc
Normal file
BIN
hwtests/oamdma/late_sp02y_2_out0.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/oamdma_busydelay_1_out5.gbc
Normal file
BIN
hwtests/oamdma/oamdma_busydelay_1_out5.gbc
Normal file
Binary file not shown.
BIN
hwtests/oamdma/oamdma_src0000_busyread0000_4_out5.gbc
Normal file
BIN
hwtests/oamdma/oamdma_src0000_busyread0000_4_out5.gbc
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp00_1_out0.gb
Normal file
BIN
hwtests/sprites/late_sizechange_sp00_1_out0.gb
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp00_2_out3.gb
Normal file
BIN
hwtests/sprites/late_sizechange_sp00_2_out3.gb
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp00_3_out3.gb
Normal file
BIN
hwtests/sprites/late_sizechange_sp00_3_out3.gb
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp00_4_out0.gb
Normal file
BIN
hwtests/sprites/late_sizechange_sp00_4_out0.gb
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp00_ds_1_out0.gbc
Normal file
BIN
hwtests/sprites/late_sizechange_sp00_ds_1_out0.gbc
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp00_ds_2_out3.gbc
Normal file
BIN
hwtests/sprites/late_sizechange_sp00_ds_2_out3.gbc
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp01_1_out0.gb
Normal file
BIN
hwtests/sprites/late_sizechange_sp01_1_out0.gb
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp01_2_out3.gb
Normal file
BIN
hwtests/sprites/late_sizechange_sp01_2_out3.gb
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp01_ds_1_out0.gbc
Normal file
BIN
hwtests/sprites/late_sizechange_sp01_ds_1_out0.gbc
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp01_ds_2_out3.gbc
Normal file
BIN
hwtests/sprites/late_sizechange_sp01_ds_2_out3.gbc
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp02_1_out0.gb
Normal file
BIN
hwtests/sprites/late_sizechange_sp02_1_out0.gb
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp02_2_out3.gb
Normal file
BIN
hwtests/sprites/late_sizechange_sp02_2_out3.gb
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp39_1_out0.gb
Normal file
BIN
hwtests/sprites/late_sizechange_sp39_1_out0.gb
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp39_2_out3.gb
Normal file
BIN
hwtests/sprites/late_sizechange_sp39_2_out3.gb
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp39_ds_1_out0.gbc
Normal file
BIN
hwtests/sprites/late_sizechange_sp39_ds_1_out0.gbc
Normal file
Binary file not shown.
BIN
hwtests/sprites/late_sizechange_sp39_ds_2_out3.gbc
Normal file
BIN
hwtests/sprites/late_sizechange_sp39_ds_2_out3.gbc
Normal file
Binary file not shown.
@ -105,13 +105,14 @@ static const unsigned char cgbObjpDump[0x40] = {
|
||||
};
|
||||
|
||||
Memory::Memory(const Interrupter &interrupter_in): display(memory + 0xFE00, vram), interrupter(interrupter_in) {
|
||||
romdata = NULL;
|
||||
romdata[0] = NULL;
|
||||
rambankdata = NULL;
|
||||
cgb_wramdata = NULL;
|
||||
wramdata[0] = NULL;
|
||||
romfile = NULL;
|
||||
savedir = NULL;
|
||||
savename = NULL;
|
||||
getInput = NULL;
|
||||
std::memset(rdisabled_ram, 0xFF, sizeof(rdisabled_ram));
|
||||
init();
|
||||
}
|
||||
|
||||
@ -139,12 +140,18 @@ void Memory::init() {
|
||||
next_serialtime = COUNTER_DISABLED;
|
||||
rombanks = 1;
|
||||
IME = false;
|
||||
oamDmaSrc = NULL;
|
||||
vrambank = vram;
|
||||
lastOamDmaUpdate = COUNTER_DISABLED;
|
||||
oamDmaArea1Lower = 0x00;
|
||||
oamDmaArea1Width = 0x00;
|
||||
oamDmaArea2Upper = 0x00;
|
||||
oamDmaPos = 0xFE;
|
||||
set_irqEvent();
|
||||
set_event();
|
||||
rtc.reset();
|
||||
|
||||
std::memset(memory, 0x00, sizeof(memory));
|
||||
std::memset(disabled_ram, 0xFF, 0x1000);
|
||||
std::memset(vram, 0, 0x4000);
|
||||
|
||||
for (unsigned addr = 0xC000; addr < 0xC800; addr += 0x10) {
|
||||
@ -172,23 +179,9 @@ void Memory::init() {
|
||||
memory[0xFF40] = 0x91;
|
||||
memory[0xFF41] = 0x80;
|
||||
memory[0xFF44] = 0x00;
|
||||
|
||||
mem[0x0] = memory;
|
||||
mem[0x1] = &memory[0x1000];
|
||||
mem[0x2] = &memory[0x2000];
|
||||
mem[0x3] = &memory[0x3000];
|
||||
mem[0x4] = &memory[0x4000];
|
||||
mem[0x5] = &memory[0x5000];
|
||||
mem[0x6] = &memory[0x6000];
|
||||
mem[0x7] = &memory[0x7000];
|
||||
mem[0x8] = vram;
|
||||
mem[0x9] = mem[0x8] + 0x1000;
|
||||
mem[0xA] = disabled_ram;
|
||||
mem[0xB] = disabled_ram;
|
||||
mem[0xC] = &memory[0xC000];
|
||||
mem[0xD] = &memory[0xD000];
|
||||
mem[0xE] = mem[0xC];
|
||||
mem[0xF] = &memory[0xF000];
|
||||
|
||||
std::fill_n(rmem, 0x10, static_cast<unsigned char*>(NULL));
|
||||
std::fill_n(wmem, 0x10, static_cast<unsigned char*>(NULL));
|
||||
|
||||
for (unsigned i = 0x00; i < 0x40; i += 0x02) {
|
||||
cgb_bgp_data[i] = 0xFF;
|
||||
@ -325,6 +318,9 @@ void Memory::set_event() {
|
||||
}
|
||||
|
||||
unsigned long Memory::event(unsigned long cycleCounter) {
|
||||
if (lastOamDmaUpdate != COUNTER_DISABLED)
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
switch (next_event) {
|
||||
case HDMA_RESCHEDULE:
|
||||
// printf("hdma_reschedule\n");
|
||||
@ -351,18 +347,39 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
||||
if (!(memory[0xFF40] & 0x80))
|
||||
dmaLength = 0;
|
||||
|
||||
cycleCounter += 4;
|
||||
|
||||
while (length--) {
|
||||
const unsigned src = dmaSrc++ & 0xFFFF;
|
||||
{
|
||||
unsigned long lOamDmaUpdate = lastOamDmaUpdate;
|
||||
lastOamDmaUpdate = COUNTER_DISABLED;
|
||||
|
||||
write(0x8000 | dmaDest++ & 0x1FFF,
|
||||
((src & 0xE000) == 0x8000 || src > 0xFDFF) ? 0xFF : read(src, cycleCounter),
|
||||
cycleCounter);
|
||||
while (length--) {
|
||||
const unsigned src = dmaSrc++ & 0xFFFF;
|
||||
const unsigned data = ((src & 0xE000) == 0x8000 || src > 0xFDFF) ? 0xFF : read(src, cycleCounter);
|
||||
|
||||
cycleCounter += 2 << doubleSpeed;
|
||||
|
||||
if (cycleCounter - 3 > lOamDmaUpdate) {
|
||||
oamDmaPos = oamDmaPos + 1 & 0xFF;
|
||||
lOamDmaUpdate += 4;
|
||||
|
||||
if (oamDmaPos < 0xA0) {
|
||||
if (oamDmaPos == 0)
|
||||
startOamDma(lOamDmaUpdate - 2);
|
||||
|
||||
memory[0xFE00 | src & 0xFF] = data;
|
||||
} else if (oamDmaPos == 0xA0) {
|
||||
endOamDma(lOamDmaUpdate - 2);
|
||||
lOamDmaUpdate = COUNTER_DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
nontrivial_write(0x8000 | dmaDest++ & 0x1FFF, data, cycleCounter);
|
||||
}
|
||||
|
||||
cycleCounter += 2 << doubleSpeed;
|
||||
lastOamDmaUpdate = lOamDmaUpdate;
|
||||
}
|
||||
|
||||
cycleCounter += 4;
|
||||
|
||||
dmaSource = dmaSrc;
|
||||
dmaDestination = dmaDest;
|
||||
memory[0xFF55] = dmaLength / 0x10 - 0x1 & 0xFF | memory[0xFF55] & 0x80;
|
||||
@ -372,14 +389,20 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
||||
hdma_transfer = 0;
|
||||
}
|
||||
|
||||
if (hdma_transfer)
|
||||
if (hdma_transfer) {
|
||||
if (lastOamDmaUpdate != COUNTER_DISABLED)
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
next_dmatime = display.nextHdmaTime(cycleCounter);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case INTERRUPTS:
|
||||
// printf("interrupts\n");
|
||||
update_irqEvents(cycleCounter);
|
||||
memory[0xFF0F] |= display.getIfReg(cycleCounter) & 3;
|
||||
|
||||
{
|
||||
/*unsigned interrupt = memory[0xFF0F] & memory[0xFFFF];
|
||||
interrupt |= interrupt << 1;
|
||||
@ -432,6 +455,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
||||
cycleCounter = interrupter.interrupt(address, cycleCounter, *this);
|
||||
}
|
||||
}
|
||||
|
||||
next_irqtime = IME ? std::min(next_irqEventTime, display.nextIrqEvent()) : COUNTER_DISABLED;
|
||||
break;
|
||||
case BLIT:
|
||||
@ -442,20 +466,19 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
||||
next_blittime += 70224 << isDoubleSpeed();
|
||||
else
|
||||
next_blittime = COUNTER_DISABLED;
|
||||
|
||||
break;
|
||||
case UNHALT:
|
||||
// printf("unhalt\n");
|
||||
update_irqEvents(cycleCounter);
|
||||
memory[0xFF0F] |= display.getIfReg(cycleCounter) & 3;
|
||||
// if(IME) {
|
||||
// next_irqtime=(memory[0xFF0F]&memory[0xFFFF]&0xF)?CycleCounter:((next_irqEventTime+1)?(next_irqEventTime):next_irqEventTime);
|
||||
// set_event();
|
||||
// }
|
||||
|
||||
if (memory[0xFF0F] & memory[0xFFFF] & 0x1F) {
|
||||
next_unhalttime = COUNTER_DISABLED;
|
||||
interrupter.unhalt();
|
||||
} else
|
||||
next_unhalttime = std::min(next_irqEventTime, display.nextIrqEvent()) + isCgb() * 4;
|
||||
|
||||
break;
|
||||
case END:
|
||||
// printf("end\n");
|
||||
@ -495,6 +518,10 @@ void Memory::speedChange(const unsigned long cycleCounter) {
|
||||
|
||||
unsigned long Memory::resetCounters(unsigned long cycleCounter) {
|
||||
std::printf("resetting counters\n");
|
||||
|
||||
if (lastOamDmaUpdate != COUNTER_DISABLED)
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
update_irqEvents(cycleCounter);
|
||||
rescheduleIrq(cycleCounter);
|
||||
display.preResetCounter(cycleCounter);
|
||||
@ -518,6 +545,9 @@ unsigned long Memory::resetCounters(unsigned long cycleCounter) {
|
||||
if (memory[0xFF07] & 0x04)
|
||||
tima_lastUpdate -= dec;
|
||||
|
||||
if (lastOamDmaUpdate != COUNTER_DISABLED)
|
||||
lastOamDmaUpdate -= dec;
|
||||
|
||||
next_eventtime -= dec;
|
||||
if (next_irqEventTime != COUNTER_DISABLED)
|
||||
next_irqEventTime -= dec;
|
||||
@ -568,38 +598,115 @@ void Memory::updateInput() {
|
||||
memory[0xFF00] &= button;
|
||||
}
|
||||
|
||||
void Memory::swap_rombank() {
|
||||
void Memory::setRombank() {
|
||||
unsigned bank = rombank;
|
||||
|
||||
if (romtype == mbc1 && !(bank & 0x1F) || romtype == mbc5 && !bank)
|
||||
++bank;
|
||||
|
||||
mem[0x4] = &romdata[bank*0x4000ul];
|
||||
mem[0x5] = mem[0x4] + 0x1000;
|
||||
mem[0x6] = mem[0x4] + 0x2000;
|
||||
mem[0x7] = mem[0x4] + 0x3000;
|
||||
rombankptr = mem[0x4] - 0x4000;
|
||||
romdata[1] = romdata[0] + bank * 0x4000ul;
|
||||
|
||||
if (oamDmaArea1Lower != 0xA0) {
|
||||
rmem[0x4] = romdata[1];
|
||||
rmem[0x5] = rmem[0x4] + 0x1000;
|
||||
rmem[0x6] = rmem[0x4] + 0x2000;
|
||||
rmem[0x7] = rmem[0x4] + 0x3000;
|
||||
} else
|
||||
setOamDmaSrc();
|
||||
}
|
||||
|
||||
//TODO: Accurate implementation.
|
||||
void Memory::oamDma(const unsigned long cycleCounter) {
|
||||
const unsigned address = memory[0xFF46] << 8;
|
||||
|
||||
unsigned i = 0;
|
||||
|
||||
while (memory[0xFE00 | i] == read(address | i, cycleCounter) && i < 0xA0)
|
||||
++i;
|
||||
|
||||
if (i < 0xA0) {
|
||||
display.oamChange(cycleCounter);
|
||||
rescheduleIrq(cycleCounter);
|
||||
rescheduleHdmaReschedule();
|
||||
|
||||
do {
|
||||
memory[0xFE00 | i] = read(address | i, cycleCounter);
|
||||
++i;
|
||||
} while (i < 0xA0);
|
||||
void Memory::setRambank() {
|
||||
if (enable_ram) {
|
||||
if (rtc.getActive()) {
|
||||
wmem[0xB] = wmem[0xA] = rmem[0xB] = rmem[0xA] = wsrambankptr = rsrambankptr = NULL;
|
||||
} else {
|
||||
wmem[0xA] = rmem[0xA] = wsrambankptr = rsrambankptr = rambankdata + rambank * 0x2000ul;
|
||||
wmem[0xB] = rmem[0xB] = rmem[0xA] + 0x1000;
|
||||
}
|
||||
} else {
|
||||
rmem[0xB] = rmem[0xA] = rsrambankptr = rdisabled_ram;
|
||||
wmem[0xB] = wmem[0xA] = wsrambankptr = wdisabled_ram;
|
||||
}
|
||||
|
||||
if (oamDmaArea1Lower == 0xA0) {
|
||||
wmem[0xB] = wmem[0xA] = rmem[0xB] = rmem[0xA] = NULL;
|
||||
setOamDmaSrc();
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::setBanks() {
|
||||
rmem[0x0] = romdata[0];
|
||||
rmem[0x1] = romdata[0] + 0x1000;
|
||||
rmem[0x2] = romdata[0] + 0x2000;
|
||||
rmem[0x3] = romdata[0] + 0x3000;
|
||||
|
||||
setRombank();
|
||||
setRambank();
|
||||
|
||||
wmem[0xE] = wmem[0xC] = rmem[0xE] = rmem[0xC] = wramdata[0];
|
||||
wmem[0xD] = rmem[0xD] = wramdata[1];
|
||||
}
|
||||
|
||||
void Memory::updateOamDma(const unsigned long cycleCounter) {
|
||||
unsigned cycles = cycleCounter - lastOamDmaUpdate >> 2;
|
||||
|
||||
while (cycles--) {
|
||||
oamDmaPos = oamDmaPos + 1 & 0xFF;
|
||||
lastOamDmaUpdate += 4;
|
||||
|
||||
//TODO: reads from vram while the ppu is reading vram should return whatever the ppu is reading.
|
||||
if (oamDmaPos < 0xA0) {
|
||||
if (oamDmaPos == 0)
|
||||
startOamDma(lastOamDmaUpdate - 2);
|
||||
|
||||
memory[0xFE00 + oamDmaPos] = oamDmaSrc ? oamDmaSrc[oamDmaPos] : *rtc.getActive();
|
||||
} else if (oamDmaPos == 0xA0) {
|
||||
endOamDma(lastOamDmaUpdate - 2);
|
||||
lastOamDmaUpdate = COUNTER_DISABLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::startOamDma(const unsigned long cycleCounter) {
|
||||
if (memory[0xFF46] < 0xC0) {
|
||||
if ((memory[0xFF46] & 0xE0) != 0x80)
|
||||
oamDmaArea2Upper = 0x80;
|
||||
|
||||
oamDmaArea1Width = 0x20;
|
||||
} else if (memory[0xFF46] < 0xE0)
|
||||
oamDmaArea1Width = 0x3E;
|
||||
|
||||
display.oamChange(rdisabled_ram, cycleCounter);
|
||||
rescheduleIrq(cycleCounter);
|
||||
rescheduleHdmaReschedule();
|
||||
}
|
||||
|
||||
void Memory::setOamDmaSrc() {
|
||||
oamDmaSrc = NULL;
|
||||
|
||||
if (memory[0xFF46] < 0xC0) {
|
||||
if ((memory[0xFF46] & 0xE0) == 0x80) {
|
||||
oamDmaSrc = vrambank + (memory[0xFF46] << 8 & 0x1FFF);
|
||||
} else {
|
||||
if (memory[0xFF46] < 0x80)
|
||||
oamDmaSrc = romdata[memory[0xFF46] >> 6] + (memory[0xFF46] << 8 & 0x3FFF);
|
||||
else if (rsrambankptr)
|
||||
oamDmaSrc = rsrambankptr + (memory[0xFF46] << 8 & 0x1FFF);
|
||||
}
|
||||
} else if (memory[0xFF46] < 0xE0) {
|
||||
oamDmaSrc = wramdata[memory[0xFF46] >> 4 & 1] + (memory[0xFF46] << 8 & 0xFFF);
|
||||
} else
|
||||
oamDmaSrc = rdisabled_ram;
|
||||
}
|
||||
|
||||
void Memory::endOamDma(const unsigned long cycleCounter) {
|
||||
oamDmaArea2Upper = oamDmaArea1Width = oamDmaArea1Lower = 0;
|
||||
oamDmaPos = 0xFE;
|
||||
setBanks();
|
||||
display.oamChange(memory + 0xFE00, cycleCounter);
|
||||
rescheduleIrq(cycleCounter);
|
||||
rescheduleHdmaReschedule();
|
||||
}
|
||||
|
||||
void Memory::update_tima(const unsigned long cycleCounter) {
|
||||
@ -634,8 +741,11 @@ void Memory::update_tima(const unsigned long cycleCounter) {
|
||||
memory[0xFF05] = tmp;
|
||||
}
|
||||
|
||||
unsigned char Memory::ff_read(const unsigned P, const unsigned long cycleCounter) {
|
||||
switch (P & 0xFF) {
|
||||
unsigned char Memory::nontrivial_ff_read(const unsigned P, const unsigned long cycleCounter) {
|
||||
if (lastOamDmaUpdate != COUNTER_DISABLED)
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
switch (P & 0x7F) {
|
||||
case 0x00:
|
||||
updateInput();
|
||||
break;
|
||||
@ -706,37 +816,57 @@ unsigned char Memory::ff_read(const unsigned P, const unsigned long cycleCounter
|
||||
return memory[P];
|
||||
}
|
||||
|
||||
unsigned char Memory::read(const unsigned P, const unsigned long cycleCounter) {
|
||||
if ((P & 0xC000) == 0x8000) {
|
||||
if (P & 0x2000) {
|
||||
if (rtc.getActive())
|
||||
return *rtc.getActive();
|
||||
} else if (!display.vramAccessible(cycleCounter))
|
||||
return 0xFF;
|
||||
} else if ((P + 0x80 & 0xFFFF) >= 0xFE80) {
|
||||
if (P & 0x100)
|
||||
return ff_read(P, cycleCounter);
|
||||
|
||||
if (!display.oamAccessible(cycleCounter)) {
|
||||
return 0xFF;
|
||||
unsigned char Memory::nontrivial_read(const unsigned P, const unsigned long cycleCounter) {
|
||||
if (P < 0xFF80) {
|
||||
if (lastOamDmaUpdate != COUNTER_DISABLED) {
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
if ((P >> 8) - oamDmaArea1Lower < oamDmaArea1Width || P >> 8 < oamDmaArea2Upper)
|
||||
return memory[0xFE00 + oamDmaPos];
|
||||
}
|
||||
|
||||
if (P < 0xC000) {
|
||||
if (P < 0x8000)
|
||||
return romdata[P >> 14][P & 0x3FFF];
|
||||
|
||||
if (P < 0xA000) {
|
||||
if (!display.vramAccessible(cycleCounter))
|
||||
return 0xFF;
|
||||
|
||||
return vrambank[P & 0x1FFF];
|
||||
}
|
||||
|
||||
if (rsrambankptr)
|
||||
return rsrambankptr[P & 0x1FFF];
|
||||
|
||||
return *rtc.getActive();
|
||||
}
|
||||
|
||||
if (P < 0xFE00)
|
||||
return wramdata[P >> 12 & 1][P & 0xFFF];
|
||||
|
||||
if (P & 0x100)
|
||||
return nontrivial_ff_read(P, cycleCounter);
|
||||
|
||||
if (!display.oamAccessible(cycleCounter) || oamDmaPos < 0xA0)
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
return mem[P >> 12][P & 0xFFF];
|
||||
|
||||
return memory[P];
|
||||
}
|
||||
|
||||
void Memory::ff_write(const unsigned P, unsigned data, const unsigned long cycleCounter) {
|
||||
void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned long cycleCounter) {
|
||||
// printf("mem[0x%X] = 0x%X\n", P, data);
|
||||
|
||||
if (lastOamDmaUpdate != COUNTER_DISABLED)
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
switch (P & 0xFF) {
|
||||
case 0x00:
|
||||
data = memory[0xFF00] & 0xCF | data & 0xF0;
|
||||
break;
|
||||
case 0x01:
|
||||
update_irqEvents(cycleCounter);
|
||||
// if (IME) {
|
||||
// next_irqtime = (memory[0xFF0F] & memory[0xFFFF] & 0x1F) ? CycleCounter : std::min(next_irqEventTime, display.nextIrqEvent());
|
||||
// set_event();
|
||||
// }
|
||||
break;
|
||||
case 0x02:
|
||||
update_irqEvents(cycleCounter);
|
||||
@ -769,17 +899,14 @@ void Memory::ff_write(const unsigned P, unsigned data, const unsigned long cycle
|
||||
set_irqEvent();
|
||||
rescheduleIrq(cycleCounter);
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x06:
|
||||
if (memory[0xFF07] & 0x04) {
|
||||
update_irqEvents(cycleCounter);
|
||||
update_tima(cycleCounter);
|
||||
// set_irqEvent();
|
||||
// if (IME) {
|
||||
// next_irqtime = (memory[0xFF0F] & memory[0xFFFF] & 0x1F) ? CycleCounter : std::min(next_irqEventTime, display.nextIrqEvent());
|
||||
// set_event();
|
||||
// }
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x07:
|
||||
// printf("tac write: %i\n", data);
|
||||
@ -905,12 +1032,6 @@ void Memory::ff_write(const unsigned P, unsigned data, const unsigned long cycle
|
||||
if(!sound.isEnabled()) return;
|
||||
sound.generate_samples(cycleCounter, isDoubleSpeed());
|
||||
sound.set_nr34(data);
|
||||
|
||||
// if (data & 0x80) {
|
||||
// for (unsigned i = 0; i < 16; ++i)
|
||||
// memory[0xFF30 | i] ^= 0x80 | 0x20 | 0x8 | 0x2;
|
||||
// }
|
||||
|
||||
data |= 0xBF;
|
||||
break;
|
||||
case 0x20:
|
||||
@ -1002,7 +1123,7 @@ void Memory::ff_write(const unsigned P, unsigned data, const unsigned long cycle
|
||||
|
||||
next_hdmaReschedule = COUNTER_DISABLED;
|
||||
}
|
||||
|
||||
|
||||
set_event();
|
||||
}
|
||||
|
||||
@ -1030,7 +1151,6 @@ void Memory::ff_write(const unsigned P, unsigned data, const unsigned long cycle
|
||||
if ((memory[0xFF40] ^ data) & 0x01)
|
||||
display.bgEnableChange(data & 0x01, cycleCounter);
|
||||
|
||||
//scheduleM0Resc();
|
||||
rescheduleIrq(cycleCounter);
|
||||
rescheduleHdmaReschedule();
|
||||
}
|
||||
@ -1042,99 +1162,100 @@ void Memory::ff_write(const unsigned P, unsigned data, const unsigned long cycle
|
||||
data = memory[0xFF41] & 0x87 | data & 0x78;
|
||||
break;
|
||||
case 0x42:
|
||||
if (memory[0xFF42] != data) {
|
||||
display.scyChange(data, cycleCounter);
|
||||
}
|
||||
display.scyChange(data, cycleCounter);
|
||||
break;
|
||||
case 0x43:
|
||||
if (memory[0xFF43] != data) {
|
||||
display.scxChange(data, cycleCounter);
|
||||
//scheduleM0Resc();
|
||||
rescheduleIrq(cycleCounter);
|
||||
rescheduleHdmaReschedule();
|
||||
}
|
||||
display.scxChange(data, cycleCounter);
|
||||
rescheduleIrq(cycleCounter);
|
||||
rescheduleHdmaReschedule();
|
||||
break;
|
||||
//If rom is trying to write to LY register, reset it to 0.
|
||||
case 0x44:
|
||||
std::printf("OMFG!!!! LY WRITE!!\n");
|
||||
// update_irqEvents(CycleCounter);
|
||||
std::printf("ly write\n");
|
||||
memory[0xFF44] = 0;
|
||||
display.enableChange(memory[0xFF41], cycleCounter);
|
||||
display.enableChange(memory[0xFF41], cycleCounter);
|
||||
// lastModeIRQ=0xFF;
|
||||
next_blittime = (memory[0xFF40] & 0x80) ? display.nextMode1IrqTime() : COUNTER_DISABLED;
|
||||
/*if (enable_display && (memory[0xFF41]&0x40) && memory[0xFF45] < 154) {
|
||||
// lastLycIRQ=uint32_t(-1);
|
||||
if (memory[0xFF45])
|
||||
next_lyctime = CycleCounter + memory[0xFF45] * linetime - 1;
|
||||
else
|
||||
next_lyctime = CycleCounter + linetime * 153 + (8 << doubleSpeed) - 1;
|
||||
// set_event();
|
||||
}
|
||||
set_irqEvent();*/
|
||||
|
||||
if (hdma_transfer) {
|
||||
next_dmatime = display.nextHdmaTime(cycleCounter);
|
||||
next_hdmaReschedule = display.nextHdmaTimeInvalid();
|
||||
}
|
||||
|
||||
set_event();
|
||||
rescheduleIrq(cycleCounter);
|
||||
/* LYC(); resetCycles();*/
|
||||
return;
|
||||
case 0x45:
|
||||
display.lycRegChange(data, memory[0xFF41], cycleCounter);
|
||||
rescheduleIrq(cycleCounter);
|
||||
break;
|
||||
case 0x46:
|
||||
if (lastOamDmaUpdate != COUNTER_DISABLED)
|
||||
endOamDma(cycleCounter);
|
||||
|
||||
if (data < 0xC0) {
|
||||
if ((data & 0xE0) == 0x80) {
|
||||
oamDmaArea1Lower = 0x80;
|
||||
} else {
|
||||
oamDmaArea1Lower = 0xA0;
|
||||
std::fill_n(rmem, 0x8, static_cast<unsigned char*>(NULL));
|
||||
rmem[0xB] = rmem[0xA] = NULL;
|
||||
wmem[0xB] = wmem[0xA] = NULL;
|
||||
}
|
||||
} else if (data < 0xE0) {
|
||||
oamDmaArea1Lower = 0xC0;
|
||||
rmem[0xE] = rmem[0xD] = rmem[0xC] = NULL;
|
||||
wmem[0xE] = wmem[0xD] = wmem[0xC] = NULL;
|
||||
}
|
||||
|
||||
lastOamDmaUpdate = cycleCounter;
|
||||
memory[0xFF46] = data;
|
||||
oamDma(cycleCounter);
|
||||
setOamDmaSrc();
|
||||
return;
|
||||
case 0x47:
|
||||
if (!isCgb() && memory[0xFF47] != data) {
|
||||
if (!isCgb()) {
|
||||
display.dmgBgPaletteChange(data, cycleCounter);
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x48:
|
||||
if (!isCgb() && memory[0xFF48] != data) {
|
||||
if (!isCgb()) {
|
||||
display.dmgSpPalette1Change(data, cycleCounter);
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x49:
|
||||
if (!isCgb() && memory[0xFF49] != data) {
|
||||
if (!isCgb()) {
|
||||
display.dmgSpPalette2Change(data, cycleCounter);
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x4A:
|
||||
if (memory[0xFF4A] != data) {
|
||||
// printf("%u: wyChange to %u\n", CycleCounter, data);
|
||||
display.wyChange(data, cycleCounter);
|
||||
// scheduleM0Resc();
|
||||
rescheduleIrq(cycleCounter);
|
||||
rescheduleHdmaReschedule();
|
||||
}
|
||||
// printf("%u: wyChange to %u\n", CycleCounter, data);
|
||||
display.wyChange(data, cycleCounter);
|
||||
rescheduleIrq(cycleCounter);
|
||||
rescheduleHdmaReschedule();
|
||||
break;
|
||||
case 0x4B:
|
||||
if (memory[0xFF4B] != data) {
|
||||
// printf("%u: wxChange to %u\n", CycleCounter, data);
|
||||
display.wxChange(data, cycleCounter);
|
||||
// scheduleM0Resc();
|
||||
rescheduleIrq(cycleCounter);
|
||||
rescheduleHdmaReschedule();
|
||||
}
|
||||
// printf("%u: wxChange to %u\n", CycleCounter, data);
|
||||
display.wxChange(data, cycleCounter);
|
||||
rescheduleIrq(cycleCounter);
|
||||
rescheduleHdmaReschedule();
|
||||
break;
|
||||
|
||||
|
||||
//cgb stuff:
|
||||
case 0x4D:
|
||||
if (isCgb())
|
||||
memory[0xFF4D] |= data & 0x01;
|
||||
|
||||
memory[0xFF4D] |= data & 0x01;
|
||||
return;
|
||||
//Select vram bank
|
||||
case 0x4F:
|
||||
if (isCgb()) {
|
||||
//cgb_vrambank = (data & 0x01);
|
||||
mem[0x8] = vram + (data & 0x01) * 0x2000;
|
||||
mem[0x9] = mem[0x8] + 0x1000;
|
||||
memory[0xFF4F] = 0xFE | (data/*&0x01*/);
|
||||
vrambank = vram + (data & 0x01) * 0x2000;
|
||||
|
||||
if (oamDmaArea1Lower == 0x80)
|
||||
setOamDmaSrc();
|
||||
|
||||
memory[0xFF4F] = 0xFE | data;
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1166,6 +1287,7 @@ void Memory::ff_write(const unsigned P, unsigned data, const unsigned long cycle
|
||||
set_event();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1238,17 +1360,16 @@ void Memory::ff_write(const unsigned P, unsigned data, const unsigned long cycle
|
||||
case 0x6C:
|
||||
if (isCgb())
|
||||
memory[0xFF6C] = data | 0xFE;
|
||||
|
||||
|
||||
return;
|
||||
case 0x70:
|
||||
if (isCgb()) {
|
||||
unsigned bank = data & 0x07;
|
||||
wramdata[1] = wramdata[0] + ((data & 0x07) ? (data & 0x07) : 1) * 0x1000;
|
||||
|
||||
if (!bank)
|
||||
bank = 1;
|
||||
|
||||
mem[0xD] = cgb_wramdata + bank * 0x1000;
|
||||
std::memcpy(mem[0xF], mem[0xD], 0xE00); //sync wram-mirror.
|
||||
if (oamDmaArea1Lower == 0xC0)
|
||||
setOamDmaSrc();
|
||||
else
|
||||
wmem[0xD] = rmem[0xD] = wramdata[1];
|
||||
|
||||
memory[0xFF70] = data | 0xF8;
|
||||
}
|
||||
@ -1271,10 +1392,8 @@ void Memory::ff_write(const unsigned P, unsigned data, const unsigned long cycle
|
||||
rescheduleIrq(cycleCounter);
|
||||
return;
|
||||
default:
|
||||
if (P < 0xFF80)
|
||||
return;
|
||||
|
||||
break;
|
||||
// if (P < 0xFF80)
|
||||
return;
|
||||
}
|
||||
|
||||
memory[P] = data;
|
||||
@ -1293,14 +1412,7 @@ void Memory::mbc_write(const unsigned P, const unsigned data) {
|
||||
if (rtcRom)
|
||||
rtc.setEnabled(enable_ram);
|
||||
|
||||
if (enable_ram) {
|
||||
mem[0xA] = &rambankdata[rambank*0x2000ul];
|
||||
mem[0xB] = mem[0xA] + 0x1000;
|
||||
} else {
|
||||
mem[0xA] = disabled_ram;
|
||||
mem[0xB] = disabled_ram;
|
||||
}
|
||||
|
||||
setRambank();
|
||||
break;
|
||||
//MBC1 writes ???n nnnn to address area 0x2000-0x3FFF, ???n nnnn makes up the lower digits to determine which rombank to load.
|
||||
//MBC3 writes ?nnn nnnn to address area 0x2000-0x3FFF, ?nnn nnnn makes up the lower digits to determine which rombank to load.
|
||||
@ -1313,7 +1425,7 @@ void Memory::mbc_write(const unsigned P, const unsigned data) {
|
||||
case mbc5:
|
||||
rombank = rombank & 0x100 | data;
|
||||
rombank = rombank % rombanks;
|
||||
swap_rombank();
|
||||
setRombank();
|
||||
return;
|
||||
default:
|
||||
break; //Only supposed to break one level.
|
||||
@ -1341,7 +1453,7 @@ void Memory::mbc_write(const unsigned P, const unsigned data) {
|
||||
}
|
||||
|
||||
rombank = rombank % rombanks;
|
||||
swap_rombank();
|
||||
setRombank();
|
||||
break;
|
||||
//MBC1 writes ???? ??nn to area 0x4000-0x5FFF either to determine rambank to load, or upper 2 bits of the rombank number to load, depending on rom-mode.
|
||||
//MBC3 writes ???? ??nn to area 0x4000-0x5FFF to determine rambank to load
|
||||
@ -1357,7 +1469,7 @@ void Memory::mbc_write(const unsigned P, const unsigned data) {
|
||||
|
||||
rombank = (data & 0x03) << 5 | rombank & 0x1F;
|
||||
rombank = rombank % rombanks;
|
||||
swap_rombank();
|
||||
setRombank();
|
||||
return;
|
||||
case mbc3:
|
||||
if (rtcRom)
|
||||
@ -1373,12 +1485,7 @@ void Memory::mbc_write(const unsigned P, const unsigned data) {
|
||||
}
|
||||
|
||||
rambank &= rambanks - 1;
|
||||
|
||||
if (enable_ram) {
|
||||
mem[0xA] = &rambankdata[rambank*0x2000];
|
||||
mem[0xB] = mem[0xA] + 0x1000;
|
||||
}
|
||||
|
||||
setRambank();
|
||||
break;
|
||||
//MBC1: If ???? ???1 is written to area 0x6000-0x7FFFF rom will be set to rambank mode.
|
||||
case 0x6:
|
||||
@ -1399,60 +1506,43 @@ void Memory::mbc_write(const unsigned P, const unsigned data) {
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (P < 0x8000) {
|
||||
mbc_write(P, data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (P < 0xA000) {
|
||||
if (mem[P >> 12][P & 0xFFF] != data) {
|
||||
if (memory[0xFF40] & 0x80) {
|
||||
if (!display.vramAccessible(cycleCounter)) {
|
||||
// printf("vram write during mode3 at line %i. Next mode0: %u\n", display.get_ly(CycleCounter), display.next_mode0(CycleCounter));
|
||||
return;
|
||||
}
|
||||
|
||||
display.vramChange(cycleCounter);
|
||||
}
|
||||
}
|
||||
} else if (P < 0xC000) {
|
||||
if (!enable_ram)
|
||||
return;
|
||||
void Memory::nontrivial_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (lastOamDmaUpdate != COUNTER_DISABLED) {
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
if (rtc.getActive()) {
|
||||
rtc.write(data);
|
||||
if ((P >> 8) - oamDmaArea1Lower < oamDmaArea1Width || P >> 8 < oamDmaArea2Upper) {
|
||||
memory[0xFE00 + oamDmaPos] = data;
|
||||
return;
|
||||
}
|
||||
} else if (P >= 0xD000 && P < 0xDE00) {
|
||||
memory[P + 0x2000] = data;
|
||||
} else if (P >= 0xF000) {
|
||||
if (P < 0xFE00)
|
||||
mem[0xD][P & 0xFFF] = data;
|
||||
else if (P < 0xFF00) {
|
||||
if (memory[P] != data) {
|
||||
if (memory[0xFF40] & 0x80) {
|
||||
if (!display.oamAccessible(cycleCounter)) { //mode2 or mode3.
|
||||
// printf("oam write during mode2 at line %i\n", display.get_ly(CycleCounter));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (P < 0xFE00) {
|
||||
if (P < 0xA000) {
|
||||
if (P < 0x8000) {
|
||||
mbc_write(P, data);
|
||||
} else if (display.vramAccessible(cycleCounter)) {
|
||||
display.vramChange(cycleCounter);
|
||||
vrambank[P & 0x1FFF] = data;
|
||||
}
|
||||
} else if (P < 0xC000) {
|
||||
if (wsrambankptr)
|
||||
wsrambankptr[P & 0x1FFF] = data;
|
||||
else
|
||||
rtc.write(data);
|
||||
} else
|
||||
wramdata[P >> 12 & 1][P & 0xFFF] = data;
|
||||
} else if ((P + 1 & 0xFFFF) < 0xFF81) {
|
||||
if (P < 0xFF00) {
|
||||
if (display.oamAccessible(cycleCounter) && oamDmaPos >= 0xA0) {
|
||||
display.oamChange(cycleCounter);
|
||||
//scheduleM0Resc();
|
||||
rescheduleIrq(cycleCounter);
|
||||
rescheduleHdmaReschedule();
|
||||
memory[P] = data;
|
||||
}
|
||||
} else if (P < 0xFF80 || P == 0xFFFF) {
|
||||
ff_write(P, data, cycleCounter);
|
||||
return;
|
||||
}
|
||||
|
||||
} else
|
||||
nontrivial_ff_write(P, data, cycleCounter);
|
||||
} else
|
||||
memory[P] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
mem[P >> 12][P & 0xFFF] = data;
|
||||
}
|
||||
|
||||
bool Memory::loadROM(const char* file) {
|
||||
@ -1468,8 +1558,8 @@ bool Memory::loadROM(const char* file) {
|
||||
}
|
||||
|
||||
bool Memory::loadROM() {
|
||||
delete []cgb_wramdata;
|
||||
cgb_wramdata = NULL;
|
||||
delete []wramdata[0];
|
||||
wramdata[0] = NULL;
|
||||
|
||||
File rom(romfile);
|
||||
|
||||
@ -1482,16 +1572,15 @@ bool Memory::loadROM() {
|
||||
|
||||
if (isCgb()) {
|
||||
// cgb = 1;
|
||||
cgb_wramdata = new unsigned char[0x8000];
|
||||
wramdata[0] = new unsigned char[0x8000];
|
||||
|
||||
std::memcpy(cgb_wramdata, memory + 0xC000, 0x2000);
|
||||
std::memcpy(cgb_wramdata + 0x2000, cgb_wramdata, 0x2000);
|
||||
std::memcpy(cgb_wramdata + 0x4000, cgb_wramdata, 0x4000);
|
||||
|
||||
mem[0xC] = &cgb_wramdata[0];
|
||||
mem[0xD] = &cgb_wramdata[0x1000];
|
||||
mem[0xE] = mem[0xC];
|
||||
std::memcpy(wramdata[0], memory + 0xC000, 0x2000);
|
||||
std::memcpy(wramdata[0] + 0x2000, wramdata[0], 0x2000);
|
||||
std::memcpy(wramdata[0] + 0x4000, wramdata[0], 0x4000);
|
||||
} else {
|
||||
wramdata[0] = new unsigned char[0x2000];
|
||||
std::memcpy(wramdata[0], memory + 0xC000, 0x2000);
|
||||
|
||||
memory[0xFF30] = 0xAC;
|
||||
memory[0xFF31] = 0xDD;
|
||||
memory[0xFF32] = 0xDA;
|
||||
@ -1524,8 +1613,8 @@ bool Memory::loadROM() {
|
||||
memory[0xFF76] = 0xFF;
|
||||
memory[0xFF77] = 0xFF;
|
||||
}
|
||||
|
||||
std::memcpy(mem[0xF], mem[0xD], 0xE00); //Make sure the wram-mirror is synced.
|
||||
|
||||
wramdata[1] = wramdata[0] + 0x1000;
|
||||
|
||||
switch (memory[0x0147]) {
|
||||
case 0x00: std::printf("Plain ROM loaded.\n");
|
||||
@ -1696,16 +1785,11 @@ bool Memory::loadROM() {
|
||||
std::printf("rombanks: %u\n", rombanks);
|
||||
rom.rewind();
|
||||
|
||||
delete []romdata;
|
||||
romdata = new unsigned char[rombanks * 0x4000];
|
||||
rom.read(reinterpret_cast<char*>(romdata), rombanks * 0x4000);
|
||||
delete []romdata[0];
|
||||
romdata[0] = new unsigned char[rombanks * 0x4000];
|
||||
rom.read(reinterpret_cast<char*>(romdata[0]), rombanks * 0x4000);
|
||||
rom.close();
|
||||
|
||||
for (unsigned i = 0; i < 0x8; ++i)
|
||||
mem[i] = &romdata[i*0x1000];
|
||||
|
||||
rombankptr = mem[0x4] - 0x4000;
|
||||
|
||||
delete []rambankdata;
|
||||
rambankdata = new unsigned char[rambanks * 0x2000];
|
||||
std::memset(rambankdata, 0xFF, rambanks * 0x2000);
|
||||
@ -1789,6 +1873,8 @@ bool Memory::loadROM() {
|
||||
|
||||
rtc.setBaseTime(basetime);
|
||||
}
|
||||
|
||||
setBanks();
|
||||
|
||||
sound.init(memory + 0xFF00, isCgb());
|
||||
display.reset(isCgb());
|
||||
@ -1915,7 +2001,7 @@ Memory::~Memory() {
|
||||
|
||||
delete []savedir;
|
||||
delete []savename;
|
||||
delete []romdata;
|
||||
delete []romdata[0];
|
||||
delete []rambankdata;
|
||||
delete []cgb_wramdata;
|
||||
delete []wramdata[0];
|
||||
}
|
||||
|
@ -40,17 +40,22 @@ class Memory {
|
||||
|
||||
unsigned char memory[0x10000];
|
||||
unsigned char vram[0x2000 * 2];
|
||||
unsigned char disabled_ram[0x1000];
|
||||
unsigned char *mem[0x10];
|
||||
unsigned char rdisabled_ram[0x1000];
|
||||
unsigned char wdisabled_ram[0x1000];
|
||||
unsigned char *rmem[0x10];
|
||||
unsigned char *wmem[0x10];
|
||||
unsigned char cgb_bgp_data[8 * 8];
|
||||
unsigned char cgb_objp_data[8 * 8];
|
||||
|
||||
unsigned char *rombankptr;
|
||||
unsigned char *romdata[2];
|
||||
unsigned char *wramdata[2];
|
||||
unsigned char *rambankdata;
|
||||
unsigned char *cgb_wramdata;
|
||||
unsigned char *oamDmaSrc;
|
||||
unsigned char *vrambank;
|
||||
unsigned char *rsrambankptr;
|
||||
unsigned char *wsrambankptr;
|
||||
|
||||
char* romfile;
|
||||
unsigned char *romdata;
|
||||
char *savedir;
|
||||
char *savename;
|
||||
|
||||
@ -69,6 +74,7 @@ class Memory {
|
||||
unsigned long tmatime;
|
||||
unsigned long next_serialtime;
|
||||
unsigned long next_eventtime;
|
||||
unsigned long lastOamDmaUpdate;
|
||||
|
||||
LCD display;
|
||||
PSG sound;
|
||||
@ -86,6 +92,10 @@ class Memory {
|
||||
|
||||
unsigned char rambank;
|
||||
unsigned char rambanks;
|
||||
unsigned char oamDmaArea1Lower;
|
||||
unsigned char oamDmaArea1Width;
|
||||
unsigned char oamDmaArea2Upper;
|
||||
unsigned char oamDmaPos;
|
||||
|
||||
bool IME;
|
||||
bool enable_ram;
|
||||
@ -99,9 +109,19 @@ class Memory {
|
||||
void save_rtc();
|
||||
void updateInput();
|
||||
|
||||
void swap_rombank();
|
||||
void oamDma(unsigned long cycleCounter);
|
||||
void setRombank();
|
||||
void setRambank();
|
||||
void setBanks();
|
||||
void updateOamDma(unsigned long cycleCounter);
|
||||
void startOamDma(unsigned long cycleCounter);
|
||||
void endOamDma(unsigned long cycleCounter);
|
||||
void setOamDmaSrc();
|
||||
|
||||
unsigned char nontrivial_ff_read(unsigned P, unsigned long cycleCounter);
|
||||
unsigned char nontrivial_read(unsigned P, unsigned long cycleCounter);
|
||||
void nontrivial_ff_write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
void mbc_write(unsigned P, unsigned data);
|
||||
void nontrivial_write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
|
||||
void set_event();
|
||||
void set_irqEvent();
|
||||
@ -134,29 +154,39 @@ public:
|
||||
void di() {
|
||||
IME = 0;
|
||||
next_irqtime = COUNTER_DISABLED;
|
||||
|
||||
if (next_event == INTERRUPTS)
|
||||
set_event();
|
||||
// next_eitime=0;
|
||||
// if(next_event==EI) set_event();
|
||||
|
||||
// next_eitime=0;
|
||||
// if(next_event==EI) set_event();
|
||||
}
|
||||
|
||||
unsigned char ff_read(const unsigned P, const unsigned long cycleCounter) {
|
||||
return P < 0xFF80 ? nontrivial_ff_read(P, cycleCounter) : memory[P];
|
||||
}
|
||||
|
||||
unsigned char ff_read(unsigned P, unsigned long cycleCounter);
|
||||
|
||||
unsigned char read(unsigned P, unsigned long cycleCounter);
|
||||
unsigned char read(const unsigned P, const unsigned long cycleCounter) {
|
||||
return rmem[P >> 12] ? rmem[P >> 12][P & 0xFFF] : nontrivial_read(P, cycleCounter);
|
||||
}
|
||||
|
||||
unsigned char pc_read(const unsigned P, const unsigned long cycleCounter) {
|
||||
if (P < 0x4000)
|
||||
return mem[0][P];
|
||||
|
||||
if (P < 0x8000)
|
||||
return rombankptr[P];
|
||||
|
||||
return read(P, cycleCounter);
|
||||
}
|
||||
|
||||
void write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
void ff_write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
void write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (wmem[P >> 12])
|
||||
wmem[P >> 12][P & 0xFFF] = data;
|
||||
else
|
||||
nontrivial_write(P, data, cycleCounter);
|
||||
}
|
||||
|
||||
void ff_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if ((P + 1 & 0xFF) < 0x81)
|
||||
nontrivial_ff_write(P, data, cycleCounter);
|
||||
else
|
||||
memory[P] = data;
|
||||
}
|
||||
|
||||
unsigned long event(unsigned long cycleCounter);
|
||||
unsigned long resetCounters(unsigned long cycleCounter);
|
||||
|
@ -96,7 +96,7 @@ LCD::LCD(const unsigned char *const oamram, const unsigned char *const vram_in)
|
||||
vEventQueue(5, VideoEventComparer()),
|
||||
win(m3EventQueue, lyCounter, m3ExtraCycles),
|
||||
scxReader(m3EventQueue, /*wyReg.reader3(),*/ win.wxReader, win.we.enableChecker(), win.we.disableChecker(), m3ExtraCycles),
|
||||
spriteMapper(m3ExtraCycles, oamram),
|
||||
spriteMapper(m3ExtraCycles, lyCounter, oamram),
|
||||
m3ExtraCycles(spriteMapper, scxReader, win),
|
||||
breakEvent(drawStartCycle, scReadOffset),
|
||||
mode3Event(m3EventQueue, vEventQueue, mode0Irq, irqEvent),
|
||||
@ -383,11 +383,13 @@ void LCD::preResetCounter(const unsigned long cycleCounter) {
|
||||
void LCD::postResetCounter(const unsigned long oldCC, const unsigned long cycleCounter) {
|
||||
enableDisplayM0Time = oldCC > enableDisplayM0Time ? 0 : (cycleCounter + enableDisplayM0Time - oldCC);
|
||||
lastUpdate = cycleCounter - (oldCC - lastUpdate);
|
||||
spriteMapper.resetCycleCounter(cycleCounter);
|
||||
rescheduleEvents(cycleCounter);
|
||||
}
|
||||
|
||||
void LCD::preSpeedChange(const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
spriteMapper.preCounterChange(cycleCounter);
|
||||
}
|
||||
|
||||
void LCD::rescheduleEvents(const unsigned long cycleCounter) {
|
||||
@ -474,7 +476,6 @@ bool LCD::isLycIrqPeriod(const unsigned lycReg, const unsigned endCycles, const
|
||||
return lyCounter.ly() == lycReg && timeToNextLy > endCycles || lyCounter.ly() < 153 && lyCounter.ly() + 1 == lycReg && timeToNextLy <= 1;
|
||||
else
|
||||
return lyCounter.ly() == 153 && timeToNextLy <= ((456U - 8U) << doubleSpeed) + 1 || lyCounter.ly() == 0 && timeToNextLy > endCycles;
|
||||
|
||||
}
|
||||
|
||||
bool LCD::isMode1IrqPeriod(const unsigned long cycleCounter) {
|
||||
@ -507,9 +508,11 @@ unsigned long LCD::nextHdmaTime(const unsigned long cycleCounter) {
|
||||
if (line < 144) {
|
||||
m3ExCs = m3ExtraCycles(line) * 2;
|
||||
next += m3ExCs;
|
||||
|
||||
if (next <= 0) {
|
||||
next += 456 * 2 - m3ExCs;
|
||||
++line;
|
||||
|
||||
if (line < 144) {
|
||||
m3ExCs = m3ExtraCycles(line) * 2;
|
||||
next += m3ExCs;
|
||||
@ -532,7 +535,8 @@ bool LCD::vramAccessible(const unsigned long cycleCounter) {
|
||||
bool accessible = true;
|
||||
|
||||
if (enabled && lyCounter.ly() < 144) {
|
||||
const unsigned lineCycles = 456 - ((lyCounter.time() - cycleCounter) >> doubleSpeed);
|
||||
const unsigned lineCycles = lyCounter.lineCycles(cycleCounter);
|
||||
|
||||
if (lineCycles > 79 && lineCycles < 80 + 169 + doubleSpeed * 3 + m3ExtraCycles(lyCounter.ly()))
|
||||
accessible = false;
|
||||
}
|
||||
@ -547,7 +551,8 @@ bool LCD::cgbpAccessible(const unsigned long cycleCounter) {
|
||||
bool accessible = true;
|
||||
|
||||
if (enabled && lyCounter.ly() < 144) {
|
||||
const unsigned lineCycles = 456 - ((lyCounter.time() - cycleCounter/* + 4*/) >> doubleSpeed);
|
||||
const unsigned lineCycles = lyCounter.lineCycles(cycleCounter);
|
||||
|
||||
if (lineCycles > 79U + doubleSpeed && lineCycles < 80U + 169U + doubleSpeed * 3 + m3ExtraCycles(lyCounter.ly()) + 4U - doubleSpeed * 2)
|
||||
accessible = false;
|
||||
}
|
||||
@ -562,15 +567,15 @@ bool LCD::oamAccessible(const unsigned long cycleCounter) {
|
||||
if (cycleCounter >= vEventQueue.top()->time())
|
||||
update(cycleCounter);
|
||||
|
||||
const unsigned timeToNextLy = lyCounter.time() - cycleCounter;
|
||||
|
||||
if (lyCounter.ly() < 144) {
|
||||
const unsigned lineCycles = 456 - (timeToNextLy >> doubleSpeed);
|
||||
const unsigned lineCycles = lyCounter.lineCycles(cycleCounter);
|
||||
|
||||
if (lineCycles < 80) {
|
||||
if (cycleCounter > enableDisplayM0Time)
|
||||
accessible = false;
|
||||
} else {
|
||||
const unsigned m0start = 80 + 169 + doubleSpeed * 3 + m3ExtraCycles(lyCounter.ly());
|
||||
|
||||
if (lineCycles < m0start || !doubleSpeed && lineCycles >= 452)
|
||||
accessible = false;
|
||||
}
|
||||
@ -635,7 +640,7 @@ void LCD::scxChange(const unsigned newScx, const unsigned long cycleCounter) {
|
||||
addEvent(mode3Event, vEventQueue);
|
||||
|
||||
|
||||
const unsigned lineCycles = 456 - ((lyCounter.time() - cycleCounter) >> doubleSpeed);
|
||||
const unsigned lineCycles = lyCounter.lineCycles(cycleCounter);
|
||||
|
||||
breakEvent.setScxSource(newScx);
|
||||
|
||||
@ -663,6 +668,7 @@ void LCD::spriteSizeChange(const bool newLarge, const unsigned long cycleCounter
|
||||
update(cycleCounter);
|
||||
//printf("spriteSizeChange\n");
|
||||
|
||||
spriteMapper.oamChange(cycleCounter);
|
||||
spriteMapper.setLargeSpritesSource(newLarge);
|
||||
addEvent(spriteMapper, lyCounter, cycleCounter, m3EventQueue);
|
||||
|
||||
@ -673,6 +679,17 @@ void LCD::oamChange(const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
//printf("oamChange\n");
|
||||
|
||||
spriteMapper.oamChange(cycleCounter);
|
||||
addEvent(spriteMapper, lyCounter, cycleCounter, m3EventQueue);
|
||||
|
||||
addEvent(mode3Event, vEventQueue);
|
||||
}
|
||||
|
||||
void LCD::oamChange(const unsigned char *const oamram, const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
//printf("oamChange\n");
|
||||
|
||||
spriteMapper.oamChange(oamram, cycleCounter);
|
||||
addEvent(spriteMapper, lyCounter, cycleCounter, m3EventQueue);
|
||||
|
||||
addEvent(mode3Event, vEventQueue);
|
||||
@ -683,13 +700,13 @@ void LCD::wdTileMapSelectChange(const bool newValue, const unsigned long cycleCo
|
||||
|
||||
// printf("%u: wdTileMapSelectChange: 0x%X\n", videoCycles, newValue);
|
||||
|
||||
wdTileMap = vram + (0x1800 | newValue * 0x400);
|
||||
wdTileMap = vram + 0x1800 + newValue * 0x400;
|
||||
}
|
||||
|
||||
void LCD::bgTileMapSelectChange(const bool newValue, const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
|
||||
bgTileMap = vram + (0x1800 | newValue * 0x400);
|
||||
bgTileMap = vram + 0x1800 + newValue * 0x400;
|
||||
}
|
||||
|
||||
void LCD::bgTileDataSelectChange(const bool newValue, const unsigned long cycleCounter) {
|
||||
@ -887,11 +904,12 @@ unsigned LCD::get_stat(const unsigned lycReg, const unsigned long cycleCounter)
|
||||
|
||||
void LCD::do_update(unsigned cycles) {
|
||||
if (lyCounter.ly() < 144) {
|
||||
const unsigned lineCycles = 456 - (lyCounter.time() - lastUpdate >> doubleSpeed);
|
||||
const unsigned lineCycles = lyCounter.lineCycles(lastUpdate);
|
||||
const unsigned xpos = lineCycles < drawStartCycle ? 0 : lineCycles - drawStartCycle;
|
||||
|
||||
const unsigned endLineCycles = lineCycles + cycles;
|
||||
unsigned endX = endLineCycles < drawStartCycle ? 0 : endLineCycles - drawStartCycle;
|
||||
|
||||
if (endX > 160)
|
||||
endX = 160;
|
||||
|
||||
@ -905,6 +923,7 @@ void LCD::do_update(unsigned cycles) {
|
||||
}
|
||||
|
||||
videoCycles += cycles;
|
||||
|
||||
if (videoCycles >= 70224U)
|
||||
videoCycles -= 70224U;
|
||||
}
|
||||
@ -1247,15 +1266,15 @@ void LCD::cgb_drawSprites(T * const buffer_line, const unsigned ypos) {
|
||||
const unsigned char *const spriteMapLine = spriteMapper.sprites(ypos);
|
||||
|
||||
for (int i = spriteMapper.numSprites(ypos) - 1; i >= 0; --i) {
|
||||
const unsigned char *const spriteInfo = spriteMapper.oamram + spriteMapLine[i];
|
||||
const unsigned spx = spriteInfo[1];
|
||||
const unsigned spNrX2 = spriteMapLine[i];
|
||||
const unsigned spx = spriteMapper.posbuf()[spNrX2 + 1];
|
||||
|
||||
if (spx < 168 && spx) {
|
||||
unsigned spLine = ypos + 16 - spriteInfo[0];
|
||||
unsigned spTile = spriteInfo[2];
|
||||
const unsigned attributes = spriteInfo[3];
|
||||
unsigned spLine = ypos + 16 - spriteMapper.posbuf()[spNrX2];
|
||||
unsigned spTile = spriteMapper.oamram()[spNrX2 * 2 + 2];
|
||||
const unsigned attributes = spriteMapper.oamram()[spNrX2 * 2 + 3];
|
||||
|
||||
if (spriteMapper.largeSprites()) {
|
||||
if (spriteMapper.largeSprites(spNrX2 >> 1)) {
|
||||
if (attributes & 0x40) //yflip
|
||||
spLine = 15 - spLine;
|
||||
|
||||
@ -1420,15 +1439,15 @@ void LCD::drawSprites(T * const buffer_line, const unsigned ypos) {
|
||||
const unsigned char *const spriteMapLine = spriteMapper.sprites(ypos);
|
||||
|
||||
for (int i = spriteMapper.numSprites(ypos) - 1; i >= 0; --i) {
|
||||
const unsigned char *const spriteInfo = spriteMapper.oamram + spriteMapLine[i];
|
||||
const unsigned spx = spriteInfo[1];
|
||||
const unsigned spNrX2 = spriteMapLine[i];
|
||||
const unsigned spx = spriteMapper.posbuf()[spNrX2 + 1];
|
||||
|
||||
if (spx < 168 && spx) {
|
||||
unsigned spLine = ypos + 16 - spriteInfo[0];
|
||||
unsigned spTile = spriteInfo[2];
|
||||
const unsigned attributes = spriteInfo[3];
|
||||
unsigned spLine = ypos + 16 - spriteMapper.posbuf()[spNrX2];
|
||||
unsigned spTile = spriteMapper.oamram()[spNrX2 * 2 + 2];
|
||||
const unsigned attributes = spriteMapper.oamram()[spNrX2 * 2 + 3];
|
||||
|
||||
if (spriteMapper.largeSprites()) {
|
||||
if (spriteMapper.largeSprites(spNrX2 >> 1)) {
|
||||
if (attributes & 0x40) //yflip
|
||||
spLine = 15 - spLine;
|
||||
|
||||
|
@ -198,6 +198,7 @@ public:
|
||||
void wxChange(unsigned newValue, unsigned long cycleCounter);
|
||||
void wyChange(unsigned newValue, unsigned long cycleCounter);
|
||||
void oamChange(unsigned long cycleCounter);
|
||||
void oamChange(const unsigned char *oamram, unsigned long cycleCounter);
|
||||
void scxChange(unsigned newScx, unsigned long cycleCounter);
|
||||
void scyChange(unsigned newValue, unsigned long cycleCounter);
|
||||
void spriteSizeChange(bool newLarge, unsigned long cycleCounter);
|
||||
|
@ -35,6 +35,10 @@ public:
|
||||
return ds;
|
||||
}
|
||||
|
||||
unsigned lineCycles(const unsigned long cc) const {
|
||||
return 456u - (time() - cc >> isDoubleSpeed());
|
||||
}
|
||||
|
||||
unsigned lineTime() const {
|
||||
return lineTime_;
|
||||
}
|
||||
|
@ -33,13 +33,13 @@ M3ExtraCycles::M3ExtraCycles(const SpriteMapper &spriteMapper,
|
||||
}
|
||||
|
||||
static const unsigned char* addLineCycles(const unsigned char *const start, const unsigned char *const end,
|
||||
const unsigned maxSpx, const unsigned scwxAnd7, const unsigned char *const oamram_plus1, unsigned char *cycles_out) {
|
||||
const unsigned maxSpx, const unsigned scwxAnd7, const unsigned char *const posbuf_plus1, unsigned char *cycles_out) {
|
||||
unsigned sum = 0;
|
||||
|
||||
const unsigned char *a = start;
|
||||
|
||||
for (; a < end; ++a) {
|
||||
const unsigned spx = oamram_plus1[*a];
|
||||
const unsigned spx = posbuf_plus1[*a];
|
||||
|
||||
if (spx > maxSpx)
|
||||
break;
|
||||
@ -51,7 +51,7 @@ static const unsigned char* addLineCycles(const unsigned char *const start, cons
|
||||
cycles = 11 - posAnd7;
|
||||
|
||||
for (const unsigned char *b = a; b > start;) {
|
||||
const unsigned bSpx = oamram_plus1[*--b];
|
||||
const unsigned bSpx = posbuf_plus1[*--b];
|
||||
|
||||
if (spx - bSpx > 4U)
|
||||
break;
|
||||
@ -86,16 +86,16 @@ void M3ExtraCycles::updateLine(const unsigned ly) const {
|
||||
|
||||
if (spriteMapper.isCgb()) {
|
||||
std::memcpy(sortBuf, tmp, sizeof(sortBuf));
|
||||
insertionSort(sortBuf, sortBuf + numSprites);
|
||||
insertionSort(sortBuf, sortBuf + numSprites, SpriteMapper::SpxLess(spriteMapper.posbuf()));
|
||||
tmp = sortBuf;
|
||||
}
|
||||
|
||||
const unsigned char *const tmpend = tmp + numSprites;
|
||||
const unsigned char *const oamram_plus1 = spriteMapper.oamram + 1;
|
||||
const unsigned char *const posbuf_plus1 = spriteMapper.posbuf() + 1;
|
||||
|
||||
if (windowEnabled) {
|
||||
addLineCycles(addLineCycles(tmp, tmpend, win.wxReader.wx(), scxReader.scxAnd7(), oamram_plus1, cycles + ly),
|
||||
tmpend, 167, 7 - win.wxReader.wx(), oamram_plus1, cycles + ly);
|
||||
addLineCycles(addLineCycles(tmp, tmpend, win.wxReader.wx(), scxReader.scxAnd7(), posbuf_plus1, cycles + ly),
|
||||
tmpend, 167, 7 - win.wxReader.wx(), posbuf_plus1, cycles + ly);
|
||||
} else
|
||||
addLineCycles(tmp, tmpend, 167, scxReader.scxAnd7(), oamram_plus1, cycles + ly);
|
||||
addLineCycles(tmp, tmpend, 167, scxReader.scxAnd7(), posbuf_plus1, cycles + ly);
|
||||
}
|
||||
|
@ -21,28 +21,87 @@
|
||||
#include "../insertion_sort.h"
|
||||
#include <cstring>
|
||||
|
||||
// #include <algorithm>
|
||||
#include <algorithm>
|
||||
|
||||
class SpxLess {
|
||||
const unsigned char *const oamram_plus1;
|
||||
SpriteMapper::OamReader::OamReader(const LyCounter &lyCounter, const unsigned char *oamram)
|
||||
: lyCounter(lyCounter), oamram(oamram) {
|
||||
setLargeSpritesSrc(false);
|
||||
reset();
|
||||
}
|
||||
|
||||
void SpriteMapper::OamReader::reset() {
|
||||
lu = 0xFFFFFFFF;
|
||||
lastChange = 0xFF;
|
||||
std::fill_n(szbuf, 40, largeSpritesSrc);
|
||||
|
||||
public:
|
||||
SpxLess(const unsigned char *const oamram) : oamram_plus1(oamram + 1) {}
|
||||
unsigned pos = 0;
|
||||
unsigned distance = 80;
|
||||
|
||||
bool operator()(const unsigned char l, const unsigned char r) const {
|
||||
return oamram_plus1[l] < oamram_plus1[r];
|
||||
while (distance--) {
|
||||
buf[pos] = oamram[pos * 2 & ~3 | pos & 1];
|
||||
++pos;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static unsigned toPosCycles(const unsigned long cc, const LyCounter &lyCounter) {
|
||||
unsigned lc = lyCounter.lineCycles(cc) + 4 - lyCounter.isDoubleSpeed() * 3;
|
||||
|
||||
if (lc >= 456)
|
||||
lc -= 456;
|
||||
|
||||
return lc >> 1;
|
||||
}
|
||||
|
||||
void SpriteMapper::OamReader::update(const unsigned long cc) {
|
||||
if (changed()) {
|
||||
const unsigned lulc = toPosCycles(lu, lyCounter);
|
||||
|
||||
unsigned pos = std::min(lulc, 40u);
|
||||
unsigned distance = 40;
|
||||
|
||||
if (cc - lu >> lyCounter.isDoubleSpeed() < 456) {
|
||||
const unsigned cclc = toPosCycles(cc, lyCounter);
|
||||
|
||||
distance = std::min(cclc, 40u) - pos + (cclc < lulc ? 40 : 0);
|
||||
}
|
||||
|
||||
{
|
||||
const unsigned targetDistance = lastChange - pos + (lastChange <= pos ? 40 : 0);
|
||||
|
||||
if (targetDistance <= distance) {
|
||||
distance = targetDistance;
|
||||
lastChange = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
while (distance--) {
|
||||
if (pos >= 40)
|
||||
pos = 0;
|
||||
|
||||
szbuf[pos] = largeSpritesSrc;
|
||||
buf[pos * 2] = oamram[pos * 4];
|
||||
buf[pos * 2 + 1] = oamram[pos * 4 + 1];
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
lu = cc;
|
||||
}
|
||||
|
||||
void SpriteMapper::OamReader::change(const unsigned long cc) {
|
||||
update(cc);
|
||||
lastChange = std::min(toPosCycles(cc, lyCounter), 40u);
|
||||
}
|
||||
|
||||
SpriteMapper::SpriteMapper(M3ExtraCycles &m3ExtraCycles,
|
||||
const LyCounter &lyCounter,
|
||||
const unsigned char *const oamram) :
|
||||
VideoEvent(2),
|
||||
m3ExtraCycles(m3ExtraCycles),
|
||||
oamram(oamram)
|
||||
oamReader(lyCounter, oamram)
|
||||
{
|
||||
setCgb(false);
|
||||
setLargeSpritesSource(false);
|
||||
largeSprites_ = largeSpritesSrc_;
|
||||
clearMap();
|
||||
}
|
||||
|
||||
@ -53,10 +112,9 @@ void SpriteMapper::clearMap() {
|
||||
void SpriteMapper::mapSprites() {
|
||||
clearMap();
|
||||
|
||||
const unsigned spriteHeight = 8u << largeSprites();
|
||||
|
||||
for (unsigned i = 0x00; i < 0xA0; i += 4) {
|
||||
const unsigned bottom_pos = oamram[i] - (17u - spriteHeight);
|
||||
for (unsigned i = 0x00; i < 0x50; i += 2) {
|
||||
const unsigned spriteHeight = 8u << largeSprites(i >> 1);
|
||||
const unsigned bottom_pos = posbuf()[i] - (17u - spriteHeight);
|
||||
|
||||
if (bottom_pos >= 143 + spriteHeight)
|
||||
continue;
|
||||
@ -86,17 +144,19 @@ void SpriteMapper::mapSprites() {
|
||||
|
||||
void SpriteMapper::sortLine(const unsigned ly) const {
|
||||
num[ly] &= ~NEED_SORTING_MASK;
|
||||
insertionSort(spritemap + ly * 10, spritemap + ly * 10 + num[ly], SpxLess(oamram));
|
||||
insertionSort(spritemap + ly * 10, spritemap + ly * 10 + num[ly], SpxLess(posbuf()));
|
||||
}
|
||||
|
||||
void SpriteMapper::doEvent() {
|
||||
largeSprites_ = largeSpritesSrc_;
|
||||
oamReader.update(time());
|
||||
mapSprites();
|
||||
setTime(DISABLED_TIME);
|
||||
setTime(oamReader.changed() ? time() + oamReader.lyCounter.lineTime() : DISABLED_TIME);
|
||||
}
|
||||
|
||||
void SpriteMapper::reset() {
|
||||
doEvent();
|
||||
oamReader.reset();
|
||||
mapSprites();
|
||||
setTime(DISABLED_TIME);
|
||||
}
|
||||
|
||||
/*void SpriteMapper::schedule() {
|
||||
|
@ -26,19 +26,54 @@
|
||||
class M3ExtraCycles;
|
||||
|
||||
class SpriteMapper : public VideoEvent {
|
||||
enum { NEED_SORTING_MASK = 0x80 };
|
||||
class OamReader {
|
||||
unsigned char buf[80];
|
||||
bool szbuf[40];
|
||||
|
||||
public:
|
||||
const LyCounter &lyCounter;
|
||||
|
||||
private:
|
||||
const unsigned char *oamram;
|
||||
unsigned long lu;
|
||||
unsigned char lastChange;
|
||||
bool largeSpritesSrc;
|
||||
|
||||
public:
|
||||
OamReader(const LyCounter &lyCounter, const unsigned char *oamram);
|
||||
void change(unsigned long cc);
|
||||
void change(const unsigned char *oamram, unsigned long cc) { change(cc); this->oamram = oamram; }
|
||||
bool changed() const { return lastChange != 0xFF; }
|
||||
bool largeSprites(unsigned spNr) const { return szbuf[spNr]; }
|
||||
const unsigned char *oam() const { return oamram; }
|
||||
void reset();
|
||||
void resetCycleCounter(const unsigned newCc) { lu = newCc; }
|
||||
void setLargeSpritesSrc(const bool src) { largeSpritesSrc = src; }
|
||||
void update(unsigned long cc);
|
||||
const unsigned char *spritePosBuf() const { return buf; }
|
||||
};
|
||||
|
||||
enum { NEED_SORTING_MASK = 0x80 };
|
||||
|
||||
public:
|
||||
class SpxLess {
|
||||
const unsigned char *const posbuf_plus1;
|
||||
|
||||
public:
|
||||
SpxLess(const unsigned char *const posbuf) : posbuf_plus1(posbuf + 1) {}
|
||||
|
||||
bool operator()(const unsigned char l, const unsigned char r) const {
|
||||
return posbuf_plus1[l] < posbuf_plus1[r];
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
mutable unsigned char spritemap[144*10];
|
||||
mutable unsigned char num[144];
|
||||
|
||||
M3ExtraCycles &m3ExtraCycles;
|
||||
OamReader oamReader;
|
||||
|
||||
public:
|
||||
const unsigned char *const oamram;
|
||||
|
||||
private:
|
||||
bool largeSprites_;
|
||||
bool largeSpritesSrc_;
|
||||
bool cgb;
|
||||
|
||||
void clearMap();
|
||||
@ -47,7 +82,8 @@ private:
|
||||
|
||||
public:
|
||||
SpriteMapper(M3ExtraCycles &m3ExtraCycles,
|
||||
const unsigned char *const oamram_in);
|
||||
const LyCounter &lyCounter,
|
||||
const unsigned char *oamram_in);
|
||||
|
||||
void doEvent();
|
||||
|
||||
@ -55,18 +91,42 @@ public:
|
||||
return cgb;
|
||||
}
|
||||
|
||||
bool largeSprites() const {
|
||||
return largeSprites_;
|
||||
bool largeSprites(unsigned spNr) const {
|
||||
return oamReader.largeSprites(spNr);
|
||||
}
|
||||
|
||||
unsigned numSprites(const unsigned ly) const {
|
||||
return num[ly] & ~NEED_SORTING_MASK;
|
||||
}
|
||||
|
||||
void oamChange(const unsigned long cc) {
|
||||
oamReader.change(cc);
|
||||
}
|
||||
|
||||
void oamChange(const unsigned char *oamram, const unsigned long cc) {
|
||||
oamReader.change(oamram, cc);
|
||||
}
|
||||
|
||||
const unsigned char *oamram() const {
|
||||
return oamReader.oam();
|
||||
}
|
||||
|
||||
const unsigned char *posbuf() const {
|
||||
return oamReader.spritePosBuf();
|
||||
}
|
||||
|
||||
void preCounterChange(const unsigned long cc) {
|
||||
oamReader.update(cc);
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
||||
void resetCycleCounter(const unsigned long newCc) {
|
||||
oamReader.resetCycleCounter(newCc);
|
||||
}
|
||||
|
||||
void schedule(const LyCounter &lyCounter, const unsigned long cycleCounter) {
|
||||
setTime(lyCounter.nextLineCycle(16 + lyCounter.isDoubleSpeed() * 4, cycleCounter));
|
||||
setTime(lyCounter.nextLineCycle(80, cycleCounter));
|
||||
}
|
||||
|
||||
void setCgb(const bool cgb_in) {
|
||||
@ -74,7 +134,7 @@ public:
|
||||
}
|
||||
|
||||
void setLargeSpritesSource(const bool src) {
|
||||
largeSpritesSrc_ = src;
|
||||
oamReader.setLargeSpritesSrc(src);
|
||||
}
|
||||
|
||||
const unsigned char* sprites(const unsigned ly) const {
|
||||
|
Loading…
Reference in New Issue
Block a user