mirror of https://github.com/bsnes-emu/bsnes.git
Update to v101r24 release.
byuu says: Changelog: - SMS: extended bus mapping of in/out ports: now decoding them fully inside ms/bus - SMS: moved Z80 disassembly code from processor/z80 to ms/cpu (cosmetic) - SMS: hooked up non-functional silent PSG sample generation, so I can cap the framerate at 60fps - SMS: hooked up the VDP main loop: 684 clocks/scanline, 262 scanlines/frame (no PAL support yet) - SMS: emulated the VDP Vcounter and Hcounter polling ... hopefully it's right, as it's very bizarre - SMS: emulated VDP in/out ports (data read, data write, status read, control write, register write) - SMS: decoding and caching all VDP register flags (variable names will probably change) - nall: \#undef IN on Windows port (prevent compilation warning on processor/z80) Watching Sonic the Hedgehog, I can definitely see some VDP register writes going through, which is a good sign. Probably the big thing that's needed before I can get enough into the VDP to start showing graphics is interrupt support. And interrupts are never fun to figure out :/ What really sucks on this front is I'm flying blind on the Z80 CPU core. Without a working VDP, I can't run any Z80 test ROMs to look for CPU bugs. And the CPU is certainly too buggy still to run said test ROM anyway. I can't find any SMS emulators with trace logging from reset. Such logs vastly accelerate tracking down CPU logic bugs, so without them, it's going to take a lot longer.
This commit is contained in:
parent
1d7b674dd4
commit
bab2ac812a
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "101.23";
|
||||
static const string Version = "101.24";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -15,14 +15,37 @@ auto Bus::write(uint16 addr, uint8 data) -> void {
|
|||
}
|
||||
|
||||
auto Bus::in(uint8 addr) -> uint8 {
|
||||
switch(addr) {
|
||||
case 0x7e: return vdp.in(addr);
|
||||
case 0x7f: return vdp.in(addr);
|
||||
switch(addr >> 6) {
|
||||
|
||||
case 0: {
|
||||
return 0xff; //SMS1 = MDR, SMS2 = 0xff
|
||||
}
|
||||
|
||||
case 1: {
|
||||
return !addr.bit(0) ? vdp.vcounter() : vdp.hcounter();
|
||||
}
|
||||
|
||||
case 2: {
|
||||
return !addr.bit(0) ? vdp.data() : vdp.status();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto Bus::out(uint8 addr, uint8 data) -> void {
|
||||
switch(addr >> 6) {
|
||||
|
||||
case 2: {
|
||||
return !addr.bit(0) ? vdp.data(data) : vdp.control(data);
|
||||
}
|
||||
|
||||
case 3: {
|
||||
return; //unmapped
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,12 @@ auto CPU::Enter() -> void {
|
|||
}
|
||||
|
||||
auto CPU::main() -> void {
|
||||
#if 1
|
||||
if(instructionsExecuted < 20)
|
||||
print(disassemble(r.pc), "\n");
|
||||
instructionsExecuted++;
|
||||
#endif
|
||||
|
||||
instruction();
|
||||
}
|
||||
|
||||
|
@ -26,6 +32,8 @@ auto CPU::power() -> void {
|
|||
auto CPU::reset() -> void {
|
||||
Z80::reset();
|
||||
create(CPU::Enter, system.colorburst());
|
||||
|
||||
instructionsExecuted = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@ struct CPU : Processor::Z80, Thread {
|
|||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
private:
|
||||
uint64 instructionsExecuted;
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
||||
|
|
|
@ -10,6 +10,7 @@ auto PSG::Enter() -> void {
|
|||
|
||||
auto PSG::main() -> void {
|
||||
step(1);
|
||||
stream->sample(0.0, 0.0);
|
||||
}
|
||||
|
||||
auto PSG::step(uint clocks) -> void {
|
||||
|
@ -22,6 +23,7 @@ auto PSG::power() -> void {
|
|||
|
||||
auto PSG::reset() -> void {
|
||||
create(PSG::Enter, system.colorburst());
|
||||
stream = Emulator::audio.createStream(2, system.colorburst());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
//TI SN76489
|
||||
|
||||
struct PSG : Thread {
|
||||
shared_pointer<Emulator::Stream> stream;
|
||||
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
auto VDP::vcounter() -> uint8 {
|
||||
if(io.lines240) {
|
||||
//NTSC 256x240
|
||||
return io.vcounter;
|
||||
} else if(io.lines224) {
|
||||
//NTSC 256x224
|
||||
return io.vcounter <= 234 ? io.vcounter : io.vcounter - 6;
|
||||
} else {
|
||||
//NTSC 256x192
|
||||
return io.vcounter <= 218 ? io.vcounter : io.vcounter - 6;
|
||||
}
|
||||
|
||||
unreachable;
|
||||
}
|
||||
|
||||
auto VDP::hcounter() -> uint8 {
|
||||
uint hcounter = io.hcounter >> 2;
|
||||
return hcounter <= 233 ? hcounter : hcounter - 86;
|
||||
}
|
||||
|
||||
auto VDP::data() -> uint8 {
|
||||
io.controlLatch = 0;
|
||||
|
||||
auto data = io.vramLatch;
|
||||
io.vramLatch = vram[io.address++];
|
||||
return data;
|
||||
}
|
||||
|
||||
auto VDP::status() -> uint8 {
|
||||
io.controlLatch = 0;
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto VDP::data(uint8 data) -> void {
|
||||
io.controlLatch = 0;
|
||||
|
||||
if(io.code <= 2) {
|
||||
vram[io.address++] = data;
|
||||
} else {
|
||||
cram[io.address++ & 0x3f] = data;
|
||||
}
|
||||
}
|
||||
|
||||
auto VDP::control(uint8 data) -> void {
|
||||
if(io.controlLatch == 0) {
|
||||
io.controlLatch = 1;
|
||||
io.address.bits(0,7) = data.bits(0,7);
|
||||
return;
|
||||
} else {
|
||||
io.controlLatch = 0;
|
||||
io.address.bits(8,13) = data.bits(0,5);
|
||||
io.code.bits(0,1) = data.bits(6,7);
|
||||
}
|
||||
|
||||
if(io.code == 0) {
|
||||
io.vramLatch = vram[io.address++];
|
||||
}
|
||||
|
||||
if(io.code == 2) {
|
||||
registerWrite(io.address.bits(11,8), io.address.bits(7,0));
|
||||
}
|
||||
}
|
||||
|
||||
auto VDP::registerWrite(uint4 addr, uint8 data) -> void {
|
||||
switch(addr) {
|
||||
|
||||
//mode control 1
|
||||
case 0x0: {
|
||||
io.externalSync = data.bit(0);
|
||||
io.extendedHeight = data.bit(1);
|
||||
io.mode4 = data.bit(2);
|
||||
io.spriteShift = data.bit(3);
|
||||
io.lineInterrupts = data.bit(4);
|
||||
io.leftClip = data.bit(5);
|
||||
io.horizontalScrollLock = data.bit(6);
|
||||
io.verticalScrollLock = data.bit(7);
|
||||
return;
|
||||
}
|
||||
|
||||
//mode control 2
|
||||
case 0x1: {
|
||||
io.spriteDouble = data.bit(0);
|
||||
io.spriteTile = data.bit(1);
|
||||
io.lines240 = data.bit(3);
|
||||
io.lines224 = data.bit(4);
|
||||
io.frameInterrupts = data.bit(5);
|
||||
io.displayEnable = data.bit(6);
|
||||
return;
|
||||
}
|
||||
|
||||
//name table base address
|
||||
case 0x2: {
|
||||
io.nameTableMask = data.bit(0);
|
||||
io.nameTableAddress = data.bits(1,3);
|
||||
return;
|
||||
}
|
||||
|
||||
//color table base address
|
||||
case 0x3: {
|
||||
io.colorTableAddress = data.bits(0,7);
|
||||
return;
|
||||
}
|
||||
|
||||
//pattern table base address
|
||||
case 0x4: {
|
||||
io.patternTableAddress = data.bits(0,7);
|
||||
return;
|
||||
}
|
||||
|
||||
//sprite attribute table base address
|
||||
case 0x5: {
|
||||
io.spriteAttributeTableMask = data.bit(0);
|
||||
io.spriteAttributeTableAddress = data.bits(1,6);
|
||||
return;
|
||||
}
|
||||
|
||||
//sprite pattern table base address
|
||||
case 0x6: {
|
||||
io.spritePatternTableMask = data.bits(0,1);
|
||||
io.spritePatternTableAddress = data.bit(2);
|
||||
return;
|
||||
}
|
||||
|
||||
//backdrop color
|
||||
case 0x7: {
|
||||
io.backdropColor = data.bits(0,3);
|
||||
return;
|
||||
}
|
||||
|
||||
//horizontal scroll offset
|
||||
case 0x8: {
|
||||
io.hscroll = data.bits(0,7);
|
||||
return;
|
||||
}
|
||||
|
||||
//vertical scroll offset
|
||||
case 0x9: {
|
||||
io.vscroll = data.bits(0,7);
|
||||
return;
|
||||
}
|
||||
|
||||
//line counter
|
||||
case 0xa: {
|
||||
io.lineCounter = data.bits(0,7);
|
||||
return;
|
||||
}
|
||||
|
||||
//0xb - 0xf unmapped
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
namespace MasterSystem {
|
||||
|
||||
VDP vdp;
|
||||
#include "io.cpp"
|
||||
|
||||
auto VDP::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), vdp.main();
|
||||
|
@ -10,7 +11,7 @@ auto VDP::Enter() -> void {
|
|||
|
||||
auto VDP::main() -> void {
|
||||
for(uint y : range(262)) {
|
||||
for(uint x : range(342)) {
|
||||
for(uint x : range(684)) {
|
||||
step(1);
|
||||
}
|
||||
if(y == 240) scheduler.exit(Scheduler::Event::Frame);
|
||||
|
@ -18,6 +19,13 @@ auto VDP::main() -> void {
|
|||
}
|
||||
|
||||
auto VDP::step(uint clocks) -> void {
|
||||
if(++io.hcounter == 684) {
|
||||
io.hcounter = 0;
|
||||
if(++io.vcounter == 262) {
|
||||
io.vcounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Thread::step(clocks);
|
||||
synchronize(cpu);
|
||||
}
|
||||
|
@ -26,23 +34,13 @@ auto VDP::refresh() -> void {
|
|||
Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240);
|
||||
}
|
||||
|
||||
auto VDP::in(uint8 addr) -> uint8 {
|
||||
switch(addr) {
|
||||
}
|
||||
|
||||
return 0xb0;
|
||||
}
|
||||
|
||||
auto VDP::out(uint8 addr, uint8 data) -> void {
|
||||
switch(addr) {
|
||||
}
|
||||
}
|
||||
|
||||
auto VDP::power() -> void {
|
||||
}
|
||||
|
||||
auto VDP::reset() -> void {
|
||||
create(VDP::Enter, system.colorburst());
|
||||
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
||||
|
||||
memory::fill(&io, sizeof(IO));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,14 +6,83 @@ struct VDP : Thread {
|
|||
auto step(uint clocks) -> void;
|
||||
auto refresh() -> void;
|
||||
|
||||
auto in(uint8 addr) -> uint8;
|
||||
auto out(uint8 addr, uint8 data) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
//io.cpp
|
||||
auto vcounter() -> uint8;
|
||||
auto hcounter() -> uint8;
|
||||
auto data() -> uint8;
|
||||
auto status() -> uint8;
|
||||
|
||||
auto data(uint8) -> void;
|
||||
auto control(uint8) -> void;
|
||||
auto registerWrite(uint4 addr, uint8 data) -> void;
|
||||
|
||||
private:
|
||||
uint32 buffer[256 * 240];
|
||||
uint8 vram[0x4000];
|
||||
uint8 cram[0x40];
|
||||
|
||||
struct IO {
|
||||
uint vcounter;
|
||||
uint hcounter;
|
||||
|
||||
bool controlLatch;
|
||||
uint16 controlData;
|
||||
uint2 code;
|
||||
uint14 address;
|
||||
|
||||
uint8 vramLatch;
|
||||
|
||||
//$00 mode control 1
|
||||
bool externalSync;
|
||||
bool extendedHeight;
|
||||
bool mode4;
|
||||
bool spriteShift;
|
||||
bool lineInterrupts;
|
||||
bool leftClip;
|
||||
bool horizontalScrollLock;
|
||||
bool verticalScrollLock;
|
||||
|
||||
//$01 mode control 2
|
||||
bool spriteDouble;
|
||||
bool spriteTile;
|
||||
bool lines240;
|
||||
bool lines224;
|
||||
bool frameInterrupts;
|
||||
bool displayEnable;
|
||||
|
||||
//$02 name table base address
|
||||
uint1 nameTableMask;
|
||||
uint3 nameTableAddress;
|
||||
|
||||
//$03 color table base address
|
||||
uint8 colorTableAddress;
|
||||
|
||||
//$04 pattern table base address
|
||||
uint8 patternTableAddress;
|
||||
|
||||
//$05 sprite attribute table base address
|
||||
uint1 spriteAttributeTableMask;
|
||||
uint6 spriteAttributeTableAddress;
|
||||
|
||||
//$06 sprite pattern table base address
|
||||
uint2 spritePatternTableMask;
|
||||
uint1 spritePatternTableAddress;
|
||||
|
||||
//$07 backdrop color
|
||||
uint4 backdropColor;
|
||||
|
||||
//$08 horizontal scroll offset
|
||||
uint8 hscroll;
|
||||
|
||||
//$09 vertical scroll offset
|
||||
uint8 vscroll;
|
||||
|
||||
//$0a line counter
|
||||
uint8 lineCounter;
|
||||
} io;
|
||||
};
|
||||
|
||||
extern VDP vdp;
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
auto Z80::instruction() -> void {
|
||||
#if 1
|
||||
if(instructionsExecuted < 20)
|
||||
print(disassemble(r.pc), "\n");
|
||||
#endif
|
||||
|
||||
instructionsExecuted++;
|
||||
|
||||
auto code = opcode();
|
||||
if(code == 0xdd) { r.hlp = &r.ix; return; }
|
||||
if(code == 0xfd) { r.hlp = &r.iy; return; }
|
||||
|
|
|
@ -15,7 +15,6 @@ auto Z80::power() -> void {
|
|||
auto Z80::reset() -> void {
|
||||
memory::fill(&r, sizeof(Registers));
|
||||
r.hlp = &r.hl;
|
||||
instructionsExecuted = 0;
|
||||
}
|
||||
|
||||
auto Z80::parity(uint8 value) const -> bool {
|
||||
|
|
|
@ -212,9 +212,6 @@ struct Z80 {
|
|||
} r;
|
||||
|
||||
Bus* bus = nullptr;
|
||||
|
||||
private:
|
||||
uint64 instructionsExecuted = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -59,8 +59,7 @@ namespace Math {
|
|||
#endif
|
||||
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
//fight Microsoft's ardent efforts at vendor lock-in
|
||||
|
||||
#undef IN
|
||||
#undef interface
|
||||
#define dllexport __declspec(dllexport)
|
||||
#define MSG_NOSIGNAL 0
|
||||
|
|
Loading…
Reference in New Issue