Update to v101r11 release.

byuu says:

Changelog:

  - 68K: fixed NEG/NEGX operand order
  - 68K: fixed bug in disassembler that was breaking trace logging
  - VDP: improved sprite rendering (still 100% broken)
  - VDP: added horizontal/vertical scrolling (90% broken)

Forgot:

  - 68K: fix extension word sign bit on indexed modes for disassembler
    as well
  - 68K: emulate STOP properly (use r.stop flag; clear on IRQs firing)

I'm really wearing out fast here. The Genesis documentation is somehow
even worse than Game Boy documentation, but this is a far more complex
system.

It's a massive time sink to sit here banging away at every possible
combination of how things could work, only to see no positive
improvements. Nothing I do seems to get sprites to do a goddamn thing.

squee says the sprite Y field is 10-bits, X field is 9-bits. genvdp says
they're both 10-bits. BlastEm treats them like they're both 10-bits,
then masks off the upper bit so it's effectively 9-bits anyway.

Nothing ever bothers to tell you whether the horizontal scroll values
are supposed to add or subtract from the current X position. Probably
the most basic detail you could imagine for explaining horizontal
scrolling and yet ... nope. Nothing.

I can't even begin to understand how the VDP FIFO functionality works,
or what the fuck is meant by "slots".

I'm completely at a loss as how how in the holy hell the 68K works with
8-bit accesses. I don't know whether I need byte/word handlers for every
device, or if I can just hook it right into the 68K core itself. This
one's probably the most major design detail. I need to know this before
I go and implement the PSG/YM2612/IO ports-\>gamepads/Z80/etc.

Trying to debug the 68K is murder because basically every game likes to
start with a 20,000,000-instruction reset phase of checksumming entire
games, and clearing out the memory as agonizingly slowly as humanly
possible. And like the ARM, there's too many registers so I'd need three
widescreen monitors to comfortably view the entire debugger output lines
onscreen.

I can't get any test ROMs to debug functionality outside of full games
because every **goddamned** test ROM coder thinks it's acceptable to tell
people to go fetch some toolchain from a link that died in the late '90s
and only works on MS-DOS 6.22 to build their fucking shit, because god
forbid you include a 32KiB assembled ROM image in your fucking archives.

... I may have to take a break for a while. We'll see.
This commit is contained in:
Tim Allen 2016-08-21 12:50:05 +10:00
parent 0b70a01b47
commit f7ddbfc462
10 changed files with 70 additions and 56 deletions

View File

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

View File

