2016-03-26 01:56:15 +00:00
|
|
|
auto CPU::dmaCounter() const -> uint {
|
2010-08-09 13:28:56 +00:00
|
|
|
return (status.dma_counter + hcounter()) & 7;
|
|
|
|
}
|
|
|
|
|
2016-03-26 01:56:15 +00:00
|
|
|
auto CPU::addClocks(uint clocks) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
status.irq_lock = false;
|
Update to v095r05 release.
byuu says:
Changelog:
- GBA: lots of emulation improvements
- PPU PRAM is 16-bits wide
- DMA masks &~1/Half, &~3/Word
- VRAM OBJ 8-bit writes are ignored
- OAM 8-bit writes are ignored
- BGnCNT unused bits are writable*
- BG(0,1)CNT can't set the d13
- BLDALPHA is readable (fixes Donkey Kong Country, etc)
- SNES: lots of code cleanups
- sfc/chip => sfc/coprocessor
- UI: save most recent controller selection
GBA test scores: 1552/1552, 37/38, 1020/1260
(* forgot to add the value to the read function, so endrift's I/O tests
for them will fail. Fixed locally.)
Note: SNES is the only system with multiple controller/expansion port
options, and as such is the only one with a "None" option. Because it's
shared by the controller and expansion port, it ends up sorted first in
the list. This means that on your first run, you'll need to go to Super
Famicom->Controller Port 1 and select "Gamepad", otherwise input won't
work.
Also note that changing the expansion port device requires loading a new
cart. Unlike controllers, you aren't meant to hotplug expansion port
devices.
2015-11-12 10:15:03 +00:00
|
|
|
uint ticks = clocks >> 1;
|
2010-08-09 13:28:56 +00:00
|
|
|
while(ticks--) {
|
|
|
|
tick();
|
2016-03-26 01:56:15 +00:00
|
|
|
if(hcounter() & 2) pollInterrupts();
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
step(clocks);
|
|
|
|
|
Update to v073r01 release.
byuu says:
While perhaps not perfect, pretty good is better than nothing ... I've
added emulation of auto-joypad poll timing.
Going off ikari_01's confirmation of what we suspected, that the strobe
happens every 256 clocks, I've set up emulation as follows:
Upon reset, our clock counter is reset to zero.
At the start of each frame, our poll counter is reset to zero.
Every 256 clocks, we call the step_auto_joypad_poll() function.
If we are at V=225/240+ (based on overscan setting), we check the poll
counter.
At zero, we poll the actual controller and set the joypad polling flag
in $4212.d0 to 1.
From zero through fifteen, we read in one bit for each controller and
shift it into the register.
At sixteen, we turn off the joypad polling flag.
The 256-clock divider allows the start point of polling for each frame
to fluctuate wildly like real hardware.
I count regardless of auto joypad enable, as per $4212.d0's behavior;
but only poll when it's actually enabled.
I do not consume any actual time from this polling. I honestly don't
know if I even should, or if it manages to do it in the background.
If it should consume time, then this most likely happens between opcode
edges and we'll have to adjust the code a good bit.
All commercial games should continue to work fine, but this will likely
break some hacks/translations not tested on hardware.
Without the timing emulation, reading $4218-421f before V=~228 would
basically give you the valid input controller values of the previous
frame.
Now, like hardware, it should give you a state that is part previous
frame, part current frame shifted into it. Button positions won't be
reliable and will shift every 256 clocks.
I've also removed the Qt GUI, and renamed ui-phoenix to just ui. This
removes 400kb of source code (phoenix is a lean 130kb), and drops the
archive size from 564KB to 475KB. Combined with the DSP HLE, and we've
knocked off ~570KB of source cruft from the entire project. I am looking
forward to not having to specify which GUI is included anymore.
2010-12-27 07:29:57 +00:00
|
|
|
status.auto_joypad_clock += clocks;
|
|
|
|
if(status.auto_joypad_clock >= 256) {
|
|
|
|
status.auto_joypad_clock -= 256;
|
2016-03-26 01:56:15 +00:00
|
|
|
stepAutoJoypadPoll();
|
Update to v073r01 release.
byuu says:
While perhaps not perfect, pretty good is better than nothing ... I've
added emulation of auto-joypad poll timing.
Going off ikari_01's confirmation of what we suspected, that the strobe
happens every 256 clocks, I've set up emulation as follows:
Upon reset, our clock counter is reset to zero.
At the start of each frame, our poll counter is reset to zero.
Every 256 clocks, we call the step_auto_joypad_poll() function.
If we are at V=225/240+ (based on overscan setting), we check the poll
counter.
At zero, we poll the actual controller and set the joypad polling flag
in $4212.d0 to 1.
From zero through fifteen, we read in one bit for each controller and
shift it into the register.
At sixteen, we turn off the joypad polling flag.
The 256-clock divider allows the start point of polling for each frame
to fluctuate wildly like real hardware.
I count regardless of auto joypad enable, as per $4212.d0's behavior;
but only poll when it's actually enabled.
I do not consume any actual time from this polling. I honestly don't
know if I even should, or if it manages to do it in the background.
If it should consume time, then this most likely happens between opcode
edges and we'll have to adjust the code a good bit.
All commercial games should continue to work fine, but this will likely
break some hacks/translations not tested on hardware.
Without the timing emulation, reading $4218-421f before V=~228 would
basically give you the valid input controller values of the previous
frame.
Now, like hardware, it should give you a state that is part previous
frame, part current frame shifted into it. Button positions won't be
reliable and will shift every 256 clocks.
I've also removed the Qt GUI, and renamed ui-phoenix to just ui. This
removes 400kb of source code (phoenix is a lean 130kb), and drops the
archive size from 564KB to 475KB. Combined with the DSP HLE, and we've
knocked off ~570KB of source cruft from the entire project. I am looking
forward to not having to specify which GUI is included anymore.
2010-12-27 07:29:57 +00:00
|
|
|
}
|
|
|
|
|
2016-03-26 01:56:15 +00:00
|
|
|
if(!status.dram_refreshed && hcounter() >= status.dram_refresh_position) {
|
2010-08-09 13:28:56 +00:00
|
|
|
status.dram_refreshed = true;
|
2016-03-26 01:56:15 +00:00
|
|
|
addClocks(40);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
Update to v085r09 release.
byuu says:
Added VRAM viewer (mouse over to get tile# and VRAM address), CPU+SMP
register editors, settings.cfg to cache path+sync audio+mute audio
settings (Windows Vista+ ignore my request for the default folder
because they are fucking stupid, so they always default to your home
folder. I'm going to have to recommend using a batch file to start
laevateinn there. Sorry, blame Microsoft for being fuck-ups),
geometry.cfg to remember where you placed windows and what size you made
them (a bug in Qt prevents me from making some windows fixed-size for
now, but that'll change when I can work around the Qt issue), usage map
invalidation if the ROM was modified after the usage files, that empty
line insertion thing creaothceann wanted on emulation resume, all chips
now synchronize immediately rather than just-in-time, which is important
for a debugger.
Going to postpone the properties viewer until after v086.
So this is pretty much ready for release. Please bug-test. I don't care
so much about little frills like "oh the memory editor window should
default to a little bigger", you can work around that by resizing it.
I care about things like, "VRAM write breakpoints don't work at all."
If we miss any bugs and it gets released, not the end of the world, but
you'll be waiting a while for the next release to address any missed
bugs now.
2012-02-12 09:58:04 +00:00
|
|
|
|
|
|
|
#if defined(DEBUGGER)
|
2015-12-15 09:30:26 +00:00
|
|
|
synchronizeSMP();
|
|
|
|
synchronizePPU();
|
|
|
|
synchronizeCoprocessors();
|
Update to v085r09 release.
byuu says:
Added VRAM viewer (mouse over to get tile# and VRAM address), CPU+SMP
register editors, settings.cfg to cache path+sync audio+mute audio
settings (Windows Vista+ ignore my request for the default folder
because they are fucking stupid, so they always default to your home
folder. I'm going to have to recommend using a batch file to start
laevateinn there. Sorry, blame Microsoft for being fuck-ups),
geometry.cfg to remember where you placed windows and what size you made
them (a bug in Qt prevents me from making some windows fixed-size for
now, but that'll change when I can work around the Qt issue), usage map
invalidation if the ROM was modified after the usage files, that empty
line insertion thing creaothceann wanted on emulation resume, all chips
now synchronize immediately rather than just-in-time, which is important
for a debugger.
Going to postpone the properties viewer until after v086.
So this is pretty much ready for release. Please bug-test. I don't care
so much about little frills like "oh the memory editor window should
default to a little bigger", you can work around that by resizing it.
I care about things like, "VRAM write breakpoints don't work at all."
If we miss any bugs and it gets released, not the end of the world, but
you'll be waiting a while for the next release to address any missed
bugs now.
2012-02-12 09:58:04 +00:00
|
|
|
#endif
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//called by ppu.tick() when Hcounter=0
|
Update to v095r05 release.
byuu says:
Changelog:
- GBA: lots of emulation improvements
- PPU PRAM is 16-bits wide
- DMA masks &~1/Half, &~3/Word
- VRAM OBJ 8-bit writes are ignored
- OAM 8-bit writes are ignored
- BGnCNT unused bits are writable*
- BG(0,1)CNT can't set the d13
- BLDALPHA is readable (fixes Donkey Kong Country, etc)
- SNES: lots of code cleanups
- sfc/chip => sfc/coprocessor
- UI: save most recent controller selection
GBA test scores: 1552/1552, 37/38, 1020/1260
(* forgot to add the value to the read function, so endrift's I/O tests
for them will fail. Fixed locally.)
Note: SNES is the only system with multiple controller/expansion port
options, and as such is the only one with a "None" option. Because it's
shared by the controller and expansion port, it ends up sorted first in
the list. This means that on your first run, you'll need to go to Super
Famicom->Controller Port 1 and select "Gamepad", otherwise input won't
work.
Also note that changing the expansion port device requires loading a new
cart. Unlike controllers, you aren't meant to hotplug expansion port
devices.
2015-11-12 10:15:03 +00:00
|
|
|
auto CPU::scanline() -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
status.dma_counter = (status.dma_counter + status.line_clocks) & 7;
|
|
|
|
status.line_clocks = lineclocks();
|
|
|
|
|
|
|
|
//forcefully sync S-CPU to other processors, in case chips are not communicating
|
Update to v095r05 release.
byuu says:
Changelog:
- GBA: lots of emulation improvements
- PPU PRAM is 16-bits wide
- DMA masks &~1/Half, &~3/Word
- VRAM OBJ 8-bit writes are ignored
- OAM 8-bit writes are ignored
- BGnCNT unused bits are writable*
- BG(0,1)CNT can't set the d13
- BLDALPHA is readable (fixes Donkey Kong Country, etc)
- SNES: lots of code cleanups
- sfc/chip => sfc/coprocessor
- UI: save most recent controller selection
GBA test scores: 1552/1552, 37/38, 1020/1260
(* forgot to add the value to the read function, so endrift's I/O tests
for them will fail. Fixed locally.)
Note: SNES is the only system with multiple controller/expansion port
options, and as such is the only one with a "None" option. Because it's
shared by the controller and expansion port, it ends up sorted first in
the list. This means that on your first run, you'll need to go to Super
Famicom->Controller Port 1 and select "Gamepad", otherwise input won't
work.
Also note that changing the expansion port device requires loading a new
cart. Unlike controllers, you aren't meant to hotplug expansion port
devices.
2015-11-12 10:15:03 +00:00
|
|
|
synchronizeSMP();
|
|
|
|
synchronizePPU();
|
2015-12-15 09:30:26 +00:00
|
|
|
synchronizeCoprocessors();
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
if(vcounter() == 0) {
|
|
|
|
//HDMA init triggers once every frame
|
2016-03-26 01:56:15 +00:00
|
|
|
status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter());
|
2010-08-09 13:28:56 +00:00
|
|
|
status.hdma_init_triggered = false;
|
Update to v073r01 release.
byuu says:
While perhaps not perfect, pretty good is better than nothing ... I've
added emulation of auto-joypad poll timing.
Going off ikari_01's confirmation of what we suspected, that the strobe
happens every 256 clocks, I've set up emulation as follows:
Upon reset, our clock counter is reset to zero.
At the start of each frame, our poll counter is reset to zero.
Every 256 clocks, we call the step_auto_joypad_poll() function.
If we are at V=225/240+ (based on overscan setting), we check the poll
counter.
At zero, we poll the actual controller and set the joypad polling flag
in $4212.d0 to 1.
From zero through fifteen, we read in one bit for each controller and
shift it into the register.
At sixteen, we turn off the joypad polling flag.
The 256-clock divider allows the start point of polling for each frame
to fluctuate wildly like real hardware.
I count regardless of auto joypad enable, as per $4212.d0's behavior;
but only poll when it's actually enabled.
I do not consume any actual time from this polling. I honestly don't
know if I even should, or if it manages to do it in the background.
If it should consume time, then this most likely happens between opcode
edges and we'll have to adjust the code a good bit.
All commercial games should continue to work fine, but this will likely
break some hacks/translations not tested on hardware.
Without the timing emulation, reading $4218-421f before V=~228 would
basically give you the valid input controller values of the previous
frame.
Now, like hardware, it should give you a state that is part previous
frame, part current frame shifted into it. Button positions won't be
reliable and will shift every 256 clocks.
I've also removed the Qt GUI, and renamed ui-phoenix to just ui. This
removes 400kb of source code (phoenix is a lean 130kb), and drops the
archive size from 564KB to 475KB. Combined with the DSP HLE, and we've
knocked off ~570KB of source cruft from the entire project. I am looking
forward to not having to specify which GUI is included anymore.
2010-12-27 07:29:57 +00:00
|
|
|
|
|
|
|
status.auto_joypad_counter = 0;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//DRAM refresh occurs once every scanline
|
2016-03-26 01:56:15 +00:00
|
|
|
if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dmaCounter();
|
2010-08-09 13:28:56 +00:00
|
|
|
status.dram_refreshed = false;
|
|
|
|
|
|
|
|
//HDMA triggers once every visible scanline
|
2016-04-09 05:20:41 +00:00
|
|
|
if(vcounter() < ppu.vdisp()) {
|
2010-08-09 13:28:56 +00:00
|
|
|
status.hdma_position = 1104;
|
|
|
|
status.hdma_triggered = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-26 01:56:15 +00:00
|
|
|
auto CPU::aluEdge() -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(alu.mpyctr) {
|
|
|
|
alu.mpyctr--;
|
|
|
|
if(status.rddiv & 1) status.rdmpy += alu.shift;
|
|
|
|
status.rddiv >>= 1;
|
|
|
|
alu.shift <<= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(alu.divctr) {
|
|
|
|
alu.divctr--;
|
|
|
|
status.rddiv <<= 1;
|
|
|
|
alu.shift >>= 1;
|
|
|
|
if(status.rdmpy >= alu.shift) {
|
|
|
|
status.rdmpy -= alu.shift;
|
|
|
|
status.rddiv |= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-26 01:56:15 +00:00
|
|
|
auto CPU::dmaEdge() -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
//H/DMA pending && DMA inactive?
|
|
|
|
//.. Run one full CPU cycle
|
|
|
|
//.. HDMA pending && HDMA enabled ? DMA sync + HDMA run
|
|
|
|
//.. DMA pending && DMA enabled ? DMA sync + DMA run
|
|
|
|
//.... HDMA during DMA && HDMA enabled ? DMA sync + HDMA run
|
|
|
|
//.. Run one bus CPU cycle
|
|
|
|
//.. CPU sync
|
|
|
|
|
|
|
|
if(status.dma_active == true) {
|
|
|
|
if(status.hdma_pending) {
|
|
|
|
status.hdma_pending = false;
|
2016-03-26 01:56:15 +00:00
|
|
|
if(hdmaEnabledChannels()) {
|
|
|
|
if(!dmaEnabledChannels()) {
|
|
|
|
dmaAddClocks(8 - dmaCounter());
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
2016-03-26 01:56:15 +00:00
|
|
|
status.hdma_mode == 0 ? hdmaInit() : hdmaRun();
|
|
|
|
if(!dmaEnabledChannels()) {
|
|
|
|
addClocks(status.clock_count - (status.dma_clocks % status.clock_count));
|
2010-08-09 13:28:56 +00:00
|
|
|
status.dma_active = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.dma_pending) {
|
|
|
|
status.dma_pending = false;
|
2016-03-26 01:56:15 +00:00
|
|
|
if(dmaEnabledChannels()) {
|
|
|
|
dmaAddClocks(8 - dmaCounter());
|
|
|
|
dmaRun();
|
|
|
|
addClocks(status.clock_count - (status.dma_clocks % status.clock_count));
|
2010-08-09 13:28:56 +00:00
|
|
|
status.dma_active = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.hdma_init_triggered == false && hcounter() >= status.hdma_init_position) {
|
|
|
|
status.hdma_init_triggered = true;
|
2016-03-26 01:56:15 +00:00
|
|
|
hdmaInitReset();
|
|
|
|
if(hdmaEnabledChannels()) {
|
2010-08-09 13:28:56 +00:00
|
|
|
status.hdma_pending = true;
|
|
|
|
status.hdma_mode = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.hdma_triggered == false && hcounter() >= status.hdma_position) {
|
|
|
|
status.hdma_triggered = true;
|
2016-03-26 01:56:15 +00:00
|
|
|
if(hdmaActiveChannels()) {
|
2010-08-09 13:28:56 +00:00
|
|
|
status.hdma_pending = true;
|
|
|
|
status.hdma_mode = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.dma_active == false) {
|
|
|
|
if(status.dma_pending || status.hdma_pending) {
|
|
|
|
status.dma_clocks = 0;
|
|
|
|
status.dma_active = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//used to test for NMI/IRQ, which can trigger on the edge of every opcode.
|
|
|
|
//test one cycle early to simulate two-stage pipeline of x816 CPU.
|
|
|
|
//
|
|
|
|
//status.irq_lock is used to simulate hardware delay before interrupts can
|
|
|
|
//trigger during certain events (immediately after DMA, writes to $4200, etc)
|
2016-03-26 01:56:15 +00:00
|
|
|
auto CPU::lastCycle() -> void {
|
|
|
|
if(!status.irq_lock) {
|
|
|
|
status.nmi_pending |= nmiTest();
|
|
|
|
status.irq_pending |= irqTest();
|
2010-08-09 13:28:56 +00:00
|
|
|
status.interrupt_pending = (status.nmi_pending || status.irq_pending);
|
|
|
|
}
|
|
|
|
}
|