mirror of https://github.com/bsnes-emu/bsnes.git
Update to v102r08 release.
byuu says: Changelog: - PCE: restructured VCE, VDCs to run one scanline at a time - PCE: bound VDCs to 1365x262 timing (in order to decouple the VDCs from the VCE) - PCE: the two changes above allow save states to function; also grants a minor speed boost - PCE: added cheat code support (uses 21-bit bus addressing; compare byte will be useful here) - 68K: fixed `mov *,ccr` to read two bytes instead of one [Cydrak] - Z80: emulated /BUSREQ, /BUSACK; allows 68K to suspend the Z80 [Cydrak] - MD: emulated the Z80 executing instructions [Cydrak] - MD: emulated Z80 interrupts (triggered during each Vblank period) [Cydrak] - MD: emulated Z80 memory map [Cydrak] - MD: added stubs for PSG, YM2612 accesses [Cydrak] - MD: improved bus emulation [Cydrak] The PCE core is pretty much ready to go. The only major feature missing is FM modulation. The Mega Drive improvements let us start to see the splash screens for Langrisser II, Shining Force, Shining in the Darkness. I was hoping I could get them in-game, but no such luck. My Z80 implementation is probably flawed in some way ... now that I think about it, I believe I missed the BusAPU::reset() check for having been granted access to the Z80 first. But I doubt that's the problem. Next step is to implement Cydrak's PSG core into the Master System emulator. Once that's in, I'm going to add save states and cheat code support to the Master System core. Next, I'll add the PSG core into the Mega Drive. Then I'll add the 'easy' PCM part of the YM2612. Then the rest of the beastly YM2612 core. Then finally, cap things off with save state and cheat code support. Should be nearing a new release at that point.
This commit is contained in:
parent
7c9b78b7bb
commit
d76c0c7e82
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "102.07";
|
||||
static const string Version = "102.08";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -9,7 +9,19 @@ auto APU::Enter() -> void {
|
|||
}
|
||||
|
||||
auto APU::main() -> void {
|
||||
step(1);
|
||||
if(!state.enabled) return step(1);
|
||||
|
||||
if(state.nmiLine) {
|
||||
state.nmiLine = 0; //edge-sensitive
|
||||
irq(0, 0x0066, 0xff);
|
||||
}
|
||||
|
||||
if(state.intLine) {
|
||||
//level-sensitive
|
||||
irq(1, 0x0038, 0xff);
|
||||
}
|
||||
|
||||
instruction();
|
||||
}
|
||||
|
||||
auto APU::step(uint clocks) -> void {
|
||||
|
@ -17,10 +29,30 @@ auto APU::step(uint clocks) -> void {
|
|||
synchronize(cpu);
|
||||
}
|
||||
|
||||
auto APU::setNMI(bool value) -> void {
|
||||
state.nmiLine = value;
|
||||
}
|
||||
|
||||
auto APU::setINT(bool value) -> void {
|
||||
state.intLine = value;
|
||||
}
|
||||
|
||||
auto APU::enable(bool value) -> void {
|
||||
if(state.enabled && !value) power();
|
||||
state.enabled = value;
|
||||
}
|
||||
|
||||
auto APU::power() -> void {
|
||||
Z80::bus = &busAPU;
|
||||
Z80::power();
|
||||
create(APU::Enter, system.colorburst());
|
||||
memory::fill(&state, sizeof(State));
|
||||
|
||||
r.pc = 0x0000;
|
||||
r.im = 0;
|
||||
r.iff1 = 0;
|
||||
r.iff2 = 0;
|
||||
r.ir = {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,18 @@ struct APU : Processor::Z80, Thread {
|
|||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
|
||||
auto enable(bool) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
auto setNMI(bool value) -> void;
|
||||
auto setINT(bool value) -> void;
|
||||
|
||||
private:
|
||||
struct State {
|
||||
boolean enabled;
|
||||
boolean nmiLine;
|
||||
boolean intLine;
|
||||
} state;
|
||||
};
|
||||
|
||||
extern APU apu;
|
||||
|
|
|
@ -8,8 +8,9 @@ BusAPU busAPU;
|
|||
auto BusCPU::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 < 0xa10000) return busAPU.granted() ? busAPU.read(addr) : (uint8)0x0000;
|
||||
if(addr < 0xa11000) return readIO(addr & ~0xff00);
|
||||
if(addr < 0xa12000) return readIO(addr & ~0x00ff);
|
||||
if(addr < 0xc00000) return 0x0000;
|
||||
if(addr < 0xe00000) return vdp.read(addr & ~1).byte(!addr.bit(0));
|
||||
return ram[addr & 0xffff];
|
||||
|
@ -18,8 +19,9 @@ auto BusCPU::readByte(uint24 addr) -> uint16 {
|
|||
auto BusCPU::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 < 0xa10000) return busAPU.granted() ? busAPU.read(addr) : (uint8)0x0000;
|
||||
if(addr < 0xa11000) return readIO(addr & ~0xff00) << 0;
|
||||
if(addr < 0xa12000) return readIO(addr & ~0x00ff) << 8;
|
||||
if(addr < 0xc00000) return 0x0000;
|
||||
if(addr < 0xe00000) return vdp.read(addr);
|
||||
uint16 data = ram[addr + 0 & 0xffff] << 8;
|
||||
|
@ -29,20 +31,26 @@ auto BusCPU::readWord(uint24 addr) -> uint16 {
|
|||
auto BusCPU::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 < 0xa10000) return busAPU.granted() ? busAPU.write(addr, data) : (void)0;
|
||||
if(addr < 0xa11000) return writeIO(addr & ~0xff00, data);
|
||||
if(addr < 0xa12000) return writeIO(addr & ~0x00ff, data);
|
||||
if(addr < 0xc00000) return;
|
||||
if(addr < 0xe00000) return vdp.write(addr & ~1, data << 8 | data << 0);
|
||||
if(addr < 0xc00010) return vdp.write(addr & ~1, data << 8 | data << 0);
|
||||
if(addr < 0xc00018) return psg.write(data);
|
||||
if(addr < 0xe00000) return;
|
||||
ram[addr & 0xffff] = data;
|
||||
}
|
||||
|
||||
auto BusCPU::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 < 0xa10000) return busAPU.granted() ? busAPU.write(addr, data) : (void)0;
|
||||
if(addr < 0xa11000) return writeIO(addr & ~0xff00, data >> 0);
|
||||
if(addr < 0xa12000) return writeIO(addr & ~0x00ff, data >> 8);
|
||||
if(addr < 0xc00000) return;
|
||||
if(addr < 0xe00000) return vdp.write(addr, data);
|
||||
if(addr < 0xc00010) return vdp.write(addr, data);
|
||||
if(addr < 0xc00018) return psg.write(data);
|
||||
if(addr < 0xe00000) return;
|
||||
ram[addr + 0 & 0xffff] = data >> 8;
|
||||
ram[addr + 1 & 0xffff] = data >> 0;
|
||||
}
|
||||
|
@ -65,6 +73,8 @@ auto BusCPU::readIO(uint24 addr) -> uint16 {
|
|||
case 0xa10008: return peripherals.controllerPort1->readControl();
|
||||
case 0xa1000a: return peripherals.controllerPort2->readControl();
|
||||
case 0xa1000c: return peripherals.extensionPort->readControl();
|
||||
|
||||
case 0xa11000: return !busAPU.granted();
|
||||
}
|
||||
|
||||
return 0x0000;
|
||||
|
@ -79,22 +89,63 @@ auto BusCPU::writeIO(uint24 addr, uint16 data) -> void {
|
|||
case 0xa10008: return peripherals.controllerPort1->writeControl(data);
|
||||
case 0xa1000a: return peripherals.controllerPort2->writeControl(data);
|
||||
case 0xa1000c: return peripherals.extensionPort->writeControl(data);
|
||||
|
||||
case 0xa11100: return busAPU.request(data.bit(0));
|
||||
case 0xa11200: return apu.enable(data.bit(0));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto BusAPU::read(uint16 addr) -> uint8 {
|
||||
return 0x00;
|
||||
if((addr & 0xe000) == 0x0000) {
|
||||
return ram[addr];
|
||||
}
|
||||
|
||||
if(addr == 0x4000) return ym2612.readStatus();
|
||||
if(addr == 0x4001) return ym2612.readStatus();
|
||||
if(addr == 0x4002) return ym2612.readStatus();
|
||||
if(addr == 0x4003) return ym2612.readStatus();
|
||||
|
||||
if((addr & 0x8000) == 0x8000) {
|
||||
return cartridge.read(bank << 15 | (addr & 0x7ffe)).byte(!addr.bit(0));
|
||||
}
|
||||
}
|
||||
|
||||
auto BusAPU::write(uint16 addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x0000) {
|
||||
ram[addr] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0x4000) return ym2612.writeAddress(0 << 8 | data);
|
||||
if(addr == 0x4001) return ym2612.writeData(data);
|
||||
if(addr == 0x4002) return ym2612.writeAddress(1 << 8 | data);
|
||||
if(addr == 0x4003) return ym2612.writeData(data);
|
||||
|
||||
if(addr == 0x6000) {
|
||||
//1-bit shift register
|
||||
bank = data.bit(0) << 8 | bank >> 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0x7f11) return psg.write(data);
|
||||
if(addr == 0x7f13) return psg.write(data);
|
||||
if(addr == 0x7f15) return psg.write(data);
|
||||
if(addr == 0x7f17) return psg.write(data);
|
||||
|
||||
if((addr & 0x8000) == 0x8000) {
|
||||
//todo: do 8-bit writes mirror to 16-bits?
|
||||
return cartridge.write(bank << 15 | (addr & 0x7ffe), data << 8 | data << 0);
|
||||
}
|
||||
}
|
||||
|
||||
//unused on Mega Drive
|
||||
auto BusAPU::in(uint8 addr) -> uint8 {
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
//unused on Mega Drive
|
||||
auto BusAPU::out(uint8 addr, uint8 data) -> void {
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,13 @@ private:
|
|||
struct BusAPU : Processor::Z80::Bus {
|
||||
auto read(uint16 addr) -> uint8 override;
|
||||
auto write(uint16 addr, uint8 data) -> void override;
|
||||
|
||||
auto in(uint8 addr) -> uint8 override;
|
||||
auto out(uint8 addr, uint8 data) -> void override;
|
||||
|
||||
private:
|
||||
uint8 ram[8 * 1024];
|
||||
uint9 bank;
|
||||
};
|
||||
|
||||
extern BusCPU busCPU;
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
auto PSG::write(uint8 data) -> void {
|
||||
}
|
|
@ -3,13 +3,14 @@
|
|||
namespace MegaDrive {
|
||||
|
||||
PSG psg;
|
||||
#include "io.cpp"
|
||||
|
||||
auto PSG::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), psg.main();
|
||||
}
|
||||
|
||||
auto PSG::main() -> void {
|
||||
stream->sample(0.0, 0.0);
|
||||
stream->sample(0.0);
|
||||
step(1);
|
||||
}
|
||||
|
||||
|
@ -19,8 +20,8 @@ auto PSG::step(uint clocks) -> void {
|
|||
}
|
||||
|
||||
auto PSG::power() -> void {
|
||||
create(PSG::Enter, 52'000); //system.colorburst());
|
||||
stream = Emulator::audio.createStream(2, 52'000.0);
|
||||
create(PSG::Enter, system.colorburst() / 16.0);
|
||||
stream = Emulator::audio.createStream(1, system.colorburst() / 16.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@ struct PSG : Thread {
|
|||
auto step(uint clocks) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
|
||||
//io.cpp
|
||||
auto write(uint8 data) -> void;
|
||||
};
|
||||
|
||||
extern PSG psg;
|
||||
|
|
|
@ -33,8 +33,10 @@ auto VDP::main() -> void {
|
|||
if(io.verticalBlankInterruptEnable) {
|
||||
cpu.raise(CPU::Interrupt::VerticalBlank);
|
||||
}
|
||||
apu.setINT(true);
|
||||
}
|
||||
step(1710);
|
||||
apu.setINT(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,6 +45,7 @@ auto VDP::step(uint clocks) -> void {
|
|||
dmaRun();
|
||||
Thread::step(1);
|
||||
synchronize(cpu);
|
||||
synchronize(apu);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
auto YM2612::readStatus() -> uint8 {
|
||||
return nall::random();
|
||||
}
|
||||
|
||||
auto YM2612::writeAddress(uint9 data) -> void {
|
||||
}
|
||||
|
||||
auto YM2612::writeData(uint8 data) -> void {
|
||||
}
|
|
@ -3,13 +3,15 @@
|
|||
namespace MegaDrive {
|
||||
|
||||
YM2612 ym2612;
|
||||
#include "io.cpp"
|
||||
|
||||
auto YM2612::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), ym2612.main();
|
||||
}
|
||||
|
||||
auto YM2612::main() -> void {
|
||||
step(1);
|
||||
stream->sample(0.0, 0.0);
|
||||
step(144);
|
||||
}
|
||||
|
||||
auto YM2612::step(uint clocks) -> void {
|
||||
|
@ -19,6 +21,7 @@ auto YM2612::step(uint clocks) -> void {
|
|||
|
||||
auto YM2612::power() -> void {
|
||||
create(YM2612::Enter, system.colorburst() * 15.0 / 7.0);
|
||||
stream = Emulator::audio.createStream(2, system.colorburst() * 15.0 / 7.0 / 144.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
//Yamaha YM2612
|
||||
|
||||
struct YM2612 : Thread {
|
||||
shared_pointer<Emulator::Stream> stream;
|
||||
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
|
||||
//io.cpp
|
||||
auto readStatus() -> uint8;
|
||||
auto writeAddress(uint9 data) -> void;
|
||||
auto writeData(uint8 data) -> void;
|
||||
};
|
||||
|
||||
extern YM2612 ym2612;
|
||||
|
|
|
@ -13,6 +13,7 @@ struct CPU : Processor::HuC6280, Thread {
|
|||
|
||||
//io.cpp
|
||||
auto read(uint8 bank, uint13 addr) -> uint8 override;
|
||||
auto read_(uint8 bank, uint13 addr) -> uint8;
|
||||
auto write(uint8 bank, uint13 addr, uint8 data) -> void override;
|
||||
auto store(uint2 addr, uint8 data) -> void override;
|
||||
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
auto CPU::read(uint8 bank, uint13 addr) -> uint8 {
|
||||
auto data = read_(bank, addr);
|
||||
if(auto result = cheat.find(bank << 13 | addr, data)) data = result();
|
||||
return data;
|
||||
}
|
||||
|
||||
auto CPU::read_(uint8 bank, uint13 addr) -> uint8 {
|
||||
//$00-7f HuCard
|
||||
if(!bank.bit(7)) {
|
||||
return cartridge.read(bank << 13 | addr);
|
||||
|
|
|
@ -11,7 +11,7 @@ Interface::Interface() {
|
|||
information.overscan = true;
|
||||
|
||||
information.capability.states = true;
|
||||
information.capability.cheats = false;
|
||||
information.capability.cheats = true;
|
||||
|
||||
Port controllerPort{ID::Port::Controller, "Controller Port"};
|
||||
|
||||
|
@ -116,6 +116,10 @@ auto Interface::unserialize(serializer& s) -> bool {
|
|||
return system.unserialize(s);
|
||||
}
|
||||
|
||||
auto Interface::cheatSet(const string_vector& list) -> void {
|
||||
cheat.assign(list);
|
||||
}
|
||||
|
||||
auto Interface::cap(const string& name) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ struct Interface : Emulator::Interface {
|
|||
auto serialize() -> serializer override;
|
||||
auto unserialize(serializer&) -> bool override;
|
||||
|
||||
auto cheatSet(const string_vector&) -> void override;
|
||||
|
||||
auto cap(const string& name) -> bool override;
|
||||
auto get(const string& name) -> any override;
|
||||
auto set(const string& name, const any& value) -> bool override;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <emulator/emulator.hpp>
|
||||
#include <emulator/thread.hpp>
|
||||
#include <emulator/scheduler.hpp>
|
||||
#include <emulator/cheat.hpp>
|
||||
|
||||
#include <processor/huc6280/huc6280.hpp>
|
||||
|
||||
|
@ -13,7 +14,9 @@ namespace PCEngine {
|
|||
#define platform Emulator::platform
|
||||
namespace File = Emulator::File;
|
||||
using Scheduler = Emulator::Scheduler;
|
||||
using Cheat = Emulator::Cheat;
|
||||
extern Scheduler scheduler;
|
||||
extern Cheat cheat;
|
||||
|
||||
struct Thread : Emulator::Thread {
|
||||
auto create(auto (*entrypoint)() -> void, double frequency) -> void {
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace PCEngine {
|
|||
|
||||
System system;
|
||||
Scheduler scheduler;
|
||||
Cheat cheat;
|
||||
#include "peripherals.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
|
|
|
@ -12,38 +12,36 @@ auto VCE::Enter() -> void {
|
|||
}
|
||||
|
||||
auto VCE::main() -> void {
|
||||
vdc0.frame();
|
||||
vdc1.frame();
|
||||
timing.vclock = 0;
|
||||
|
||||
while(timing.vclock < 262) {
|
||||
vdc0.scanline();
|
||||
vdc1.scanline();
|
||||
timing.hclock = 0;
|
||||
|
||||
auto output = buffer + 1365 * timing.vclock;
|
||||
|
||||
while(timing.hclock < 1360) {
|
||||
uint9 color;
|
||||
if(Model::PCEngine()) color = vdc0.bus();
|
||||
if(Model::SuperGrafx()) color = vpc.bus(timing.hclock);
|
||||
color = cram.read(color);
|
||||
|
||||
//*output++ = color;
|
||||
//step(1);
|
||||
|
||||
if(clock() >= 2) *output++ = color;
|
||||
if(clock() >= 2) *output++ = color;
|
||||
if(clock() >= 3) *output++ = color;
|
||||
if(clock() >= 4) *output++ = color;
|
||||
step(clock());
|
||||
}
|
||||
|
||||
step(1365 - timing.hclock);
|
||||
timing.vclock++;
|
||||
if(timing.vclock == 0) {
|
||||
vdc0.frame();
|
||||
vdc1.frame();
|
||||
}
|
||||
|
||||
scheduler.exit(Scheduler::Event::Frame);
|
||||
vdc0.scanline();
|
||||
vdc1.scanline();
|
||||
timing.hclock = 0;
|
||||
|
||||
auto output = buffer + 1365 * timing.vclock;
|
||||
|
||||
while(timing.hclock < 1360) {
|
||||
uint9 color;
|
||||
if(Model::PCEngine()) color = vdc0.bus();
|
||||
if(Model::SuperGrafx()) color = vpc.bus(timing.hclock);
|
||||
color = cram.read(color);
|
||||
|
||||
if(clock() >= 2) *output++ = color;
|
||||
if(clock() >= 2) *output++ = color;
|
||||
if(clock() >= 3) *output++ = color;
|
||||
if(clock() >= 4) *output++ = color;
|
||||
step(clock());
|
||||
}
|
||||
|
||||
step(1365 - timing.hclock);
|
||||
|
||||
if(++timing.vclock == 262) {
|
||||
timing.vclock = 0;
|
||||
scheduler.exit(Scheduler::Event::Frame);
|
||||
}
|
||||
}
|
||||
|
||||
auto VCE::step(uint clocks) -> void {
|
||||
|
|
|
@ -23,61 +23,58 @@ auto VDC::Enter() -> void {
|
|||
auto VDC::main() -> void {
|
||||
if(Model::PCEngine() && vdc1.active()) return step(frequency());
|
||||
|
||||
timing.vpulse = false;
|
||||
timing.vclock = 0;
|
||||
timing.voffset = 0;
|
||||
timing.vstart = max((uint8)2, timing.verticalDisplayStart) - 2;
|
||||
timing.vlength = min(242, timing.verticalDisplayLength + 1);
|
||||
if(timing.vclock == 0) {
|
||||
timing.voffset = 0;
|
||||
timing.vstart = max((uint8)2, timing.verticalDisplayStart) - 2;
|
||||
timing.vlength = min(242, timing.verticalDisplayLength + 1);
|
||||
}
|
||||
|
||||
while(!timing.vpulse) {
|
||||
timing.hpulse = false;
|
||||
timing.hclock = 0;
|
||||
timing.hoffset = 0;
|
||||
timing.hstart = timing.horizontalDisplayStart;
|
||||
timing.hlength = (timing.horizontalDisplayLength + 1) << 3;
|
||||
timing.hclock = 0;
|
||||
timing.hoffset = 0;
|
||||
timing.hstart = timing.horizontalDisplayStart;
|
||||
timing.hlength = (timing.horizontalDisplayLength + 1) << 3;
|
||||
|
||||
if(timing.vclock >= timing.vstart && timing.voffset < timing.vlength) {
|
||||
background.scanline(timing.voffset);
|
||||
sprite.scanline(timing.voffset);
|
||||
if(timing.vclock >= timing.vstart && timing.voffset < timing.vlength) {
|
||||
background.scanline(timing.voffset);
|
||||
sprite.scanline(timing.voffset);
|
||||
|
||||
step(timing.hstart);
|
||||
step(timing.hstart);
|
||||
|
||||
while(timing.hoffset < timing.hlength) {
|
||||
data = 0;
|
||||
|
||||
background.run(timing.hoffset, timing.voffset);
|
||||
sprite.run(timing.hoffset, timing.voffset);
|
||||
|
||||
if(sprite.color && sprite.priority) {
|
||||
data = 1 << 8 | sprite.palette << 4 | sprite.color << 0;
|
||||
} else if(background.color) {
|
||||
data = 0 << 8 | background.palette << 4 | background.color << 0;
|
||||
} else if(sprite.color) {
|
||||
data = 1 << 8 | sprite.palette << 4 | sprite.color << 0;
|
||||
}
|
||||
|
||||
step(vce.clock());
|
||||
timing.hoffset++;
|
||||
}
|
||||
while(timing.hclock < 1360 && timing.hoffset < timing.hlength) {
|
||||
data = 0;
|
||||
|
||||
if(timing.voffset == io.lineCoincidence - 64) {
|
||||
irq.raise(IRQ::Line::LineCoincidence);
|
||||
background.run(timing.hoffset, timing.voffset);
|
||||
sprite.run(timing.hoffset, timing.voffset);
|
||||
|
||||
if(sprite.color && sprite.priority) {
|
||||
data = 1 << 8 | sprite.palette << 4 | sprite.color << 0;
|
||||
} else if(background.color) {
|
||||
data = 0 << 8 | background.palette << 4 | background.color << 0;
|
||||
} else if(sprite.color) {
|
||||
data = 1 << 8 | sprite.palette << 4 | sprite.color << 0;
|
||||
}
|
||||
|
||||
while(!timing.hpulse) step(1);
|
||||
timing.vclock++;
|
||||
timing.voffset++;
|
||||
} else {
|
||||
data = 0;
|
||||
while(!timing.hpulse) step(1);
|
||||
timing.vclock++;
|
||||
step(vce.clock());
|
||||
timing.hoffset++;
|
||||
}
|
||||
|
||||
if(timing.vclock == timing.vstart + timing.vlength) {
|
||||
irq.raise(IRQ::Line::Vblank);
|
||||
dma.satbStart();
|
||||
if(timing.voffset == io.lineCoincidence - 64) {
|
||||
irq.raise(IRQ::Line::LineCoincidence);
|
||||
}
|
||||
|
||||
timing.voffset++;
|
||||
}
|
||||
|
||||
data = 0;
|
||||
step(1365 - timing.hclock);
|
||||
|
||||
if(timing.vclock == timing.vstart + timing.vlength) {
|
||||
irq.raise(IRQ::Line::Vblank);
|
||||
dma.satbStart();
|
||||
}
|
||||
|
||||
if(++timing.vclock == 262) {
|
||||
timing.vclock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -706,7 +706,7 @@ auto M68K::instructionMOVE_FROM_SR(EffectiveAddress ea) -> void {
|
|||
}
|
||||
|
||||
auto M68K::instructionMOVE_TO_CCR(EffectiveAddress ea) -> void {
|
||||
auto data = read<Byte>(ea);
|
||||
auto data = read<Word>(ea);
|
||||
writeCCR(data);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
auto Z80::yield() -> void {
|
||||
//freeze Z80, allow external access until relinquished
|
||||
if(bus->requested()) {
|
||||
bus->grant(true);
|
||||
while(bus->requested()) step(1);
|
||||
bus->grant(false);
|
||||
}
|
||||
}
|
||||
|
||||
auto Z80::wait(uint clocks) -> void {
|
||||
yield();
|
||||
step(clocks);
|
||||
}
|
||||
|
||||
auto Z80::opcode() -> uint8 {
|
||||
yield();
|
||||
step(4);
|
||||
return bus->read(r.pc++);
|
||||
}
|
||||
|
||||
auto Z80::operand() -> uint8 {
|
||||
yield();
|
||||
step(3);
|
||||
return bus->read(r.pc++);
|
||||
}
|
||||
|
@ -35,21 +47,25 @@ auto Z80::displace(uint16& x) -> uint16 {
|
|||
}
|
||||
|
||||
auto Z80::read(uint16 addr) -> uint8 {
|
||||
yield();
|
||||
step(3);
|
||||
return bus->read(addr);
|
||||
}
|
||||
|
||||
auto Z80::write(uint16 addr, uint8 data) -> void {
|
||||
yield();
|
||||
step(3);
|
||||
return bus->write(addr, data);
|
||||
}
|
||||
|
||||
auto Z80::in(uint8 addr) -> uint8 {
|
||||
yield();
|
||||
step(4);
|
||||
return bus->in(addr);
|
||||
}
|
||||
|
||||
auto Z80::out(uint8 addr, uint8 data) -> void {
|
||||
yield();
|
||||
step(4);
|
||||
return bus->out(addr, data);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace Processor {
|
|||
auto Z80::power() -> void {
|
||||
memory::fill(&r, sizeof(Registers));
|
||||
r.hlp = &r.hl;
|
||||
bus->request(false);
|
||||
bus->grant(false);
|
||||
}
|
||||
|
||||
auto Z80::irq(bool maskable, uint16 pc, uint8 extbus) -> bool {
|
||||
|
|
|
@ -6,10 +6,21 @@ namespace Processor {
|
|||
|
||||
struct Z80 {
|
||||
struct Bus {
|
||||
virtual auto requested() -> bool { return _requested; }
|
||||
virtual auto granted() -> bool { return _granted; }
|
||||
|
||||
virtual auto request(bool value) -> void { _requested = value; }
|
||||
virtual auto grant(bool value) -> void { _granted = value; }
|
||||
|
||||
virtual auto read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto write(uint16 addr, uint8 data) -> void = 0;
|
||||
|
||||
virtual auto in(uint8 addr) -> uint8 = 0;
|
||||
virtual auto out(uint8 addr, uint8 data) -> void = 0;
|
||||
|
||||
private:
|
||||
bool _requested;
|
||||
bool _granted;
|
||||
};
|
||||
|
||||
virtual auto step(uint clocks) -> void = 0;
|
||||
|
@ -21,6 +32,7 @@ struct Z80 {
|
|||
auto parity(uint8) const -> bool;
|
||||
|
||||
//memory.cpp
|
||||
auto yield() -> void;
|
||||
auto wait(uint clocks = 1) -> void;
|
||||
auto opcode() -> uint8;
|
||||
auto operand() -> uint8;
|
||||
|
|
Loading…
Reference in New Issue