Update to v101r35 release.

byuu says:

Changelog:
  - PCE: added 384KB HuCard ROM mirroring mode
  - PCE: corrected D-pad polling order
  - PCE: corrected palette color ordering (GRB, not RGB -- yes,
    seriously)
  - PCE: corrected SATB DMA -- should write to SATB, not to VRAM
  - PCE: broke out Background, Sprite VDC settings to separate
    subclasses
  - PCE: emulated VDC backgrounds
  - PCE: emulated VDC sprites
  - PCE: emulated VDC sprite overflow, collision interrupts
  - HuC6280: fixed disassembler output for STi instructions
  - HuC6280: added missing LastCycle check to interrupt()
  - HuC6280: fixed BIT, CMP, CPX, CPY, TRB, TSB, TST flag testing and
    result
  - HuC6280: added extra cycle delays to the block move instructions
  - HuC6280: fixed ordering for flag set/clear instructions (happens
    after LastCycle check)
  - HuC6280: removed extra cycle from immediate instructions
  - HuC6280: fixed indirectLoad, indirectYStore absolute addressing
  - HuC6280: fixed BBR, BBS zeropage value testing
  - HuC6280: fixed stack push/pull direction

Neutopia looks okay until the main title screen, then there's some
gibberish on the bottom. The game also locks up with some gibberish once
you actually start a new game. So, still not playable just yet =(
This commit is contained in:
Tim Allen 2017-01-19 19:38:57 +11:00
parent f500426158
commit b03563426f
15 changed files with 287 additions and 97 deletions

View File

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

View File

@ -54,6 +54,12 @@ auto Cartridge::write(uint20 addr, uint8 data) -> void {
}
auto Cartridge::mirror(uint addr, uint size) -> uint {
//384KB games have unusual mirroring (only second ROM repeats)
if(size == 0x60000) {
if(addr <= 0x3ffff) return addr;
return 0x40000 + (addr & 0x1ffff);
}
uint base = 0;
uint mask = 1 << 20;
while(addr >= size) {

View File

@ -7,17 +7,23 @@ auto Gamepad::readData() -> uint4 {
uint4 data;
if(sel) {
data.bit(0) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Up);
data.bit(1) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Down);
data.bit(2) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Right);
data.bit(3) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Left);
if(data.bits(0,1) == 0) data.bits(0,1) = 3; //disallow up+down at the same time
if(data.bits(2,3) == 0) data.bits(2,3) = 3; //disallow left+right at the same time
bool up = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Up);
bool right = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Right);
bool down = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Down);
bool left = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Left);
data.bit(0) = !(up & !down);
data.bit(1) = !(right & !left);
data.bit(2) = !(down & !up);
data.bit(3) = !(left & !right);
} else {
data.bit(0) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, One);
data.bit(1) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Two);
data.bit(2) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Select);
data.bit(3) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Run);
bool one = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, One);
bool two = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Two);
bool select = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Select);
bool run = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Run);
data.bit(0) = !one;
data.bit(1) = !two;
data.bit(2) = !select;
data.bit(3) = !run;
}
return data;

View File

@ -12,14 +12,7 @@ auto CPU::Enter() -> void {
}
auto CPU::main() -> void {
#if 1
static uint counter = 0;
if(counter++ < 40) {
print(disassemble(r.pc), "\n");
}
#endif
if(irq.pending()) interrupt(irq.vector());
if(irq.pending()) return interrupt(irq.vector());
instruction();
}

View File

