Update to v102 release.

byuu says (in the public announcement):

This release adds very preliminary emulation of the Sega Master System
(Mark III), Sega Game Gear, Sega Mega Drive (Genesis), and NEC PC Engine
(Turbografx-16). These cores do not yet offer sound emulation, save
states or cheat codes.

I'm always very hesitant to release a new emulation core in its alpha
stages, as in the past this has resulted in lasting bad impressions
of cores that have since improved greatly. For instance, the Game Boy
Advance emulation offered today is easily the second most accurate around,
yet it is still widely judged by its much older alpha implementation.

However, it's always been tradition with higan to not hold onto code
in secret. Rather than delay future releases for another year or two,
I'll put my faith in you all to understand that the emulation of these
systems will improve over time.

I hope that by releasing things as they are now, I might be able to
receive some much needed assistance in improving these cores, as the
documentation for these new systems is very much less than ideal.

byuu says (in the WIP forum):

Changelog:

  - PCE: latch background scroll registers (fixes Neutopia scrolling)
  - PCE: clip background attribute table scrolling (fixes Blazing Lazers
    scrolling)
  - PCE: support background/sprite enable/disable bits
  - PCE: fix large sprite indexing (fixes Blazing Lazers title screen
    sprites)
  - HuC6280: wrap zeropage accesses to never go beyond $20xx
  - HuC6280: fix alternating addresses for block move instructions
    (fixes Neutopia II)
  - HuC6280: block move instructions save and restore A,X,Y registers
  - HuC6280: emulate BCD mode (may not be 100% correct, based on SNES
    BCD) (fixes Blazing Lazers scoring)
This commit is contained in:
Tim Allen 2017-01-20 08:01:15 +11:00
parent b03563426f
commit ae5968cfeb
10 changed files with 152 additions and 96 deletions

View File

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

