mirror of https://github.com/bsnes-emu/bsnes.git
Update to v101r25 release.
byuu says: Changelog: - SMS: emulated VDP mode 4 graphical output (background, sprites) - added $(windres) to icarus as well I'm sure the VDP emulation is still really, really buggy, but essentially I handle: - mode 4 rendering - background scrolling - background hscroll lock - background vscroll lock - background nametable relocation - sprite nametable relocation - sprite tiledata relocation - sprite 192-line y=0xd0 edge case (end sprite rendering) - sprite 8-pixel x-coordinate displacement - sprite extended size (height only in mode 4) - sprite overflow - sprite collision - left column masking - display disable - backdrop color - 192, 224, 240 height I do not support: - mode 2 rendering - sprite zoom - disallowing 240 height in NTSC mode - PAL mode - probably lots more
This commit is contained in:
parent
e30780bb72
commit
5bdf55f08f
|
@ -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.25";
|
static const string Version = "101.26";
|
||||||
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/";
|
||||||
|
|
|
@ -66,7 +66,15 @@ auto Interface::videoColors() -> uint32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::videoColor(uint32 color) -> uint64 {
|
auto Interface::videoColor(uint32 color) -> uint64 {
|
||||||
return 0;
|
uint2 B = color >> 4;
|
||||||
|
uint2 G = color >> 2;
|
||||||
|
uint2 R = color >> 0;
|
||||||
|
|
||||||
|
uint64 r = image::normalize(R, 2, 16);
|
||||||
|
uint64 g = image::normalize(G, 2, 16);
|
||||||
|
uint64 b = image::normalize(B, 2, 16);
|
||||||
|
|
||||||
|
return r << 32 | g << 16 | b << 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::audioFrequency() -> double {
|
auto Interface::audioFrequency() -> double {
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
auto VDP::Background::scanline() -> void {
|
||||||
|
state.x = 0;
|
||||||
|
state.y = vdp.io.vcounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto VDP::Background::run() -> void {
|
||||||
|
if(state.y >= vdp.vlines()) {
|
||||||
|
output.color = 0;
|
||||||
|
output.palette = 0;
|
||||||
|
output.priority = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 hoffset = state.x;
|
||||||
|
if(!vdp.io.horizontalScrollLock || hoffset >= 16) hoffset += vdp.io.hscroll;
|
||||||
|
|
||||||
|
uint8 voffset = state.y;
|
||||||
|
if(!vdp.io.verticalScrollLock || hoffset <= 191) voffset += vdp.io.vscroll;
|
||||||
|
|
||||||
|
uint14 nameTableAddress;
|
||||||
|
if(vdp.vlines() == 192) {
|
||||||
|
nameTableAddress = vdp.io.nameTableAddress << 11;
|
||||||
|
} else {
|
||||||
|
nameTableAddress = (vdp.io.nameTableAddress & ~1) << 11 | 0x700;
|
||||||
|
}
|
||||||
|
nameTableAddress += ((voffset >> 3) << 6) + ((hoffset >> 3) << 1);
|
||||||
|
|
||||||
|
uint16 tiledata;
|
||||||
|
tiledata = vdp.vram[nameTableAddress + 0] << 0;
|
||||||
|
tiledata |= vdp.vram[nameTableAddress + 1] << 8;
|
||||||
|
|
||||||
|
uint14 patternAddress = tiledata.bits(0,8) << 5;
|
||||||
|
if(tiledata.bit(9)) hoffset ^= 7;
|
||||||
|
if(tiledata.bit(10)) voffset ^= 7;
|
||||||
|
output.palette = tiledata.bit(11);
|
||||||
|
output.priority = tiledata.bit(12);
|
||||||
|
|
||||||
|
auto index = hoffset & 7;
|
||||||
|
patternAddress += (voffset & 7) << 2;
|
||||||
|
output.color.bit(0) = vdp.vram[patternAddress + 0].bit(index);
|
||||||
|
output.color.bit(1) = vdp.vram[patternAddress + 1].bit(index);
|
||||||
|
output.color.bit(2) = vdp.vram[patternAddress + 2].bit(index);
|
||||||
|
output.color.bit(3) = vdp.vram[patternAddress + 3].bit(index);
|
||||||
|
|
||||||
|
state.x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto VDP::Background::power() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto VDP::Background::reset() -> void {
|
||||||
|
memory::fill(&state, sizeof(State));
|
||||||
|
memory::fill(&output, sizeof(Output));
|
||||||
|
}
|
|
@ -50,7 +50,7 @@ auto VDP::data(uint8 data) -> void {
|
||||||
if(io.code <= 2) {
|
if(io.code <= 2) {
|
||||||
vram[io.address++] = data;
|
vram[io.address++] = data;
|
||||||
} else {
|
} else {
|
||||||
cram[io.address++ & 0x3f] = data;
|
cram[io.address++ & 0x1f] = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
auto VDP::Sprite::scanline() -> void {
|
||||||
|
state.x = 0;
|
||||||
|
state.y = vdp.io.vcounter;
|
||||||
|
objects.reset();
|
||||||
|
|
||||||
|
bool large = vdp.io.extendedHeight;
|
||||||
|
uint14 attributeAddress = vdp.io.spriteAttributeTableAddress << 8;
|
||||||
|
for(uint index : range(64)) {
|
||||||
|
uint8 y = vdp.vram[attributeAddress + index];
|
||||||
|
uint8 x = vdp.vram[attributeAddress + 0x80 + (index << 1)];
|
||||||
|
uint8 pattern = vdp.vram[attributeAddress + 0x81 + (index << 1)];
|
||||||
|
if(vdp.vlines() == 192 && y == 0xd0) break;
|
||||||
|
|
||||||
|
if(vdp.io.spriteShift) x -= 8;
|
||||||
|
y += 1;
|
||||||
|
if(state.y < y) continue;
|
||||||
|
if(state.y > y + (large ? 15 : 7)) continue;
|
||||||
|
|
||||||
|
if(large) pattern.bit(0) = 0;
|
||||||
|
|
||||||
|
objects.append({x, y, pattern});
|
||||||
|
if(objects.size() == 8) {
|
||||||
|
vdp.io.spriteOverflow = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto VDP::Sprite::run() -> void {
|
||||||
|
output.color = 0;
|
||||||
|
|
||||||
|
if(state.y >= vdp.vlines()) return;
|
||||||
|
|
||||||
|
bool large = vdp.io.extendedHeight;
|
||||||
|
for(auto& o : objects) {
|
||||||
|
if(state.x < o.x) continue;
|
||||||
|
if(state.x > o.x + 7) continue;
|
||||||
|
|
||||||
|
uint x = o.x - state.x;
|
||||||
|
uint y = o.y - state.y;
|
||||||
|
|
||||||
|
uint14 address = vdp.io.spritePatternTableAddress << 13;
|
||||||
|
address += o.pattern << 5;
|
||||||
|
address += (y & (large ? 15 : 7)) << 2;
|
||||||
|
|
||||||
|
uint4 color;
|
||||||
|
color.bit(0) = vdp.vram[address + 0].bit(x & 7);
|
||||||
|
color.bit(1) = vdp.vram[address + 1].bit(x & 7);
|
||||||
|
color.bit(2) = vdp.vram[address + 2].bit(x & 7);
|
||||||
|
color.bit(3) = vdp.vram[address + 3].bit(x & 7);
|
||||||
|
if(color == 0) continue;
|
||||||
|
|
||||||
|
if(output.color) {
|
||||||
|
vdp.io.spriteCollision = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto VDP::Sprite::power() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto VDP::Sprite::reset() -> void {
|
||||||
|
memory::fill(&state, sizeof(State));
|
||||||
|
memory::fill(&output, sizeof(Output));
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ namespace MasterSystem {
|
||||||
|
|
||||||
VDP vdp;
|
VDP vdp;
|
||||||
#include "io.cpp"
|
#include "io.cpp"
|
||||||
|
#include "background.cpp"
|
||||||
|
#include "sprite.cpp"
|
||||||
|
|
||||||
auto VDP::Enter() -> void {
|
auto VDP::Enter() -> void {
|
||||||
while(true) scheduler.synchronize(), vdp.main();
|
while(true) scheduler.synchronize(), vdp.main();
|
||||||
|
@ -15,16 +17,34 @@ auto VDP::main() -> void {
|
||||||
io.lcounter = io.lineCounter;
|
io.lcounter = io.lineCounter;
|
||||||
io.intLine = 1;
|
io.intLine = 1;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
io.lcounter = io.lineCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(io.vcounter == vlines() + 1) {
|
if(io.vcounter == vlines() + 1) {
|
||||||
io.lcounter = io.lineCounter;
|
|
||||||
io.intFrame = 1;
|
io.intFrame = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(uint x : range(684)) {
|
background.scanline();
|
||||||
step(1);
|
sprite.scanline();
|
||||||
|
|
||||||
|
//684 clocks/scanline
|
||||||
|
for(uint x : range(256)) {
|
||||||
|
background.run();
|
||||||
|
sprite.run();
|
||||||
|
step(2);
|
||||||
|
|
||||||
|
uint5 color = cram[16 | io.backdropColor];
|
||||||
|
if(background.output.color && (background.output.priority || !sprite.output.color)) {
|
||||||
|
color = cram[background.output.palette << 4 | background.output.color];
|
||||||
|
} else if(sprite.output.color) {
|
||||||
|
color = cram[16 | sprite.output.color];
|
||||||
}
|
}
|
||||||
|
if(x <= 7 && io.leftClip) color = cram[7];
|
||||||
|
if(!io.displayEnable) color = 0;
|
||||||
|
buffer[io.vcounter * 256 + x] = color;
|
||||||
|
}
|
||||||
|
step(172);
|
||||||
|
|
||||||
if(io.vcounter == 240) scheduler.exit(Scheduler::Event::Frame);
|
if(io.vcounter == 240) scheduler.exit(Scheduler::Event::Frame);
|
||||||
}
|
}
|
||||||
|
@ -59,12 +79,17 @@ auto VDP::vblank() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::power() -> void {
|
auto VDP::power() -> void {
|
||||||
|
background.power();
|
||||||
|
sprite.power();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::reset() -> void {
|
auto VDP::reset() -> void {
|
||||||
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
||||||
|
|
||||||
memory::fill(&io, sizeof(IO));
|
memory::fill(&io, sizeof(IO));
|
||||||
|
|
||||||
|
background.reset();
|
||||||
|
sprite.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,56 @@ struct VDP : Thread {
|
||||||
auto control(uint8) -> void;
|
auto control(uint8) -> void;
|
||||||
auto registerWrite(uint4 addr, uint8 data) -> void;
|
auto registerWrite(uint4 addr, uint8 data) -> void;
|
||||||
|
|
||||||
|
//background.cpp
|
||||||
|
struct Background {
|
||||||
|
auto scanline() -> void;
|
||||||
|
auto run() -> void;
|
||||||
|
|
||||||
|
auto power() -> void;
|
||||||
|
auto reset() -> void;
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
uint x;
|
||||||
|
uint y;
|
||||||
|
} state;
|
||||||
|
|
||||||
|
struct Output {
|
||||||
|
uint4 color;
|
||||||
|
uint1 palette;
|
||||||
|
uint1 priority;
|
||||||
|
} output;
|
||||||
|
} background;
|
||||||
|
|
||||||
|
//sprite.cpp
|
||||||
|
struct Sprite {
|
||||||
|
auto scanline() -> void;
|
||||||
|
auto run() -> void;
|
||||||
|
|
||||||
|
auto power() -> void;
|
||||||
|
auto reset() -> void;
|
||||||
|
|
||||||
|
struct Object {
|
||||||
|
uint8 x;
|
||||||
|
uint8 y;
|
||||||
|
uint8 pattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
uint x;
|
||||||
|
uint y;
|
||||||
|
} state;
|
||||||
|
|
||||||
|
struct Output {
|
||||||
|
uint4 color;
|
||||||
|
} output;
|
||||||
|
|
||||||
|
array<Object, 8> objects;
|
||||||
|
} sprite;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32 buffer[256 * 240];
|
uint32 buffer[256 * 262];
|
||||||
uint8 vram[0x4000];
|
uint8 vram[0x4000];
|
||||||
uint8 cram[0x40];
|
uint8 cram[0x20];
|
||||||
|
|
||||||
struct IO {
|
struct IO {
|
||||||
uint vcounter; //vertical counter
|
uint vcounter; //vertical counter
|
||||||
|
|
|
@ -20,7 +20,6 @@ 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
|
||||||
|
|
|
@ -29,7 +29,7 @@ obj/icarus.o: icarus.cpp $(call rwildcard,core/) $(call rwildcard,heuristics/) $
|
||||||
$(compiler) $(cppflags) $(flags) -o obj/icarus.o -c icarus.cpp
|
$(compiler) $(cppflags) $(flags) -o obj/icarus.o -c icarus.cpp
|
||||||
|
|
||||||
obj/resource.o:
|
obj/resource.o:
|
||||||
windres ../hiro/windows/hiro.rc obj/resource.o
|
$(windres) ../hiro/windows/hiro.rc obj/resource.o
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
ifeq ($(platform),macosx)
|
ifeq ($(platform),macosx)
|
||||||
|
|
|
@ -70,6 +70,7 @@ endif
|
||||||
# windows settings
|
# windows settings
|
||||||
ifeq ($(platform),windows)
|
ifeq ($(platform),windows)
|
||||||
link += -lws2_32 -lole32
|
link += -lws2_32 -lole32
|
||||||
|
windres := windres
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# macosx settings
|
# macosx settings
|
||||||
|
|
Loading…
Reference in New Issue