Update to v097r30 release.

byuu says:

Changelog:
- fixed sprite window attribute bit (Final Fantasy, Tekken Card
  Challenge, etc)
- rewrote renderer to support 2bpp color mode (Dark Eyes, Dokodemo
  Hamster, Flash Koibito-kun, etc)
This commit is contained in:
Tim Allen 2016-03-29 19:44:03 +11:00
parent 680d16561e
commit 2d83300235
14 changed files with 150 additions and 236 deletions

View File

@ -6,7 +6,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "097.29";
static const string Version = "097.30";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -39,12 +39,12 @@ auto CPU::portRead(uint16 addr) -> uint8 {
if(addr == 0x0047) return r.dmaLength.byte(1);
//DMA_CTRL
if(addr == 0x0048) return r.dmaEnable << 7 | r.dmaMode << 0;
if(addr == 0x0048) return r.dmaMode << 0 | r.dmaEnable << 7;
//WSC_SYSTEM
if(addr == 0x0062) {
return (system.model() == Model::SwanCrystal) << 7;
}
if(addr == 0x0062) return (
(system.model() == Model::SwanCrystal) << 7
);
//HW_FLAGS
if(addr == 0x00a0) {

View File

@ -17,12 +17,12 @@ auto InternalRAM::read(uint16 addr, uint size) -> uint32 {
if(size == Long) return read(addr + 0, Word) << 0 | read(addr + 2, Word) << 16;
if(size == Word) return read(addr + 0, Byte) << 0 | read(addr + 1, Byte) << 8;
if(addr >= 0x4000 && !system.r.depth) return 0x90;
if(addr >= 0x4000 && !system.color()) return 0x90;
return memory[addr];
}
auto InternalRAM::write(uint16 addr, uint8 data) -> void {
if(addr >= 0x4000 && !system.r.depth) return;
if(addr >= 0x4000 && !system.color()) return;
memory[addr] = data;
}

View File

@ -11,7 +11,7 @@ auto PPU::portRead(uint16 addr) -> uint8 {
//BACK_COLOR
if(addr == 0x0001) return (
r.backColor.bits(0, !system.depth() ? 2 : 7)
r.backColor.bits(0, !system.color() ? 2 : 7)
);
//LINE_CUR

View File

@ -43,7 +43,7 @@ auto PPU::latchSprites() -> void {
sprite.hflip = attributes.bit(14);
sprite.priority = attributes.bit(13);
sprite.window = attributes.bit(12);
if(l.spriteWindowEnable && sprite.window == windowInside) continue;
if(l.spriteWindowEnable && !sprite.window && !windowInside) continue;
sprite.palette = 8 + attributes.bits(9,11);
sprite.tile = attributes.bits(0,8);

View File

@ -5,8 +5,7 @@ namespace WonderSwan {
PPU ppu;
#include "io.cpp"
#include "latch.cpp"
#include "render-mono.cpp"
#include "render-color.cpp"
#include "render.cpp"
#include "video.cpp"
#include "serialization.cpp"
@ -23,18 +22,12 @@ auto PPU::main() -> void {
latchRegisters();
latchSprites();
for(auto x : range(224)) {
if(!r.lcdEnable) {
s.pixel = {Pixel::Source::Back, 0x000};
} else if(!system.color()) {
renderMonoBack();
renderMonoScreenOne();
renderMonoScreenTwo();
renderMonoSprite();
} else {
renderColorBack();
renderColorScreenOne();
renderColorScreenTwo();
renderColorSprite();
s.pixel = {Pixel::Source::Back, 0x000};
if(r.lcdEnable) {
renderBack();
if(l.screenOneEnable) renderScreenOne();
if(l.screenTwoEnable) renderScreenTwo();
if(l.spriteEnable) renderSprite();
}
output[s.vclk * 224 + s.hclk] = s.pixel.color;
step(1);

View File

@ -17,21 +17,14 @@ struct PPU : Thread, IO {
auto latchSprites() -> void;
auto latchOAM() -> void;
//render-mono.cpp
auto renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2;
auto renderMonoPalette(uint4 palette, uint2 index) -> uint12;
auto renderMonoBack() -> void;
auto renderMonoScreenOne() -> void;
auto renderMonoScreenTwo() -> void;
auto renderMonoSprite() -> void;
//render-color.cpp
auto renderColorFetch(uint16 offset, uint3 y, uint3 x) -> uint4;
auto renderColorPalette(uint4 palette, uint4 index) -> uint12;
auto renderColorBack() -> void;
auto renderColorScreenOne() -> void;
auto renderColorScreenTwo() -> void;
auto renderColorSprite() -> void;
//render.cpp
auto renderFetch(uint10 tile, uint3 y, uint3 x) -> uint4;
auto renderTransparent(bool palette, uint4 color) -> bool;
auto renderPalette(uint4 palette, uint4 color) -> uint12;
auto renderBack() -> void;
auto renderScreenOne() -> void;
auto renderScreenTwo() -> void;
auto renderSprite() -> void;
//serialization.cpp
auto serialize(serializer&) -> void;

View File

@ -1,93 +0,0 @@
auto PPU::renderColorFetch(uint16 offset, uint3 y, uint3 x) -> uint4 {
uint4 color;
if(system.planar()) {
uint32 data = iram.read(offset + (y << 2), Long);
color |= data.bit( 7 - x) << 0;
color |= data.bit(15 - x) << 1;
color |= data.bit(23 - x) << 2;
color |= data.bit(31 - x) << 3;
}
if(system.packed()) {
uint8 data = iram.read(offset + (y << 2) + (x >> 1));
color = data >> (4 - (x.bit(0) << 2));
}
return color;
}
auto PPU::renderColorPalette(uint4 palette, uint4 index) -> uint12 {
return iram.read(0xfe00 + (palette << 5) + (index << 1), Word);
}
auto PPU::renderColorBack() -> void {
uint12 color = iram.read(0xfe00 + (l.backColor << 1), Word);
s.pixel = {Pixel::Source::Back, color};
}
auto PPU::renderColorScreenOne() -> void {
if(!l.screenOneEnable) return;
uint8 scrollY = s.vclk + l.scrollOneY;
uint8 scrollX = s.hclk + l.scrollOneX;
uint16 tilemapOffset = l.screenOneMapBase << 11;
tilemapOffset += (scrollY >> 3) << 6;
tilemapOffset += (scrollX >> 3) << 1;
uint16 tile = iram.read(tilemapOffset, Word);
uint16 tileOffset = 0x4000 + (tile.bit(13) << 14) + (tile.bits(0,8) << 5);
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX);
if(tileColor == 0) return;
s.pixel = {Pixel::Source::ScreenOne, renderColorPalette(tile.bits(9, 12), tileColor)};
}
auto PPU::renderColorScreenTwo() -> void {
if(!l.screenTwoEnable) return;
bool windowInside = s.vclk >= l.screenTwoWindowY0 && s.vclk <= l.screenTwoWindowY1
&& s.hclk >= l.screenTwoWindowX0 && s.hclk <= l.screenTwoWindowX1;
windowInside ^= l.screenTwoWindowInvert;
if(l.screenTwoWindowEnable && !windowInside) return;
uint8 scrollY = s.vclk + l.scrollTwoY;
uint8 scrollX = s.hclk + l.scrollTwoX;
uint16 tilemapOffset = l.screenTwoMapBase << 11;
tilemapOffset += (scrollY >> 3) << 6;
tilemapOffset += (scrollX >> 3) << 1;
uint16 tile = iram.read(tilemapOffset, Word);
uint16 tileOffset = 0x4000 + (tile.bit(13) << 14) + (tile.bits(0,8) << 5);
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX);
if(tileColor == 0) return;
s.pixel = {Pixel::Source::ScreenTwo, renderColorPalette(tile.bits(9, 12), tileColor)};
}
auto PPU::renderColorSprite() -> void {
if(!l.spriteEnable) return;
bool windowInside = s.hclk >= l.spriteWindowX0 && s.hclk <= l.spriteWindowX1;
for(auto index : range(l.spriteCount)) {
auto& sprite = l.sprite[index];
if(l.spriteWindowEnable && sprite.window == windowInside) continue;
if((uint8)(s.hclk - sprite.x) > 7) continue;
uint16 tileOffset = 0x4000 + (sprite.tile << 5);
uint3 tileY = (uint8)(s.vclk - sprite.y) ^ (sprite.vflip ? 7 : 0);
uint3 tileX = (uint8)(s.hclk - sprite.x) ^ (sprite.hflip ? 7 : 0);
uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX);
if(tileColor == 0) continue;
if(!sprite.priority && s.pixel.source == Pixel::Source::ScreenTwo) continue;
s.pixel = {Pixel::Source::Sprite, renderColorPalette(sprite.palette, tileColor)};
break;
}
}

View File

@ -1,93 +0,0 @@
auto PPU::renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2 {
uint2 color;
if(system.planar()) {
uint16 data = iram.read(offset + (y << 1), Word);
color |= data.bit( 7 - x) << 0;
color |= data.bit(15 - x) << 1;
}
if(system.packed()) {
uint8 data = iram.read(offset + (y << 1) + (x >> 2));
color = data >> (6 - (x.bits(0,1) << 1));
}
return color;
}
auto PPU::renderMonoPalette(uint4 palette, uint2 index) -> uint12 {
uint3 paletteColor = r.palette[palette].color[index];
uint4 poolColor = 15 - r.pool[paletteColor];
return poolColor << 0 | poolColor << 4 | poolColor << 8;
}
auto PPU::renderMonoBack() -> void {
uint4 poolColor = 15 - r.pool[l.backColor.bits(0,2)];
s.pixel = {Pixel::Source::Back, poolColor << 0 | poolColor << 4 | poolColor << 8};
}
auto PPU::renderMonoScreenOne() -> void {
if(!l.screenOneEnable) return;
uint8 scrollY = s.vclk + l.scrollOneY;
uint8 scrollX = s.hclk + l.scrollOneX;
uint14 tilemapOffset = l.screenOneMapBase.bits(0,2) << 11;
tilemapOffset += (scrollY >> 3) << 6;
tilemapOffset += (scrollX >> 3) << 1;
uint16 tile = iram.read(tilemapOffset, Word);
uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4);
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
if(tile.bit(11) && tileColor == 0) return;
s.pixel = {Pixel::Source::ScreenOne, renderMonoPalette(tile.bits(9,12), tileColor)};
}
auto PPU::renderMonoScreenTwo() -> void {
if(!l.screenTwoEnable) return;
bool windowInside = s.vclk >= l.screenTwoWindowY0 && s.vclk <= l.screenTwoWindowY1
&& s.hclk >= l.screenTwoWindowX0 && s.hclk <= l.screenTwoWindowX1;
windowInside ^= l.screenTwoWindowInvert;
if(l.screenTwoWindowEnable && !windowInside) return;
uint8 scrollY = s.vclk + l.scrollTwoY;
uint8 scrollX = s.hclk + l.scrollTwoX;
uint14 tilemapOffset = l.screenTwoMapBase.bits(0,2) << 11;
tilemapOffset += (scrollY >> 3) << 6;
tilemapOffset += (scrollX >> 3) << 1;
uint16 tile = iram.read(tilemapOffset, Word);
uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4);
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
if(tile.bit(11) && tileColor == 0) return;
s.pixel = {Pixel::Source::ScreenTwo, renderMonoPalette(tile.bits(9,12), tileColor)};
}
auto PPU::renderMonoSprite() -> void {
if(!l.spriteEnable) return;
bool windowInside = s.hclk >= l.spriteWindowX0 && s.hclk <= l.spriteWindowX1;
for(auto index : range(l.spriteCount)) {
auto& sprite = l.sprite[index];
if(l.spriteWindowEnable && sprite.window == windowInside) continue;
if((uint8)(s.hclk - sprite.x) > 7) continue;
uint14 tileOffset = 0x2000 + (sprite.tile << 4);
uint3 tileY = (uint8)(s.vclk - sprite.y) ^ (sprite.vflip ? 7 : 0);
uint3 tileX = (uint8)(s.hclk - sprite.x) ^ (sprite.hflip ? 7 : 0);
uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
if(sprite.palette.bit(2) && tileColor == 0) continue;
if(!sprite.priority && s.pixel.source == Pixel::Source::ScreenTwo) continue;
s.pixel = {Pixel::Source::Sprite, renderMonoPalette(sprite.palette, tileColor)};
break;
}
}

114
higan/ws/ppu/render.cpp Normal file
View File

@ -0,0 +1,114 @@
auto PPU::renderFetch(uint10 tile, uint3 y, uint3 x) -> uint4 {
uint16 offset = 0x200 + tile << (4 + system.depth());
uint4 color = 0;
if(system.planar()) {
if(!system.depth()) {
uint16 data = iram.read(offset + (y << 1), Word);
color |= data.bit( 7 - x) << 0;
color |= data.bit(15 - x) << 1;
} else {
uint32 data = iram.read(offset + (y << 2), Long);
color |= data.bit( 7 - x) << 0;
color |= data.bit(15 - x) << 1;
color |= data.bit(23 - x) << 2;
color |= data.bit(31 - x) << 3;
}
}
if(system.packed()) {
if(!system.depth()) {
uint8 data = iram.read(offset + (y << 1) + (x >> 2));
color = data >> (6 - (x.bits(0,1) << 1));
color = color.bits(0,1);
} else {
uint8 data = iram.read(offset + (y << 2) + (x >> 1));
color = data >> (4 - (x.bit(0) << 2));
}
}
return color;
}
auto PPU::renderTransparent(bool palette, uint4 color) -> bool {
if(color) return false;
if(!system.depth() && !palette) return false;
return true;
}
auto PPU::renderPalette(uint4 palette, uint4 color) -> uint12 {
if(!system.color()) {
uint3 paletteColor = r.palette[palette].color[color.bits(0,1)];
uint4 poolColor = 15 - r.pool[paletteColor];
return poolColor << 0 | poolColor << 4 | poolColor << 8;
} else {
return iram.read(0xfe00 + (palette << 5) + (color << 1), Word);
}
}
auto PPU::renderBack() -> void {
if(!system.color()) {
uint4 poolColor = 15 - r.pool[l.backColor.bits(0,2)];
s.pixel = {Pixel::Source::Back, poolColor << 0 | poolColor << 4 | poolColor << 8};
} else {
uint12 color = iram.read(0xfe00 + (l.backColor << 1), Word);
s.pixel = {Pixel::Source::Back, color};
}
}
auto PPU::renderScreenOne() -> void {
uint8 scrollY = s.vclk + l.scrollOneY;
uint8 scrollX = s.hclk + l.scrollOneX;
uint16 tilemapOffset = l.screenOneMapBase.bits(0, 2 + system.depth()) << 11;
tilemapOffset += (scrollY >> 3) << 6;
tilemapOffset += (scrollX >> 3) << 1;
uint16 tile = iram.read(tilemapOffset, Word);
uint3 tileY = scrollY ^ tile.bit(15) * 7;
uint3 tileX = scrollX ^ tile.bit(14) * 7;
uint4 tileColor = renderFetch(tile.bit(13) << 9 | tile.bits(0,8), tileY, tileX);
if(renderTransparent(tile.bit(11), tileColor)) return;
s.pixel = {Pixel::Source::ScreenOne, renderPalette(tile.bits(9,12), tileColor)};
}
auto PPU::renderScreenTwo() -> void {
bool windowInside = s.vclk >= l.screenTwoWindowY0 && s.vclk <= l.screenTwoWindowY1
&& s.hclk >= l.screenTwoWindowX0 && s.hclk <= l.screenTwoWindowX1;
windowInside ^= l.screenTwoWindowInvert;
if(l.screenTwoWindowEnable && !windowInside) return;
uint8 scrollY = s.vclk + l.scrollTwoY;
uint8 scrollX = s.hclk + l.scrollTwoX;
uint16 tilemapOffset = l.screenTwoMapBase.bits(0, 2 + system.depth()) << 11;
tilemapOffset += (scrollY >> 3) << 6;
tilemapOffset += (scrollX >> 3) << 1;
uint16 tile = iram.read(tilemapOffset, Word);
uint3 tileY = scrollY ^ tile.bit(15) * 7;
uint3 tileX = scrollX ^ tile.bit(14) * 7;
uint4 tileColor = renderFetch(tile.bit(13) << 9 | tile.bits(0,8), tileY, tileX);
if(renderTransparent(tile.bit(11), tileColor)) return;
s.pixel = {Pixel::Source::ScreenTwo, renderPalette(tile.bits(9,12), tileColor)};
}
auto PPU::renderSprite() -> void {
bool windowInside = s.hclk >= l.spriteWindowX0 && s.hclk <= l.spriteWindowY0;
for(auto index : range(l.spriteCount)) {
auto& sprite = l.sprite[index];
if(l.spriteWindowEnable && !sprite.window && !windowInside) continue;
if((uint8)(s.hclk - sprite.x) > 7) continue;
uint3 tileY = (s.vclk - sprite.y) ^ sprite.vflip * 7;
uint3 tileX = (s.hclk - sprite.x) ^ sprite.hflip * 7;
uint4 tileColor = renderFetch(sprite.tile, tileY, tileX);
if(renderTransparent(sprite.palette.bit(2), tileColor)) continue;
if(!sprite.priority && s.pixel.source == Pixel::Source::ScreenTwo) continue;
s.pixel = {Pixel::Source::Sprite, renderPalette(sprite.palette, tileColor)};
break;
}
}

View File

@ -3,8 +3,8 @@ auto System::portRead(uint16 addr) -> uint8 {
if(addr == 0x0060) return (
r.unknown << 0
| r.format << 5
| r.color << 6
| r.depth << 7
| r.depth << 6
| r.color << 7
);
//IEEP_DATA
@ -24,8 +24,8 @@ auto System::portWrite(uint16 addr, uint8 data) -> void {
if(addr == 0x0060) {
r.unknown = data.bits(0,4) & 0b01011;
r.format = data.bit (5);
r.color = data.bit (6);
r.depth = data.bit (7);
r.depth = data.bit (6);
r.color = data.bit (7);
return;
}

View File

@ -59,8 +59,8 @@ auto System::serializeAll(serializer& s) -> void {
auto System::serialize(serializer& s) -> void {
eeprom.serialize(s);
s.integer(r.unknown);
s.integer(r.format);
s.integer(r.depth);
s.integer(r.color);
s.integer(r.format);
s.integer(r.unknown);
}

View File

@ -12,7 +12,7 @@ auto System::orientation() const -> bool { return _orientation; }
auto System::color() const -> bool { return r.color; }
auto System::planar() const -> bool { return r.format == 0; }
auto System::packed() const -> bool { return r.format == 1; }
auto System::depth() const -> bool { return r.depth == 1; }
auto System::depth() const -> bool { return r.color && r.depth == 1; }
auto System::init() -> void {
assert(interface != nullptr);
@ -67,10 +67,10 @@ auto System::power() -> void {
bus.map(this, 0x0060);
bus.map(this, 0x00ba, 0x00be);
r.unknown = 0;
r.format = 0;
r.depth = 0;
r.color = 0;
r.format = 0;
r.unknown = 0;
}
auto System::run() -> void {

View File

@ -40,15 +40,15 @@ struct System : IO {
bool rotate;
} keypad;
privileged:
struct Registers {
//$0060 DISP_MODE
uint5 unknown;
uint1 format;
uint1 depth;
uint1 color;
uint1 format;
uint5 unknown;
} r;
privileged:
bool _loaded = false;
Model _model = Model::WonderSwan;
bool _orientation = 0; //0 = horizontal, 1 = vertical