@ -45,13 +45,13 @@ auto Interface::title() -> string {
}
auto Interface::videoSize() -> VideoSize {
return {512, 484};
return {256, 240};
}
auto Interface::videoSize(uint width, uint height, bool arc) -> VideoSize {
auto a = arc ? 8.0 / 7.0 : 1.0;
uint w = 256;
uint h = 242;
uint h = 240;
uint m = min(width / (w * a), height / h);
return {uint(w * a * m), uint(h * m)};
}
@ -66,8 +66,8 @@ auto Interface::videoColors() -> uint32 {
auto Interface::videoColor(uint32 color) -> uint64 {
uint3 B = color.bits(0,2);
uint3 G = color.bits(3,5);
uint3 R = color.bits(6,8);
uint3 R = color.bits(3,5);
uint3 G = color.bits(6,8);
uint64 r = image::normalize(R, 3, 16);
uint64 g = image::normalize(G, 3, 16);

View File

@ -0,0 +1,29 @@
auto VDC::Background::scanline(uint y) -> void {
}
auto VDC::Background::run(uint x, uint y) -> void {
color = nothing;
//if(blank) return;
uint10 hoffset = x + hscroll;
uint9 voffset = y + vscroll;
uint16 batAddress = (voffset >> 3) * width + (hoffset >> 3);
uint16 tiledata = vdc.vramRead(batAddress);
uint16 patternAddress = tiledata.bits(0,11) << 4;
patternAddress += (voffset & 7);
uint4 palette = tiledata.bits(12,15);
uint16 d0 = vdc.vramRead(patternAddress + 0);
uint16 d1 = vdc.vramRead(patternAddress + 8);
uint3 index = 7 - (hoffset & 7);
uint4 output;
output.bit(0) = d0.bit(0 + index);
output.bit(1) = d0.bit(8 + index);
output.bit(2) = d1.bit(0 + index);
output.bit(3) = d1.bit(8 + index);
if(output == 0) return;
color = vdc.cram[palette << 4 | output];
}

View File

@ -12,10 +12,11 @@ auto VDC::DMA::step(uint clocks) -> void {
}
if(satbActive) {
uint16 data = vdc.vramRead(satbSource + satbTarget);
vdc.vramWrite(satbTarget++, data);
if(satbTarget == 256) {
uint16 data = vdc.vramRead(satbSource + satbOffset);
vdc.satb[satbOffset] = data;
if(++satbOffset == 256) {
satbActive = false;
satbOffset = 0;
satbPending = satbRepeat;
vdc.irq.raise(VDC::IRQ::Line::TransferSATB);
}
@ -30,7 +31,7 @@ auto VDC::DMA::vramStart() -> void {
auto VDC::DMA::satbStart() -> void {
if(!satbPending) return;
satbActive = true;
satbTarget = 0;
satbOffset = 0;
}
auto VDC::DMA::satbQueue() -> void {

View File

@ -99,8 +99,8 @@ auto VDC::write(uint11 addr, uint8 data) -> void {
irq.enableLineCoincidence = data.bit(2);
irq.enableVblank = data.bit(3);
io.externalSync = data.bits(4,5);
io.spriteBlank = data.bit(6);
io.backgroundBlank = data.bit(7);
sprite.blank = data.bit(6);
background.blank = data.bit(7);
} else {
io.displayOutput = data.bits(0,1);
io.dramRefresh = data.bit(2);
@ -120,13 +120,13 @@ auto VDC::write(uint11 addr, uint8 data) -> void {
if(io.address == 0x07) {
//BXR
io.backgroundHscroll.byte(a0) = data;
background.hscroll.byte(a0) = data;
return;
}
if(io.address == 0x08) {
//BYR
io.backgroundVscroll.byte(a0) = data;
background.vscroll.byte(a0) = data;
return;
}
@ -135,12 +135,12 @@ auto VDC::write(uint11 addr, uint8 data) -> void {
if(a0) return;
io.vramAccess = data.bits(0,1);
io.spriteAccess = data.bits(2,3);
if(data.bits(4,5) == 0) io.backgroundWidth = 32;
if(data.bits(4,5) == 1) io.backgroundWidth = 64;
if(data.bits(4,5) == 2) io.backgroundWidth = 128;
if(data.bits(4,5) == 3) io.backgroundWidth = 128;
if(data.bit(6) == 0) io.backgroundHeight = 32;
if(data.bit(6) == 1) io.backgroundHeight = 64;
if(data.bits(4,5) == 0) background.width = 32;
if(data.bits(4,5) == 1) background.width = 64;
if(data.bits(4,5) == 2) background.width = 128;
if(data.bits(4,5) == 3) background.width = 128;
if(data.bit(6) == 0) background.height = 32;
if(data.bit(6) == 1) background.height = 64;
io.cgMode = data.bit(7);
return;
}

88
higan/pce/vdc/sprite.cpp Normal file
View File

@ -0,0 +1,88 @@
auto VDC::Sprite::scanline(uint y) -> void {
y += 64;
objects.reset();
static const uint width[] = {15, 31};
static const uint height[] = {15, 31, 63, 63};
uint count = 0;
for(uint index : range(64)) {
uint16 d0 = vdc.satb[index << 2 | 0];
uint16 d1 = vdc.satb[index << 2 | 1];
uint16 d2 = vdc.satb[index << 2 | 2];
uint16 d3 = vdc.satb[index << 2 | 3];
Object object;
object.y = d0.bits(0,9);
object.height = height[d3.bits(12,13)];
if(y < object.y) continue;
if(y > object.y + object.height) continue;
object.x = d1.bits(0,9);
object.mode = d2.bit(0);
object.pattern = d2.bits(1,10);
object.palette = d3.bits(0,3);
object.priority = d3.bit(7);
object.width = width[d3.bit(8)];
object.hflip = d3.bit(11);
object.vflip = d3.bit(15);
objects.append(object);
count += 1 + d3.bit(8); //32-width sprites consume two slots
if(count >= 16) {
vdc.irq.raise(VDC::IRQ::Line::Overflow);
break;
}
}
}
auto VDC::Sprite::run(uint x, uint y) -> void {
x += 32;
y += 64;
color = nothing;
bool zero = 0;
uint index = 0;
for(auto& object : objects) {
uint id = index++;
if(x < object.x) continue;
if(x > object.x + object.width) continue;
uint10 hoffset = x - object.x;
uint10 voffset = y - object.y;
if(object.hflip) hoffset ^= object.width;
if(object.vflip) voffset ^= object.height;
uint10 pattern = object.pattern;
if(object.width == 31) pattern.bit(0) = 0;
if(object.height == 31) pattern.bit(1) = 0;
if(object.height == 63) pattern.bits(1,2) = 0;
uint16 patternAddress = pattern << 6;
patternAddress += (voffset >> 4) << (6 + (object.height == 31));
patternAddress += (hoffset >> 4) << 6;
patternAddress += (voffset & 15);
uint16 d0 = vdc.vramRead(patternAddress + 0);
uint16 d1 = vdc.vramRead(patternAddress + 16);
uint16 d2 = vdc.vramRead(patternAddress + 32);
uint16 d3 = vdc.vramRead(patternAddress + 48);
uint4 index = 15 - (hoffset & 15);
uint4 output;
output.bit(0) = d0.bit(index);
output.bit(1) = d1.bit(index);
output.bit(2) = d2.bit(index);
output.bit(3) = d3.bit(index);
if(output == 0) continue;
if(color) {
if(zero) vdc.irq.raise(VDC::IRQ::Line::Collision);
break;
}
color = vdc.cram[1 << 8 | object.palette << 4 | output];
priority = object.priority;
if(id == 0) zero = 1;
}
}

View File

@ -6,6 +6,8 @@ VDC vdc;
#include "io.cpp"
#include "irq.cpp"
#include "dma.cpp"
#include "background.cpp"
#include "sprite.cpp"
auto VDC::Enter() -> void {
while(true) scheduler.synchronize(), vdc.main();
@ -13,7 +15,25 @@ auto VDC::Enter() -> void {
auto VDC::main() -> void {
//1365 cycles/scanline
uint y = state.y;
auto output = buffer + y * 512;
background.scanline(y);
sprite.scanline(y);
for(uint x : range(256)) {
if(y < 240) {
background.run(x, y);
sprite.run(x, y);
if(sprite.color && sprite.priority) {
*output++ = sprite.color();
} else if(background.color) {
*output++ = background.color();
} else if(sprite.color) {
*output++ = sprite.color();
} else {
*output++ = cram[0];
}
}
step(4);
}
step(341);
@ -41,7 +61,7 @@ auto VDC::step(uint clocks) -> void {
}
auto VDC::refresh() -> void {
Emulator::video.refresh(buffer, 512 * sizeof(uint32), 512, 484);
Emulator::video.refresh(buffer, 512 * sizeof(uint32), 256, 240);
}
auto VDC::power() -> void {
@ -55,6 +75,8 @@ auto VDC::power() -> void {
memory::fill(&irq, sizeof(IRQ));
memory::fill(&dma, sizeof(DMA));
memory::fill(&io, sizeof(IO));
memory::fill(&background, sizeof(Background));
memory::fill(&sprite, sizeof(Sprite));
}
}

View File

@ -77,9 +77,48 @@ private:
bool vramActive;
bool satbActive;
bool satbPending;
uint16 satbTarget;
uint16 satbOffset;
} dma;
struct Background {
//background.cpp
auto scanline(uint y) -> void;
auto run(uint x, uint y) -> void;
bool blank;
uint10 hscroll;
uint9 vscroll;
uint8 width;
uint8 height;
maybe<uint9> color;
} background;
struct Sprite {
//sprite.cpp
auto scanline(uint y) -> void;
auto run(uint x, uint y) -> void;
bool blank;
struct Object {
uint10 y;
uint10 x;
bool mode;
uint10 pattern;
uint4 palette;
bool priority;
uint width;
bool hflip;
uint height;
bool vflip;
};
array<Object, 64> objects;
maybe<uint9> color;
bool priority;
} sprite;
struct IO {
uint5 address;
@ -98,8 +137,6 @@ private:
//$05 CR (W)
uint2 externalSync;
bool spriteBlank;
bool backgroundBlank;
uint2 displayOutput;
bool dramRefresh;
uint vramAddressIncrement;
@ -107,17 +144,9 @@ private:
//$06 RCR
uint10 lineCoincidence;
//$07 BXR
uint10 backgroundHscroll;
//$08 BYR
uint9 backgroundVscroll;
//$09 MWR
uint2 vramAccess;
uint2 spriteAccess;
uint backgroundWidth;
uint backgroundHeight;
bool cgMode;
//$0a HSR

View File

@ -75,7 +75,7 @@ auto HuC6280::disassemble(uint16 pc_) -> string {
op(0x00, "brk")
op(0x01, "ora", indirectX())
op(0x02, "sxy")
op(0x03, "st0")
op(0x03, "st0", immediate())
op(0x04, "tsb", zeropage())
op(0x05, "ora", zeropage())
op(0x06, "asl", zeropage())
@ -91,7 +91,7 @@ U op(0x0b, "nop", "$0b")
op(0x10, "bpl", relative())
op(0x11, "ora", indirectY())
op(0x12, "ora", indirect())
op(0x13, "st1")
op(0x13, "st1", immediate())
op(0x14, "trb", zeropage())
op(0x15, "ora", zeropageX())
op(0x16, "asl", zeropageX())
@ -107,7 +107,7 @@ U op(0x1b, "nop", "$1b")
op(0x20, "jsr", absolute())
op(0x21, "and", indirectX())
op(0x22, "sax")
op(0x23, "st2")
op(0x23, "st2", immediate())
op(0x24, "bit", zeropage())
op(0x25, "and", zeropage())
op(0x26, "rol", zeropage())

View File

@ -7,10 +7,10 @@ auto HuC6280::interrupt(uint16 vector) -> void {
push(PC >> 8);
push(PC >> 0);
push(P);
PC.byte(0) = load(vector + 0);
PC.byte(1) = load(vector + 1);
D = 0;
I = 1;
PC.byte(0) = load(vector + 0);
L PC.byte(1) = load(vector + 1);
}
auto HuC6280::instruction() -> void {

View File

@ -23,34 +23,34 @@ auto HuC6280::ASL(uint8 i) -> uint8 {
}
auto HuC6280::BIT(uint8 i) -> uint8 {
Z = i == 0;
Z = (A & i) == 0;
V = i.bit(6);
N = i.bit(7);
return i;
return A;
}
auto HuC6280::CMP(uint8 i) -> uint8 {
uint9 o = A - i;
C = o.bit(8);
C = !o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return i;
return A;
}
auto HuC6280::CPX(uint8 i) -> uint8 {
uint9 o = X - i;
C = o.bit(8);
C = !o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return i;
return X;
}
auto HuC6280::CPY(uint8 i) -> uint8 {
uint9 o = Y - i;
C = o.bit(8);
C = !o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return i;
return Y;
}
auto HuC6280::DEC(uint8 i) -> uint8 {
@ -114,23 +114,26 @@ auto HuC6280::ROR(uint8 i) -> uint8 {
}
auto HuC6280::SBC(uint8 i) -> uint8 {
return ADC(~i);
uint9 o = A - i - !C;
C = !o.bit(8);
Z = uint8(o) == 0;
V = (A ^ i) & (A ^ o) & 0x80;
N = o.bit(7);
return o;
}
auto HuC6280::TRB(uint8 i) -> uint8 {
uint8 o = i & A;
Z = o == 0;
V = o.bit(6);
N = o.bit(7);
return i & ~A;
Z = (A & i) == 0;
V = i.bit(6);
N = i.bit(7);
return ~A & i;
}
auto HuC6280::TSB(uint8 i) -> uint8 {
uint8 o = i & A;
Z = o == 0;
V = o.bit(6);
N = o.bit(7);
return i | A;
Z = (A & i) == 0;
V = i.bit(6);
N = i.bit(7);
return A | i;
}
//
@ -187,15 +190,29 @@ L store(absolute + index, data);
auto HuC6280::instruction_blockmove(bp alu) -> void {
uint16 source = operand();
source |= operand() << 8;
io();
io();
io();
uint16 target = operand();
target |= operand() << 8;
io();
io();
io();
uint16 length = operand();
length |= operand() << 8;
io();
io();
io();
do {
auto data = load(source);
store(target, data);
ALU(source, target);
io();
io();
io();
io();
} while(--length);
io();
L io();
}
@ -211,23 +228,22 @@ auto HuC6280::instruction_branch(bool take) -> void {
}
auto HuC6280::instruction_clear(uint8& data) -> void {
data = 0;
L io();
data = 0;
}
auto HuC6280::instruction_clear(bool& flag) -> void {
flag = 0;
L io();
flag = 0;
}
auto HuC6280::instruction_immediate(fp alu, uint8& data) -> void {
data = ALU(operand());
L io();
L data = ALU(operand());
}
auto HuC6280::instruction_implied(fp alu, uint8& data) -> void {
data = ALU(data);
L io();
data = ALU(data);
}
auto HuC6280::instruction_indirectLoad(fp alu, uint8& data, uint8 index) -> void {
@ -242,7 +258,7 @@ L data = ALU(load(absolute));
auto HuC6280::instruction_indirectStore(uint8 data, uint8 index) -> void {
auto zeropage = operand();
io();
auto absolute = load(0x2000 + zeropage + index);
uint16 absolute = load(0x2000 + zeropage + index);
absolute |= load(0x2001 + zeropage + index) << 8;
L store(absolute, data);
}
@ -259,7 +275,7 @@ L data = ALU(load(absolute + Y));
auto HuC6280::instruction_indirectYStore(uint8 data) -> void {
auto zeropage = operand();
io();
auto absolute = load(0x2000 + zeropage);
uint16 absolute = load(0x2000 + zeropage);
absolute |= load(0x2001 + zeropage) << 8;
L store(absolute + Y, data);
}
@ -289,19 +305,19 @@ L push(data);
}
auto HuC6280::instruction_set(bool& flag) -> void {
flag = 1;
L io();
flag = 1;
}
auto HuC6280::instruction_swap(uint8& lhs, uint8& rhs) -> void {
swap(lhs, rhs);
io();
L io();
swap(lhs, rhs);
}
auto HuC6280::instruction_transfer(uint8& source, uint8& target) -> void {
target = source;
L io();
target = source;
Z = target == 0;
N = target.bit(7);
}
@ -333,8 +349,8 @@ auto HuC6280::instruction_BBR(uint3 index) -> void {
auto displacement = operand();
io();
io();
L io();
if(zeropage.bit(index) == 0) {
L auto data = load(0x2000 + zeropage);
if(data.bit(index) == 0) {
PC += (int8)displacement;
}
}
@ -344,8 +360,8 @@ auto HuC6280::instruction_BBS(uint3 index) -> void {
auto displacement = operand();
io();
io();
L io();
if(zeropage.bit(index) == 1) {
L auto data = load(0x2000 + zeropage);
if(data.bit(index) == 1) {
PC += (int8)displacement;
}
}
@ -357,8 +373,8 @@ auto HuC6280::instruction_BRK() -> void {
push(PC >> 0);
uint8 p = P;
push(p | 0x10); //B flag set on push
I = 1;
D = 0;
I = 1;
PC.byte(0) = load(0xfff6);
L PC.byte(1) = load(0xfff7);
}
@ -375,13 +391,13 @@ L push((PC - 1) >> 0);
}
auto HuC6280::instruction_CSL() -> void {
r.cs = 4;
L io();
r.cs = 4;
}
auto HuC6280::instruction_CSH() -> void {
r.cs = 1;
L io();
r.cs = 1;
}
auto HuC6280::instruction_JMP_absolute() -> void {
@ -486,8 +502,8 @@ auto HuC6280::instruction_TST_absolute(uint8 index) -> void {
io();
io();
io();
L uint8 data = load(absolute + index) & mask;
Z = data == 0;
L uint8 data = load(absolute + index);
Z = (data & mask) == 0;
V = data.bit(6);
N = data.bit(7);
}
@ -498,13 +514,13 @@ auto HuC6280::instruction_TST_zeropage(uint8 index) -> void {
io();
io();
io();
L uint8 data = load(0x2000 + zeropage + index) & mask;
Z = data == 0;
L uint8 data = load(0x2000 + zeropage + index);
Z = (data & mask) == 0;
V = data.bit(6);
N = data.bit(7);
}
auto HuC6280::instruction_TXS() -> void {
S = X;
L io();
S = X;
}

View File

@ -31,9 +31,9 @@ auto HuC6280::operand() -> uint8 {
//
auto HuC6280::push(uint8 data) -> void {
store(0x2100 + ++S, data);
store(0x2100 + (S--), data);
}
auto HuC6280::pull() -> uint8 {
return load(0x2100 + S--);
return load(0x2100 + (++S));
}