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
|
||||
link += -mwindows
|
||||
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-runtime-pseudo-reloc
|
||||
else ifeq ($(platform),macosx)
|
||||
|
|
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
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 License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -148,7 +148,7 @@ auto CPU::power() -> void {
|
|||
for(auto& swait : regs.wait.control.swait) swait = 0;
|
||||
regs.wait.control.phi = 0;
|
||||
regs.wait.control.prefetch = 0;
|
||||
regs.wait.control.gametype = 0;
|
||||
regs.wait.control.gametype = 0; //0 = GBA, 1 = GBC
|
||||
regs.postboot = 0;
|
||||
regs.mode = Registers::Mode::Normal;
|
||||
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.phi = data.bit (3);
|
||||
regs.wait.control.prefetch = data.bit (6);
|
||||
regs.wait.control.gametype = data.bit (7);
|
||||
//regs.wait.control.gametype is read-only
|
||||
return;
|
||||
|
||||
//IME
|
||||
|
|
|
@ -10,11 +10,24 @@ auto CPU::Enter() -> void {
|
|||
|
||||
auto CPU::main() -> void {
|
||||
#if 1
|
||||
static uint64 instructionsExecuted = 0;
|
||||
if(instructionsExecuted < 20)
|
||||
print(disassemble(r.pc), "\n");
|
||||
instructionsExecuted++;
|
||||
#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();
|
||||
}
|
||||
|
||||
|
@ -24,6 +37,14 @@ auto CPU::step(uint clocks) -> void {
|
|||
synchronize(psg);
|
||||
}
|
||||
|
||||
auto CPU::setNMI(bool value) -> void {
|
||||
state.nmiLine = value;
|
||||
}
|
||||
|
||||
auto CPU::setINT(bool value) -> void {
|
||||
state.intLine = value;
|
||||
}
|
||||
|
||||
auto CPU::power() -> void {
|
||||
Z80::bus = &MasterSystem::bus;
|
||||
Z80::power();
|
||||
|
@ -33,7 +54,7 @@ auto CPU::reset() -> void {
|
|||
Z80::reset();
|
||||
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 step(uint clocks) -> void;
|
||||
|
||||
auto setNMI(bool value) -> void;
|
||||
auto setINT(bool value) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
private:
|
||||
uint64 instructionsExecuted;
|
||||
struct State {
|
||||
boolean nmiLine;
|
||||
boolean intLine;
|
||||
} state;
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
||||
|
|
|
@ -14,7 +14,7 @@ auto VDP::vcounter() -> uint8 {
|
|||
}
|
||||
|
||||
auto VDP::hcounter() -> uint8 {
|
||||
uint hcounter = io.hcounter >> 2;
|
||||
uint hcounter = io.hcounter >> 1;
|
||||
return hcounter <= 233 ? hcounter : hcounter - 86;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,19 @@ auto VDP::data() -> uint8 {
|
|||
auto VDP::status() -> uint8 {
|
||||
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 {
|
||||
|
|
|
@ -10,30 +10,54 @@ auto VDP::Enter() -> void {
|
|||
}
|
||||
|
||||
auto VDP::main() -> void {
|
||||
for(uint y : range(262)) {
|
||||
for(uint x : range(684)) {
|
||||
step(1);
|
||||
if(io.vcounter <= vlines()) {
|
||||
if(io.lcounter-- == 0) {
|
||||
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 {
|
||||
if(++io.hcounter == 684) {
|
||||
io.hcounter = 0;
|
||||
if(++io.vcounter == 262) {
|
||||
io.vcounter = 0;
|
||||
while(clocks--) {
|
||||
if(++io.hcounter == 684) {
|
||||
io.hcounter = 0;
|
||||
if(++io.vcounter == 262) {
|
||||
io.vcounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Thread::step(clocks);
|
||||
synchronize(cpu);
|
||||
cpu.setINT((io.lineInterrupts && io.intLine) || (io.frameInterrupts && io.intFrame));
|
||||
Thread::step(1);
|
||||
synchronize(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
auto VDP::refresh() -> void {
|
||||
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 {
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ struct VDP : Thread {
|
|||
auto step(uint clocks) -> void;
|
||||
auto refresh() -> void;
|
||||
|
||||
auto vlines() -> uint;
|
||||
auto vblank() -> bool;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
|
@ -25,9 +28,20 @@ private:
|
|||
uint8 cram[0x40];
|
||||
|
||||
struct IO {
|
||||
uint vcounter;
|
||||
uint hcounter;
|
||||
uint vcounter; //vertical counter
|
||||
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;
|
||||
uint16 controlData;
|
||||
uint2 code;
|
||||
|
|
|
@ -2,6 +2,13 @@ auto Z80::instruction() -> void {
|
|||
auto code = opcode();
|
||||
if(code == 0xdd) { r.hlp = &r.ix; return; }
|
||||
if(code == 0xfd) { r.hlp = &r.iy; return; }
|
||||
|
||||
if(r.ei) {
|
||||
r.ei = 0;
|
||||
r.iff1 = 1;
|
||||
r.iff2 = 1;
|
||||
}
|
||||
|
||||
instruction__(code);
|
||||
r.hlp = &r.hl;
|
||||
}
|
||||
|
|
|
@ -433,8 +433,7 @@ auto Z80::instructionDJNZ_e() -> void {
|
|||
}
|
||||
|
||||
auto Z80::instructionEI() -> void {
|
||||
r.iff1 = 1;
|
||||
r.iff2 = 1;
|
||||
r.ei = 1; //raise IFF1, IFF2 after the next instruction
|
||||
}
|
||||
|
||||
auto Z80::instructionEX_rr_rr(uint16& x, uint16& y) -> void {
|
||||
|
|
|
@ -17,6 +17,40 @@ auto Z80::reset() -> void {
|
|||
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 {
|
||||
value ^= value >> 4;
|
||||
value ^= value >> 2;
|
||||
|
|
|
@ -18,6 +18,7 @@ struct Z80 {
|
|||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto irq(bool maskable, uint16 vector = 0x0000, uint8 extbus = 0xff) -> bool;
|
||||
auto parity(uint8) const -> bool;
|
||||
|
||||
//memory.cpp
|
||||
|
@ -203,6 +204,7 @@ struct Z80 {
|
|||
uint16 sp;
|
||||
uint16 pc;
|
||||
|
||||
boolean ei; //EI instruction executed
|
||||
boolean halt; //HALT instruction executed
|
||||
boolean iff1; //interrupt flip-flop 1
|
||||
boolean iff2; //interrupt flip-flop 2
|
||||
|
|
|
@ -20,6 +20,7 @@ ifeq ($(platform),windows)
|
|||
ruby += video.direct3d video.wgl video.directdraw video.gdi
|
||||
ruby += audio.wasapi audio.xaudio2 audio.directsound
|
||||
ruby += input.windows
|
||||
windres := windres
|
||||
else ifeq ($(platform),macosx)
|
||||
ruby += video.cgl
|
||||
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-resource.o:
|
||||
windres data/resource.rc obj/ui-resource.o
|
||||
$(windres) data/resource.rc obj/ui-resource.o
|
||||
|
||||
# targets
|
||||
build: $(objects)
|
||||
|
|
Loading…
Reference in New Issue