diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 4a4f4d43..b4909108 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -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/"; diff --git a/higan/md/GNUmakefile b/higan/md/GNUmakefile index 01261213..a8086bb1 100644 --- a/higan/md/GNUmakefile +++ b/higan/md/GNUmakefile @@ -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) diff --git a/higan/md/bus/bus.cpp b/higan/md/bus/bus.cpp new file mode 100644 index 00000000..7f809b66 --- /dev/null +++ b/higan/md/bus/bus.cpp @@ -0,0 +1,77 @@ +#include + +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); + } +} + +} diff --git a/higan/md/bus/bus.hpp b/higan/md/bus/bus.hpp new file mode 100644 index 00000000..c230b65a --- /dev/null +++ b/higan/md/bus/bus.hpp @@ -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; diff --git a/higan/md/cartridge/cartridge.cpp b/higan/md/cartridge/cartridge.cpp index 7c28be32..804888dc 100644 --- a/higan/md/cartridge/cartridge.cpp +++ b/higan/md/cartridge/cartridge.cpp @@ -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 { } } diff --git a/higan/md/cartridge/cartridge.hpp b/higan/md/cartridge/cartridge.hpp index a36a3ce5..08323503 100644 --- a/higan/md/cartridge/cartridge.hpp +++ b/higan/md/cartridge/cartridge.hpp @@ -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; diff --git a/higan/md/controller/controller.cpp b/higan/md/controller/controller.cpp new file mode 100644 index 00000000..96195fb6 --- /dev/null +++ b/higan/md/controller/controller.cpp @@ -0,0 +1,28 @@ +#include + +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); +} + +} diff --git a/higan/md/controller/controller.hpp b/higan/md/controller/controller.hpp new file mode 100644 index 00000000..a2f23011 --- /dev/null +++ b/higan/md/controller/controller.hpp @@ -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" diff --git a/higan/md/controller/gamepad/gamepad.cpp b/higan/md/controller/gamepad/gamepad.cpp new file mode 100644 index 00000000..7a630b42 --- /dev/null +++ b/higan/md/controller/gamepad/gamepad.cpp @@ -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); +} diff --git a/higan/md/controller/gamepad/gamepad.hpp b/higan/md/controller/gamepad/gamepad.hpp new file mode 100644 index 00000000..f0e9311a --- /dev/null +++ b/higan/md/controller/gamepad/gamepad.hpp @@ -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; +}; diff --git a/higan/md/cpu/cpu.cpp b/higan/md/cpu/cpu.cpp index d8929774..55551f5a 100644 --- a/higan/md/cpu/cpu.cpp +++ b/higan/md/cpu/cpu.cpp @@ -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); } } diff --git a/higan/md/cpu/cpu.hpp b/higan/md/cpu/cpu.hpp index d7a79232..781c2f92 100644 --- a/higan/md/cpu/cpu.hpp +++ b/higan/md/cpu/cpu.hpp @@ -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 peripherals; +private: struct State { uint32 interruptLine; uint32 interruptPending; diff --git a/higan/md/interface/interface.cpp b/higan/md/interface/interface.cpp index 1b39979f..757d1d23 100644 --- a/higan/md/interface/interface.cpp +++ b/higan/md/interface/interface.cpp @@ -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(); } diff --git a/higan/md/interface/interface.hpp b/higan/md/interface/interface.hpp index 37fa5862..2eda14c8 100644 --- a/higan/md/interface/interface.hpp +++ b/higan/md/interface/interface.hpp @@ -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; diff --git a/higan/md/md.hpp b/higan/md/md.hpp index 43590e35..65966edf 100644 --- a/higan/md/md.hpp +++ b/higan/md/md.hpp @@ -35,6 +35,8 @@ namespace MegaDrive { uint wait = 0; }; + #include + #include #include #include @@ -43,6 +45,7 @@ namespace MegaDrive { #include #include + #include } #include diff --git a/higan/md/psg/psg.cpp b/higan/md/psg/psg.cpp index 6a408180..06cf78f0 100644 --- a/higan/md/psg/psg.cpp +++ b/higan/md/psg/psg.cpp @@ -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); } } diff --git a/higan/md/psg/psg.hpp b/higan/md/psg/psg.hpp index f9d20933..89ba7388 100644 --- a/higan/md/psg/psg.hpp +++ b/higan/md/psg/psg.hpp @@ -1,6 +1,8 @@ //TI SN76489 struct PSG : Thread { + shared_pointer stream; + static auto Enter() -> void; auto main() -> void; auto step(uint clocks) -> void; diff --git a/higan/md/system/peripherals.cpp b/higan/md/system/peripherals.cpp new file mode 100644 index 00000000..1afb1479 --- /dev/null +++ b/higan/md/system/peripherals.cpp @@ -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); +} diff --git a/higan/md/system/system.cpp b/higan/md/system/system.cpp index ad594e8e..5ad4ccb5 100644 --- a/higan/md/system/system.cpp +++ b/higan/md/system/system.cpp @@ -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(); } } diff --git a/higan/md/system/system.hpp b/higan/md/system/system.hpp index 2a406015..ae3d905a 100644 --- a/higan/md/system/system.hpp +++ b/higan/md/system/system.hpp @@ -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; diff --git a/higan/md/vdp/background.cpp b/higan/md/vdp/background.cpp index 5c8a04f0..42d71f95 100644 --- a/higan/md/vdp/background.cpp +++ b/higan/md/vdp/background.cpp @@ -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; diff --git a/higan/md/vdp/dma.cpp b/higan/md/vdp/dma.cpp index dd7d7e61..0c385250 100644 --- a/higan/md/vdp/dma.cpp +++ b/higan/md/vdp/dma.cpp @@ -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(); diff --git a/higan/md/vdp/io.cpp b/higan/md/vdp/io.cpp index f653ee96..fd185192 100644 --- a/higan/md/vdp/io.cpp +++ b/higan/md/vdp/io.cpp @@ -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 { diff --git a/higan/md/vdp/render.cpp b/higan/md/vdp/render.cpp index 56a2c2e7..761ba9ab 100644 --- a/higan/md/vdp/render.cpp +++ b/higan/md/vdp/render.cpp @@ -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); diff --git a/higan/md/vdp/sprite.cpp b/higan/md/vdp/sprite.cpp index 71ac3b8a..18e364d9 100644 --- a/higan/md/vdp/sprite.cpp +++ b/higan/md/vdp/sprite.cpp @@ -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; } } } diff --git a/higan/md/vdp/vdp.cpp b/higan/md/vdp/vdp.cpp index 6fbe5586..5ebf7340 100644 --- a/higan/md/vdp/vdp.cpp +++ b/higan/md/vdp/vdp.cpp @@ -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); } diff --git a/higan/md/vdp/vdp.hpp b/higan/md/vdp/vdp.hpp index c29f2112..bb9d6cfe 100644 --- a/higan/md/vdp/vdp.hpp +++ b/higan/md/vdp/vdp.hpp @@ -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; diff --git a/higan/processor/m68k/effective-address.cpp b/higan/processor/m68k/effective-address.cpp index fc58d836..28ad251e 100644 --- a/higan/processor/m68k/effective-address.cpp +++ b/higan/processor/m68k/effective-address.cpp @@ -189,19 +189,3 @@ template auto M68K::write(EffectiveAddress& ea, uint32 dat } } - -template auto M68K::flush(EffectiveAddress& ea, uint32 data) -> void { - switch(ea.mode) { - - case AddressRegisterIndirectWithPostIncrement: { - write(AddressRegister{ea.reg}, data); - return; - } - - case AddressRegisterIndirectWithPreDecrement: { - write(AddressRegister{ea.reg}, data); - return; - } - - } -} diff --git a/higan/processor/m68k/instructions.cpp b/higan/processor/m68k/instructions.cpp index 81961050..a4e95ee5 100644 --- a/higan/processor/m68k/instructions.cpp +++ b/higan/processor/m68k/instructions.cpp @@ -106,7 +106,7 @@ template auto M68K::instructionADD(DataRegister from, EffectiveAddres template auto M68K::instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void { auto source = sign(read(ea)); - auto target = read(ar); + auto target = read(ar); write(ar, source + target); } @@ -364,8 +364,8 @@ template auto M68K::instructionCMP(DataRegister dr, EffectiveAddress template auto M68K::instructionCMPA(AddressRegister ar, EffectiveAddress ea) -> void { auto source = sign(read(ea)); - auto target = read(ar); - CMP(source, target); + auto target = read(ar); + CMP(source, target); } template auto M68K::instructionCMPI(EffectiveAddress ea) -> void { @@ -623,7 +623,7 @@ template auto M68K::instructionMOVE(EffectiveAddress to, EffectiveAdd } template auto M68K::instructionMOVEA(AddressRegister ar, EffectiveAddress ea) -> void { - auto data = read(ea); + auto data = sign(read(ea)); write(ar, data); } @@ -639,10 +639,12 @@ template auto M68K::instructionMOVEM_TO_MEM(EffectiveAddress to) -> v if(to.mode == AddressRegisterIndirectWithPreDecrement) addr -= bytes(); auto data = index < 8 ? read(DataRegister{index}) : read(AddressRegister{index}); write(addr, data); - if(to.mode == AddressRegisterIndirectWithPostIncrement) addr += bytes(); + if(to.mode != AddressRegisterIndirectWithPreDecrement) addr += bytes(); } - flush(to, addr); + AddressRegister with{to.reg}; + if(to.mode == AddressRegisterIndirectWithPreDecrement ) write(with, addr); + if(to.mode == AddressRegisterIndirectWithPostIncrement) write(with, addr); } template auto M68K::instructionMOVEM_TO_REG(EffectiveAddress from) -> void { @@ -657,10 +659,12 @@ template auto M68K::instructionMOVEM_TO_REG(EffectiveAddress from) -> auto data = read(addr); data = sign(data); index < 8 ? write(DataRegister{index}, data) : write(AddressRegister{index}, data); - if(from.mode == AddressRegisterIndirectWithPostIncrement) addr += bytes(); + if(from.mode != AddressRegisterIndirectWithPreDecrement) addr += bytes(); } - flush(from, addr); + AddressRegister with{from.reg}; + if(from.mode == AddressRegisterIndirectWithPreDecrement ) write(with, addr); + if(from.mode == AddressRegisterIndirectWithPostIncrement) write(with, addr); } template auto M68K::instructionMOVEP(DataRegister from, EffectiveAddress to) -> void { @@ -1074,7 +1078,7 @@ template auto M68K::instructionSUB(DataRegister source_, EffectiveAdd template auto M68K::instructionSUBA(AddressRegister to, EffectiveAddress from) -> void { auto source = sign(read(from)); - auto target = read(to); + auto target = read(to); write(to, target - source); } diff --git a/higan/processor/m68k/m68k.hpp b/higan/processor/m68k/m68k.hpp index c06f222c..85ab051a 100644 --- a/higan/processor/m68k/m68k.hpp +++ b/higan/processor/m68k/m68k.hpp @@ -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 auto fetch(EffectiveAddress& ea) -> uint32; template auto read(EffectiveAddress& ea) -> uint32; template auto write(EffectiveAddress& ea, uint32 data) -> void; - template auto flush(EffectiveAddress& ea, uint32 data) -> void; //instruction.cpp auto instruction() -> void;