mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-04-21 19:21:58 +02:00
Update to v097r20 release.
byuu says: Changelog: - WS: fixed a major CPU bug where I was using the wrong bits for ModR/M's memory mode - WS: added grayscale PPU emulation (exceptionally buggy) GunPey now runs, as long as you add: eeprom name=save.ram size=0x800 to the manifest after importing with icarus. Right now, you can't control the game due to missing keypad polling. There's also a lot of glitchiness with the sprites. Seems like they're not getting properly cleared sometimes or something. Also, the PPU emulation is totally unrealistic bullshit. I decode and evaluate every single tile and sprite on every single pixel of output. No way in hell the hardware could ever come close to that. The speed's around 500fps without the insane sprite evaluations, and around 90fps with it. Obviously, I'll fix this in time. Nothing else seems to run that I've tried. Not even far enough to display any output whatsoever. Tried Langrisser Millenium, Rockman & Forte and Riviera. I really need to update icarus to try and encode eeprom/sram sizes, because that's going to break a lot of stuff if it's missing.
This commit is contained in:
parent
7dc62e3a69
commit
570eb9c5f5
@ -6,7 +6,7 @@ using namespace nall;
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "097.19";
|
||||
static const string Version = "097.20";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
@ -1,19 +1,14 @@
|
||||
//ModRM functions
|
||||
//d7-d6 => mod
|
||||
//d5-d3 => reg
|
||||
//d2-d0 => mem
|
||||
|
||||
auto V30MZ::modRM() -> void {
|
||||
auto byte = fetch();
|
||||
modrm.mod = byte >> 6;
|
||||
modrm.reg = byte >> 3;
|
||||
modrm.mem = byte >> 0;
|
||||
auto data = fetch();
|
||||
modrm.mem = data.bits(0,2);
|
||||
modrm.reg = data.bits(3,5);
|
||||
modrm.mod = data.bits(6,7);
|
||||
|
||||
if(modrm.mod == 0 && modrm.mem == 6) {
|
||||
modrm.segment = segment(r.ds);
|
||||
modrm.address = fetch(Word);
|
||||
} else {
|
||||
switch(modrm.reg) {
|
||||
switch(modrm.mem) {
|
||||
case 0: modrm.segment = segment(r.ds); modrm.address = r.bx + r.si; break;
|
||||
case 1: modrm.segment = segment(r.ds); modrm.address = r.bx + r.di; break;
|
||||
case 2: modrm.segment = segment(r.ss); modrm.address = r.bp + r.si; break;
|
||||
|
@ -3,9 +3,10 @@ auto CPU::poll() -> void {
|
||||
state.halt = false;
|
||||
if(!V30MZ::r.f.i) return;
|
||||
|
||||
//find and execute first pending interrupt in order of priority (7-0)
|
||||
for(int n = 7; n >= 0; n--) {
|
||||
if(r.interruptStatus & r.interruptEnable & (1 << n)) {
|
||||
interrupt(r.interruptBase + n);
|
||||
return interrupt(r.interruptBase + n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,12 +12,12 @@ auto IO::power() -> void {
|
||||
}
|
||||
|
||||
auto IO::portRead(uint16 addr) -> uint8 {
|
||||
print("[", hex(addr, 4L), "]: port unmapped\n");
|
||||
//print("[", hex(addr, 4L), "]: port unmapped\n");
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto IO::portWrite(uint16 addr, uint8 data) -> void {
|
||||
print("[", hex(addr, 4L), "] = ", hex(data, 2L), ": port unmapped\n");
|
||||
//print("[", hex(addr, 4L), "] = ", hex(data, 2L), ": port unmapped\n");
|
||||
}
|
||||
|
||||
auto Bus::read(uint20 addr) -> uint8 {
|
||||
|
@ -3,7 +3,7 @@ auto PPU::portRead(uint16 addr) -> uint8 {
|
||||
if(addr == 0x0000) {
|
||||
return (
|
||||
r.screenTwoWindowEnable << 5
|
||||
| r.screenTwoWindowMode << 4
|
||||
| r.screenTwoWindowInvert << 4
|
||||
| r.spriteWindowEnable << 3
|
||||
| r.spriteEnable << 2
|
||||
| r.screenTwoEnable << 1
|
||||
@ -122,7 +122,7 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void {
|
||||
//DISP_CTRL
|
||||
if(addr == 0x0000) {
|
||||
r.screenTwoWindowEnable = data.bit(5);
|
||||
r.screenTwoWindowMode = data.bit(4);
|
||||
r.screenTwoWindowInvert = data.bit(4);
|
||||
r.spriteWindowEnable = data.bit(3);
|
||||
r.spriteEnable = data.bit(2);
|
||||
r.screenTwoEnable = data.bit(1);
|
||||
@ -292,8 +292,8 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void {
|
||||
|
||||
//PALMONO
|
||||
if(addr >= 0x0020 && addr <= 0x003f) {
|
||||
r.palette[addr.bits(3,1)].color[addr.bit(0) * 2 + 1] = data.bits(6,4);
|
||||
r.palette[addr.bits(3,1)].color[addr.bit(0) * 2 + 0] = data.bits(2,0);
|
||||
r.palette[addr.bits(4,1)].color[addr.bit(0) * 2 + 1] = data.bits(6,4);
|
||||
r.palette[addr.bits(4,1)].color[addr.bit(0) * 2 + 0] = data.bits(2,0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ namespace WonderSwan {
|
||||
|
||||
PPU ppu;
|
||||
#include "io.cpp"
|
||||
#include "render.cpp"
|
||||
#include "video.cpp"
|
||||
|
||||
auto PPU::Enter() -> void {
|
||||
@ -11,7 +12,21 @@ auto PPU::Enter() -> void {
|
||||
}
|
||||
|
||||
auto PPU::main() -> void {
|
||||
step(256);
|
||||
if(status.vclk < 144) {
|
||||
for(uint x = 0; x < 224; x++) {
|
||||
pixel = {Pixel::Source::None, 0xfff};
|
||||
renderScreenOne();
|
||||
renderScreenTwo();
|
||||
renderSprite();
|
||||
output[status.vclk * 224 + status.hclk] = pixel.color;
|
||||
step(1);
|
||||
}
|
||||
for(uint x = 224; x < 256; x++) {
|
||||
step(1);
|
||||
}
|
||||
} else {
|
||||
step(256);
|
||||
}
|
||||
scanline();
|
||||
}
|
||||
|
||||
|
@ -8,20 +8,33 @@ struct PPU : Thread, IO {
|
||||
auto step(uint clocks) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
//io.cpp
|
||||
auto portRead(uint16 addr) -> uint8 override;
|
||||
auto portWrite(uint16 addr, uint8 data) -> void override;
|
||||
|
||||
uint16 output[224 * 144];
|
||||
//render.cpp
|
||||
auto renderScreenOne() -> void;
|
||||
auto renderScreenTwo() -> void;
|
||||
auto renderSprite() -> void;
|
||||
|
||||
//state
|
||||
uint12 output[224 * 144];
|
||||
|
||||
struct Status {
|
||||
uint vclk;
|
||||
uint hclk;
|
||||
} status;
|
||||
|
||||
struct Pixel {
|
||||
enum class Source : uint { None, ScreenOne, ScreenTwo, Sprite };
|
||||
Source source;
|
||||
uint12 color;
|
||||
} pixel;
|
||||
|
||||
struct Registers {
|
||||
//$0000 DISP_CTRL
|
||||
bool screenTwoWindowEnable;
|
||||
bool screenTwoWindowMode;
|
||||
bool screenTwoWindowInvert;
|
||||
bool spriteWindowEnable;
|
||||
bool spriteEnable;
|
||||
bool screenTwoEnable;
|
||||
|
121
higan/ws/ppu/render.cpp
Normal file
121
higan/ws/ppu/render.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
auto PPU::renderScreenOne() -> void {
|
||||
if(!r.screenOneEnable) return;
|
||||
|
||||
uint8 scrollX = status.hclk + r.scrollOneX;
|
||||
uint8 scrollY = status.vclk + r.scrollOneY;
|
||||
|
||||
uint14 tilemapOffset = r.screenOneMapBase << 11;
|
||||
tilemapOffset += (scrollY >> 3) << 6;
|
||||
tilemapOffset += (scrollX >> 3) << 1;
|
||||
|
||||
uint16 tile;
|
||||
tile.byte(0) = iram[tilemapOffset++];
|
||||
tile.byte(1) = iram[tilemapOffset++];
|
||||
|
||||
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
|
||||
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
|
||||
|
||||
uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4) + (tileY << 1);
|
||||
uint8 d0 = iram[tileOffset++];
|
||||
uint8 d1 = iram[tileOffset++];
|
||||
|
||||
uint8 tileMask = 0x80 >> tileX;
|
||||
uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0);
|
||||
|
||||
uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor];
|
||||
uint4 poolColor = 15 - r.pool[paletteColor];
|
||||
|
||||
pixel = {Pixel::Source::ScreenOne, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
||||
}
|
||||
|
||||
auto PPU::renderScreenTwo() -> void {
|
||||
if(!r.screenTwoEnable) return;
|
||||
|
||||
bool windowInside = (
|
||||
status.hclk >= r.screenTwoWindowX0
|
||||
&& status.hclk <= r.screenTwoWindowX1
|
||||
&& status.vclk >= r.screenTwoWindowY0
|
||||
&& status.vclk <= r.screenTwoWindowY1
|
||||
);
|
||||
windowInside ^= r.screenTwoWindowInvert;
|
||||
if(r.screenTwoWindowEnable && !windowInside) return;
|
||||
|
||||
uint8 scrollX = status.hclk + r.scrollTwoX;
|
||||
uint8 scrollY = status.vclk + r.scrollTwoY;
|
||||
|
||||
uint14 tilemapOffset = r.screenTwoMapBase << 11;
|
||||
tilemapOffset += (scrollY >> 3) << 6;
|
||||
tilemapOffset += (scrollX >> 3) << 1;
|
||||
|
||||
uint16 tile;
|
||||
tile.byte(0) = iram[tilemapOffset++];
|
||||
tile.byte(1) = iram[tilemapOffset++];
|
||||
|
||||
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
|
||||
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
|
||||
|
||||
uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4) + (tileY << 1);
|
||||
uint8 d0 = iram[tileOffset++];
|
||||
uint8 d1 = iram[tileOffset++];
|
||||
|
||||
uint8 tileMask = 0x80 >> tileX;
|
||||
uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0);
|
||||
|
||||
if(tile.bit(11) && tileColor == 0) return;
|
||||
uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor];
|
||||
uint4 poolColor = 15 - r.pool[paletteColor];
|
||||
|
||||
pixel = {Pixel::Source::ScreenTwo, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
||||
}
|
||||
|
||||
auto PPU::renderSprite() -> void {
|
||||
if(!r.spriteEnable) return;
|
||||
|
||||
bool windowInside = (
|
||||
status.hclk >= r.spriteWindowX0
|
||||
&& status.hclk <= r.spriteWindowX1
|
||||
&& status.vclk >= r.spriteWindowY0
|
||||
&& status.vclk <= r.spriteWindowY1
|
||||
);
|
||||
|
||||
uint14 spriteBase = r.spriteBase << 9;
|
||||
|
||||
uint7 spriteIndex = r.spriteFirst;
|
||||
uint8 spriteCount = max(128, (uint)r.spriteCount);
|
||||
while(spriteCount--) {
|
||||
uint32 sprite;
|
||||
sprite.byte(0) = iram[spriteBase + (spriteIndex << 2) + 0];
|
||||
sprite.byte(1) = iram[spriteBase + (spriteIndex << 2) + 1];
|
||||
sprite.byte(2) = iram[spriteBase + (spriteIndex << 2) + 2];
|
||||
sprite.byte(3) = iram[spriteBase + (spriteIndex << 2) + 3];
|
||||
spriteIndex++;
|
||||
|
||||
if(r.spriteWindowEnable && sprite.bit(12) && !windowInside) continue;
|
||||
if(pixel.source == Pixel::Source::ScreenTwo && !sprite.bit(13)) continue;
|
||||
|
||||
uint8 spriteY = sprite.bits(16,23);
|
||||
uint8 spriteX = sprite.bits(24,31);
|
||||
|
||||
if(status.hclk < spriteX) continue;
|
||||
if(status.hclk > (uint8)(spriteX + 7)) continue;
|
||||
if(status.vclk < spriteY) continue;
|
||||
if(status.vclk > (uint8)(spriteY + 7)) continue;
|
||||
|
||||
uint3 tileX = (uint8)(status.hclk - spriteX) ^ (sprite.bit(14) ? 7 : 0);
|
||||
uint3 tileY = (uint8)(status.vclk - spriteY) ^ (sprite.bit(15) ? 7 : 0);
|
||||
|
||||
uint14 tileOffset = 0x2000 + (sprite.bits(0,8) << 4) + (tileY << 1);
|
||||
uint8 d0 = iram[tileOffset++];
|
||||
uint8 d1 = iram[tileOffset++];
|
||||
|
||||
uint8 tileMask = 0x80 >> tileX;
|
||||
uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0);
|
||||
|
||||
if(sprite.bit(11) && tileColor == 0) continue;
|
||||
uint3 paletteColor = r.palette[8 + sprite.bits(9,11)].color[tileColor];
|
||||
uint4 poolColor = 15 - r.pool[paletteColor];
|
||||
|
||||
pixel = {Pixel::Source::Sprite, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
||||
return;
|
||||
}
|
||||
}
|
@ -9,12 +9,12 @@ Video::Video() {
|
||||
auto Video::power() -> void {
|
||||
memory::fill(output(), 224 * 224 * sizeof(uint32));
|
||||
|
||||
for(auto color : range(1 << 12)) {
|
||||
for(uint12 color : range(1 << 12)) {
|
||||
paletteLiteral[color] = color;
|
||||
|
||||
uint R = (uint4)(color >> 8);
|
||||
uint G = (uint4)(color >> 4);
|
||||
uint B = (uint4)(color >> 0);
|
||||
uint B = color.bits(0, 3);
|
||||
uint G = color.bits(4, 7);
|
||||
uint R = color.bits(8,11);
|
||||
|
||||
R = image::normalize(R, 4, 16);
|
||||
G = image::normalize(G, 4, 16);
|
||||
@ -26,10 +26,10 @@ auto Video::power() -> void {
|
||||
auto Video::refresh() -> void {
|
||||
for(uint y = 0; y < 144; y++) {
|
||||
auto source = ppu.output + y * 224;
|
||||
auto target = output() + y * 224;
|
||||
for(uint x = 0; x < 224; x++) {
|
||||
auto color = paletteStandard[*source++];
|
||||
*target++ = color;
|
||||
//*(output() + y * 224 + x) = color;
|
||||
*(output() + (223 - x) * 224 + 40 + y) = color;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user