@ -95,8 +95,8 @@ auto CPU::readWord(uint24 addr) -> uint16 {
if(addr < 0xa00000) return 0x0000;
if(addr < 0xc00000) return rand(), 0;
if(addr < 0xe00000) return vdp.readWord(addr);
uint16 data = ram[addr + 0 & 65535] << 8;
return data | ram[addr + 1 & 65535] << 0;
uint16 data = ram[addr + 0 & 0xffff] << 8;
return data | ram[addr + 1 & 0xffff] << 0;
}
auto CPU::writeByte(uint24 addr, uint8 data) -> void {

View File

@ -1,14 +1,27 @@
auto VDP::Background::scanline(uint y) -> void {
uint15 address = io.horizontalScrollAddress;
static const uint mask[] = {0u, 7u, ~7u, ~0u};
address += (y & mask[io.horizontalScrollMode]) << 1;
address += (this == &vdp.planeB);
state.horizontalScroll = vdp.vram[address].bits(0,9);
}
auto VDP::Background::run(uint x, uint y) -> void {
output.priority = 0;
output.color = 0;
static const uint tiles[] = {32, 64, 0, 128};
y -= vdp.vsram[(x >> 4) & (io.verticalScrollMode ? ~0u : 0u)];
y &= (tiles[io.nametableHeight] << 3) - 1;
x -= state.horizontalScroll;
x &= (tiles[io.nametableWidth] << 3) - 1;
uint tileX = x >> 3;
uint tileY = y >> 3;
uint15 nametableAddress = io.nametableAddress;
nametableAddress += (tileY << io.nametableWidth) + tileX;
nametableAddress += tileY * tiles[io.nametableWidth] + tileX;
uint16 tileAttributes = vdp.vram[nametableAddress];
uint15 tileAddress = tileAttributes.bits(0,10) << 4;
@ -29,4 +42,5 @@ auto VDP::Background::power() -> void {
auto VDP::Background::reset() -> void {
memory::fill(&io, sizeof(IO));
memory::fill(&state, sizeof(State));
}

View File

@ -217,8 +217,12 @@ auto VDP::writeControlPort(uint16 data) -> void {
//mode register 3
case 0x0b: {
io.horizontalScrollMode = data.bits(0,1);
io.verticalScrollMode = data.bit(2);
planeA.io.horizontalScrollMode = data.bits(0,1);
window.io.horizontalScrollMode = data.bits(0,1);
planeB.io.horizontalScrollMode = data.bits(0,1);
planeA.io.verticalScrollMode = data.bit(2);
window.io.verticalScrollMode = data.bit(2);
planeB.io.verticalScrollMode = data.bit(2);
io.externalInterruptEnable = data.bit(3);
return;
}
@ -236,7 +240,9 @@ auto VDP::writeControlPort(uint16 data) -> void {
//horizontal scroll data location
case 0x0d: {
io.horizontalScrollTable = data.bits(1,6);
planeA.io.horizontalScrollAddress = data.bits(0,6) << 9;
window.io.horizontalScrollAddress = data.bits(0,6) << 9;
planeB.io.horizontalScrollAddress = data.bits(0,6) << 9;
return;
}
@ -255,20 +261,12 @@ auto VDP::writeControlPort(uint16 data) -> void {
//plane size
case 0x10: {
//0 = 32 tiles
//1 = 64 tiles
//2 = invalid (repeats first row for every scanline)
//3 = 128 tiles
static const uint shift[] = {5, 6, 0, 7};
planeA.io.nametableWidth = shift[data.bits(0,1)];
window.io.nametableWidth = shift[data.bits(0,1)];
planeB.io.nametableWidth = shift[data.bits(0,1)];
planeA.io.nametableHeight = shift[data.bits(4,5)];
window.io.nametableHeight = shift[data.bits(4,5)];
planeB.io.nametableHeight = shift[data.bits(4,5)];
planeA.io.nametableWidth = data.bits(0,1);
window.io.nametableWidth = data.bits(0,1);
planeB.io.nametableWidth = data.bits(0,1);
planeA.io.nametableHeight = data.bits(4,5);
window.io.nametableHeight = data.bits(4,5);
planeB.io.nametableHeight = data.bits(4,5);
return;
}

View File

@ -2,7 +2,7 @@ auto VDP::scanline() -> void {
state.x = 0;
if(++state.y >= 262) state.y = 0;
if(state.y < 240) {
if(state.y < screenHeight()) {
planeA.scanline(state.y);
window.scanline(state.y);
planeB.scanline(state.y);
@ -16,6 +16,7 @@ auto VDP::scanline() -> void {
auto VDP::run() -> void {
if(!io.displayEnable) return outputPixel(0);
if(state.y >= screenHeight()) return outputPixel(0);
bool windowed = false; //todo: broken
windowed &= state.x >= io.windowHorizontalLo && state.x <= io.windowHorizontalHi;

View File

@ -5,7 +5,7 @@ auto VDP::Sprite::write(uint9 address, uint16 data) -> void {
switch(address.bits(0,1)) {
case 0: {
object.y = data.bits(0,9) - 128;
object.y = data.bits(0,8);
break;
}
@ -26,7 +26,7 @@ auto VDP::Sprite::write(uint9 address, uint16 data) -> void {
}
case 3: {
object.x = data.bits(0,9) - 128;
object.x = data.bits(0,8);
break;
}
@ -34,34 +34,31 @@ auto VDP::Sprite::write(uint9 address, uint16 data) -> void {
}
auto VDP::Sprite::scanline(uint y) -> void {
object.reset();
objects.reset();
uint7 link = 0;
while(link) {
auto& o = oam[link];
do {
auto& object = oam[link];
link = object.link;
if((uint9)(o.y + o.height - 1) < y) continue;
if((uint9)(y + o.height - 1) < o.y) continue;
if(o.x == 0) break;
if(128 + y < object.y) continue;
if(128 + y >= object.y + object.height - 1) continue;
if(object.x == 0) break;
object.append(o);
if(object.size() >= 20) break;
link = o.link;
if(!link || link >= 80) break;
}
objects.append(object);
} while(link && link < 80 && objects.size() < 20);
}
auto VDP::Sprite::run(uint x, uint y) -> void {
output.priority = 0;
output.color = 0;
for(auto& o : object) {
if((uint9)(o.x + o.width - 1) < x) continue;
if((uint9)(y + o.width - 1) < o.x) continue;
for(auto& o : objects) {
if(128 + x < o.x) continue;
if(128 + x >= o.x + o.width - 1) continue;
auto objectX = (uint9)(x - o.x);
auto objectY = (uint9)(y - o.y);
uint objectX = 128 + x - o.x;
uint objectY = 128 + y - o.y;
if(o.horizontalFlip) objectX = (o.width - 1) - objectX;
if(o.verticalFlip) objectY = (o.height - 1) - objectY;

View File

@ -61,6 +61,7 @@ auto VDP::reset() -> void {
create(VDP::Enter, system.colorburst() * 15.0 / 2.0);
memory::fill(&io, sizeof(IO));
memory::fill(&state, sizeof(State));
planeA.reset();
window.reset();

View File

@ -43,10 +43,17 @@ struct VDP : Thread {
struct IO {
uint15 nametableAddress;
uint3 nametableWidth; //1 << value
uint3 nametableHeight; //1 << value
uint2 nametableWidth;
uint2 nametableHeight;
uint15 horizontalScrollAddress;
uint2 horizontalScrollMode;
uint1 verticalScrollMode;
} io;
struct State {
uint10 horizontalScroll;
} state;
struct Output {
uint6 color;
boolean priority;
@ -71,8 +78,8 @@ struct VDP : Thread {
} io;
struct Object {
uint10 x;
uint10 y;
uint9 x;
uint9 y;
uint width;
uint height;
bool horizontalFlip;
@ -89,11 +96,14 @@ struct VDP : Thread {
} output;
array<Object, 80> oam;
array<Object, 20> object;
array<Object, 20> objects;
};
Sprite sprite;
private:
auto screenWidth() const -> uint { return io.tileWidth ? 320 : 256; }
auto screenHeight() const -> uint { return io.overscan ? 240 : 224; }
uint16 vram[32768];
uint16 vramExpansion[32768]; //not present in stock Mega Drive hardware
uint9 cram[64];
@ -130,8 +140,6 @@ private:
uint8 horizontalInterruptCounter;
//$0b mode register 3
uint2 horizontalScrollMode;
uint1 verticalScrollMode;
uint1 externalInterruptEnable;
//$0c mode register 4
@ -142,9 +150,6 @@ private:
uint1 horizontalSync;
uint1 verticalSync;
//$0d horizontal scroll data location
uint7 horizontalScrollTable;
//$0e nametable pattern base address
uint1 nametableBasePatternA;
uint1 nametableBasePatternB;

View File

@ -22,7 +22,7 @@ auto M68K::_readDisplacement(uint32 base) -> uint32 {
}
auto M68K::_readIndex(uint32 base) -> uint32 {
auto extension = readPC<Word>();
auto extension = _readPC<Word>();
auto index = extension & 0x8000
? read(AddressRegister{extension >> 12})
: read(DataRegister{extension >> 12});

View File

@ -779,14 +779,12 @@ auto M68K::instructionNBCD(EffectiveAddress with) -> void {
}
template<uint Size> auto M68K::instructionNEG(EffectiveAddress with) -> void {
auto source = read<Size, Hold>(with);
auto result = SUB<Size>(0, source);
auto result = SUB<Size>(read<Size, Hold>(with), 0);
write<Size>(with, result);
}
template<uint Size> auto M68K::instructionNEGX(EffectiveAddress with) -> void {
auto source = read<Size, Hold>(with);
auto result = SUB<Size, Extend>(0, source);
auto result = SUB<Size, Extend>(read<Size, Hold>(with), 0);
write<Size>(with, result);
}