View File

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

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);
sprite.blank = data.bit(6);
background.blank = data.bit(7);
sprite.enable = data.bit(6);
background.enable = data.bit(7);
} else {
io.displayOutput = data.bits(0,1);
io.dramRefresh = data.bit(2);
@ -127,6 +127,7 @@ auto VDC::write(uint11 addr, uint8 data) -> void {
if(io.address == 0x08) {
//BYR
background.vscroll.byte(a0) = data;
background.voffset = background.vscroll;
return;
}

View File

@ -39,7 +39,9 @@ auto VDC::Sprite::scanline(uint y) -> void {
auto VDC::Sprite::run(uint x, uint y) -> void {
x += 32;
y += 64;
color = nothing;
if(!enable) return;
bool zero = 0;
uint index = 0;
@ -58,10 +60,11 @@ auto VDC::Sprite::run(uint x, uint y) -> void {
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 patternAddress = pattern;
patternAddress += (voffset >> 4) << 1;
patternAddress += (hoffset >> 4);
patternAddress <<= 6;
patternAddress += (voffset & 15);
uint16 d0 = vdc.vramRead(patternAddress + 0);
uint16 d1 = vdc.vramRead(patternAddress + 16);

View File

@ -15,6 +15,7 @@ auto VDC::Enter() -> void {
auto VDC::main() -> void {
//1365 cycles/scanline
state.x = 0;
uint y = state.y;
auto output = buffer + y * 512;
background.scanline(y);
@ -37,11 +38,7 @@ auto VDC::main() -> void {
step(4);
}
step(341);
scanline();
}
auto VDC::scanline() -> void {
state.x = 0;
if(++state.y == 262) {
state.y = 0;
}

View File

@ -4,7 +4,6 @@
struct VDC : Thread {
static auto Enter() -> void;
auto main() -> void;
auto scanline() -> void;
auto step(uint clocks) -> void;
auto refresh() -> void;
@ -85,12 +84,15 @@ private:
auto scanline(uint y) -> void;
auto run(uint x, uint y) -> void;
bool blank;
bool enable;
uint10 hscroll;
uint9 vscroll;
uint8 width;
uint8 height;
uint10 hoffset;
uint9 voffset;
maybe<uint9> color;
} background;
@ -99,7 +101,7 @@ private:
auto scanline(uint y) -> void;
auto run(uint x, uint y) -> void;
bool blank;
bool enable;
struct Object {
uint10 y;

View File

@ -14,8 +14,11 @@ struct HuC6280 {
//memory.cpp
inline auto mmu(uint16) const -> uint21;
inline auto load(uint16) -> uint8;
inline auto store(uint16, uint8) -> void;
inline auto load8(uint8) -> uint8;
inline auto load16(uint16) -> uint8;
inline auto store8(uint8, uint8) -> void;
inline auto store16(uint16, uint8) -> void;
inline auto store21(uint21, uint8) -> void;
auto io() -> uint8;
auto opcode() -> uint8;
@ -49,12 +52,12 @@ struct HuC6280 {
auto TRB(uint8) -> uint8;
auto TSB(uint8) -> uint8;
using bp = auto (HuC6280::*)(uint16&, uint16&) -> void;
auto TAI(uint16&, uint16&) -> void;
auto TDD(uint16&, uint16&) -> void;
auto TIA(uint16&, uint16&) -> void;
auto TII(uint16&, uint16&) -> void;
auto TIN(uint16&, uint16&) -> void;
using bp = auto (HuC6280::*)(uint16&, uint16&, bool) -> void;
auto TAI(uint16&, uint16&, bool) -> void;
auto TDD(uint16&, uint16&, bool) -> void;
auto TIA(uint16&, uint16&, bool) -> void;
auto TII(uint16&, uint16&, bool) -> void;
auto TIN(uint16&, uint16&, bool) -> void;
auto instruction_absoluteLoad(fp, uint8&, uint8 = 0) -> void;
auto instruction_absoluteModify(fp, uint8 = 0) -> void;

View File

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

View File

@ -1,8 +1,18 @@
auto HuC6280::ADC(uint8 i) -> uint8 {
uint9 o = A + i + C;
int16 o;
if(!D) {
o = A + i + C;
V = ~(A ^ i) & (A ^ o) & 0x80;
} else {
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o > 0x09) o += 0x06;
C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
V = ~(A ^ i) & (A ^ o) & 0x80;
if(o > 0x9f) o += 0x60;
}
C = o.bit(8);
Z = uint8(o) == 0;
V = ~(A ^ i) & (A ^ o) & 0x80;
N = o.bit(7);
return o;
}
@ -114,10 +124,21 @@ auto HuC6280::ROR(uint8 i) -> uint8 {
}
auto HuC6280::SBC(uint8 i) -> uint8 {
uint9 o = A - i - !C;
C = !o.bit(8);
i ^= 0xff;
int16 o;
if(!D) {
o = A + i + C;
V = ~(A ^ i) & (A ^ o) & 0x80;
} else {
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o <= 0x0f) o -= 0x06;
C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
V = ~(A ^ i) & (A ^ o) & 0x80;
if(o <= 0xff) o -= 0x60;
}
C = o.bit(8);
Z = uint8(o) == 0;
V = (A ^ i) & (A ^ o) & 0x80;
N = o.bit(7);
return o;
}
@ -138,27 +159,27 @@ auto HuC6280::TSB(uint8 i) -> uint8 {
//
auto HuC6280::TAI(uint16& source, uint16& target) -> void {
source ^= 1;
auto HuC6280::TAI(uint16& source, uint16& target, bool alternate) -> void {
!alternate ? source++ : source--;
target++;
}
auto HuC6280::TDD(uint16& source, uint16& target) -> void {
auto HuC6280::TDD(uint16& source, uint16& target, bool) -> void {
source--;
target--;
}
auto HuC6280::TIA(uint16& source, uint16& target) -> void {
auto HuC6280::TIA(uint16& source, uint16& target, bool alternate) -> void {
source++;
target ^= 1;
!alternate ? target++ : target--;
}
auto HuC6280::TII(uint16& source, uint16& target) -> void {
auto HuC6280::TII(uint16& source, uint16& target, bool) -> void {
source++;
target++;
}
auto HuC6280::TIN(uint16& source, uint16& target) -> void {
auto HuC6280::TIN(uint16& source, uint16& target, bool) -> void {
source++;
}
@ -168,7 +189,7 @@ auto HuC6280::instruction_absoluteLoad(fp alu, uint8& data, uint8 index) -> void
uint16 absolute = operand();
absolute |= operand() << 8;
io();
L data = ALU(load(absolute + index));
L data = ALU(load16(absolute + index));
}
auto HuC6280::instruction_absoluteModify(fp alu, uint8 index) -> void {
@ -176,44 +197,46 @@ auto HuC6280::instruction_absoluteModify(fp alu, uint8 index) -> void {
absolute |= operand() << 8;
io();
io();
auto data = ALU(load(absolute + index));
L store(absolute + index, data);
auto data = ALU(load16(absolute + index));
L store16(absolute + index, data);
}
auto HuC6280::instruction_absoluteStore(uint8 data, uint8 index) -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
io();
L store(absolute + index, data);
L store16(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;
push(Y);
push(A);
push(X);
io();
io();
io();
io();
io();
bool alternate = 0;
do {
auto data = load(source);
store(target, data);
ALU(source, target);
auto data = load16(source);
store16(target, data);
ALU(source, target, alternate);
alternate ^= 1;
io();
io();
io();
io();
} while(--length);
io();
L io();
X = pull();
A = pull();
L Y = pull();
}
auto HuC6280::instruction_branch(bool take) -> void {
@ -249,41 +272,41 @@ L io();
auto HuC6280::instruction_indirectLoad(fp alu, uint8& data, uint8 index) -> void {
auto zeropage = operand();
io();
uint16 absolute = load(0x2000 + zeropage + index);
absolute |= load(0x2001 + zeropage + index) << 8;
uint16 absolute = load8(zeropage + index + 0);
absolute |= load8(zeropage + index + 1) << 8;
io();
L data = ALU(load(absolute));
L data = ALU(load16(absolute));
}
auto HuC6280::instruction_indirectStore(uint8 data, uint8 index) -> void {
auto zeropage = operand();
io();
uint16 absolute = load(0x2000 + zeropage + index);
absolute |= load(0x2001 + zeropage + index) << 8;
L store(absolute, data);
uint16 absolute = load8(zeropage + index + 0);
absolute |= load8(zeropage + index + 1) << 8;
L store16(absolute, data);
}
auto HuC6280::instruction_indirectYLoad(fp alu, uint8& data) -> void {
auto zeropage = operand();
io();
uint16 absolute = load(0x2000 + zeropage);
absolute |= load(0x2001 + zeropage) << 8;
uint16 absolute = load8(zeropage + 0);
absolute |= load8(zeropage + 1) << 8;
io();
L data = ALU(load(absolute + Y));
L data = ALU(load16(absolute + Y));
}
auto HuC6280::instruction_indirectYStore(uint8 data) -> void {
auto zeropage = operand();
io();
uint16 absolute = load(0x2000 + zeropage);
absolute |= load(0x2001 + zeropage) << 8;
L store(absolute + Y, data);
uint16 absolute = load8(zeropage + 0);
absolute |= load8(zeropage + 1) << 8;
L store16(absolute + Y, data);
}
auto HuC6280::instruction_memory(fp alu) -> void {
auto a = A;
A = ALU(load(0x2000 + X));
L store(0x2000 + X, A);
A = ALU(load8(X));
L store8(X, A);
A = a;
}
@ -325,21 +348,21 @@ L io();
auto HuC6280::instruction_zeropageLoad(fp alu, uint8& data, uint8 index) -> void {
auto zeropage = operand();
io();
L data = ALU(load(0x2000 + zeropage + index));
L data = ALU(load8(zeropage + index));
}
auto HuC6280::instruction_zeropageModify(fp alu, uint8 index) -> void {
auto zeropage = operand();
io();
io();
auto data = ALU(load(0x2000 + zeropage + index));
L store(0x2000 + zeropage + index, data);
auto data = ALU(load8(zeropage + index));
L store8(zeropage + index, data);
}
auto HuC6280::instruction_zeropageStore(uint8 data, uint8 index) -> void {
auto zeropage = operand();
io();
L store(0x2000 + zeropage + index, data);
L store8(zeropage + index, data);
}
//
@ -349,7 +372,7 @@ auto HuC6280::instruction_BBR(uint3 index) -> void {
auto displacement = operand();
io();
io();
L auto data = load(0x2000 + zeropage);
L auto data = load8(zeropage);
if(data.bit(index) == 0) {
PC += (int8)displacement;
}
@ -360,7 +383,7 @@ auto HuC6280::instruction_BBS(uint3 index) -> void {
auto displacement = operand();
io();
io();
L auto data = load(0x2000 + zeropage);
L auto data = load8(zeropage);
if(data.bit(index) == 1) {
PC += (int8)displacement;
}
@ -375,8 +398,8 @@ auto HuC6280::instruction_BRK() -> void {
push(p | 0x10); //B flag set on push
D = 0;
I = 1;
PC.byte(0) = load(0xfff6);
L PC.byte(1) = load(0xfff7);
PC.byte(0) = load16(0xfff6);
L PC.byte(1) = load16(0xfff7);
}
auto HuC6280::instruction_BSR() -> void {
@ -412,8 +435,8 @@ auto HuC6280::instruction_JMP_indirect(uint8 index) -> void {
address |= operand() << 8;
io();
io();
PC.byte(0) = load(address + index + 0);
L PC.byte(1) = load(address + index + 1);
PC.byte(0) = load16(address + index + 0);
L PC.byte(1) = load16(address + index + 1);
}
auto HuC6280::instruction_JSR() -> void {
@ -435,9 +458,9 @@ auto HuC6280::instruction_RMB(uint3 index) -> void {
io();
io();
io();
auto data = load(0x2000 + zeropage);
auto data = load8(zeropage);
data.bit(index) = 0;
L store(0x2000 + zeropage, data);
L store8(zeropage, data);
}
auto HuC6280::instruction_RTI() -> void {
@ -464,16 +487,15 @@ auto HuC6280::instruction_SMB(uint3 index) -> void {
io();
io();
io();
auto data = load(0x2000 + zeropage);
auto data = load8(zeropage);
data.bit(index) = 1;
L store(0x2000 + zeropage, data);
L store8(zeropage, data);
}
auto HuC6280::instruction_ST(uint2 index) -> void {
auto data = operand();
io();
L io();
write(0x1fe000 + index, data);
L store21(0x1fe000 + index, data);
}
auto HuC6280::instruction_TAM() -> void {
@ -502,7 +524,7 @@ auto HuC6280::instruction_TST_absolute(uint8 index) -> void {
io();
io();
io();
L uint8 data = load(absolute + index);
L uint8 data = load16(absolute + index);
Z = (data & mask) == 0;
V = data.bit(6);
N = data.bit(7);
@ -514,7 +536,7 @@ auto HuC6280::instruction_TST_zeropage(uint8 index) -> void {
io();
io();
io();
L uint8 data = load(0x2000 + zeropage + index);
L uint8 data = load8(zeropage + index);
Z = (data & mask) == 0;
V = data.bit(6);
N = data.bit(7);

View File

@ -4,36 +4,58 @@ auto HuC6280::mmu(uint16 addr) const -> uint21 {
//
auto HuC6280::load(uint16 addr) -> uint8 {
auto HuC6280::load8(uint8 addr) -> uint8 {
step(r.cs);
return read(mmu(0x2000 + addr));
}
auto HuC6280::load16(uint16 addr) -> uint8 {
step(r.cs);
return read(mmu(addr));
}
auto HuC6280::store(uint16 addr, uint8 data) -> void {
auto HuC6280::store8(uint8 addr, uint8 data) -> void {
step(r.cs);
return write(mmu(0x2000 + addr), data);
}
auto HuC6280::store16(uint16 addr, uint8 data) -> void {
step(r.cs);
return write(mmu(addr), data);
}
auto HuC6280::store21(uint21 addr, uint8 data) -> void {
step(r.cs);
return write(addr, data);
}
//
auto HuC6280::io() -> uint8 {
return load(r.pc);
step(r.cs);
return read(mmu(PC));
}
auto HuC6280::opcode() -> uint8 {
return load(r.pc++);
step(r.cs);
return read(mmu(PC++));
}
auto HuC6280::operand() -> uint8 {
return load(r.pc++);
step(r.cs);
return read(mmu(PC++));
}
//
auto HuC6280::push(uint8 data) -> void {
store(0x2100 + (S--), data);
step(r.cs);
write(mmu(0x2100 + S), data);
S--;
}
auto HuC6280::pull() -> uint8 {
return load(0x2100 + (++S));
step(r.cs);
S++;
return read(mmu(0x2100 + S));
}