mirror of https://github.com/bsnes-emu/bsnes.git
Update to v101r25 release.
byuu says: Changelog: - Makefile: added $(windres), -lpthread to Windows port - GBA: WAITCNT.prefetch is not writable (should fix Donkey Kong: King of Swing) \[endrift\] - SMS: fixed hcounter shift value \[hex\_usr\] - SMS: emulated interrupts (reset button isn't hooked up anywhere, not sure where to put it yet) This WIP actually took a really long time because the documentation on SMS interrupts was all over the place. I'm hoping I've emulated them correctly, but I honestly have no idea. It's based off my best understanding from four or five different sources. So it's probably quite buggy. However, a few interrupts fire in Sonic the Hedgehog, so that's something to start with. Now I just have to hope I've gotten some games far enough in that I can start seeing some data in the VDP VRAM. I need that before I can start emulating graphics mode 4 to get some actual screen output. Or I can just say to hell with it and use a "Hello World" test ROM. That'd probably be smarter.
This commit is contained in:
parent
bab2ac812a
commit
e30780bb72
|
@ -24,7 +24,7 @@ ifeq ($(platform),windows)
|
||||||
else
|
else
|
||||||
link += -mwindows
|
link += -mwindows
|
||||||
endif
|
endif
|
||||||
link += -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
|
link += -mthreads -lpthread -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
|
||||||
link += -Wl,-enable-auto-import
|
link += -Wl,-enable-auto-import
|
||||||
link += -Wl,-enable-runtime-pseudo-reloc
|
link += -Wl,-enable-runtime-pseudo-reloc
|
||||||
else ifeq ($(platform),macosx)
|
else ifeq ($(platform),macosx)
|
||||||
|
|
|
@ -12,7 +12,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "101.24";
|
static const string Version = "101.25";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
|
|
@ -148,7 +148,7 @@ auto CPU::power() -> void {
|
||||||
for(auto& swait : regs.wait.control.swait) swait = 0;
|
for(auto& swait : regs.wait.control.swait) swait = 0;
|
||||||
regs.wait.control.phi = 0;
|
regs.wait.control.phi = 0;
|
||||||
regs.wait.control.prefetch = 0;
|
regs.wait.control.prefetch = 0;
|
||||||
regs.wait.control.gametype = 0;
|
regs.wait.control.gametype = 0; //0 = GBA, 1 = GBC
|
||||||
regs.postboot = 0;
|
regs.postboot = 0;
|
||||||
regs.mode = Registers::Mode::Normal;
|
regs.mode = Registers::Mode::Normal;
|
||||||
regs.clock = 0;
|
regs.clock = 0;
|
||||||
|
|
|
@ -383,7 +383,7 @@ auto CPU::writeIO(uint32 addr, uint8 data) -> void {
|
||||||
regs.wait.control.swait[2] = data.bit (2);
|
regs.wait.control.swait[2] = data.bit (2);
|
||||||
regs.wait.control.phi = data.bit (3);
|
regs.wait.control.phi = data.bit (3);
|
||||||
regs.wait.control.prefetch = data.bit (6);
|
regs.wait.control.prefetch = data.bit (6);
|
||||||
regs.wait.control.gametype = data.bit (7);
|
//regs.wait.control.gametype is read-only
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//IME
|
//IME
|
||||||
|
|
|
@ -10,11 +10,24 @@ auto CPU::Enter() -> void {
|
||||||
|
|
||||||
auto CPU::main() -> void {
|
auto CPU::main() -> void {
|
||||||
#if 1
|
#if 1
|
||||||
|
static uint64 instructionsExecuted = 0;
|
||||||
if(instructionsExecuted < 20)
|
if(instructionsExecuted < 20)
|
||||||
print(disassemble(r.pc), "\n");
|
print(disassemble(r.pc), "\n");
|
||||||
instructionsExecuted++;
|
instructionsExecuted++;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//note: SMS1 extbus value is random; SMS2+ is pulled high ($ff)
|
||||||
|
|
||||||
|
if(state.nmiLine) {
|
||||||
|
state.nmiLine = 0; //edge-sensitive
|
||||||
|
irq(0, 0x0066, 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(state.intLine) {
|
||||||
|
//level-sensitive
|
||||||
|
irq(1, 0x0038, 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
instruction();
|
instruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +37,14 @@ auto CPU::step(uint clocks) -> void {
|
||||||
synchronize(psg);
|
synchronize(psg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto CPU::setNMI(bool value) -> void {
|
||||||
|
state.nmiLine = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::setINT(bool value) -> void {
|
||||||
|
state.intLine = value;
|
||||||
|
}
|
||||||
|
|
||||||
auto CPU::power() -> void {
|
auto CPU::power() -> void {
|
||||||
Z80::bus = &MasterSystem::bus;
|
Z80::bus = &MasterSystem::bus;
|
||||||
Z80::power();
|
Z80::power();
|
||||||
|
@ -33,7 +54,7 @@ auto CPU::reset() -> void {
|
||||||
Z80::reset();
|
Z80::reset();
|
||||||
create(CPU::Enter, system.colorburst());
|
create(CPU::Enter, system.colorburst());
|
||||||
|
|
||||||
instructionsExecuted = 0;
|
memory::fill(&state, sizeof(State));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,17 @@ struct CPU : Processor::Z80, Thread {
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
|
|
||||||
|
auto setNMI(bool value) -> void;
|
||||||
|
auto setINT(bool value) -> void;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64 instructionsExecuted;
|
struct State {
|
||||||
|
boolean nmiLine;
|
||||||
|
boolean intLine;
|
||||||
|
} state;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPU cpu;
|
extern CPU cpu;
|
||||||
|
|
|
@ -14,7 +14,7 @@ auto VDP::vcounter() -> uint8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::hcounter() -> uint8 {
|
auto VDP::hcounter() -> uint8 {
|
||||||
uint hcounter = io.hcounter >> 2;
|
uint hcounter = io.hcounter >> 1;
|
||||||
return hcounter <= 233 ? hcounter : hcounter - 86;
|
return hcounter <= 233 ? hcounter : hcounter - 86;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,19 @@ auto VDP::data() -> uint8 {
|
||||||
auto VDP::status() -> uint8 {
|
auto VDP::status() -> uint8 {
|
||||||
io.controlLatch = 0;
|
io.controlLatch = 0;
|
||||||
|
|
||||||
return 0x00;
|
uint8 result = 0x00;
|
||||||
|
result |= io.intFrame << 7;
|
||||||
|
result |= io.spriteOverflow << 6;
|
||||||
|
result |= io.spriteCollision << 5;
|
||||||
|
result |= io.fifthSprite << 0;
|
||||||
|
|
||||||
|
io.intLine = 0;
|
||||||
|
io.intFrame = 0;
|
||||||
|
io.spriteOverflow = 0;
|
||||||
|
io.spriteCollision = 0;
|
||||||
|
io.fifthSprite = 0;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::data(uint8 data) -> void {
|
auto VDP::data(uint8 data) -> void {
|
||||||
|
|
|
@ -10,30 +10,54 @@ auto VDP::Enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::main() -> void {
|
auto VDP::main() -> void {
|
||||||
for(uint y : range(262)) {
|
if(io.vcounter <= vlines()) {
|
||||||
for(uint x : range(684)) {
|
if(io.lcounter-- == 0) {
|
||||||
step(1);
|
io.lcounter = io.lineCounter;
|
||||||
|
io.intLine = 1;
|
||||||
}
|
}
|
||||||
if(y == 240) scheduler.exit(Scheduler::Event::Frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(io.vcounter == vlines() + 1) {
|
||||||
|
io.lcounter = io.lineCounter;
|
||||||
|
io.intFrame = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint x : range(684)) {
|
||||||
|
step(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(io.vcounter == 240) scheduler.exit(Scheduler::Event::Frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::step(uint clocks) -> void {
|
auto VDP::step(uint clocks) -> void {
|
||||||
if(++io.hcounter == 684) {
|
while(clocks--) {
|
||||||
io.hcounter = 0;
|
if(++io.hcounter == 684) {
|
||||||
if(++io.vcounter == 262) {
|
io.hcounter = 0;
|
||||||
io.vcounter = 0;
|
if(++io.vcounter == 262) {
|
||||||
|
io.vcounter = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Thread::step(clocks);
|
cpu.setINT((io.lineInterrupts && io.intLine) || (io.frameInterrupts && io.intFrame));
|
||||||
synchronize(cpu);
|
Thread::step(1);
|
||||||
|
synchronize(cpu);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::refresh() -> void {
|
auto VDP::refresh() -> void {
|
||||||
Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240);
|
Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto VDP::vlines() -> uint {
|
||||||
|
if(io.lines240) return 240;
|
||||||
|
if(io.lines224) return 224;
|
||||||
|
return 192;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto VDP::vblank() -> bool {
|
||||||
|
return io.vcounter >= vlines();
|
||||||
|
}
|
||||||
|
|
||||||
auto VDP::power() -> void {
|
auto VDP::power() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ struct VDP : Thread {
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
auto refresh() -> void;
|
auto refresh() -> void;
|
||||||
|
|
||||||
|
auto vlines() -> uint;
|
||||||
|
auto vblank() -> bool;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
|
@ -25,9 +28,20 @@ private:
|
||||||
uint8 cram[0x40];
|
uint8 cram[0x40];
|
||||||
|
|
||||||
struct IO {
|
struct IO {
|
||||||
uint vcounter;
|
uint vcounter; //vertical counter
|
||||||
uint hcounter;
|
uint hcounter; //horizontal counter
|
||||||
|
uint lcounter; //line counter
|
||||||
|
|
||||||
|
//interrupt flags
|
||||||
|
bool intLine;
|
||||||
|
bool intFrame;
|
||||||
|
|
||||||
|
//status flags
|
||||||
|
bool spriteOverflow;
|
||||||
|
bool spriteCollision;
|
||||||
|
uint5 fifthSprite;
|
||||||
|
|
||||||
|
//latches
|
||||||
bool controlLatch;
|
bool controlLatch;
|
||||||
uint16 controlData;
|
uint16 controlData;
|
||||||
uint2 code;
|
uint2 code;
|
||||||
|
|
|
@ -2,6 +2,13 @@ auto Z80::instruction() -> void {
|
||||||
auto code = opcode();
|
auto code = opcode();
|
||||||
if(code == 0xdd) { r.hlp = &r.ix; return; }
|
if(code == 0xdd) { r.hlp = &r.ix; return; }
|
||||||
if(code == 0xfd) { r.hlp = &r.iy; return; }
|
if(code == 0xfd) { r.hlp = &r.iy; return; }
|
||||||
|
|
||||||
|
if(r.ei) {
|
||||||
|
r.ei = 0;
|
||||||
|
r.iff1 = 1;
|
||||||
|
r.iff2 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
instruction__(code);
|
instruction__(code);
|
||||||
r.hlp = &r.hl;
|
r.hlp = &r.hl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -433,8 +433,7 @@ auto Z80::instructionDJNZ_e() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Z80::instructionEI() -> void {
|
auto Z80::instructionEI() -> void {
|
||||||
r.iff1 = 1;
|
r.ei = 1; //raise IFF1, IFF2 after the next instruction
|
||||||
r.iff2 = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Z80::instructionEX_rr_rr(uint16& x, uint16& y) -> void {
|
auto Z80::instructionEX_rr_rr(uint16& x, uint16& y) -> void {
|
||||||
|
|
|
@ -17,6 +17,40 @@ auto Z80::reset() -> void {
|
||||||
r.hlp = &r.hl;
|
r.hlp = &r.hl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Z80::irq(bool maskable, uint16 pc, uint8 extbus) -> bool {
|
||||||
|
if(maskable && !r.iff1) return false;
|
||||||
|
|
||||||
|
push(r.pc);
|
||||||
|
|
||||||
|
switch(r.im) {
|
||||||
|
|
||||||
|
case 0: {
|
||||||
|
//external data bus ($ff = RST $38)
|
||||||
|
r.pc = extbus;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 1: {
|
||||||
|
//constant address
|
||||||
|
r.pc = pc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2: {
|
||||||
|
//vector table with external data bus
|
||||||
|
uint16 addr = (r.ir.byte.hi << 8) | extbus;
|
||||||
|
r.pc = read(addr + 0) << 0;
|
||||||
|
r.pc |= read(addr + 1) << 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
r.iff1 = 0;
|
||||||
|
if(maskable) r.iff2 = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
auto Z80::parity(uint8 value) const -> bool {
|
auto Z80::parity(uint8 value) const -> bool {
|
||||||
value ^= value >> 4;
|
value ^= value >> 4;
|
||||||
value ^= value >> 2;
|
value ^= value >> 2;
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct Z80 {
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
|
auto irq(bool maskable, uint16 vector = 0x0000, uint8 extbus = 0xff) -> bool;
|
||||||
auto parity(uint8) const -> bool;
|
auto parity(uint8) const -> bool;
|
||||||
|
|
||||||
//memory.cpp
|
//memory.cpp
|
||||||
|
@ -203,6 +204,7 @@ struct Z80 {
|
||||||
uint16 sp;
|
uint16 sp;
|
||||||
uint16 pc;
|
uint16 pc;
|
||||||
|
|
||||||
|
boolean ei; //EI instruction executed
|
||||||
boolean halt; //HALT instruction executed
|
boolean halt; //HALT instruction executed
|
||||||
boolean iff1; //interrupt flip-flop 1
|
boolean iff1; //interrupt flip-flop 1
|
||||||
boolean iff2; //interrupt flip-flop 2
|
boolean iff2; //interrupt flip-flop 2
|
||||||
|
|
|
@ -20,6 +20,7 @@ ifeq ($(platform),windows)
|
||||||
ruby += video.direct3d video.wgl video.directdraw video.gdi
|
ruby += video.direct3d video.wgl video.directdraw video.gdi
|
||||||
ruby += audio.wasapi audio.xaudio2 audio.directsound
|
ruby += audio.wasapi audio.xaudio2 audio.directsound
|
||||||
ruby += input.windows
|
ruby += input.windows
|
||||||
|
windres := windres
|
||||||
else ifeq ($(platform),macosx)
|
else ifeq ($(platform),macosx)
|
||||||
ruby += video.cgl
|
ruby += video.cgl
|
||||||
ruby += audio.openal
|
ruby += audio.openal
|
||||||
|
@ -62,7 +63,7 @@ obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/)
|
||||||
obj/ui-presentation.o: $(ui)/presentation/presentation.cpp $(call rwildcard,$(ui)/)
|
obj/ui-presentation.o: $(ui)/presentation/presentation.cpp $(call rwildcard,$(ui)/)
|
||||||
|
|
||||||
obj/ui-resource.o:
|
obj/ui-resource.o:
|
||||||
windres data/resource.rc obj/ui-resource.o
|
$(windres) data/resource.rc obj/ui-resource.o
|
||||||
|
|
||||||
# targets
|
# targets
|
||||||
build: $(objects)
|
build: $(objects)
|
||||||
|
|
Loading…
Reference in New Issue