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:
sinamas 2008-01-31 07:43:54 +00:00
parent 7e6d5246da
commit d7e9f01a3f
42 changed files with 578 additions and 318 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

@ -35,6 +35,10 @@ public:
return ds;
}
unsigned lineCycles(const unsigned long cc) const {
return 456u - (time() - cc >> isDoubleSpeed());
}
unsigned lineTime() const {
return lineTime_;
}

View File

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

View File

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

View File

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