Update to v101r12 release.

byuu says:

Changelog:

  - new md/bus/ module for bus reads/writes
      - abstracts byte/word accesses wherever possible (everything but
        RAM; forces all but I/O to word, I/O to byte)
      - holds the system RAM since that's technically not part of the
        CPU anyway
  - added md/controller and md/system/peripherals
  - added emulation of gamepads
  - added stub PSG audio output (silent) to cap the framerate at 60fps
    with audio sync enabled
  - fixed VSRAM reads for plane vertical scrolling (two bugs here: add
    instead of sub; interlave plane A/B)
  - mask nametable read offsets (can't exceed 8192-byte nametables
    apparently)
  - emulated VRAM/VSRAM/CRAM reads from VDP data port
  - fixed sprite width/height size calculations
  - added partial emulation of 40-tile per scanline limitation (enough
    to fix Sonic's title screen)
  - fixed off-by-one sprite range testing
  - fixed sprite tile indexing
  - Vblank happens at Y=224 with overscan disabled
      - unsure what happens when you toggle it between Y=224 and Y=240
        ... probably bad things
  - fixed reading of address register for ADDA, CMPA, SUBA
  - fixed sign extension for MOVEA effect address reads
  - updated MOVEM to increment the read addresses (but not writeback)
    for (aN) mode

With all of that out of the way, we finally have Sonic the Hedgehog
(fully?) playable. I played to stage 1-2 and through the special stage,
at least. EDIT: yeah, we probably need HIRQs for Labyrinth Zone.

Not much else works, of course. Most games hang waiting on the Z80, and
those that don't (like Altered Beast) are still royally screwed. Tons of
features still missing; including all of the Z80/PSG/YM2612.

A note on the perihperals this time around: the Mega Drive EXT port is
basically identical to the regular controller ports. So unlike with the
Famicom and Super Famicom, I'm inheriting the exension port from the
controller class.
This commit is contained in:
Tim Allen 2016-08-22 08:11:24 +10:00
parent f7ddbfc462
commit 5df717ff2a
30 changed files with 353 additions and 131 deletions

View File

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

View File

@ -2,13 +2,16 @@ processors += m68k z80
objects += md-interface
objects += md-cpu md-apu md-vdp md-psg md-ym2612
objects += md-system md-cartridge
objects += md-system md-cartridge md-bus
objects += md-controller
obj/md-interface.o: md/interface/interface.cpp $(call rwildcard,md/interface)
obj/md-cpu.o: md/cpu/cpu.cpp $(call rwildcard,md/cpu)
obj/md-apu.o: md/apu/apu.cpp $(call rwildcard,md/apu)
obj/md-vdp.o: md/vdp/vdp.cpp $(call rwildcard,md/vdp)
obj/md-psg.o: md/psg/psg.cpp $(call rwildcard,md/psg)
obj/md-ym2612.o: md/ym2612/ym2612.cpp $(call rwildcard,md/ym2612)
obj/md-system.o: md/system/system.cpp $(call rwildcard,md/system)
obj/md-cartridge.o: md/cartridge/cartridge.cpp $(call rwildcard,md/cartridge)
obj/md-interface.o: md/interface/interface.cpp $(call rwildcard,md/interface)
obj/md-cpu.o: md/cpu/cpu.cpp $(call rwildcard,md/cpu)
obj/md-apu.o: md/apu/apu.cpp $(call rwildcard,md/apu)
obj/md-vdp.o: md/vdp/vdp.cpp $(call rwildcard,md/vdp)
obj/md-psg.o: md/psg/psg.cpp $(call rwildcard,md/psg)
obj/md-ym2612.o: md/ym2612/ym2612.cpp $(call rwildcard,md/ym2612)
obj/md-system.o: md/system/system.cpp $(call rwildcard,md/system)
obj/md-cartridge.o: md/cartridge/cartridge.cpp $(call rwildcard,md/cartridge)
obj/md-bus.o: md/bus/bus.cpp $(call rwildcard,md/bus)
obj/md-controller.o: md/controller/controller.cpp $(call rwildcard,md/controller)

77
higan/md/bus/bus.cpp Normal file
View File

@ -0,0 +1,77 @@
#include <md/md.hpp>
namespace MegaDrive {
Bus bus;
auto Bus::readByte(uint24 addr) -> uint16 {
if(addr < 0x400000) return cartridge.read(addr & ~1).byte(!addr.bit(0));
if(addr < 0xa00000) return 0x0000;
if(addr < 0xa10000) return 0x0000;
if(addr < 0xa10020) return readIO(addr);
if(addr < 0xc00000) return 0x0000;
if(addr < 0xe00000) return vdp.read(addr & ~1).byte(!addr.bit(0));
return ram[addr & 0xffff];
}
auto Bus::readWord(uint24 addr) -> uint16 {
if(addr < 0x400000) return cartridge.read(addr);
if(addr < 0xa00000) return 0x0000;
if(addr < 0xa10000) return 0x0000;
if(addr < 0xa10020) return readIO(addr);
if(addr < 0xc00000) return 0x0000;
if(addr < 0xe00000) return vdp.read(addr);
uint16 data = ram[addr + 0 & 0xffff] << 8;
return data | ram[addr + 1 & 0xffff] << 0;
}
auto Bus::writeByte(uint24 addr, uint16 data) -> void {
if(addr < 0x400000) return cartridge.write(addr & ~1, data << 8 | data << 0);
if(addr < 0xa00000) return;
if(addr < 0xa10000) return;
if(addr < 0xa10020) return writeIO(addr, data);
if(addr < 0xc00000) return;
if(addr < 0xe00000) return vdp.write(addr & ~1, data << 8 | data << 0);
ram[addr & 0xffff] = data;
}
auto Bus::writeWord(uint24 addr, uint16 data) -> void {
if(addr < 0x400000) return cartridge.write(addr, data);
if(addr < 0xa00000) return;
if(addr < 0xa10000) return;
if(addr < 0xa10020) return writeIO(addr, data);
if(addr < 0xc00000) return;
if(addr < 0xe00000) return vdp.write(addr, data);
ram[addr + 0 & 0xffff] = data >> 8;
ram[addr + 1 & 0xffff] = data >> 0;
}
//
auto Bus::readIO(uint24 addr) -> uint16 {
switch(addr & ~1) {
case 0xa10002: return peripherals.controllerPort1->readData();
case 0xa10004: return peripherals.controllerPort2->readData();
case 0xa10006: return peripherals.extensionPort->readData();
case 0xa10008: return peripherals.controllerPort1->readControl();
case 0xa1000a: return peripherals.controllerPort2->readControl();
case 0xa1000c: return peripherals.extensionPort->readControl();
}
return 0x0000;
}
auto Bus::writeIO(uint24 addr, uint16 data) -> void {
switch(addr & ~1) {
case 0xa10002: return peripherals.controllerPort1->writeData(data);
case 0xa10004: return peripherals.controllerPort2->writeData(data);
case 0xa10006: return peripherals.extensionPort->writeData(data);
case 0xa10008: return peripherals.controllerPort1->writeControl(data);
case 0xa1000a: return peripherals.controllerPort2->writeControl(data);
case 0xa1000c: return peripherals.extensionPort->writeControl(data);
}
}
}

14
higan/md/bus/bus.hpp Normal file
View File

@ -0,0 +1,14 @@
struct Bus {
auto readByte(uint24 addr) -> uint16;
auto readWord(uint24 addr) -> uint16;
auto writeByte(uint24 addr, uint16 data) -> void;
auto writeWord(uint24 addr, uint16 data) -> void;
auto readIO(uint24 addr) -> uint16;
auto writeIO(uint24 addr, uint16 data) -> void;
private:
uint8 ram[64 * 1024];
};
extern Bus bus;

View File

@ -70,19 +70,12 @@ auto Cartridge::power() -> void {
auto Cartridge::reset() -> void {
}
auto Cartridge::readByte(uint24 addr) -> uint8 {
return rom.data[addr & rom.mask];
}
auto Cartridge::readWord(uint24 addr) -> uint16 {
auto Cartridge::read(uint24 addr) -> uint16 {
uint16 data = rom.data[addr + 0 & rom.mask] << 8;
return data | rom.data[addr + 1 & rom.mask] << 0;
}
auto Cartridge::writeByte(uint24 addr, uint8 data) -> void {
}
auto Cartridge::writeWord(uint24 addr, uint16 data) -> void {
auto Cartridge::write(uint24 addr, uint16 data) -> void {
}
}

View File

@ -10,10 +10,8 @@ struct Cartridge {
auto power() -> void;
auto reset() -> void;
auto readByte(uint24 addr) -> uint8;
auto readWord(uint24 addr) -> uint16;
auto writeByte(uint24 addr, uint8 data) -> void;
auto writeWord(uint24 addr, uint16 data) -> void;
auto read(uint24 addr) -> uint16;
auto write(uint24 addr, uint16 data) -> void;
struct Information {
uint pathID = 0;

View File

@ -0,0 +1,28 @@
#include <md/md.hpp>
namespace MegaDrive {
#include "gamepad/gamepad.cpp"
Controller::Controller(uint port) : port(port) {
if(!handle()) create(Controller::Enter, 100);
}
Controller::~Controller() {
}
auto Controller::Enter() -> void {
while(true) {
scheduler.synchronize();
if(peripherals.controllerPort1->active()) peripherals.controllerPort1->main();
if(peripherals.controllerPort2->active()) peripherals.controllerPort2->main();
if(peripherals.extensionPort->active()) peripherals.extensionPort->main();
}
}
auto Controller::main() -> void {
step(1);
synchronize(cpu);
}
}

View File

@ -0,0 +1,17 @@
struct Controller : Thread {
Controller(uint port);
virtual ~Controller();
static auto Enter() -> void;
auto main() -> void;
virtual auto readData() -> uint8 { return 0xff; }
virtual auto writeData(uint8 data) -> void {}
virtual auto readControl() -> uint8 { return 0x00; }
virtual auto writeControl(uint8 data) -> void {}
const uint port;
};
#include "gamepad/gamepad.hpp"

View File

@ -0,0 +1,28 @@
Gamepad::Gamepad(uint port) : Controller(port) {
}
auto Gamepad::readData() -> uint8 {
uint6 data;
if(select == 0) {
data.bit(0) = interface->inputPoll(port, ID::Device::Gamepad, Up);
data.bit(1) = interface->inputPoll(port, ID::Device::Gamepad, Down);
data.bit(4) = interface->inputPoll(port, ID::Device::Gamepad, A);
data.bit(5) = interface->inputPoll(port, ID::Device::Gamepad, Start);
} else {
data.bit(0) = interface->inputPoll(port, ID::Device::Gamepad, Up);
data.bit(1) = interface->inputPoll(port, ID::Device::Gamepad, Down);
data.bit(2) = interface->inputPoll(port, ID::Device::Gamepad, Left);
data.bit(3) = interface->inputPoll(port, ID::Device::Gamepad, Right);
data.bit(4) = interface->inputPoll(port, ID::Device::Gamepad, B);
data.bit(5) = interface->inputPoll(port, ID::Device::Gamepad, C);
}
data = ~data;
return latch << 7 | select << 6 | data;
}
auto Gamepad::writeData(uint8 data) -> void {
select = data.bit(6);
latch = data.bit(7);
}

View File

@ -0,0 +1,13 @@
struct Gamepad : Controller {
enum : uint {
Up, Down, Left, Right, A, B, C, X, Y, Z, Start,
};
Gamepad(uint port);
auto readData() -> uint8 override;
auto writeData(uint8 data) -> void override;
boolean select;
boolean latch;
};

View File

@ -55,6 +55,7 @@ auto CPU::synchronize() -> void {
synchronize(vdp);
synchronize(psg);
synchronize(ym2612);
for(auto peripheral : peripherals) synchronize(*peripheral);
}
auto CPU::raise(Interrupt interrupt) -> void {
@ -71,8 +72,6 @@ auto CPU::lower(Interrupt interrupt) -> void {
auto CPU::power() -> void {
M68K::power();
for(auto& byte : ram) byte = 0x00;
}
auto CPU::reset() -> void {
@ -82,36 +81,9 @@ auto CPU::reset() -> void {
memory::fill(&state, sizeof(State));
}
auto CPU::readByte(uint24 addr) -> uint8 {
if(addr < 0x400000) return cartridge.readByte(addr);
if(addr < 0xa00000) return 0x00;
if(addr < 0xc00000) return rand(), 0;
if(addr < 0xe00000) return vdp.readByte(addr);
return ram[addr & 0xffff];
}
auto CPU::readWord(uint24 addr) -> uint16 {
if(addr < 0x400000) return cartridge.readWord(addr);
if(addr < 0xa00000) return 0x0000;
if(addr < 0xc00000) return rand(), 0;
if(addr < 0xe00000) return vdp.readWord(addr);
uint16 data = ram[addr + 0 & 0xffff] << 8;
return data | ram[addr + 1 & 0xffff] << 0;
}
auto CPU::writeByte(uint24 addr, uint8 data) -> void {
if(addr < 0x400000) return cartridge.writeByte(addr, data);
if(addr < 0xc00000) return;
if(addr < 0xe00000) return vdp.writeByte(addr, data);
ram[addr & 0xffff] = data;
}
auto CPU::writeWord(uint24 addr, uint16 data) -> void {
if(addr < 0x400000) return cartridge.writeWord(addr, data);
if(addr < 0xc00000) return;
if(addr < 0xe00000) return vdp.writeWord(addr, data);
ram[addr + 0 & 0xffff] = data >> 8;
ram[addr + 1 & 0xffff] = data >> 0;
}
auto CPU::readByte(uint24 addr) -> uint16 { return bus.readByte(addr); }
auto CPU::readWord(uint24 addr) -> uint16 { return bus.readWord(addr); }
auto CPU::writeByte(uint24 addr, uint16 data) -> void { return bus.writeByte(addr, data); }
auto CPU::writeWord(uint24 addr, uint16 data) -> void { return bus.writeWord(addr, data); }
}

View File

@ -20,14 +20,14 @@ struct CPU : Processor::M68K, Thread {
auto power() -> void;
auto reset() -> void;
auto readByte(uint24 addr) -> uint8 override;
auto readByte(uint24 addr) -> uint16 override;
auto readWord(uint24 addr) -> uint16 override;
auto writeByte(uint24 addr, uint8 data) -> void override;
auto writeByte(uint24 addr, uint16 data) -> void override;
auto writeWord(uint24 addr, uint16 data) -> void override;
private:
uint8 ram[64 * 1024];
vector<Thread*> peripherals;
private:
struct State {
uint32 interruptLine;
uint32 interruptPending;

View File

@ -20,6 +20,13 @@ Interface::Interface() {
Port controllerPort1{ID::Port::Controller1, "Controller Port 1"};
Port controllerPort2{ID::Port::Controller2, "Controller Port 2"};
Port extensionPort{ID::Port::Extension, "Extension Port"};
{ Device device{ID::Device::None, "None"};
controllerPort1.devices.append(device);
controllerPort2.devices.append(device);
extensionPort.devices.append(device);
}
{ Device device{ID::Device::Gamepad, "Gamepad"};
device.inputs.append({0, "Up" });
@ -39,6 +46,7 @@ Interface::Interface() {
ports.append(move(controllerPort1));
ports.append(move(controllerPort2));
ports.append(move(extensionPort));
}
auto Interface::manifest() -> string {
@ -100,6 +108,10 @@ auto Interface::unload() -> void {
system.unload();
}
auto Interface::connect(uint port, uint device) -> void {
MegaDrive::peripherals.connect(port, device);
}
auto Interface::power() -> void {
system.power();
}

View File

@ -9,9 +9,11 @@ struct ID {
struct Port { enum : uint {
Controller1,
Controller2,
Extension,
};};
struct Device { enum : uint {
None,
Gamepad,
};};
};
@ -37,6 +39,7 @@ struct Interface : Emulator::Interface {
auto save() -> void override;
auto unload() -> void override;
auto connect(uint port, uint device) -> void override;
auto power() -> void override;
auto reset() -> void override;
auto run() -> void override;
@ -50,6 +53,9 @@ struct Interface : Emulator::Interface {
};
struct Settings {
uint controllerPort1 = 0;
uint controllerPort2 = 0;
uint extensionPort = 0;
};
extern Interface* interface;

View File

@ -35,6 +35,8 @@ namespace MegaDrive {
uint wait = 0;
};
#include <md/controller/controller.hpp>
#include <md/cpu/cpu.hpp>
#include <md/apu/apu.hpp>
#include <md/vdp/vdp.hpp>
@ -43,6 +45,7 @@ namespace MegaDrive {
#include <md/system/system.hpp>
#include <md/cartridge/cartridge.hpp>
#include <md/bus/bus.hpp>
}
#include <md/interface/interface.hpp>

View File

@ -9,6 +9,7 @@ auto PSG::Enter() -> void {
}
auto PSG::main() -> void {
stream->sample(0.0, 0.0);
step(1);
}
@ -21,7 +22,8 @@ auto PSG::power() -> void {
}
auto PSG::reset() -> void {
create(PSG::Enter, system.colorburst());
create(PSG::Enter, 52'000); //system.colorburst());
stream = Emulator::audio.createStream(2, 52'000.0);
}
}

View File

@ -1,6 +1,8 @@
//TI SN76489
struct PSG : Thread {
shared_pointer<Emulator::Stream> stream;
static auto Enter() -> void;
auto main() -> void;
auto step(uint clocks) -> void;

View File

@ -0,0 +1,55 @@
Peripherals peripherals;
auto Peripherals::unload() -> void {
delete controllerPort1;
delete controllerPort2;
delete extensionPort;
controllerPort1 = nullptr;
controllerPort2 = nullptr;
extensionPort = nullptr;
}
auto Peripherals::reset() -> void {
connect(ID::Port::Controller1, settings.controllerPort1);
connect(ID::Port::Controller2, settings.controllerPort2);
connect(ID::Port::Extension, settings.extensionPort);
}
auto Peripherals::connect(uint port, uint device) -> void {
if(port == ID::Port::Controller1) {
settings.controllerPort1 = device;
if(!system.loaded()) return;
delete controllerPort1;
switch(device) { default:
case ID::Device::None: controllerPort1 = new Controller(0); break;
case ID::Device::Gamepad: controllerPort1 = new Gamepad(0); break;
}
}
if(port == ID::Port::Controller2) {
settings.controllerPort2 = device;
if(!system.loaded()) return;
delete controllerPort2;
switch(device) { default:
case ID::Device::None: controllerPort2 = new Controller(1); break;
case ID::Device::Gamepad: controllerPort2 = new Gamepad(1); break;
}
}
if(port == ID::Port::Extension) {
settings.extensionPort = device;
if(!system.loaded()) return;
delete extensionPort;
switch(device) { default:
case ID::Device::None: extensionPort = new Controller(2); break;
}
}
cpu.peripherals.reset();
cpu.peripherals.append(controllerPort1);
cpu.peripherals.append(controllerPort2);
cpu.peripherals.append(extensionPort);
}

View File

@ -2,6 +2,7 @@
namespace MegaDrive {
#include "peripherals.cpp"
System system;
Scheduler scheduler;
@ -25,6 +26,7 @@ auto System::save() -> void {
}
auto System::unload() -> void {
peripherals.unload();
cartridge.unload();
}
@ -54,6 +56,8 @@ auto System::reset() -> void {
psg.reset();
ym2612.reset();
scheduler.primary(cpu);
peripherals.reset();
}
}

View File

@ -17,4 +17,15 @@ struct System {
} information;
};
struct Peripherals {
auto unload() -> void;
auto reset() -> void;
auto connect(uint port, uint device) -> void;
Controller* controllerPort1 = nullptr;
Controller* controllerPort2 = nullptr;
Controller* extensionPort = nullptr;
};
extern System system;
extern Peripherals peripherals;

View File

@ -12,16 +12,14 @@ 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;
static const uint tiles[] = {32, 64, 96, 128};
y += vdp.vsram[((x >> 4) & (io.verticalScrollMode ? ~0u : 0u)) * 2 + (this == &vdp.planeB)];
x -= state.horizontalScroll;
x &= (tiles[io.nametableWidth] << 3) - 1;
uint tileX = x >> 3;
uint tileY = y >> 3;
uint tileX = x >> 3 & (tiles[io.nametableWidth ] - 1);
uint tileY = y >> 3 & (tiles[io.nametableHeight] - 1);
uint15 nametableAddress = io.nametableAddress;
nametableAddress += tileY * tiles[io.nametableWidth] + tileX;
nametableAddress += (tileY * tiles[io.nametableWidth] + tileX) & 0x0fff;
uint16 tileAttributes = vdp.vram[nametableAddress];
uint15 tileAddress = tileAttributes.bits(0,10) << 4;

View File

@ -1,6 +1,6 @@
auto VDP::dmaRun() -> void {
if(!io.dmaEnable) return;
if(io.command.bits(4,5) != 2) return;
if(!io.command.bit(5)) return;
if(io.dmaMode <= 1) return dmaLoad();
if(io.dmaMode == 2) return dmaFill();

View File

@ -1,16 +1,5 @@
auto VDP::readByte(uint24 addr) -> uint8 {
auto data = readWord(addr & ~1);
return data.byte(!addr.bit(0));
}
auto VDP::writeByte(uint24 addr, uint8 data) -> void {
return writeWord(addr & ~1, data << 8 | data << 0);
}
//
auto VDP::readWord(uint24 addr) -> uint16 {
switch(addr & 0xc0001f) {
auto VDP::read(uint24 addr) -> uint16 {
switch(addr & 0xc0001e) {
//data port
case 0xc00000: case 0xc00002: {
@ -32,10 +21,8 @@ auto VDP::readWord(uint24 addr) -> uint16 {
return 0x0000;
}
auto VDP::writeWord(uint24 addr, uint16 data) -> void {
//print("[VDP] ", hex(addr, 6L), "=", hex(data, 4L), "\n");
switch(addr & 0xc0001f) {
auto VDP::write(uint24 addr, uint16 data) -> void {
switch(addr & 0xc0001e) {
//data port
case 0xc00000: case 0xc00002: {
@ -57,18 +44,30 @@ auto VDP::readDataPort() -> uint16 {
//VRAM read
if(io.command.bits(0,3) == 0) {
return 0x0000;
auto address = io.address.bits(1,15);
auto data = vram[address];
io.address += io.dataIncrement;
return data;
}
//VSRAM read
if(io.command.bits(0,3) == 4) {
return 0x0000;
auto address = io.address.bits(1,6);
if(address >= 40) return 0x0000;
auto data = vsram[address];
io.address += io.dataIncrement;
return data;
}
//CRAM read
if(io.command.bits(0,3) == 8) {
return 0x0000;
auto address = io.address.bits(1,6);
auto data = cram[address];
io.address += io.dataIncrement;
return data.bits(0,2) << 1 | data.bits(3,5) << 2 | data.bits(6,8) << 3;
}
return 0x0000;
}
auto VDP::writeDataPort(uint16 data) -> void {

View File

@ -20,7 +20,7 @@ auto VDP::run() -> void {
bool windowed = false; //todo: broken
windowed &= state.x >= io.windowHorizontalLo && state.x <= io.windowHorizontalHi;
windowed &= state.y >= io.windowVerticalLo && state.y <= io.windowVerticalHi;
windowed &= state.y >= io.windowVerticalLo && state.y <= io.windowVerticalHi;
auto& planeA = windowed ? this->window : this->planeA;
planeA.run(state.x, state.y);

View File

@ -11,8 +11,8 @@ auto VDP::Sprite::write(uint9 address, uint16 data) -> void {
case 1: {
object.link = data.bits(0,6);
object.height = data.bits(8,9) << 3;
object.width = data.bits(10,11) << 3;
object.height = 1 + data.bits(8,9) << 3;
object.width = 1 + data.bits(10,11) << 3;
break;
}
@ -37,16 +37,18 @@ auto VDP::Sprite::scanline(uint y) -> void {
objects.reset();
uint7 link = 0;
uint tiles = 0;
do {
auto& object = oam[link];
link = object.link;
if(128 + y < object.y) continue;
if(128 + y >= object.y + object.height - 1) continue;
if(128 + y >= object.y + object.height) continue;
if(object.x == 0) break;
objects.append(object);
} while(link && link < 80 && objects.size() < 20);
tiles += object.width >> 3;
} while(link && link < 80 && objects.size() < 20 && tiles < 40);
}
auto VDP::Sprite::run(uint x, uint y) -> void {
@ -55,7 +57,7 @@ auto VDP::Sprite::run(uint x, uint y) -> void {
for(auto& o : objects) {
if(128 + x < o.x) continue;
if(128 + x >= o.x + o.width - 1) continue;
if(128 + x >= o.x + o.width) continue;
uint objectX = 128 + x - o.x;
uint objectY = 128 + y - o.y;
@ -64,7 +66,7 @@ auto VDP::Sprite::run(uint x, uint y) -> void {
uint tileX = objectX >> 3;
uint tileY = objectY >> 3;
uint tileNumber = tileX * (o.width >> 3) + tileY;
uint tileNumber = tileX * (o.height >> 3) + tileY;
uint15 tileAddress = o.address + (tileNumber << 4);
uint pixelX = objectX & 7;
uint pixelY = objectY & 7;
@ -75,6 +77,7 @@ auto VDP::Sprite::run(uint x, uint y) -> void {
if(color) {
output.color = o.palette << 4 | color;
output.priority = o.priority;
break;
}
}
}

View File

@ -15,7 +15,7 @@ auto VDP::Enter() -> void {
auto VDP::main() -> void {
scanline();
if(state.y < 240) {
if(state.y < screenHeight()) {
if(state.y == 0) {
cpu.lower(CPU::Interrupt::VerticalBlank);
}
@ -29,7 +29,7 @@ auto VDP::main() -> void {
}
step(430);
} else {
if(state.y == 240) {
if(state.y == screenHeight()) {
if(io.verticalBlankInterruptEnable) {
cpu.raise(CPU::Interrupt::VerticalBlank);
}

View File

@ -10,11 +10,8 @@ struct VDP : Thread {
auto reset() -> void;
//io.cpp
auto readByte(uint24 addr) -> uint8;
auto writeByte(uint24 addr, uint8 data) -> void;
auto readWord(uint24 addr) -> uint16;
auto writeWord(uint24 addr, uint16 data) -> void;
auto read(uint24 addr) -> uint16;
auto write(uint24 addr, uint16 data) -> void;
auto readDataPort() -> uint16;
auto writeDataPort(uint16 data) -> void;

View File

@ -189,19 +189,3 @@ template<uint Size, bool Hold> auto M68K::write(EffectiveAddress& ea, uint32 dat
}
}
template<uint Size> auto M68K::flush(EffectiveAddress& ea, uint32 data) -> void {
switch(ea.mode) {
case AddressRegisterIndirectWithPostIncrement: {
write<Size>(AddressRegister{ea.reg}, data);
return;
}
case AddressRegisterIndirectWithPreDecrement: {
write<Size>(AddressRegister{ea.reg}, data);
return;
}
}
}

View File

@ -106,7 +106,7 @@ template<uint Size> auto M68K::instructionADD(DataRegister from, EffectiveAddres
template<uint Size> auto M68K::instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void {
auto source = sign<Size>(read<Size>(ea));
auto target = read<Size>(ar);
auto target = read<Long>(ar);
write<Long>(ar, source + target);
}
@ -364,8 +364,8 @@ template<uint Size> auto M68K::instructionCMP(DataRegister dr, EffectiveAddress
template<uint Size> auto M68K::instructionCMPA(AddressRegister ar, EffectiveAddress ea) -> void {
auto source = sign<Size>(read<Size>(ea));
auto target = read<Size>(ar);
CMP<Size>(source, target);
auto target = read<Long>(ar);
CMP<Long>(source, target);
}
template<uint Size> auto M68K::instructionCMPI(EffectiveAddress ea) -> void {
@ -623,7 +623,7 @@ template<uint Size> auto M68K::instructionMOVE(EffectiveAddress to, EffectiveAdd
}
template<uint Size> auto M68K::instructionMOVEA(AddressRegister ar, EffectiveAddress ea) -> void {
auto data = read<Size>(ea);
auto data = sign<Size>(read<Size>(ea));
write<Long>(ar, data);
}
@ -639,10 +639,12 @@ template<uint Size> auto M68K::instructionMOVEM_TO_MEM(EffectiveAddress to) -> v
if(to.mode == AddressRegisterIndirectWithPreDecrement) addr -= bytes<Size>();
auto data = index < 8 ? read<Size>(DataRegister{index}) : read<Size>(AddressRegister{index});
write<Size>(addr, data);
if(to.mode == AddressRegisterIndirectWithPostIncrement) addr += bytes<Size>();
if(to.mode != AddressRegisterIndirectWithPreDecrement) addr += bytes<Size>();
}
flush<Long>(to, addr);
AddressRegister with{to.reg};
if(to.mode == AddressRegisterIndirectWithPreDecrement ) write<Long>(with, addr);
if(to.mode == AddressRegisterIndirectWithPostIncrement) write<Long>(with, addr);
}
template<uint Size> auto M68K::instructionMOVEM_TO_REG(EffectiveAddress from) -> void {
@ -657,10 +659,12 @@ template<uint Size> auto M68K::instructionMOVEM_TO_REG(EffectiveAddress from) ->
auto data = read<Size>(addr);
data = sign<Size>(data);
index < 8 ? write<Long>(DataRegister{index}, data) : write<Long>(AddressRegister{index}, data);
if(from.mode == AddressRegisterIndirectWithPostIncrement) addr += bytes<Size>();
if(from.mode != AddressRegisterIndirectWithPreDecrement) addr += bytes<Size>();
}
flush<Long>(from, addr);
AddressRegister with{from.reg};
if(from.mode == AddressRegisterIndirectWithPreDecrement ) write<Long>(with, addr);
if(from.mode == AddressRegisterIndirectWithPostIncrement) write<Long>(with, addr);
}
template<uint Size> auto M68K::instructionMOVEP(DataRegister from, EffectiveAddress to) -> void {
@ -1074,7 +1078,7 @@ template<uint Size> auto M68K::instructionSUB(DataRegister source_, EffectiveAdd
template<uint Size> auto M68K::instructionSUBA(AddressRegister to, EffectiveAddress from) -> void {
auto source = sign<Size>(read<Size>(from));
auto target = read<Size>(to);
auto target = read<Long>(to);
write<Long>(to, target - source);
}

View File

@ -50,9 +50,9 @@ struct M68K {
M68K();
virtual auto step(uint clocks) -> void = 0;
virtual auto readByte(uint24 addr) -> uint8 = 0;
virtual auto readByte(uint24 addr) -> uint16 = 0;
virtual auto readWord(uint24 addr) -> uint16 = 0;
virtual auto writeByte(uint24 addr, uint8 data) -> void = 0;
virtual auto writeByte(uint24 addr, uint16 data) -> void = 0;
virtual auto writeWord(uint24 addr, uint16 data) -> void = 0;
auto power() -> void;
@ -103,7 +103,6 @@ struct M68K {
template<uint Size> auto fetch(EffectiveAddress& ea) -> uint32;
template<uint Size, bool Hold = 0> auto read(EffectiveAddress& ea) -> uint32;
template<uint Size, bool Hold = 0> auto write(EffectiveAddress& ea, uint32 data) -> void;
template<uint Size> auto flush(EffectiveAddress& ea, uint32 data) -> void;
//instruction.cpp
auto instruction() -> void;