mirror of https://github.com/bsnes-emu/bsnes.git
Update to v098r01 release.
byuu says: Changelog: - SFC: balanced profile removed - SFC: performance profile removed - SFC: code for handling non-threaded CPU, SMP, DSP, PPU removed - SFC: Coprocessor, Controller (and expansion port) shared Thread code merged to SFC::Cothread - Cothread here just means "Thread with CPU affinity" (couldn't think of a better name, sorry) - SFC: CPU now has vector<Thread*> coprocessors, peripherals; - this is the beginning of work to allow expansion port devices to be dynamically changed at run-time - ruby: all audio drivers default to 48000hz instead of 22050hz now if no frequency is assigned - note: the WASAPI driver can default to whatever the native frequency is; doesn't have to be 48000hz - tomoko: removed the ability to change the frequency from the UI (but it will display the frequency used) - tomoko: removed the timing settings panel - the goal is to work toward smooth video via adaptive sync - the model is broken by not being in control of the audio frequency anyway - it's further broken by PAL running at 50hz and WSC running at 75hz - it was always broken anyway by SNES interlace timing varying from progressive timing - higan: audio/ stub created (for now, it's just nall/dsp/ moved here and included as a header) - higan: video/ stub created - higan/GNUmakefile: now includes build rules for essential components (libco, emulator, audio, video) The audio changes are in preparation to merge wareya's awesome WASAPI work without the need for the nall/dsp resampler.
This commit is contained in:
parent
aff00506c5
commit
19e1d89f00
|
@ -2,11 +2,10 @@ include ../nall/GNUmakefile
|
|||
|
||||
target := tomoko
|
||||
# target := loki
|
||||
profile := accuracy
|
||||
# console := true
|
||||
|
||||
flags += -I. -I.. -O3
|
||||
objects := libco
|
||||
objects := libco emulator audio video
|
||||
|
||||
# profile-guided optimization mode
|
||||
# pgo := instrument
|
||||
|
@ -54,6 +53,11 @@ compile = \
|
|||
|
||||
all: build;
|
||||
|
||||
obj/libco.o: ../libco/libco.c $(call rwildcard,../libco/)
|
||||
obj/emulator.o: emulator/emulator.cpp $(call rwildcard,emulator/)
|
||||
obj/audio.o: audio/audio.cpp $(call rwildcard,audio/)
|
||||
obj/video.o: video/video.cpp $(call rwildcard,video/)
|
||||
|
||||
ui := target-$(target)
|
||||
include $(ui)/GNUmakefile
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#include <emulator/emulator.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "core.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
objects += emulator
|
||||
|
||||
obj/emulator.o: emulator/emulator.cpp $(call rwildcard,emulator/)
|
|
@ -1,23 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <nall/nall.hpp>
|
||||
#include <nall/dsp.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <audio/audio.hpp>
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "098";
|
||||
static const string Version = "098.01";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
||||
#if defined(PROFILE_ACCURACY)
|
||||
static const string Profile = "Accuracy";
|
||||
#elif defined(PROFILE_BALANCED)
|
||||
static const string Profile = "Balanced";
|
||||
#elif defined(PROFILE_PERFORMANCE)
|
||||
static const string Profile = "Performance";
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "interface.hpp"
|
||||
|
|
|
@ -13,28 +13,6 @@ objects += sfc-spc7110 sfc-sdd1 sfc-obc1
|
|||
objects += sfc-msu1
|
||||
objects += sfc-bsmemory sfc-sufamiturbo
|
||||
|
||||
ifeq ($(profile),accuracy)
|
||||
flags += -DPROFILE_ACCURACY
|
||||
sfccpu := cpu
|
||||
sfcsmp := smp
|
||||
sfcdsp := dsp
|
||||
sfcppu := ppu
|
||||
else ifeq ($(profile),balanced)
|
||||
flags += -DPROFILE_BALANCED
|
||||
sfccpu := cpu
|
||||
sfcsmp := smp
|
||||
sfcdsp := alt/dsp
|
||||
sfcppu := alt/ppu-balanced
|
||||
else ifeq ($(profile),performance)
|
||||
flags += -DPROFILE_PERFORMANCE
|
||||
sfccpu := alt/cpu
|
||||
sfcsmp := alt/smp
|
||||
sfcdsp := alt/dsp
|
||||
sfcppu := alt/ppu-performance
|
||||
else
|
||||
$(error "unknown Super Famicom profile")
|
||||
endif
|
||||
|
||||
obj/sfc-interface.o: sfc/interface/interface.cpp $(call rwildcard,sfc/interface)
|
||||
obj/sfc-system.o: sfc/system/system.cpp $(call rwildcard,sfc/system/)
|
||||
obj/sfc-scheduler.o: sfc/scheduler/scheduler.cpp $(call rwildcard,sfc/scheduler/)
|
||||
|
@ -42,10 +20,11 @@ obj/sfc-controller.o: sfc/controller/controller.cpp $(call rwildcard,sfc/contro
|
|||
obj/sfc-cartridge.o: sfc/cartridge/cartridge.cpp $(call rwildcard,sfc/cartridge/)
|
||||
obj/sfc-cheat.o: sfc/cheat/cheat.cpp $(call rwildcard,sfc/cheat/)
|
||||
obj/sfc-memory.o: sfc/memory/memory.cpp $(call rwildcard,sfc/memory/)
|
||||
obj/sfc-cpu.o: sfc/$(sfccpu)/cpu.cpp $(call rwildcard,sfc/$(sfccpu)/)
|
||||
obj/sfc-smp.o: sfc/$(sfcsmp)/smp.cpp $(call rwildcard,sfc/$(sfcsmp)/)
|
||||
obj/sfc-dsp.o: sfc/$(sfcdsp)/dsp.cpp $(call rwildcard,sfc/$(sfcdsp)/)
|
||||
obj/sfc-ppu.o: sfc/$(sfcppu)/ppu.cpp $(call rwildcard,sfc/$(sfcppu)/)
|
||||
|
||||
obj/sfc-cpu.o: sfc/cpu/cpu.cpp $(call rwildcard,sfc/cpu/)
|
||||
obj/sfc-smp.o: sfc/smp/smp.cpp $(call rwildcard,sfc/smp/)
|
||||
obj/sfc-dsp.o: sfc/dsp/dsp.cpp $(call rwildcard,sfc/dsp/)
|
||||
obj/sfc-ppu.o: sfc/ppu/ppu.cpp $(call rwildcard,sfc/ppu/)
|
||||
|
||||
obj/sfc-satellaview.o: sfc/expansion/satellaview/satellaview.cpp $(call rwildcard,sfc/expansion/satellaview/)
|
||||
obj/sfc-superdisc.o: sfc/expansion/superdisc/superdisc.cpp $(call rwildcard,sfc/expansion/superdisc/)
|
||||
|
|
|
@ -1,167 +0,0 @@
|
|||
#include <sfc/sfc.hpp>
|
||||
|
||||
namespace SuperFamicom {
|
||||
|
||||
CPU cpu;
|
||||
|
||||
#include "serialization.cpp"
|
||||
#include "dma.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "mmio.cpp"
|
||||
#include "timing.cpp"
|
||||
|
||||
CPU::CPU() : queue(512, {&CPU::queue_event, this}) {
|
||||
PPUcounter::scanline = {&CPU::scanline, this};
|
||||
}
|
||||
|
||||
auto CPU::step(uint clocks) -> void {
|
||||
smp.clock -= clocks * (uint64)smp.frequency;
|
||||
ppu.clock -= clocks;
|
||||
for(uint i = 0; i < coprocessors.size(); i++) {
|
||||
auto& chip = *coprocessors[i];
|
||||
chip.clock -= clocks * (uint64)chip.frequency;
|
||||
}
|
||||
device.controllerPort1->clock -= clocks * (uint64)device.controllerPort1->frequency;
|
||||
device.controllerPort2->clock -= clocks * (uint64)device.controllerPort2->frequency;
|
||||
synchronizeDevices();
|
||||
}
|
||||
|
||||
auto CPU::synchronizeSMP() -> void {
|
||||
if(SMP::Threaded == true) {
|
||||
if(smp.clock < 0) co_switch(smp.thread);
|
||||
} else {
|
||||
while(smp.clock < 0) smp.main();
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::synchronizePPU() -> void {
|
||||
if(PPU::Threaded == true) {
|
||||
if(ppu.clock < 0) co_switch(ppu.thread);
|
||||
} else {
|
||||
while(ppu.clock < 0) ppu.main();
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::synchronizeCoprocessors() -> void {
|
||||
for(uint i = 0; i < coprocessors.size(); i++) {
|
||||
auto& chip = *coprocessors[i];
|
||||
if(chip.clock < 0) co_switch(chip.thread);
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::synchronizeDevices() -> void {
|
||||
if(device.controllerPort1->clock < 0) co_switch(device.controllerPort1->thread);
|
||||
if(device.controllerPort2->clock < 0) co_switch(device.controllerPort2->thread);
|
||||
}
|
||||
|
||||
auto CPU::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), cpu.main();
|
||||
}
|
||||
|
||||
auto CPU::main() -> void {
|
||||
if(status.nmi_pending) {
|
||||
status.nmi_pending = false;
|
||||
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
|
||||
interrupt();
|
||||
}
|
||||
|
||||
if(status.irq_pending) {
|
||||
status.irq_pending = false;
|
||||
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
|
||||
interrupt();
|
||||
}
|
||||
|
||||
instruction();
|
||||
}
|
||||
|
||||
auto CPU::enable() -> void {
|
||||
function<auto (uint, uint8) -> uint8> reader{&CPU::mmio_read, (CPU*)&cpu};
|
||||
function<auto (uint, uint8) -> void> writer{&CPU::mmio_write, (CPU*)&cpu};
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x2183);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x2183);
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x4016, 0x4017);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x4016, 0x4017);
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x4200, 0x421f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x4200, 0x421f);
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x4300, 0x437f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x4300, 0x437f);
|
||||
|
||||
reader = [](uint addr, uint8 data) { return cpu.wram[addr]; };
|
||||
writer = [](uint addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x0000, 0x1fff, 0x002000);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x0000, 0x1fff, 0x002000);
|
||||
bus.map(reader, writer, 0x7e, 0x7f, 0x0000, 0xffff, 0x020000);
|
||||
}
|
||||
|
||||
auto CPU::power() -> void {
|
||||
regs.a = 0x0000;
|
||||
regs.x = 0x0000;
|
||||
regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
auto CPU::reset() -> void {
|
||||
create(Enter, system.cpuFrequency());
|
||||
coprocessors.reset();
|
||||
PPUcounter::reset();
|
||||
|
||||
regs.pc = 0x000000;
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
regs.s.h = 0x01;
|
||||
regs.d = 0x0000;
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
regs.wai = false;
|
||||
|
||||
regs.pc.l = bus.read(0xfffc, regs.mdr);
|
||||
regs.pc.h = bus.read(0xfffd, regs.mdr);
|
||||
regs.pc.b = 0x00;
|
||||
|
||||
status.nmi_valid = false;
|
||||
status.nmi_line = false;
|
||||
status.nmi_transition = false;
|
||||
status.nmi_pending = false;
|
||||
|
||||
status.irq_valid = false;
|
||||
status.irq_line = false;
|
||||
status.irq_transition = false;
|
||||
status.irq_pending = false;
|
||||
|
||||
status.irq_lock = false;
|
||||
status.hdma_pending = false;
|
||||
|
||||
status.wram_addr = 0x000000;
|
||||
|
||||
status.joypad_strobe_latch = 0;
|
||||
|
||||
status.nmi_enabled = false;
|
||||
status.virq_enabled = false;
|
||||
status.hirq_enabled = false;
|
||||
status.auto_joypad_poll_enabled = false;
|
||||
|
||||
status.pio = 0xff;
|
||||
|
||||
status.htime = 0x0000;
|
||||
status.vtime = 0x0000;
|
||||
|
||||
status.rom_speed = 8;
|
||||
|
||||
status.joy1l = status.joy1h = 0x00;
|
||||
status.joy2l = status.joy2h = 0x00;
|
||||
status.joy3l = status.joy3h = 0x00;
|
||||
status.joy4l = status.joy4h = 0x00;
|
||||
|
||||
dma_reset();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
struct CPU : Processor::R65816, Thread, public PPUcounter {
|
||||
enum : bool { Threaded = true };
|
||||
|
||||
CPU();
|
||||
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto synchronizeSMP() -> void;
|
||||
auto synchronizePPU() -> void;
|
||||
auto synchronizeCoprocessors() -> void;
|
||||
auto synchronizeDevices() -> void;
|
||||
|
||||
auto pio() -> uint8;
|
||||
auto joylatch() -> bool;
|
||||
auto interruptPending() const -> bool;
|
||||
auto port_read(uint8 port) -> uint8;
|
||||
auto port_write(uint8 port, uint8 data) -> void;
|
||||
auto dmaPortRead(uint24 addr, uint8 data) -> uint8;
|
||||
auto dmaPortWrite(uint24 addr, uint8 data) -> void;
|
||||
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmio_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto io() -> void;
|
||||
auto read(uint24 addr) -> uint8;
|
||||
auto write(uint24 addr, uint8 data) -> void;
|
||||
|
||||
auto main() -> void;
|
||||
auto enable() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint8 wram[128 * 1024];
|
||||
vector<Thread*> coprocessors;
|
||||
|
||||
private:
|
||||
//cpu
|
||||
static auto Enter() -> void;
|
||||
|
||||
//timing
|
||||
auto queue_event(uint id) -> void;
|
||||
auto lastCycle() -> void;
|
||||
auto add_clocks(uint clocks) -> void;
|
||||
auto scanline() -> void;
|
||||
auto run_auto_joypad_poll() -> void;
|
||||
|
||||
struct QueueEvent {
|
||||
enum : uint {
|
||||
DramRefresh,
|
||||
HdmaRun,
|
||||
};
|
||||
};
|
||||
nall::priority_queue<uint> queue;
|
||||
|
||||
//memory
|
||||
auto speed(uint addr) const -> uint;
|
||||
|
||||
//dma
|
||||
auto dma_transfer_valid(uint8 bbus, uint abus) -> bool;
|
||||
auto dma_addr_valid(uint abus) -> bool;
|
||||
auto dma_read(uint abus) -> uint8;
|
||||
auto dma_write(bool valid, uint addr, uint8 data) -> void;
|
||||
auto dma_transfer(bool direction, uint8 bbus, uint abus) -> void;
|
||||
auto dma_bbus(uint i, uint index) -> uint8;
|
||||
auto dma_addr(uint i) -> uint;
|
||||
auto hdma_addr(uint i) -> uint;
|
||||
auto hdma_iaddr(uint i) -> uint;
|
||||
auto dma_run() -> void;
|
||||
auto hdma_active_after(uint i) -> bool;
|
||||
auto hdma_update(uint i) -> void;
|
||||
auto hdma_run() -> void;
|
||||
auto hdma_init() -> void;
|
||||
auto dma_reset() -> void;
|
||||
|
||||
//registers
|
||||
uint8 port_data[4];
|
||||
|
||||
struct Channel {
|
||||
bool dma_enabled;
|
||||
bool hdma_enabled;
|
||||
|
||||
bool direction;
|
||||
bool indirect;
|
||||
bool unused;
|
||||
bool reverse_transfer;
|
||||
bool fixed_transfer;
|
||||
uint8 transfer_mode;
|
||||
|
||||
uint8 dest_addr;
|
||||
uint16 source_addr;
|
||||
uint8 source_bank;
|
||||
|
||||
union {
|
||||
uint16_t transfer_size;
|
||||
uint16_t indirect_addr;
|
||||
};
|
||||
|
||||
uint8 indirect_bank;
|
||||
uint16 hdma_addr;
|
||||
uint8 line_counter;
|
||||
uint8 unknown;
|
||||
|
||||
bool hdma_completed;
|
||||
bool hdma_do_transfer;
|
||||
} channel[8];
|
||||
|
||||
struct Status {
|
||||
bool nmi_valid;
|
||||
bool nmi_line;
|
||||
bool nmi_transition;
|
||||
bool nmi_pending;
|
||||
|
||||
bool irq_valid;
|
||||
bool irq_line;
|
||||
bool irq_transition;
|
||||
bool irq_pending;
|
||||
|
||||
bool irq_lock;
|
||||
bool hdma_pending;
|
||||
|
||||
uint wram_addr;
|
||||
|
||||
bool joypad_strobe_latch;
|
||||
|
||||
bool nmi_enabled;
|
||||
bool virq_enabled;
|
||||
bool hirq_enabled;
|
||||
bool auto_joypad_poll_enabled;
|
||||
|
||||
uint8 pio;
|
||||
|
||||
uint8 wrmpya;
|
||||
uint8 wrmpyb;
|
||||
uint16 wrdiva;
|
||||
uint8 wrdivb;
|
||||
|
||||
uint16 htime;
|
||||
uint16 vtime;
|
||||
|
||||
uint rom_speed;
|
||||
|
||||
uint16 rddiv;
|
||||
uint16 rdmpy;
|
||||
|
||||
uint8 joy1l, joy1h;
|
||||
uint8 joy2l, joy2h;
|
||||
uint8 joy3l, joy3h;
|
||||
uint8 joy4l, joy4h;
|
||||
} status;
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
|
@ -1,200 +0,0 @@
|
|||
auto CPU::dma_transfer_valid(uint8 bbus, uint abus) -> bool {
|
||||
//transfers from WRAM to WRAM are invalid; chip only has one address bus
|
||||
if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto CPU::dma_addr_valid(uint abus) -> bool {
|
||||
//A-bus access to B-bus or S-CPU registers are invalid
|
||||
if((abus & 0x40ff00) == 0x2100) return false; //$[00-3f|80-bf]:[2100-21ff]
|
||||
if((abus & 0x40fe00) == 0x4000) return false; //$[00-3f|80-bf]:[4000-41ff]
|
||||
if((abus & 0x40ffe0) == 0x4200) return false; //$[00-3f|80-bf]:[4200-421f]
|
||||
if((abus & 0x40ff80) == 0x4300) return false; //$[00-3f|80-bf]:[4300-437f]
|
||||
return true;
|
||||
}
|
||||
|
||||
auto CPU::dma_read(uint abus) -> uint8 {
|
||||
if(dma_addr_valid(abus) == false) return 0x00;
|
||||
return bus.read(abus, regs.mdr);
|
||||
}
|
||||
|
||||
auto CPU::dma_write(bool valid, uint addr, uint8 data) -> void {
|
||||
if(valid) bus.write(addr, data);
|
||||
}
|
||||
|
||||
auto CPU::dma_transfer(bool direction, uint8 bbus, uint abus) -> void {
|
||||
if(direction == 0) {
|
||||
uint8 data = dma_read(abus);
|
||||
add_clocks(8);
|
||||
dma_write(dma_transfer_valid(bbus, abus), 0x2100 | bbus, data);
|
||||
} else {
|
||||
uint8 data = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus, regs.mdr) : (uint8)0x00;
|
||||
add_clocks(8);
|
||||
dma_write(dma_addr_valid(abus), abus, data);
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::dma_bbus(uint i, uint index) -> uint8 {
|
||||
switch(channel[i].transfer_mode) { default:
|
||||
case 0: return (channel[i].dest_addr); //0
|
||||
case 1: return (channel[i].dest_addr + (index & 1)); //0,1
|
||||
case 2: return (channel[i].dest_addr); //0,0
|
||||
case 3: return (channel[i].dest_addr + ((index >> 1) & 1)); //0,0,1,1
|
||||
case 4: return (channel[i].dest_addr + (index & 3)); //0,1,2,3
|
||||
case 5: return (channel[i].dest_addr + (index & 1)); //0,1,0,1
|
||||
case 6: return (channel[i].dest_addr); //0,0 [2]
|
||||
case 7: return (channel[i].dest_addr + ((index >> 1) & 1)); //0,0,1,1 [3]
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::dma_addr(uint i) -> uint {
|
||||
uint result = (channel[i].source_bank << 16) | (channel[i].source_addr);
|
||||
|
||||
if(channel[i].fixed_transfer == false) {
|
||||
if(channel[i].reverse_transfer == false) {
|
||||
channel[i].source_addr++;
|
||||
} else {
|
||||
channel[i].source_addr--;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
auto CPU::hdma_addr(uint i) -> uint {
|
||||
return (channel[i].source_bank << 16) | (channel[i].hdma_addr++);
|
||||
}
|
||||
|
||||
auto CPU::hdma_iaddr(uint i) -> uint {
|
||||
return (channel[i].indirect_bank << 16) | (channel[i].indirect_addr++);
|
||||
}
|
||||
|
||||
auto CPU::dma_run() -> void {
|
||||
add_clocks(16);
|
||||
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
if(channel[i].dma_enabled == false) continue;
|
||||
add_clocks(8);
|
||||
|
||||
uint index = 0;
|
||||
do {
|
||||
dma_transfer(channel[i].direction, dma_bbus(i, index++), dma_addr(i));
|
||||
} while(channel[i].dma_enabled && --channel[i].transfer_size);
|
||||
|
||||
channel[i].dma_enabled = false;
|
||||
}
|
||||
|
||||
status.irq_lock = true;
|
||||
}
|
||||
|
||||
auto CPU::hdma_active_after(uint i) -> bool {
|
||||
for(uint n = i + 1; i < 8; i++) {
|
||||
if(channel[i].hdma_enabled && !channel[i].hdma_completed) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto CPU::hdma_update(uint i) -> void {
|
||||
if((channel[i].line_counter & 0x7f) == 0) {
|
||||
channel[i].line_counter = dma_read(hdma_addr(i));
|
||||
channel[i].hdma_completed = (channel[i].line_counter == 0);
|
||||
channel[i].hdma_do_transfer = !channel[i].hdma_completed;
|
||||
add_clocks(8);
|
||||
|
||||
if(channel[i].indirect) {
|
||||
channel[i].indirect_addr = dma_read(hdma_addr(i)) << 8;
|
||||
add_clocks(8);
|
||||
|
||||
//emulating this glitch causes a slight slowdown; only enable if needed
|
||||
//if(!channel[i].hdma_completed || hdma_active_after(i)) {
|
||||
channel[i].indirect_addr >>= 8;
|
||||
channel[i].indirect_addr |= dma_read(hdma_addr(i)) << 8;
|
||||
add_clocks(8);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::hdma_run() -> void {
|
||||
uint channels = 0;
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
if(channel[i].hdma_enabled) channels++;
|
||||
}
|
||||
if(channels == 0) return;
|
||||
|
||||
add_clocks(16);
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
if(channel[i].hdma_enabled == false || channel[i].hdma_completed == true) continue;
|
||||
channel[i].dma_enabled = false;
|
||||
|
||||
if(channel[i].hdma_do_transfer) {
|
||||
static const uint transfer_length[] = {1, 2, 2, 4, 4, 4, 2, 4};
|
||||
uint length = transfer_length[channel[i].transfer_mode];
|
||||
for(uint index = 0; index < length; index++) {
|
||||
uint addr = channel[i].indirect == false ? hdma_addr(i) : hdma_iaddr(i);
|
||||
dma_transfer(channel[i].direction, dma_bbus(i, index), addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
if(channel[i].hdma_enabled == false || channel[i].hdma_completed == true) continue;
|
||||
|
||||
channel[i].line_counter--;
|
||||
channel[i].hdma_do_transfer = channel[i].line_counter & 0x80;
|
||||
hdma_update(i);
|
||||
}
|
||||
|
||||
status.irq_lock = true;
|
||||
}
|
||||
|
||||
auto CPU::hdma_init() -> void {
|
||||
uint channels = 0;
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
channel[i].hdma_completed = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
if(channel[i].hdma_enabled) channels++;
|
||||
}
|
||||
if(channels == 0) return;
|
||||
|
||||
add_clocks(16);
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
if(!channel[i].hdma_enabled) continue;
|
||||
channel[i].dma_enabled = false;
|
||||
|
||||
channel[i].hdma_addr = channel[i].source_addr;
|
||||
channel[i].line_counter = 0;
|
||||
hdma_update(i);
|
||||
}
|
||||
|
||||
status.irq_lock = true;
|
||||
}
|
||||
|
||||
auto CPU::dma_reset() -> void {
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
channel[i].dma_enabled = false;
|
||||
channel[i].hdma_enabled = false;
|
||||
|
||||
channel[i].direction = 1;
|
||||
channel[i].indirect = true;
|
||||
channel[i].unused = true;
|
||||
channel[i].reverse_transfer = true;
|
||||
channel[i].fixed_transfer = true;
|
||||
channel[i].transfer_mode = 0x07;
|
||||
|
||||
channel[i].dest_addr = 0xff;
|
||||
channel[i].source_addr = 0xffff;
|
||||
channel[i].source_bank = 0xff;
|
||||
|
||||
channel[i].transfer_size = 0xffff;
|
||||
channel[i].indirect_addr = 0xffff;
|
||||
|
||||
channel[i].indirect_bank = 0xff;
|
||||
channel[i].hdma_addr = 0xff;
|
||||
channel[i].line_counter = 0xff;
|
||||
channel[i].unknown = 0xff;
|
||||
|
||||
channel[i].hdma_completed = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
auto CPU::pio() -> uint8 {
|
||||
return status.pio;
|
||||
}
|
||||
|
||||
auto CPU::joylatch() -> bool {
|
||||
return status.joypad_strobe_latch;
|
||||
}
|
||||
|
||||
auto CPU::interruptPending() const -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto CPU::port_read(uint8 port) -> uint8 {
|
||||
return port_data[port & 3];
|
||||
}
|
||||
|
||||
auto CPU::port_write(uint8 port, uint8 data) -> void {
|
||||
port_data[port & 3] = data;
|
||||
}
|
||||
|
||||
auto CPU::io() -> void {
|
||||
add_clocks(6);
|
||||
}
|
||||
|
||||
auto CPU::read(uint24 addr) -> uint8 {
|
||||
regs.mdr = bus.read(addr, regs.mdr);
|
||||
add_clocks(speed(addr));
|
||||
return regs.mdr;
|
||||
}
|
||||
|
||||
auto CPU::write(uint24 addr, uint8 data) -> void {
|
||||
add_clocks(speed(addr));
|
||||
bus.write(addr, regs.mdr = data);
|
||||
}
|
||||
|
||||
auto CPU::speed(uint addr) const -> uint {
|
||||
if(addr & 0x408000) {
|
||||
if(addr & 0x800000) return status.rom_speed;
|
||||
return 8;
|
||||
}
|
||||
if((addr + 0x6000) & 0x4000) return 8;
|
||||
if((addr - 0x4000) & 0x7e00) return 6;
|
||||
return 12;
|
||||
}
|
|
@ -1,307 +0,0 @@
|
|||
auto CPU::dmaPortRead(uint24 addr, uint8 data) -> uint8 {
|
||||
return mmio_read(addr, data);
|
||||
}
|
||||
|
||||
auto CPU::dmaPortWrite(uint24 addr, uint8 data) -> void {
|
||||
return mmio_write(addr, data);
|
||||
}
|
||||
|
||||
auto CPU::mmio_read(uint addr, uint8 data) -> uint8 {
|
||||
if((addr & 0xffc0) == 0x2140) {
|
||||
synchronizeSMP();
|
||||
return smp.port_read(addr & 3);
|
||||
}
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
case 0x2180: {
|
||||
uint8 result = bus.read(0x7e0000 | status.wram_addr, regs.mdr);
|
||||
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
|
||||
return result;
|
||||
}
|
||||
|
||||
case 0x4016: {
|
||||
uint8 result = regs.mdr & 0xfc;
|
||||
result |= device.controllerPort1->data() & 3;
|
||||
return result;
|
||||
}
|
||||
|
||||
case 0x4017: {
|
||||
uint8 result = (regs.mdr & 0xe0) | 0x1c;
|
||||
result |= device.controllerPort2->data() & 3;
|
||||
return result;
|
||||
}
|
||||
|
||||
case 0x4210: {
|
||||
uint8 result = (regs.mdr & 0x70);
|
||||
result |= status.nmi_line << 7;
|
||||
result |= 0x02; //CPU revision
|
||||
status.nmi_line = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
case 0x4211: {
|
||||
uint8 result = (regs.mdr & 0x7f);
|
||||
result |= status.irq_line << 7;
|
||||
status.irq_line = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
case 0x4212: {
|
||||
uint8 result = (regs.mdr & 0x3e);
|
||||
unsigned vbstart = ppu.overscan() == false ? 225 : 240;
|
||||
|
||||
if(vcounter() >= vbstart && vcounter() <= vbstart + 2) result |= 0x01;
|
||||
if(hcounter() <= 2 || hcounter() >= 1096) result |= 0x40;
|
||||
if(vcounter() >= vbstart) result |= 0x80;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case 0x4213: return status.pio;
|
||||
|
||||
case 0x4214: return status.rddiv >> 0;
|
||||
case 0x4215: return status.rddiv >> 8;
|
||||
case 0x4216: return status.rdmpy >> 0;
|
||||
case 0x4217: return status.rdmpy >> 8;
|
||||
|
||||
case 0x4218: return status.joy1l;
|
||||
case 0x4219: return status.joy1h;
|
||||
case 0x421a: return status.joy2l;
|
||||
case 0x421b: return status.joy2h;
|
||||
case 0x421c: return status.joy3l;
|
||||
case 0x421d: return status.joy3h;
|
||||
case 0x421e: return status.joy4l;
|
||||
case 0x421f: return status.joy4h;
|
||||
}
|
||||
|
||||
if((addr & 0xff80) == 0x4300) {
|
||||
unsigned i = (addr >> 4) & 7;
|
||||
switch(addr & 0xff8f) {
|
||||
case 0x4300: {
|
||||
return (channel[i].direction << 7)
|
||||
| (channel[i].indirect << 6)
|
||||
| (channel[i].unused << 5)
|
||||
| (channel[i].reverse_transfer << 4)
|
||||
| (channel[i].fixed_transfer << 3)
|
||||
| (channel[i].transfer_mode << 0);
|
||||
}
|
||||
|
||||
case 0x4301: return channel[i].dest_addr;
|
||||
case 0x4302: return channel[i].source_addr >> 0;
|
||||
case 0x4303: return channel[i].source_addr >> 8;
|
||||
case 0x4304: return channel[i].source_bank;
|
||||
case 0x4305: return channel[i].transfer_size >> 0;
|
||||
case 0x4306: return channel[i].transfer_size >> 8;
|
||||
case 0x4307: return channel[i].indirect_bank;
|
||||
case 0x4308: return channel[i].hdma_addr >> 0;
|
||||
case 0x4309: return channel[i].hdma_addr >> 8;
|
||||
case 0x430a: return channel[i].line_counter;
|
||||
case 0x430b: case 0x430f: return channel[i].unknown;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto CPU::mmio_write(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xffc0) == 0x2140) {
|
||||
synchronizeSMP();
|
||||
port_write(addr & 3, data);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
case 0x2180: {
|
||||
bus.write(0x7e0000 | status.wram_addr, data);
|
||||
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2181: {
|
||||
status.wram_addr = (status.wram_addr & 0x01ff00) | (data << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2182: {
|
||||
status.wram_addr = (status.wram_addr & 0x0100ff) | (data << 8);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2183: {
|
||||
status.wram_addr = (status.wram_addr & 0x00ffff) | ((data & 1) << 16);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4016: {
|
||||
device.controllerPort1->latch(data & 1);
|
||||
device.controllerPort2->latch(data & 1);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4200: {
|
||||
bool nmi_enabled = status.nmi_enabled;
|
||||
bool virq_enabled = status.virq_enabled;
|
||||
bool hirq_enabled = status.hirq_enabled;
|
||||
|
||||
status.nmi_enabled = data & 0x80;
|
||||
status.virq_enabled = data & 0x20;
|
||||
status.hirq_enabled = data & 0x10;
|
||||
status.auto_joypad_poll_enabled = data & 0x01;
|
||||
|
||||
if(!nmi_enabled && status.nmi_enabled && status.nmi_line) {
|
||||
status.nmi_transition = true;
|
||||
}
|
||||
|
||||
if(status.virq_enabled && !status.hirq_enabled && status.irq_line) {
|
||||
status.irq_transition = true;
|
||||
}
|
||||
|
||||
if(!status.virq_enabled && !status.hirq_enabled) {
|
||||
status.irq_line = false;
|
||||
status.irq_transition = false;
|
||||
}
|
||||
|
||||
status.irq_lock = true;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4201: {
|
||||
if((status.pio & 0x80) && !(data & 0x80)) ppu.latch_counters();
|
||||
status.pio = data;
|
||||
}
|
||||
|
||||
case 0x4202: {
|
||||
status.wrmpya = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4203: {
|
||||
status.wrmpyb = data;
|
||||
status.rdmpy = status.wrmpya * status.wrmpyb;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4204: {
|
||||
status.wrdiva = (status.wrdiva & 0xff00) | (data << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4205: {
|
||||
status.wrdiva = (data << 8) | (status.wrdiva & 0x00ff);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4206: {
|
||||
status.wrdivb = data;
|
||||
status.rddiv = status.wrdivb ? status.wrdiva / status.wrdivb : 0xffff;
|
||||
status.rdmpy = status.wrdivb ? status.wrdiva % status.wrdivb : (uint)status.wrdiva;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4207: {
|
||||
status.htime = (status.htime & 0x0100) | (data << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4208: {
|
||||
status.htime = ((data & 1) << 8) | (status.htime & 0x00ff);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4209: {
|
||||
status.vtime = (status.vtime & 0x0100) | (data << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x420a: {
|
||||
status.vtime = ((data & 1) << 8) | (status.vtime & 0x00ff);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x420b: {
|
||||
for(unsigned i = 0; i < 8; i++) channel[i].dma_enabled = data & (1 << i);
|
||||
if(data) dma_run();
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x420c: {
|
||||
for(unsigned i = 0; i < 8; i++) channel[i].hdma_enabled = data & (1 << i);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x420d: {
|
||||
status.rom_speed = data & 1 ? 6 : 8;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if((addr & 0xff80) == 0x4300) {
|
||||
uint i = (addr >> 4) & 7;
|
||||
switch(addr & 0xff8f) {
|
||||
case 0x4300: {
|
||||
channel[i].direction = data & 0x80;
|
||||
channel[i].indirect = data & 0x40;
|
||||
channel[i].unused = data & 0x20;
|
||||
channel[i].reverse_transfer = data & 0x10;
|
||||
channel[i].fixed_transfer = data & 0x08;
|
||||
channel[i].transfer_mode = data & 0x07;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4301: {
|
||||
channel[i].dest_addr = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4302: {
|
||||
channel[i].source_addr = (channel[i].source_addr & 0xff00) | (data << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4303: {
|
||||
channel[i].source_addr = (data << 8) | (channel[i].source_addr & 0x00ff);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4304: {
|
||||
channel[i].source_bank = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4305: {
|
||||
channel[i].transfer_size = (channel[i].transfer_size & 0xff00) | (data << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4306: {
|
||||
channel[i].transfer_size = (data << 8) | (channel[i].transfer_size & 0x00ff);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4307: {
|
||||
channel[i].indirect_bank = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4308: {
|
||||
channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4309: {
|
||||
channel[i].hdma_addr = (data << 8) | (channel[i].hdma_addr & 0x00ff);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x430a: {
|
||||
channel[i].line_counter = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x430b: case 0x430f: {
|
||||
channel[i].unknown = data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
auto CPU::serialize(serializer& s) -> void {
|
||||
R65816::serialize(s);
|
||||
Thread::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(wram);
|
||||
|
||||
queue.serialize(s);
|
||||
s.array(port_data);
|
||||
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
s.integer(channel[i].dma_enabled);
|
||||
s.integer(channel[i].hdma_enabled);
|
||||
|
||||
s.integer(channel[i].direction);
|
||||
s.integer(channel[i].indirect);
|
||||
s.integer(channel[i].unused);
|
||||
s.integer(channel[i].reverse_transfer);
|
||||
s.integer(channel[i].fixed_transfer);
|
||||
s.integer(channel[i].transfer_mode);
|
||||
|
||||
s.integer(channel[i].dest_addr);
|
||||
s.integer(channel[i].source_addr);
|
||||
s.integer(channel[i].source_bank);
|
||||
|
||||
s.integer(channel[i].transfer_size);
|
||||
|
||||
s.integer(channel[i].indirect_bank);
|
||||
s.integer(channel[i].hdma_addr);
|
||||
s.integer(channel[i].line_counter);
|
||||
s.integer(channel[i].unknown);
|
||||
|
||||
s.integer(channel[i].hdma_completed);
|
||||
s.integer(channel[i].hdma_do_transfer);
|
||||
}
|
||||
|
||||
s.integer(status.nmi_valid);
|
||||
s.integer(status.nmi_line);
|
||||
s.integer(status.nmi_transition);
|
||||
s.integer(status.nmi_pending);
|
||||
|
||||
s.integer(status.irq_valid);
|
||||
s.integer(status.irq_line);
|
||||
s.integer(status.irq_transition);
|
||||
s.integer(status.irq_pending);
|
||||
|
||||
s.integer(status.irq_lock);
|
||||
s.integer(status.hdma_pending);
|
||||
|
||||
s.integer(status.wram_addr);
|
||||
|
||||
s.integer(status.joypad_strobe_latch);
|
||||
|
||||
s.integer(status.nmi_enabled);
|
||||
s.integer(status.virq_enabled);
|
||||
s.integer(status.hirq_enabled);
|
||||
s.integer(status.auto_joypad_poll_enabled);
|
||||
|
||||
s.integer(status.pio);
|
||||
|
||||
s.integer(status.wrmpya);
|
||||
s.integer(status.wrmpyb);
|
||||
s.integer(status.wrdiva);
|
||||
s.integer(status.wrdivb);
|
||||
|
||||
s.integer(status.htime);
|
||||
s.integer(status.vtime);
|
||||
|
||||
s.integer(status.rom_speed);
|
||||
|
||||
s.integer(status.rddiv);
|
||||
s.integer(status.rdmpy);
|
||||
|
||||
s.integer(status.joy1l);
|
||||
s.integer(status.joy1h);
|
||||
s.integer(status.joy2l);
|
||||
s.integer(status.joy2h);
|
||||
s.integer(status.joy3l);
|
||||
s.integer(status.joy3h);
|
||||
s.integer(status.joy4l);
|
||||
s.integer(status.joy4h);
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
auto CPU::queue_event(uint id) -> void {
|
||||
switch(id) {
|
||||
case QueueEvent::DramRefresh: return add_clocks(40);
|
||||
case QueueEvent::HdmaRun: return hdma_run();
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::lastCycle() -> void {
|
||||
if(status.irq_lock) {
|
||||
status.irq_lock = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(status.nmi_transition) {
|
||||
regs.wai = false;
|
||||
status.nmi_transition = false;
|
||||
status.nmi_pending = true;
|
||||
}
|
||||
|
||||
if(status.irq_transition || regs.irq) {
|
||||
regs.wai = false;
|
||||
status.irq_transition = false;
|
||||
status.irq_pending = !regs.p.i;
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::add_clocks(uint clocks) -> void {
|
||||
if(status.hirq_enabled) {
|
||||
if(status.virq_enabled) {
|
||||
uint cpu_time = vcounter() * 1364 + hcounter();
|
||||
uint irq_time = status.vtime * 1364 + status.htime * 4;
|
||||
uint framelines = (system.region() == System::Region::NTSC ? 262 : 312) + (ppu.interlace() && !field());
|
||||
if(cpu_time > irq_time) irq_time += framelines * 1364;
|
||||
bool irq_valid = status.irq_valid;
|
||||
status.irq_valid = cpu_time <= irq_time && cpu_time + clocks > irq_time;
|
||||
if(!irq_valid && status.irq_valid) status.irq_line = true;
|
||||
} else {
|
||||
uint irq_time = status.htime * 4;
|
||||
if(hcounter() > irq_time) irq_time += 1364;
|
||||
bool irq_valid = status.irq_valid;
|
||||
status.irq_valid = hcounter() <= irq_time && hcounter() + clocks > irq_time;
|
||||
if(!irq_valid && status.irq_valid) status.irq_line = true;
|
||||
}
|
||||
if(status.irq_line) status.irq_transition = true;
|
||||
} else if(status.virq_enabled) {
|
||||
bool irq_valid = status.irq_valid;
|
||||
status.irq_valid = vcounter() == status.vtime;
|
||||
if(!irq_valid && status.irq_valid) status.irq_line = true;
|
||||
if(status.irq_line) status.irq_transition = true;
|
||||
} else {
|
||||
status.irq_valid = false;
|
||||
}
|
||||
|
||||
tick(clocks);
|
||||
queue.tick(clocks);
|
||||
step(clocks);
|
||||
}
|
||||
|
||||
auto CPU::scanline() -> void {
|
||||
synchronizeSMP();
|
||||
synchronizePPU();
|
||||
synchronizeCoprocessors();
|
||||
|
||||
if(vcounter() == 0) hdma_init();
|
||||
|
||||
queue.enqueue(534, QueueEvent::DramRefresh);
|
||||
|
||||
if(vcounter() <= (ppu.overscan() == false ? 224 : 239)) {
|
||||
queue.enqueue(1104 + 8, QueueEvent::HdmaRun);
|
||||
}
|
||||
|
||||
bool nmi_valid = status.nmi_valid;
|
||||
status.nmi_valid = vcounter() >= (ppu.overscan() == false ? 225 : 240);
|
||||
if(!nmi_valid && status.nmi_valid) {
|
||||
status.nmi_line = true;
|
||||
if(status.nmi_enabled) status.nmi_transition = true;
|
||||
} else if(nmi_valid && !status.nmi_valid) {
|
||||
status.nmi_line = false;
|
||||
}
|
||||
|
||||
if(status.auto_joypad_poll_enabled && vcounter() == (ppu.overscan() == false ? 227 : 242)) {
|
||||
run_auto_joypad_poll();
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::run_auto_joypad_poll() -> void {
|
||||
device.controllerPort1->latch(1);
|
||||
device.controllerPort2->latch(1);
|
||||
device.controllerPort1->latch(0);
|
||||
device.controllerPort2->latch(0);
|
||||
|
||||
uint16 joy1 = 0, joy2 = 0, joy3 = 0, joy4 = 0;
|
||||
for(uint i = 0; i < 16; i++) {
|
||||
uint8 port0 = device.controllerPort1->data();
|
||||
uint8 port1 = device.controllerPort2->data();
|
||||
|
||||
joy1 |= (port0 & 1) ? (0x8000 >> i) : 0;
|
||||
joy2 |= (port1 & 1) ? (0x8000 >> i) : 0;
|
||||
joy3 |= (port0 & 2) ? (0x8000 >> i) : 0;
|
||||
joy4 |= (port1 & 2) ? (0x8000 >> i) : 0;
|
||||
}
|
||||
|
||||
status.joy1l = joy1;
|
||||
status.joy1h = joy1 >> 8;
|
||||
|
||||
status.joy2l = joy2;
|
||||
status.joy2h = joy2 >> 8;
|
||||
|
||||
status.joy3l = joy3;
|
||||
status.joy3h = joy3 >> 8;
|
||||
|
||||
status.joy4l = joy4;
|
||||
status.joy4h = joy4 >> 8;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,307 +0,0 @@
|
|||
// Highly accurate SNES SPC-700 DSP emulator
|
||||
|
||||
// snes_spc 0.9.0
|
||||
#ifndef SPC_DSP_H
|
||||
#define SPC_DSP_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); }
|
||||
|
||||
class SPC_DSP {
|
||||
public:
|
||||
typedef BOOST::uint8_t uint8_t;
|
||||
|
||||
// Setup
|
||||
|
||||
// Initializes DSP and has it use the 64K RAM provided
|
||||
void init( void* ram_64k );
|
||||
|
||||
// Sets destination for output samples. If out is NULL or out_size is 0,
|
||||
// doesn't generate any.
|
||||
typedef short sample_t;
|
||||
void set_output( sample_t* out, int out_size );
|
||||
|
||||
// Number of samples written to output since it was last set, always
|
||||
// a multiple of 2. Undefined if more samples were generated than
|
||||
// output buffer could hold.
|
||||
int sample_count() const;
|
||||
|
||||
// Emulation
|
||||
|
||||
// Resets DSP to power-on state
|
||||
void reset();
|
||||
|
||||
// Emulates pressing reset switch on SNES
|
||||
void soft_reset();
|
||||
|
||||
// Reads/writes DSP registers. For accuracy, you must first call run()
|
||||
// to catch the DSP up to present.
|
||||
int read ( int addr ) const;
|
||||
void write( int addr, int data );
|
||||
|
||||
// Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks
|
||||
// a pair of samples is be generated.
|
||||
void run( int clock_count );
|
||||
|
||||
// Sound control
|
||||
|
||||
// Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events).
|
||||
// Reduces emulation accuracy.
|
||||
enum { voice_count = 8 };
|
||||
void mute_voices( int mask );
|
||||
|
||||
// State
|
||||
|
||||
// Resets DSP and uses supplied values to initialize registers
|
||||
enum { register_count = 128 };
|
||||
void load( uint8_t const regs [register_count] );
|
||||
|
||||
// Saves/loads exact emulator state
|
||||
enum { state_size = 640 }; // maximum space needed when saving
|
||||
typedef dsp_copy_func_t copy_func_t;
|
||||
void copy_state( unsigned char** io, copy_func_t );
|
||||
|
||||
// Returns non-zero if new key-on events occurred since last call
|
||||
bool check_kon();
|
||||
|
||||
// DSP register addresses
|
||||
|
||||
// Global registers
|
||||
enum {
|
||||
r_mvoll = 0x0C, r_mvolr = 0x1C,
|
||||
r_evoll = 0x2C, r_evolr = 0x3C,
|
||||
r_kon = 0x4C, r_koff = 0x5C,
|
||||
r_flg = 0x6C, r_endx = 0x7C,
|
||||
r_efb = 0x0D, r_pmon = 0x2D,
|
||||
r_non = 0x3D, r_eon = 0x4D,
|
||||
r_dir = 0x5D, r_esa = 0x6D,
|
||||
r_edl = 0x7D,
|
||||
r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F
|
||||
};
|
||||
|
||||
// Voice registers
|
||||
enum {
|
||||
v_voll = 0x00, v_volr = 0x01,
|
||||
v_pitchl = 0x02, v_pitchh = 0x03,
|
||||
v_srcn = 0x04, v_adsr0 = 0x05,
|
||||
v_adsr1 = 0x06, v_gain = 0x07,
|
||||
v_envx = 0x08, v_outx = 0x09
|
||||
};
|
||||
|
||||
public:
|
||||
enum { extra_size = 16 };
|
||||
sample_t* extra() { return m.extra; }
|
||||
sample_t const* out_pos() const { return m.out; }
|
||||
void disable_surround( bool ) { } // not supported
|
||||
public:
|
||||
BLARGG_DISABLE_NOTHROW
|
||||
|
||||
typedef BOOST::int8_t int8_t;
|
||||
typedef BOOST::int16_t int16_t;
|
||||
|
||||
enum { echo_hist_size = 8 };
|
||||
|
||||
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
|
||||
enum { brr_buf_size = 12 };
|
||||
struct voice_t
|
||||
{
|
||||
int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling)
|
||||
int buf_pos; // place in buffer where next samples will be decoded
|
||||
int interp_pos; // relative fractional position in sample (0x1000 = 1.0)
|
||||
int brr_addr; // address of current BRR block
|
||||
int brr_offset; // current decoding offset in BRR block
|
||||
uint8_t* regs; // pointer to voice's DSP registers
|
||||
int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc.
|
||||
int kon_delay; // KON delay/current setup phase
|
||||
env_mode_t env_mode;
|
||||
int env; // current envelope level
|
||||
int hidden_env; // used by GAIN mode 7, very obscure quirk
|
||||
uint8_t t_envx_out;
|
||||
};
|
||||
private:
|
||||
enum { brr_block_size = 9 };
|
||||
|
||||
struct state_t
|
||||
{
|
||||
uint8_t regs [register_count];
|
||||
|
||||
// Echo history keeps most recent 8 samples (twice the size to simplify wrap handling)
|
||||
int echo_hist [echo_hist_size * 2] [2];
|
||||
int (*echo_hist_pos) [2]; // &echo_hist [0 to 7]
|
||||
|
||||
int every_other_sample; // toggles every sample
|
||||
int kon; // KON value when last checked
|
||||
int noise;
|
||||
int counter;
|
||||
int echo_offset; // offset from ESA in echo buffer
|
||||
int echo_length; // number of bytes that echo_offset will stop at
|
||||
int phase; // next clock cycle to run (0-31)
|
||||
bool kon_check; // set when a new KON occurs
|
||||
|
||||
// Hidden registers also written to when main register is written to
|
||||
int new_kon;
|
||||
uint8_t endx_buf;
|
||||
uint8_t envx_buf;
|
||||
uint8_t outx_buf;
|
||||
|
||||
// Temporary state between clocks
|
||||
|
||||
// read once per sample
|
||||
int t_pmon;
|
||||
int t_non;
|
||||
int t_eon;
|
||||
int t_dir;
|
||||
int t_koff;
|
||||
|
||||
// read a few clocks ahead then used
|
||||
int t_brr_next_addr;
|
||||
int t_adsr0;
|
||||
int t_brr_header;
|
||||
int t_brr_byte;
|
||||
int t_srcn;
|
||||
int t_esa;
|
||||
int t_echo_enabled;
|
||||
|
||||
// internal state that is recalculated every sample
|
||||
int t_dir_addr;
|
||||
int t_pitch;
|
||||
int t_output;
|
||||
int t_looped;
|
||||
int t_echo_ptr;
|
||||
|
||||
// left/right sums
|
||||
int t_main_out [2];
|
||||
int t_echo_out [2];
|
||||
int t_echo_in [2];
|
||||
|
||||
voice_t voices [voice_count];
|
||||
|
||||
// non-emulation state
|
||||
uint8_t* ram; // 64K shared RAM between DSP and SMP
|
||||
int mute_mask;
|
||||
sample_t* out;
|
||||
sample_t* out_end;
|
||||
sample_t* out_begin;
|
||||
sample_t extra [extra_size];
|
||||
};
|
||||
state_t m;
|
||||
|
||||
void init_counter();
|
||||
void run_counters();
|
||||
unsigned read_counter( int rate );
|
||||
|
||||
int interpolate( voice_t const* v );
|
||||
void run_envelope( voice_t* const v );
|
||||
void decode_brr( voice_t* v );
|
||||
|
||||
void misc_27();
|
||||
void misc_28();
|
||||
void misc_29();
|
||||
void misc_30();
|
||||
|
||||
void voice_output( voice_t const* v, int ch );
|
||||
void voice_V1( voice_t* const );
|
||||
void voice_V2( voice_t* const );
|
||||
void voice_V3( voice_t* const );
|
||||
void voice_V3a( voice_t* const );
|
||||
void voice_V3b( voice_t* const );
|
||||
void voice_V3c( voice_t* const );
|
||||
void voice_V4( voice_t* const );
|
||||
void voice_V5( voice_t* const );
|
||||
void voice_V6( voice_t* const );
|
||||
void voice_V7( voice_t* const );
|
||||
void voice_V8( voice_t* const );
|
||||
void voice_V9( voice_t* const );
|
||||
void voice_V7_V4_V1( voice_t* const );
|
||||
void voice_V8_V5_V2( voice_t* const );
|
||||
void voice_V9_V6_V3( voice_t* const );
|
||||
|
||||
void echo_read( int ch );
|
||||
int echo_output( int ch );
|
||||
void echo_write( int ch );
|
||||
void echo_22();
|
||||
void echo_23();
|
||||
void echo_24();
|
||||
void echo_25();
|
||||
void echo_26();
|
||||
void echo_27();
|
||||
void echo_28();
|
||||
void echo_29();
|
||||
void echo_30();
|
||||
|
||||
void soft_reset_common();
|
||||
|
||||
public:
|
||||
bool mute() { return m.regs[r_flg] & 0x40; }
|
||||
};
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; }
|
||||
|
||||
inline int SPC_DSP::read( int addr ) const
|
||||
{
|
||||
assert( (unsigned) addr < register_count );
|
||||
return m.regs [addr];
|
||||
}
|
||||
|
||||
inline void SPC_DSP::write( int addr, int data )
|
||||
{
|
||||
assert( (unsigned) addr < register_count );
|
||||
|
||||
m.regs [addr] = (uint8_t) data;
|
||||
switch ( addr & 0x0F )
|
||||
{
|
||||
case v_envx:
|
||||
m.envx_buf = (uint8_t) data;
|
||||
break;
|
||||
|
||||
case v_outx:
|
||||
m.outx_buf = (uint8_t) data;
|
||||
break;
|
||||
|
||||
case 0x0C:
|
||||
if ( addr == r_kon )
|
||||
m.new_kon = (uint8_t) data;
|
||||
|
||||
if ( addr == r_endx ) // always cleared, regardless of data written
|
||||
{
|
||||
m.endx_buf = 0;
|
||||
m.regs [r_endx] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; }
|
||||
|
||||
inline bool SPC_DSP::check_kon()
|
||||
{
|
||||
bool old = m.kon_check;
|
||||
m.kon_check = 0;
|
||||
return old;
|
||||
}
|
||||
|
||||
#if !SPC_NO_COPY_STATE_FUNCS
|
||||
|
||||
class SPC_State_Copier {
|
||||
SPC_DSP::copy_func_t func;
|
||||
unsigned char** buf;
|
||||
public:
|
||||
SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; }
|
||||
void copy( void* state, size_t size );
|
||||
int copy_int( int state, int size );
|
||||
void skip( int count );
|
||||
void extra();
|
||||
};
|
||||
|
||||
#define SPC_COPY( type, state )\
|
||||
{\
|
||||
state = (BOOST::type) copier.copy_int( state, sizeof (BOOST::type) );\
|
||||
assert( (BOOST::type) state == state );\
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,186 +0,0 @@
|
|||
// Sets up common environment for Shay Green's libraries.
|
||||
// To change configuration options, modify blargg_config.h, not this file.
|
||||
|
||||
// snes_spc 0.9.0
|
||||
#ifndef BLARGG_COMMON_H
|
||||
#define BLARGG_COMMON_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#undef BLARGG_COMMON_H
|
||||
// allow blargg_config.h to #include blargg_common.h
|
||||
#include "blargg_config.h"
|
||||
#ifndef BLARGG_COMMON_H
|
||||
#define BLARGG_COMMON_H
|
||||
|
||||
// BLARGG_RESTRICT: equivalent to restrict, where supported
|
||||
#if defined (__GNUC__) || _MSC_VER >= 1100
|
||||
#define BLARGG_RESTRICT __restrict
|
||||
#else
|
||||
#define BLARGG_RESTRICT
|
||||
#endif
|
||||
|
||||
// STATIC_CAST(T,expr): Used in place of static_cast<T> (expr)
|
||||
#ifndef STATIC_CAST
|
||||
#define STATIC_CAST(T,expr) ((T) (expr))
|
||||
#endif
|
||||
|
||||
// blargg_err_t (0 on success, otherwise error string)
|
||||
#ifndef blargg_err_t
|
||||
typedef const char* blargg_err_t;
|
||||
#endif
|
||||
|
||||
// blargg_vector - very lightweight vector of POD types (no constructor/destructor)
|
||||
template<class T>
|
||||
class blargg_vector {
|
||||
T* begin_;
|
||||
size_t size_;
|
||||
public:
|
||||
blargg_vector() : begin_( 0 ), size_( 0 ) { }
|
||||
~blargg_vector() { free( begin_ ); }
|
||||
size_t size() const { return size_; }
|
||||
T* begin() const { return begin_; }
|
||||
T* end() const { return begin_ + size_; }
|
||||
blargg_err_t resize( size_t n )
|
||||
{
|
||||
// TODO: blargg_common.cpp to hold this as an outline function, ugh
|
||||
void* p = realloc( begin_, n * sizeof (T) );
|
||||
if ( p )
|
||||
begin_ = (T*) p;
|
||||
else if ( n > size_ ) // realloc failure only a problem if expanding
|
||||
return "Out of memory";
|
||||
size_ = n;
|
||||
return 0;
|
||||
}
|
||||
void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); }
|
||||
T& operator [] ( size_t n ) const
|
||||
{
|
||||
assert( n <= size_ ); // <= to allow past-the-end value
|
||||
return begin_ [n];
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef BLARGG_DISABLE_NOTHROW
|
||||
// throw spec mandatory in ISO C++ if operator new can return NULL
|
||||
#if __cplusplus >= 199711 || defined (__GNUC__)
|
||||
#define BLARGG_THROWS( spec ) throw spec
|
||||
#else
|
||||
#define BLARGG_THROWS( spec )
|
||||
#endif
|
||||
#define BLARGG_DISABLE_NOTHROW \
|
||||
void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\
|
||||
void operator delete ( void* p ) { free( p ); }
|
||||
#define BLARGG_NEW new
|
||||
#else
|
||||
#include <new>
|
||||
#define BLARGG_NEW new (std::nothrow)
|
||||
#endif
|
||||
|
||||
// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant)
|
||||
#define BLARGG_4CHAR( a, b, c, d ) \
|
||||
((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF))
|
||||
|
||||
// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
|
||||
#ifndef BOOST_STATIC_ASSERT
|
||||
#ifdef _MSC_VER
|
||||
// MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified
|
||||
#define BOOST_STATIC_ASSERT( expr ) \
|
||||
void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] )
|
||||
#else
|
||||
// Some other compilers fail when declaring same function multiple times in class,
|
||||
// so differentiate them by line
|
||||
#define BOOST_STATIC_ASSERT( expr ) \
|
||||
void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1,
|
||||
// compiler is assumed to support bool. If undefined, availability is determined.
|
||||
#ifndef BLARGG_COMPILER_HAS_BOOL
|
||||
#if defined (__MWERKS__)
|
||||
#if !__option(bool)
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#endif
|
||||
#elif defined (_MSC_VER)
|
||||
#if _MSC_VER < 1100
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#endif
|
||||
#elif defined (__GNUC__)
|
||||
// supports bool
|
||||
#elif __cplusplus < 199711
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#endif
|
||||
#endif
|
||||
#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
|
||||
// If you get errors here, modify your blargg_config.h file
|
||||
typedef int bool;
|
||||
const bool true = 1;
|
||||
const bool false = 0;
|
||||
#endif
|
||||
|
||||
// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough
|
||||
|
||||
#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF
|
||||
typedef long blargg_long;
|
||||
#else
|
||||
typedef int blargg_long;
|
||||
#endif
|
||||
|
||||
#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF
|
||||
typedef unsigned long blargg_ulong;
|
||||
#else
|
||||
typedef unsigned blargg_ulong;
|
||||
#endif
|
||||
|
||||
// BOOST::int8_t etc.
|
||||
|
||||
// HAVE_STDINT_H: If defined, use <stdint.h> for int8_t etc.
|
||||
#if defined (HAVE_STDINT_H)
|
||||
#include <stdint.h>
|
||||
#define BOOST
|
||||
|
||||
// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
|
||||
#elif defined (HAVE_INTTYPES_H)
|
||||
#include <inttypes.h>
|
||||
#define BOOST
|
||||
|
||||
#else
|
||||
struct BOOST
|
||||
{
|
||||
#if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
#else
|
||||
// No suitable 8-bit type available
|
||||
typedef struct see_blargg_common_h int8_t;
|
||||
typedef struct see_blargg_common_h uint8_t;
|
||||
#endif
|
||||
|
||||
#if USHRT_MAX == 0xFFFF
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
#else
|
||||
// No suitable 16-bit type available
|
||||
typedef struct see_blargg_common_h int16_t;
|
||||
typedef struct see_blargg_common_h uint16_t;
|
||||
#endif
|
||||
|
||||
#if ULONG_MAX == 0xFFFFFFFF
|
||||
typedef long int32_t;
|
||||
typedef unsigned long uint32_t;
|
||||
#elif UINT_MAX == 0xFFFFFFFF
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
// No suitable 32-bit type available
|
||||
typedef struct see_blargg_common_h int32_t;
|
||||
typedef struct see_blargg_common_h uint32_t;
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,24 +0,0 @@
|
|||
// snes_spc 0.9.0 user configuration file. Don't replace when updating library.
|
||||
|
||||
// snes_spc 0.9.0
|
||||
#ifndef BLARGG_CONFIG_H
|
||||
#define BLARGG_CONFIG_H
|
||||
|
||||
// Uncomment to disable debugging checks
|
||||
#define NDEBUG 1
|
||||
|
||||
// Uncomment to enable platform-specific (and possibly non-portable) optimizations
|
||||
//#define BLARGG_NONPORTABLE 1
|
||||
|
||||
// Uncomment if automatic byte-order determination doesn't work
|
||||
//#define BLARGG_BIG_ENDIAN 1
|
||||
|
||||
// Uncomment if you get errors in the bool section of blargg_common.h
|
||||
//#define BLARGG_COMPILER_HAS_BOOL 1
|
||||
|
||||
// Use standard config.h if present
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,185 +0,0 @@
|
|||
// CPU Byte Order Utilities
|
||||
|
||||
// snes_spc 0.9.0
|
||||
#ifndef BLARGG_ENDIAN
|
||||
#define BLARGG_ENDIAN
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
|
||||
#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
|
||||
defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
|
||||
#define BLARGG_CPU_X86 1
|
||||
#define BLARGG_CPU_CISC 1
|
||||
#endif
|
||||
|
||||
#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc)
|
||||
#define BLARGG_CPU_POWERPC 1
|
||||
#define BLARGG_CPU_RISC 1
|
||||
#endif
|
||||
|
||||
// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
|
||||
// one may be #defined to 1. Only needed if something actually depends on byte order.
|
||||
#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
|
||||
#ifdef __GLIBC__
|
||||
// GCC handles this for us
|
||||
#include <endian.h>
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define BLARGG_BIG_ENDIAN 1
|
||||
#endif
|
||||
#else
|
||||
|
||||
#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \
|
||||
(defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234)
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \
|
||||
defined (__sparc__) || BLARGG_CPU_POWERPC || \
|
||||
(defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321)
|
||||
#define BLARGG_BIG_ENDIAN 1
|
||||
#elif !defined (__mips__)
|
||||
// No endian specified; assume little-endian, since it's most common
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN
|
||||
#undef BLARGG_LITTLE_ENDIAN
|
||||
#undef BLARGG_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
inline void blargg_verify_byte_order()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
#if BLARGG_BIG_ENDIAN
|
||||
volatile int i = 1;
|
||||
assert( *(volatile char*) &i == 0 );
|
||||
#elif BLARGG_LITTLE_ENDIAN
|
||||
volatile int i = 1;
|
||||
assert( *(volatile char*) &i != 0 );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
inline unsigned get_le16( void const* p )
|
||||
{
|
||||
return (unsigned) ((unsigned char const*) p) [1] << 8 |
|
||||
(unsigned) ((unsigned char const*) p) [0];
|
||||
}
|
||||
|
||||
inline unsigned get_be16( void const* p )
|
||||
{
|
||||
return (unsigned) ((unsigned char const*) p) [0] << 8 |
|
||||
(unsigned) ((unsigned char const*) p) [1];
|
||||
}
|
||||
|
||||
inline blargg_ulong get_le32( void const* p )
|
||||
{
|
||||
return (blargg_ulong) ((unsigned char const*) p) [3] << 24 |
|
||||
(blargg_ulong) ((unsigned char const*) p) [2] << 16 |
|
||||
(blargg_ulong) ((unsigned char const*) p) [1] << 8 |
|
||||
(blargg_ulong) ((unsigned char const*) p) [0];
|
||||
}
|
||||
|
||||
inline blargg_ulong get_be32( void const* p )
|
||||
{
|
||||
return (blargg_ulong) ((unsigned char const*) p) [0] << 24 |
|
||||
(blargg_ulong) ((unsigned char const*) p) [1] << 16 |
|
||||
(blargg_ulong) ((unsigned char const*) p) [2] << 8 |
|
||||
(blargg_ulong) ((unsigned char const*) p) [3];
|
||||
}
|
||||
|
||||
inline void set_le16( void* p, unsigned n )
|
||||
{
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [0] = (unsigned char) n;
|
||||
}
|
||||
|
||||
inline void set_be16( void* p, unsigned n )
|
||||
{
|
||||
((unsigned char*) p) [0] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [1] = (unsigned char) n;
|
||||
}
|
||||
|
||||
inline void set_le32( void* p, blargg_ulong n )
|
||||
{
|
||||
((unsigned char*) p) [0] = (unsigned char) n;
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [2] = (unsigned char) (n >> 16);
|
||||
((unsigned char*) p) [3] = (unsigned char) (n >> 24);
|
||||
}
|
||||
|
||||
inline void set_be32( void* p, blargg_ulong n )
|
||||
{
|
||||
((unsigned char*) p) [3] = (unsigned char) n;
|
||||
((unsigned char*) p) [2] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 16);
|
||||
((unsigned char*) p) [0] = (unsigned char) (n >> 24);
|
||||
}
|
||||
|
||||
#if BLARGG_NONPORTABLE
|
||||
// Optimized implementation if byte order is known
|
||||
#if BLARGG_LITTLE_ENDIAN
|
||||
#define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr))
|
||||
#define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr))
|
||||
#define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
||||
#define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
||||
#elif BLARGG_BIG_ENDIAN
|
||||
#define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr))
|
||||
#define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr))
|
||||
#define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
||||
#define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
||||
|
||||
#if BLARGG_CPU_POWERPC
|
||||
// PowerPC has special byte-reversed instructions
|
||||
#if defined (__MWERKS__)
|
||||
#define GET_LE16( addr ) (__lhbrx( addr, 0 ))
|
||||
#define GET_LE32( addr ) (__lwbrx( addr, 0 ))
|
||||
#define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 ))
|
||||
#define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 ))
|
||||
#elif defined (__GNUC__)
|
||||
#define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;})
|
||||
#define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;})
|
||||
#define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );})
|
||||
#define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );})
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GET_LE16
|
||||
#define GET_LE16( addr ) get_le16( addr )
|
||||
#define SET_LE16( addr, data ) set_le16( addr, data )
|
||||
#endif
|
||||
|
||||
#ifndef GET_LE32
|
||||
#define GET_LE32( addr ) get_le32( addr )
|
||||
#define SET_LE32( addr, data ) set_le32( addr, data )
|
||||
#endif
|
||||
|
||||
#ifndef GET_BE16
|
||||
#define GET_BE16( addr ) get_be16( addr )
|
||||
#define SET_BE16( addr, data ) set_be16( addr, data )
|
||||
#endif
|
||||
|
||||
#ifndef GET_BE32
|
||||
#define GET_BE32( addr ) get_be32( addr )
|
||||
#define SET_BE32( addr, data ) set_be32( addr, data )
|
||||
#endif
|
||||
|
||||
// auto-selecting versions
|
||||
|
||||
inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); }
|
||||
inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); }
|
||||
inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); }
|
||||
inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); }
|
||||
inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); }
|
||||
inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); }
|
||||
inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); }
|
||||
inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); }
|
||||
|
||||
#endif
|
|
@ -1,100 +0,0 @@
|
|||
/* Included at the beginning of library source files, after all other #include lines.
|
||||
Sets up helpful macros and services used in my source code. They don't need
|
||||
module an annoying module prefix on their names since they are defined after
|
||||
all other #include lines. */
|
||||
|
||||
// snes_spc 0.9.0
|
||||
#ifndef BLARGG_SOURCE_H
|
||||
#define BLARGG_SOURCE_H
|
||||
|
||||
// If debugging is enabled, abort program if expr is false. Meant for checking
|
||||
// internal state and consistency. A failed assertion indicates a bug in the module.
|
||||
// void assert( bool expr );
|
||||
#include <assert.h>
|
||||
|
||||
// If debugging is enabled and expr is false, abort program. Meant for checking
|
||||
// caller-supplied parameters and operations that are outside the control of the
|
||||
// module. A failed requirement indicates a bug outside the module.
|
||||
// void require( bool expr );
|
||||
#undef require
|
||||
#define require( expr ) assert( expr )
|
||||
|
||||
// Like printf() except output goes to debug log file. Might be defined to do
|
||||
// nothing (not even evaluate its arguments).
|
||||
// void dprintf( const char* format, ... );
|
||||
static inline void blargg_dprintf_( const char*, ... ) { }
|
||||
#undef dprintf
|
||||
#define dprintf (1) ? (void) 0 : blargg_dprintf_
|
||||
|
||||
// If enabled, evaluate expr and if false, make debug log entry with source file
|
||||
// and line. Meant for finding situations that should be examined further, but that
|
||||
// don't indicate a problem. In all cases, execution continues normally.
|
||||
#undef check
|
||||
#define check( expr ) ((void) 0)
|
||||
|
||||
// If expr yields error string, return it from current function, otherwise continue.
|
||||
#undef RETURN_ERR
|
||||
#define RETURN_ERR( expr ) do { \
|
||||
blargg_err_t blargg_return_err_ = (expr); \
|
||||
if ( blargg_return_err_ ) return blargg_return_err_; \
|
||||
} while ( 0 )
|
||||
|
||||
// If ptr is 0, return out of memory error string.
|
||||
#undef CHECK_ALLOC
|
||||
#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 )
|
||||
|
||||
// Avoid any macros which evaluate their arguments multiple times
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
#define DEF_MIN_MAX( type ) \
|
||||
static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\
|
||||
static inline type max( type x, type y ) { if ( y < x ) return x; return y; }
|
||||
|
||||
DEF_MIN_MAX( int )
|
||||
DEF_MIN_MAX( unsigned )
|
||||
DEF_MIN_MAX( long )
|
||||
DEF_MIN_MAX( unsigned long )
|
||||
DEF_MIN_MAX( float )
|
||||
DEF_MIN_MAX( double )
|
||||
|
||||
#undef DEF_MIN_MAX
|
||||
|
||||
/*
|
||||
// using const references generates crappy code, and I am currenly only using these
|
||||
// for built-in types, so they take arguments by value
|
||||
|
||||
// TODO: remove
|
||||
inline int min( int x, int y )
|
||||
template<class T>
|
||||
inline T min( T x, T y )
|
||||
{
|
||||
if ( x < y )
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T max( T x, T y )
|
||||
{
|
||||
if ( x < y )
|
||||
return y;
|
||||
return x;
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: good idea? bad idea?
|
||||
#undef byte
|
||||
#define byte byte_
|
||||
typedef unsigned char byte;
|
||||
|
||||
// deprecated
|
||||
#define BLARGG_CHECK_ALLOC CHECK_ALLOC
|
||||
#define BLARGG_RETURN_ERR RETURN_ERR
|
||||
|
||||
// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check
|
||||
#ifdef BLARGG_SOURCE_BEGIN
|
||||
#include BLARGG_SOURCE_BEGIN
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,71 +0,0 @@
|
|||
#include <sfc/sfc.hpp>
|
||||
|
||||
namespace SuperFamicom {
|
||||
|
||||
#include <sfc/dsp/audio.cpp>
|
||||
DSP dsp;
|
||||
|
||||
#include "serialization.cpp"
|
||||
#include "SPC_DSP.cpp"
|
||||
|
||||
DSP::DSP() {
|
||||
for(auto i : range(8)) channel_enabled[i] = true;
|
||||
}
|
||||
|
||||
auto DSP::step(uint clocks) -> void {
|
||||
clock += clocks;
|
||||
}
|
||||
|
||||
auto DSP::synchronizeSMP() -> void {
|
||||
if(SMP::Threaded == true) {
|
||||
if(clock >= 0 && !scheduler.synchronizing()) co_switch(smp.thread);
|
||||
} else {
|
||||
while(clock >= 0) smp.main();
|
||||
}
|
||||
}
|
||||
|
||||
auto DSP::main() -> void {
|
||||
spc_dsp.run(1);
|
||||
step(24);
|
||||
|
||||
int count = spc_dsp.sample_count();
|
||||
if(count > 0) {
|
||||
for(uint n = 0; n < count; n += 2) audio.sample(samplebuffer[n + 0], samplebuffer[n + 1]);
|
||||
spc_dsp.set_output(samplebuffer, 8192);
|
||||
}
|
||||
}
|
||||
|
||||
auto DSP::mute() -> bool {
|
||||
return spc_dsp.mute();
|
||||
}
|
||||
|
||||
auto DSP::read(uint8 addr) -> uint8 {
|
||||
return spc_dsp.read(addr);
|
||||
}
|
||||
|
||||
auto DSP::write(uint8 addr, uint8 data) -> void {
|
||||
spc_dsp.write(addr, data);
|
||||
}
|
||||
|
||||
auto DSP::power() -> void {
|
||||
spc_dsp.init(smp.apuram);
|
||||
spc_dsp.reset();
|
||||
spc_dsp.set_output(samplebuffer, 8192);
|
||||
}
|
||||
|
||||
auto DSP::reset() -> void {
|
||||
Thread::clock = 0;
|
||||
spc_dsp.soft_reset();
|
||||
spc_dsp.set_output(samplebuffer, 8192);
|
||||
}
|
||||
|
||||
auto DSP::channel_enable(uint channel, bool enable) -> void {
|
||||
channel_enabled[channel & 7] = enable;
|
||||
uint mask = 0;
|
||||
for(auto i : range(8)) {
|
||||
if(channel_enabled[i] == false) mask |= 1 << i;
|
||||
}
|
||||
spc_dsp.mute_voices(mask);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#include <sfc/dsp/audio.hpp>
|
||||
|
||||
#include "SPC_DSP.h"
|
||||
|
||||
struct DSP : Thread {
|
||||
enum : bool { Threaded = false };
|
||||
|
||||
DSP();
|
||||
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto synchronizeSMP() -> void;
|
||||
|
||||
auto mute() -> bool;
|
||||
auto read(uint8 addr) -> uint8;
|
||||
auto write(uint8 addr, uint8 data) -> void;
|
||||
|
||||
auto main() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto channel_enable(uint channel, bool enable) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
SPC_DSP spc_dsp;
|
||||
int16_t samplebuffer[8192];
|
||||
bool channel_enabled[8];
|
||||
};
|
||||
|
||||
extern DSP dsp;
|
|
@ -1,27 +0,0 @@
|
|||
static auto dsp_state_save(unsigned char** out, void* in, size_t size) -> void {
|
||||
memcpy(*out, in, size);
|
||||
*out += size;
|
||||
}
|
||||
|
||||
static auto dsp_state_load(unsigned char** in, void* out, size_t size) -> void {
|
||||
memcpy(out, *in, size);
|
||||
*in += size;
|
||||
}
|
||||
|
||||
auto DSP::serialize(serializer &s) -> void {
|
||||
Thread::serialize(s);
|
||||
s.array(samplebuffer);
|
||||
|
||||
unsigned char state[SPC_DSP::state_size];
|
||||
unsigned char *p = state;
|
||||
memset(&state, 0, SPC_DSP::state_size);
|
||||
if(s.mode() == serializer::Save) {
|
||||
spc_dsp.copy_state(&p, dsp_state_save);
|
||||
s.array(state);
|
||||
} else if(s.mode() == serializer::Load) {
|
||||
s.array(state);
|
||||
spc_dsp.copy_state(&p, dsp_state_load);
|
||||
} else {
|
||||
s.array(state);
|
||||
}
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
auto PPU::latch_counters() -> void {
|
||||
regs.hcounter = cpu.hdot();
|
||||
regs.vcounter = cpu.vcounter();
|
||||
regs.counters_latched = true;
|
||||
}
|
||||
|
||||
auto PPU::get_vram_address() -> uint16 {
|
||||
uint16 addr = regs.vram_addr;
|
||||
switch(regs.vram_mapping) {
|
||||
case 0: break; //direct mapping
|
||||
case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break;
|
||||
case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break;
|
||||
case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break;
|
||||
}
|
||||
return (addr << 1);
|
||||
}
|
||||
|
||||
//NOTE: all VRAM writes during active display are invalid. Unlike OAM and CGRAM, they will
|
||||
//not be written anywhere at all. The below address ranges for where writes are invalid have
|
||||
//been validated on hardware, as has the edge case where the S-CPU MDR can be written if the
|
||||
//write occurs during the very last clock cycle of vblank.
|
||||
|
||||
auto PPU::vram_mmio_read(uint16 addr) -> uint8 {
|
||||
uint8 data;
|
||||
|
||||
if(regs.display_disabled == true) {
|
||||
data = vram[addr];
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
uint16 ls = ((system.region() == System::Region::NTSC ? 525 : 625) >> 1) - 1;
|
||||
if(interlace() && !cpu.field()) ls++;
|
||||
|
||||
if(v == ls && h == 1362) {
|
||||
data = 0x00;
|
||||
} else if(v < (!overscan() ? 224 : 239)) {
|
||||
data = 0x00;
|
||||
} else if(v == (!overscan() ? 224 : 239)) {
|
||||
if(h == 1362) {
|
||||
data = vram[addr];
|
||||
} else {
|
||||
data = 0x00;
|
||||
}
|
||||
} else {
|
||||
data = vram[addr];
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto PPU::vram_mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if(regs.display_disabled == true) {
|
||||
vram[addr] = data;
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
if(v == 0) {
|
||||
if(h <= 4) {
|
||||
vram[addr] = data;
|
||||
} else if(h == 6) {
|
||||
vram[addr] = cpu.regs.mdr;
|
||||
} else {
|
||||
//no write
|
||||
}
|
||||
} else if(v < (!overscan() ? 225 : 240)) {
|
||||
//no write
|
||||
} else if(v == (!overscan() ? 225 : 240)) {
|
||||
if(h <= 4) {
|
||||
//no write
|
||||
} else {
|
||||
vram[addr] = data;
|
||||
}
|
||||
} else {
|
||||
vram[addr] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::oam_mmio_read(uint16 addr) -> uint8 {
|
||||
addr &= 0x03ff;
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
uint8 data;
|
||||
|
||||
if(regs.display_disabled == true) {
|
||||
data = oam[addr];
|
||||
} else {
|
||||
if(cpu.vcounter() < (!overscan() ? 225 : 240)) {
|
||||
data = oam[regs.ioamaddr];
|
||||
} else {
|
||||
data = oam[addr];
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto PPU::oam_mmio_write(uint16 addr, uint8 data) -> void {
|
||||
addr &= 0x03ff;
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
|
||||
sprite_list_valid = false;
|
||||
|
||||
if(regs.display_disabled == true) {
|
||||
oam[addr] = data;
|
||||
update_sprite_list(addr, data);
|
||||
} else {
|
||||
if(cpu.vcounter() < (!overscan() ? 225 : 240)) {
|
||||
oam[regs.ioamaddr] = data;
|
||||
update_sprite_list(regs.ioamaddr, data);
|
||||
} else {
|
||||
oam[addr] = data;
|
||||
update_sprite_list(addr, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::cgram_mmio_read(uint16 addr) -> uint8 {
|
||||
addr &= 0x01ff;
|
||||
uint8 data;
|
||||
|
||||
if(1 || regs.display_disabled == true) {
|
||||
data = cgram[addr];
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
if(v < (!overscan() ? 225 : 240) && h >= 128 && h < 1096) {
|
||||
data = cgram[regs.icgramaddr] & 0x7f;
|
||||
} else {
|
||||
data = cgram[addr];
|
||||
}
|
||||
}
|
||||
|
||||
if(addr & 1) data &= 0x7f;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto PPU::cgram_mmio_write(uint16 addr, uint8 data) -> void {
|
||||
addr &= 0x01ff;
|
||||
if(addr & 1) data &= 0x7f;
|
||||
|
||||
if(1 || regs.display_disabled == true) {
|
||||
cgram[addr] = data;
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
if(v < (!overscan() ? 225 : 240) && h >= 128 && h < 1096) {
|
||||
cgram[regs.icgramaddr] = data & 0x7f;
|
||||
} else {
|
||||
cgram[addr] = data;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
auto get_vram_address() -> uint16;
|
||||
|
||||
auto vram_mmio_read(uint16 addr) -> uint8;
|
||||
auto vram_mmio_write(uint16 addr, uint8 data) -> void;
|
||||
|
||||
auto oam_mmio_read(uint16 addr) -> uint8;
|
||||
auto oam_mmio_write(uint16 addr, uint8 data) -> void;
|
||||
|
||||
auto cgram_mmio_read(uint16 addr) -> uint8;
|
||||
auto cgram_mmio_write(uint16 addr, uint8 data) -> void;
|
|
@ -1,667 +0,0 @@
|
|||
//INIDISP
|
||||
auto PPU::mmio_w2100(uint8 value) -> void {
|
||||
if(regs.display_disabled == true && cpu.vcounter() == (!overscan() ? 225 : 240)) {
|
||||
regs.oam_addr = regs.oam_baseaddr << 1;
|
||||
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
||||
}
|
||||
|
||||
regs.display_disabled = !!(value & 0x80);
|
||||
regs.display_brightness = value & 15;
|
||||
}
|
||||
|
||||
//OBSEL
|
||||
auto PPU::mmio_w2101(uint8 value) -> void {
|
||||
regs.oam_basesize = (value >> 5) & 7;
|
||||
regs.oam_nameselect = (value >> 3) & 3;
|
||||
regs.oam_tdaddr = (value & 3) << 14;
|
||||
}
|
||||
|
||||
//OAMADDL
|
||||
auto PPU::mmio_w2102(uint8 data) -> void {
|
||||
regs.oam_baseaddr = (regs.oam_baseaddr & ~0xff) | (data << 0);
|
||||
regs.oam_baseaddr &= 0x01ff;
|
||||
regs.oam_addr = regs.oam_baseaddr << 1;
|
||||
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
||||
}
|
||||
|
||||
//OAMADDH
|
||||
auto PPU::mmio_w2103(uint8 data) -> void {
|
||||
regs.oam_priority = !!(data & 0x80);
|
||||
regs.oam_baseaddr = (regs.oam_baseaddr & 0xff) | (data << 8);
|
||||
regs.oam_baseaddr &= 0x01ff;
|
||||
regs.oam_addr = regs.oam_baseaddr << 1;
|
||||
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
||||
}
|
||||
|
||||
//OAMDATA
|
||||
auto PPU::mmio_w2104(uint8 data) -> void {
|
||||
if((regs.oam_addr & 1) == 0) regs.oam_latchdata = data;
|
||||
|
||||
if(regs.oam_addr & 0x0200) {
|
||||
oam_mmio_write(regs.oam_addr, data);
|
||||
} else if((regs.oam_addr & 1) == 1) {
|
||||
oam_mmio_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
|
||||
oam_mmio_write((regs.oam_addr & ~1) + 1, data);
|
||||
}
|
||||
|
||||
regs.oam_addr++;
|
||||
regs.oam_addr &= 0x03ff;
|
||||
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
||||
}
|
||||
|
||||
//BGMODE
|
||||
auto PPU::mmio_w2105(uint8 value) -> void {
|
||||
regs.bg_tilesize[BG4] = !!(value & 0x80);
|
||||
regs.bg_tilesize[BG3] = !!(value & 0x40);
|
||||
regs.bg_tilesize[BG2] = !!(value & 0x20);
|
||||
regs.bg_tilesize[BG1] = !!(value & 0x10);
|
||||
regs.bg3_priority = !!(value & 0x08);
|
||||
regs.bg_mode = (value & 7);
|
||||
}
|
||||
|
||||
//MOSAIC
|
||||
auto PPU::mmio_w2106(uint8 value) -> void {
|
||||
regs.mosaic_size = (value >> 4) & 15;
|
||||
regs.mosaic_enabled[BG4] = !!(value & 0x08);
|
||||
regs.mosaic_enabled[BG3] = !!(value & 0x04);
|
||||
regs.mosaic_enabled[BG2] = !!(value & 0x02);
|
||||
regs.mosaic_enabled[BG1] = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//BG1SC
|
||||
auto PPU::mmio_w2107(uint8 value) -> void {
|
||||
regs.bg_scaddr[BG1] = (value & 0x7c) << 9;
|
||||
regs.bg_scsize[BG1] = value & 3;
|
||||
}
|
||||
|
||||
//BG2SC
|
||||
auto PPU::mmio_w2108(uint8 value) -> void {
|
||||
regs.bg_scaddr[BG2] = (value & 0x7c) << 9;
|
||||
regs.bg_scsize[BG2] = value & 3;
|
||||
}
|
||||
|
||||
//BG3SC
|
||||
auto PPU::mmio_w2109(uint8 value) -> void {
|
||||
regs.bg_scaddr[BG3] = (value & 0x7c) << 9;
|
||||
regs.bg_scsize[BG3] = value & 3;
|
||||
}
|
||||
|
||||
//BG4SC
|
||||
auto PPU::mmio_w210a(uint8 value) -> void {
|
||||
regs.bg_scaddr[BG4] = (value & 0x7c) << 9;
|
||||
regs.bg_scsize[BG4] = value & 3;
|
||||
}
|
||||
|
||||
//BG12NBA
|
||||
auto PPU::mmio_w210b(uint8 value) -> void {
|
||||
regs.bg_tdaddr[BG1] = (value & 0x07) << 13;
|
||||
regs.bg_tdaddr[BG2] = (value & 0x70) << 9;
|
||||
}
|
||||
|
||||
//BG34NBA
|
||||
auto PPU::mmio_w210c(uint8 value) -> void {
|
||||
regs.bg_tdaddr[BG3] = (value & 0x07) << 13;
|
||||
regs.bg_tdaddr[BG4] = (value & 0x70) << 9;
|
||||
}
|
||||
|
||||
//BG1HOFS
|
||||
auto PPU::mmio_w210d(uint8 value) -> void {
|
||||
regs.m7_hofs = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
|
||||
regs.bg_hofs[BG1] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG1] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG1VOFS
|
||||
auto PPU::mmio_w210e(uint8 value) -> void {
|
||||
regs.m7_vofs = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
|
||||
regs.bg_vofs[BG1] = (value << 8) | (regs.bg_ofslatch);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG2HOFS
|
||||
auto PPU::mmio_w210f(uint8 value) -> void {
|
||||
regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG2] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG2VOFS
|
||||
auto PPU::mmio_w2110(uint8 value) -> void {
|
||||
regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ofslatch);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG3HOFS
|
||||
auto PPU::mmio_w2111(uint8 value) -> void {
|
||||
regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG3] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG3VOFS
|
||||
auto PPU::mmio_w2112(uint8 value) -> void {
|
||||
regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ofslatch);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG4HOFS
|
||||
auto PPU::mmio_w2113(uint8 value) -> void {
|
||||
regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG4] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG4VOFS
|
||||
auto PPU::mmio_w2114(uint8 value) -> void {
|
||||
regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ofslatch);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//VMAIN
|
||||
auto PPU::mmio_w2115(uint8 value) -> void {
|
||||
regs.vram_incmode = !!(value & 0x80);
|
||||
regs.vram_mapping = (value >> 2) & 3;
|
||||
switch(value & 3) {
|
||||
case 0: regs.vram_incsize = 1; break;
|
||||
case 1: regs.vram_incsize = 32; break;
|
||||
case 2: regs.vram_incsize = 128; break;
|
||||
case 3: regs.vram_incsize = 128; break;
|
||||
}
|
||||
}
|
||||
|
||||
//VMADDL
|
||||
auto PPU::mmio_w2116(uint8 value) -> void {
|
||||
regs.vram_addr = (regs.vram_addr & 0xff00) | value;
|
||||
uint16 addr = get_vram_address();
|
||||
regs.vram_readbuffer = vram_mmio_read(addr + 0);
|
||||
regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
|
||||
}
|
||||
|
||||
//VMADDH
|
||||
auto PPU::mmio_w2117(uint8 value) -> void {
|
||||
regs.vram_addr = (value << 8) | (regs.vram_addr & 0x00ff);
|
||||
uint16 addr = get_vram_address();
|
||||
regs.vram_readbuffer = vram_mmio_read(addr + 0);
|
||||
regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
|
||||
}
|
||||
|
||||
//VMDATAL
|
||||
auto PPU::mmio_w2118(uint8 value) -> void {
|
||||
uint16 addr = get_vram_address();
|
||||
vram_mmio_write(addr, value);
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
||||
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
||||
|
||||
if(regs.vram_incmode == 0) {
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
}
|
||||
|
||||
//VMDATAH
|
||||
auto PPU::mmio_w2119(uint8 value) -> void {
|
||||
uint16 addr = get_vram_address() + 1;
|
||||
vram_mmio_write(addr, value);
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
||||
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
||||
|
||||
if(regs.vram_incmode == 1) {
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
}
|
||||
|
||||
//M7SEL
|
||||
auto PPU::mmio_w211a(uint8 value) -> void {
|
||||
regs.mode7_repeat = (value >> 6) & 3;
|
||||
regs.mode7_vflip = !!(value & 0x02);
|
||||
regs.mode7_hflip = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//M7A
|
||||
auto PPU::mmio_w211b(uint8 value) -> void {
|
||||
regs.m7a = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7B
|
||||
auto PPU::mmio_w211c(uint8 value) -> void {
|
||||
regs.m7b = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7C
|
||||
auto PPU::mmio_w211d(uint8 value) -> void {
|
||||
regs.m7c = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7D
|
||||
auto PPU::mmio_w211e(uint8 value) -> void {
|
||||
regs.m7d = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7X
|
||||
auto PPU::mmio_w211f(uint8 value) -> void {
|
||||
regs.m7x = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7Y
|
||||
auto PPU::mmio_w2120(uint8 value) -> void {
|
||||
regs.m7y = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//CGADD
|
||||
auto PPU::mmio_w2121(uint8 value) -> void {
|
||||
regs.cgram_addr = value << 1;
|
||||
}
|
||||
|
||||
//CGDATA
|
||||
//note: CGRAM palette data format is 15-bits
|
||||
//(0,bbbbb,ggggg,rrrrr). Highest bit is ignored,
|
||||
//as evidenced by $213b CGRAM data reads.
|
||||
//
|
||||
//anomie indicates writes to CGDATA work the same
|
||||
//as writes to OAMDATA's low table. need to verify
|
||||
//this on hardware.
|
||||
auto PPU::mmio_w2122(uint8 value) -> void {
|
||||
if(!(regs.cgram_addr & 1)) {
|
||||
regs.cgram_latchdata = value;
|
||||
} else {
|
||||
cgram_mmio_write((regs.cgram_addr & 0x01fe), regs.cgram_latchdata);
|
||||
cgram_mmio_write((regs.cgram_addr & 0x01fe) + 1, value & 0x7f);
|
||||
}
|
||||
regs.cgram_addr++;
|
||||
regs.cgram_addr &= 0x01ff;
|
||||
}
|
||||
|
||||
//W12SEL
|
||||
auto PPU::mmio_w2123(uint8 value) -> void {
|
||||
regs.window2_enabled[BG2] = !!(value & 0x80);
|
||||
regs.window2_invert [BG2] = !!(value & 0x40);
|
||||
regs.window1_enabled[BG2] = !!(value & 0x20);
|
||||
regs.window1_invert [BG2] = !!(value & 0x10);
|
||||
regs.window2_enabled[BG1] = !!(value & 0x08);
|
||||
regs.window2_invert [BG1] = !!(value & 0x04);
|
||||
regs.window1_enabled[BG1] = !!(value & 0x02);
|
||||
regs.window1_invert [BG1] = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//W34SEL
|
||||
auto PPU::mmio_w2124(uint8 value) -> void {
|
||||
regs.window2_enabled[BG4] = !!(value & 0x80);
|
||||
regs.window2_invert [BG4] = !!(value & 0x40);
|
||||
regs.window1_enabled[BG4] = !!(value & 0x20);
|
||||
regs.window1_invert [BG4] = !!(value & 0x10);
|
||||
regs.window2_enabled[BG3] = !!(value & 0x08);
|
||||
regs.window2_invert [BG3] = !!(value & 0x04);
|
||||
regs.window1_enabled[BG3] = !!(value & 0x02);
|
||||
regs.window1_invert [BG3] = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//WOBJSEL
|
||||
auto PPU::mmio_w2125(uint8 value) -> void {
|
||||
regs.window2_enabled[COL] = !!(value & 0x80);
|
||||
regs.window2_invert [COL] = !!(value & 0x40);
|
||||
regs.window1_enabled[COL] = !!(value & 0x20);
|
||||
regs.window1_invert [COL] = !!(value & 0x10);
|
||||
regs.window2_enabled[OAM] = !!(value & 0x08);
|
||||
regs.window2_invert [OAM] = !!(value & 0x04);
|
||||
regs.window1_enabled[OAM] = !!(value & 0x02);
|
||||
regs.window1_invert [OAM] = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//WH0
|
||||
auto PPU::mmio_w2126(uint8 value) -> void {
|
||||
regs.window1_left = value;
|
||||
}
|
||||
|
||||
//WH1
|
||||
auto PPU::mmio_w2127(uint8 value) -> void {
|
||||
regs.window1_right = value;
|
||||
}
|
||||
|
||||
//WH2
|
||||
auto PPU::mmio_w2128(uint8 value) -> void {
|
||||
regs.window2_left = value;
|
||||
}
|
||||
|
||||
//WH3
|
||||
auto PPU::mmio_w2129(uint8 value) -> void {
|
||||
regs.window2_right = value;
|
||||
}
|
||||
|
||||
//WBGLOG
|
||||
auto PPU::mmio_w212a(uint8 value) -> void {
|
||||
regs.window_mask[BG4] = (value >> 6) & 3;
|
||||
regs.window_mask[BG3] = (value >> 4) & 3;
|
||||
regs.window_mask[BG2] = (value >> 2) & 3;
|
||||
regs.window_mask[BG1] = (value ) & 3;
|
||||
}
|
||||
|
||||
//WOBJLOG
|
||||
auto PPU::mmio_w212b(uint8 value) -> void {
|
||||
regs.window_mask[COL] = (value >> 2) & 3;
|
||||
regs.window_mask[OAM] = (value ) & 3;
|
||||
}
|
||||
|
||||
//TM
|
||||
auto PPU::mmio_w212c(uint8 value) -> void {
|
||||
regs.bg_enabled[OAM] = !!(value & 0x10);
|
||||
regs.bg_enabled[BG4] = !!(value & 0x08);
|
||||
regs.bg_enabled[BG3] = !!(value & 0x04);
|
||||
regs.bg_enabled[BG2] = !!(value & 0x02);
|
||||
regs.bg_enabled[BG1] = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//TS
|
||||
auto PPU::mmio_w212d(uint8 value) -> void {
|
||||
regs.bgsub_enabled[OAM] = !!(value & 0x10);
|
||||
regs.bgsub_enabled[BG4] = !!(value & 0x08);
|
||||
regs.bgsub_enabled[BG3] = !!(value & 0x04);
|
||||
regs.bgsub_enabled[BG2] = !!(value & 0x02);
|
||||
regs.bgsub_enabled[BG1] = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//TMW
|
||||
auto PPU::mmio_w212e(uint8 value) -> void {
|
||||
regs.window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.window_enabled[BG3] = !!(value & 0x04);
|
||||
regs.window_enabled[BG2] = !!(value & 0x02);
|
||||
regs.window_enabled[BG1] = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//TSW
|
||||
auto PPU::mmio_w212f(uint8 value) -> void {
|
||||
regs.sub_window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.sub_window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.sub_window_enabled[BG3] = !!(value & 0x04);
|
||||
regs.sub_window_enabled[BG2] = !!(value & 0x02);
|
||||
regs.sub_window_enabled[BG1] = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//CGWSEL
|
||||
auto PPU::mmio_w2130(uint8 value) -> void {
|
||||
regs.color_mask = (value >> 6) & 3;
|
||||
regs.colorsub_mask = (value >> 4) & 3;
|
||||
regs.addsub_mode = !!(value & 0x02);
|
||||
regs.direct_color = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//CGADDSUB
|
||||
auto PPU::mmio_w2131(uint8 value) -> void {
|
||||
regs.color_mode = !!(value & 0x80);
|
||||
regs.color_halve = !!(value & 0x40);
|
||||
regs.color_enabled[BACK] = !!(value & 0x20);
|
||||
regs.color_enabled[OAM] = !!(value & 0x10);
|
||||
regs.color_enabled[BG4] = !!(value & 0x08);
|
||||
regs.color_enabled[BG3] = !!(value & 0x04);
|
||||
regs.color_enabled[BG2] = !!(value & 0x02);
|
||||
regs.color_enabled[BG1] = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//COLDATA
|
||||
auto PPU::mmio_w2132(uint8 value) -> void {
|
||||
if(value & 0x80) regs.color_b = value & 0x1f;
|
||||
if(value & 0x40) regs.color_g = value & 0x1f;
|
||||
if(value & 0x20) regs.color_r = value & 0x1f;
|
||||
|
||||
regs.color_rgb = (regs.color_r)
|
||||
| (regs.color_g << 5)
|
||||
| (regs.color_b << 10);
|
||||
}
|
||||
|
||||
//SETINI
|
||||
auto PPU::mmio_w2133(uint8 value) -> void {
|
||||
regs.mode7_extbg = !!(value & 0x40);
|
||||
regs.pseudo_hires = !!(value & 0x08);
|
||||
regs.overscan = !!(value & 0x04);
|
||||
regs.oam_interlace = !!(value & 0x02);
|
||||
regs.interlace = !!(value & 0x01);
|
||||
|
||||
display.overscan = regs.overscan;
|
||||
sprite_list_valid = false;
|
||||
}
|
||||
|
||||
//MPYL
|
||||
auto PPU::mmio_r2134() -> uint8 {
|
||||
uint32 r;
|
||||
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
regs.ppu1_mdr = r;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//MPYM
|
||||
auto PPU::mmio_r2135() -> uint8 {
|
||||
uint32 r;
|
||||
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
regs.ppu1_mdr = r >> 8;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//MPYH
|
||||
auto PPU::mmio_r2136() -> uint8 {
|
||||
uint32 r;
|
||||
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
regs.ppu1_mdr = r >> 16;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//SLHV
|
||||
auto PPU::mmio_r2137() -> uint8 {
|
||||
if(cpu.pio() & 0x80) {
|
||||
latch_counters();
|
||||
}
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
//OAMDATAREAD
|
||||
auto PPU::mmio_r2138() -> uint8 {
|
||||
regs.ppu1_mdr = oam_mmio_read(regs.oam_addr);
|
||||
|
||||
regs.oam_addr++;
|
||||
regs.oam_addr &= 0x03ff;
|
||||
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
||||
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//VMDATALREAD
|
||||
auto PPU::mmio_r2139() -> uint8 {
|
||||
uint16 addr = get_vram_address();
|
||||
regs.ppu1_mdr = regs.vram_readbuffer;
|
||||
if(regs.vram_incmode == 0) {
|
||||
addr &= 0xfffe;
|
||||
regs.vram_readbuffer = vram_mmio_read(addr + 0);
|
||||
regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//VMDATAHREAD
|
||||
auto PPU::mmio_r213a() -> uint8 {
|
||||
uint16 addr = get_vram_address() + 1;
|
||||
regs.ppu1_mdr = regs.vram_readbuffer >> 8;
|
||||
if(regs.vram_incmode == 1) {
|
||||
addr &= 0xfffe;
|
||||
regs.vram_readbuffer = vram_mmio_read(addr + 0);
|
||||
regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//CGDATAREAD
|
||||
//note: CGRAM palette data is 15-bits (0,bbbbb,ggggg,rrrrr)
|
||||
//therefore, the high byte read from each color does not
|
||||
//update bit 7 of the PPU2 MDR.
|
||||
auto PPU::mmio_r213b() -> uint8 {
|
||||
if(!(regs.cgram_addr & 1)) {
|
||||
regs.ppu2_mdr = cgram_mmio_read(regs.cgram_addr) & 0xff;
|
||||
} else {
|
||||
regs.ppu2_mdr &= 0x80;
|
||||
regs.ppu2_mdr |= cgram_mmio_read(regs.cgram_addr) & 0x7f;
|
||||
}
|
||||
regs.cgram_addr++;
|
||||
regs.cgram_addr &= 0x01ff;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
//OPHCT
|
||||
auto PPU::mmio_r213c() -> uint8 {
|
||||
if(!regs.latch_hcounter) {
|
||||
regs.ppu2_mdr = regs.hcounter & 0xff;
|
||||
} else {
|
||||
regs.ppu2_mdr &= 0xfe;
|
||||
regs.ppu2_mdr |= (regs.hcounter >> 8) & 1;
|
||||
}
|
||||
regs.latch_hcounter ^= 1;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
//OPVCT
|
||||
auto PPU::mmio_r213d() -> uint8 {
|
||||
if(!regs.latch_vcounter) {
|
||||
regs.ppu2_mdr = regs.vcounter & 0xff;
|
||||
} else {
|
||||
regs.ppu2_mdr &= 0xfe;
|
||||
regs.ppu2_mdr |= (regs.vcounter >> 8) & 1;
|
||||
}
|
||||
regs.latch_vcounter ^= 1;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
//STAT77
|
||||
auto PPU::mmio_r213e() -> uint8 {
|
||||
uint8 r = 0x00;
|
||||
r |= (regs.time_over) ? 0x80 : 0x00;
|
||||
r |= (regs.range_over) ? 0x40 : 0x00;
|
||||
r |= (regs.ppu1_mdr & 0x10);
|
||||
r |= (ppu1_version & 0x0f);
|
||||
regs.ppu1_mdr = r;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//STAT78
|
||||
auto PPU::mmio_r213f() -> uint8 {
|
||||
uint8 r = 0x00;
|
||||
regs.latch_hcounter = 0;
|
||||
regs.latch_vcounter = 0;
|
||||
|
||||
r |= cpu.field() << 7;
|
||||
if(!(cpu.pio() & 0x80)) {
|
||||
r |= 0x40;
|
||||
} else if(regs.counters_latched == true) {
|
||||
r |= 0x40;
|
||||
regs.counters_latched = false;
|
||||
}
|
||||
r |= (regs.ppu2_mdr & 0x20);
|
||||
r |= (region << 4); //0 = NTSC, 1 = PAL
|
||||
r |= (ppu2_version & 0x0f);
|
||||
regs.ppu2_mdr = r;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
auto PPU::mmio_read(uint addr, uint8 data) -> uint8 {
|
||||
cpu.synchronizePPU();
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
case 0x2104:
|
||||
case 0x2105:
|
||||
case 0x2106:
|
||||
case 0x2108:
|
||||
case 0x2109:
|
||||
case 0x210a:
|
||||
case 0x2114:
|
||||
case 0x2115:
|
||||
case 0x2116:
|
||||
case 0x2118:
|
||||
case 0x2119:
|
||||
case 0x211a:
|
||||
case 0x2124:
|
||||
case 0x2125:
|
||||
case 0x2126:
|
||||
case 0x2128:
|
||||
case 0x2129:
|
||||
case 0x212a: return regs.ppu1_mdr;
|
||||
case 0x2134: return mmio_r2134(); //MPYL
|
||||
case 0x2135: return mmio_r2135(); //MPYM
|
||||
case 0x2136: return mmio_r2136(); //MPYH
|
||||
case 0x2137: return mmio_r2137(); //SLHV
|
||||
case 0x2138: return mmio_r2138(); //OAMDATAREAD
|
||||
case 0x2139: return mmio_r2139(); //VMDATALREAD
|
||||
case 0x213a: return mmio_r213a(); //VMDATAHREAD
|
||||
case 0x213b: return mmio_r213b(); //CGDATAREAD
|
||||
case 0x213c: return mmio_r213c(); //OPHCT
|
||||
case 0x213d: return mmio_r213d(); //OPVCT
|
||||
case 0x213e: return mmio_r213e(); //STAT77
|
||||
case 0x213f: return mmio_r213f(); //STAT78
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto PPU::mmio_write(uint addr, uint8 data) -> void {
|
||||
cpu.synchronizePPU();
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
case 0x2100: return mmio_w2100(data); //INIDISP
|
||||
case 0x2101: return mmio_w2101(data); //OBSEL
|
||||
case 0x2102: return mmio_w2102(data); //OAMADDL
|
||||
case 0x2103: return mmio_w2103(data); //OAMADDH
|
||||
case 0x2104: return mmio_w2104(data); //OAMDATA
|
||||
case 0x2105: return mmio_w2105(data); //BGMODE
|
||||
case 0x2106: return mmio_w2106(data); //MOSAIC
|
||||
case 0x2107: return mmio_w2107(data); //BG1SC
|
||||
case 0x2108: return mmio_w2108(data); //BG2SC
|
||||
case 0x2109: return mmio_w2109(data); //BG3SC
|
||||
case 0x210a: return mmio_w210a(data); //BG4SC
|
||||
case 0x210b: return mmio_w210b(data); //BG12NBA
|
||||
case 0x210c: return mmio_w210c(data); //BG34NBA
|
||||
case 0x210d: return mmio_w210d(data); //BG1HOFS
|
||||
case 0x210e: return mmio_w210e(data); //BG1VOFS
|
||||
case 0x210f: return mmio_w210f(data); //BG2HOFS
|
||||
case 0x2110: return mmio_w2110(data); //BG2VOFS
|
||||
case 0x2111: return mmio_w2111(data); //BG3HOFS
|
||||
case 0x2112: return mmio_w2112(data); //BG3VOFS
|
||||
case 0x2113: return mmio_w2113(data); //BG4HOFS
|
||||
case 0x2114: return mmio_w2114(data); //BG4VOFS
|
||||
case 0x2115: return mmio_w2115(data); //VMAIN
|
||||
case 0x2116: return mmio_w2116(data); //VMADDL
|
||||
case 0x2117: return mmio_w2117(data); //VMADDH
|
||||
case 0x2118: return mmio_w2118(data); //VMDATAL
|
||||
case 0x2119: return mmio_w2119(data); //VMDATAH
|
||||
case 0x211a: return mmio_w211a(data); //M7SEL
|
||||
case 0x211b: return mmio_w211b(data); //M7A
|
||||
case 0x211c: return mmio_w211c(data); //M7B
|
||||
case 0x211d: return mmio_w211d(data); //M7C
|
||||
case 0x211e: return mmio_w211e(data); //M7D
|
||||
case 0x211f: return mmio_w211f(data); //M7X
|
||||
case 0x2120: return mmio_w2120(data); //M7Y
|
||||
case 0x2121: return mmio_w2121(data); //CGADD
|
||||
case 0x2122: return mmio_w2122(data); //CGDATA
|
||||
case 0x2123: return mmio_w2123(data); //W12SEL
|
||||
case 0x2124: return mmio_w2124(data); //W34SEL
|
||||
case 0x2125: return mmio_w2125(data); //WOBJSEL
|
||||
case 0x2126: return mmio_w2126(data); //WH0
|
||||
case 0x2127: return mmio_w2127(data); //WH1
|
||||
case 0x2128: return mmio_w2128(data); //WH2
|
||||
case 0x2129: return mmio_w2129(data); //WH3
|
||||
case 0x212a: return mmio_w212a(data); //WBGLOG
|
||||
case 0x212b: return mmio_w212b(data); //WOBJLOG
|
||||
case 0x212c: return mmio_w212c(data); //TM
|
||||
case 0x212d: return mmio_w212d(data); //TS
|
||||
case 0x212e: return mmio_w212e(data); //TMW
|
||||
case 0x212f: return mmio_w212f(data); //TSW
|
||||
case 0x2130: return mmio_w2130(data); //CGWSEL
|
||||
case 0x2131: return mmio_w2131(data); //CGADDSUB
|
||||
case 0x2132: return mmio_w2132(data); //COLDATA
|
||||
case 0x2133: return mmio_w2133(data); //SETINI
|
||||
}
|
||||
}
|
|
@ -1,202 +0,0 @@
|
|||
struct {
|
||||
//open bus support
|
||||
uint8 ppu1_mdr, ppu2_mdr;
|
||||
|
||||
//bg line counters
|
||||
uint16 bg_y[4];
|
||||
|
||||
//internal state
|
||||
uint16 ioamaddr;
|
||||
uint16 icgramaddr;
|
||||
|
||||
//$2100
|
||||
bool display_disabled;
|
||||
uint8 display_brightness;
|
||||
|
||||
//$2101
|
||||
uint8 oam_basesize;
|
||||
uint8 oam_nameselect;
|
||||
uint16 oam_tdaddr;
|
||||
|
||||
//$2102-$2103
|
||||
uint16 oam_baseaddr;
|
||||
uint16 oam_addr;
|
||||
bool oam_priority;
|
||||
uint8 oam_firstsprite;
|
||||
|
||||
//$2104
|
||||
uint8 oam_latchdata;
|
||||
|
||||
//$2105
|
||||
bool bg_tilesize[4];
|
||||
bool bg3_priority;
|
||||
uint8 bg_mode;
|
||||
|
||||
//$2106
|
||||
uint8 mosaic_size;
|
||||
bool mosaic_enabled[4];
|
||||
uint16 mosaic_countdown;
|
||||
|
||||
//$2107-$210a
|
||||
uint16 bg_scaddr[4];
|
||||
uint8 bg_scsize[4];
|
||||
|
||||
//$210b-$210c
|
||||
uint16 bg_tdaddr[4];
|
||||
|
||||
//$210d-$2114
|
||||
uint8 bg_ofslatch;
|
||||
uint16 m7_hofs, m7_vofs;
|
||||
uint16 bg_hofs[4];
|
||||
uint16 bg_vofs[4];
|
||||
|
||||
//$2115
|
||||
bool vram_incmode;
|
||||
uint8 vram_mapping;
|
||||
uint8 vram_incsize;
|
||||
|
||||
//$2116-$2117
|
||||
uint16 vram_addr;
|
||||
|
||||
//$211a
|
||||
uint8 mode7_repeat;
|
||||
bool mode7_vflip;
|
||||
bool mode7_hflip;
|
||||
|
||||
//$211b-$2120
|
||||
uint8 m7_latch;
|
||||
uint16 m7a, m7b, m7c, m7d, m7x, m7y;
|
||||
|
||||
//$2121
|
||||
uint16 cgram_addr;
|
||||
|
||||
//$2122
|
||||
uint8 cgram_latchdata;
|
||||
|
||||
//$2123-$2125
|
||||
bool window1_enabled[6];
|
||||
bool window1_invert [6];
|
||||
bool window2_enabled[6];
|
||||
bool window2_invert [6];
|
||||
|
||||
//$2126-$2129
|
||||
uint8 window1_left, window1_right;
|
||||
uint8 window2_left, window2_right;
|
||||
|
||||
//$212a-$212b
|
||||
uint8 window_mask[6];
|
||||
|
||||
//$212c-$212d
|
||||
bool bg_enabled[5], bgsub_enabled[5];
|
||||
|
||||
//$212e-$212f
|
||||
bool window_enabled[5], sub_window_enabled[5];
|
||||
|
||||
//$2130
|
||||
uint8 color_mask, colorsub_mask;
|
||||
bool addsub_mode;
|
||||
bool direct_color;
|
||||
|
||||
//$2131
|
||||
bool color_mode, color_halve;
|
||||
bool color_enabled[6];
|
||||
|
||||
//$2132
|
||||
uint8 color_r, color_g, color_b;
|
||||
uint16 color_rgb;
|
||||
|
||||
//$2133
|
||||
//overscan and interlace are checked once per frame to
|
||||
//determine if entire frame should be interlaced/non-interlace
|
||||
//and overscan adjusted. therefore, the variables act sort of
|
||||
//like a buffer, but they do still affect internal rendering
|
||||
bool mode7_extbg;
|
||||
bool pseudo_hires;
|
||||
bool overscan;
|
||||
uint16 scanlines;
|
||||
bool oam_interlace;
|
||||
bool interlace;
|
||||
|
||||
//$2137
|
||||
uint16 hcounter, vcounter;
|
||||
bool latch_hcounter, latch_vcounter;
|
||||
bool counters_latched;
|
||||
|
||||
//$2139-$213a
|
||||
uint16 vram_readbuffer;
|
||||
|
||||
//$213e
|
||||
bool time_over, range_over;
|
||||
uint16 oam_itemcount, oam_tilecount;
|
||||
} regs;
|
||||
|
||||
auto mmio_w2100(uint8 value) -> void; //INIDISP
|
||||
auto mmio_w2101(uint8 value) -> void; //OBSEL
|
||||
auto mmio_w2102(uint8 value) -> void; //OAMADDL
|
||||
auto mmio_w2103(uint8 value) -> void; //OAMADDH
|
||||
auto mmio_w2104(uint8 value) -> void; //OAMDATA
|
||||
auto mmio_w2105(uint8 value) -> void; //BGMODE
|
||||
auto mmio_w2106(uint8 value) -> void; //MOSAIC
|
||||
auto mmio_w2107(uint8 value) -> void; //BG1SC
|
||||
auto mmio_w2108(uint8 value) -> void; //BG2SC
|
||||
auto mmio_w2109(uint8 value) -> void; //BG3SC
|
||||
auto mmio_w210a(uint8 value) -> void; //BG4SC
|
||||
auto mmio_w210b(uint8 value) -> void; //BG12NBA
|
||||
auto mmio_w210c(uint8 value) -> void; //BG34NBA
|
||||
auto mmio_w210d(uint8 value) -> void; //BG1HOFS
|
||||
auto mmio_w210e(uint8 value) -> void; //BG1VOFS
|
||||
auto mmio_w210f(uint8 value) -> void; //BG2HOFS
|
||||
auto mmio_w2110(uint8 value) -> void; //BG2VOFS
|
||||
auto mmio_w2111(uint8 value) -> void; //BG3HOFS
|
||||
auto mmio_w2112(uint8 value) -> void; //BG3VOFS
|
||||
auto mmio_w2113(uint8 value) -> void; //BG4HOFS
|
||||
auto mmio_w2114(uint8 value) -> void; //BG4VOFS
|
||||
auto mmio_w2115(uint8 value) -> void; //VMAIN
|
||||
auto mmio_w2116(uint8 value) -> void; //VMADDL
|
||||
auto mmio_w2117(uint8 value) -> void; //VMADDH
|
||||
auto mmio_w2118(uint8 value) -> void; //VMDATAL
|
||||
auto mmio_w2119(uint8 value) -> void; //VMDATAH
|
||||
auto mmio_w211a(uint8 value) -> void; //M7SEL
|
||||
auto mmio_w211b(uint8 value) -> void; //M7A
|
||||
auto mmio_w211c(uint8 value) -> void; //M7B
|
||||
auto mmio_w211d(uint8 value) -> void; //M7C
|
||||
auto mmio_w211e(uint8 value) -> void; //M7D
|
||||
auto mmio_w211f(uint8 value) -> void; //M7X
|
||||
auto mmio_w2120(uint8 value) -> void; //M7Y
|
||||
auto mmio_w2121(uint8 value) -> void; //CGADD
|
||||
auto mmio_w2122(uint8 value) -> void; //CGDATA
|
||||
auto mmio_w2123(uint8 value) -> void; //W12SEL
|
||||
auto mmio_w2124(uint8 value) -> void; //W34SEL
|
||||
auto mmio_w2125(uint8 value) -> void; //WOBJSEL
|
||||
auto mmio_w2126(uint8 value) -> void; //WH0
|
||||
auto mmio_w2127(uint8 value) -> void; //WH1
|
||||
auto mmio_w2128(uint8 value) -> void; //WH2
|
||||
auto mmio_w2129(uint8 value) -> void; //WH3
|
||||
auto mmio_w212a(uint8 value) -> void; //WBGLOG
|
||||
auto mmio_w212b(uint8 value) -> void; //WOBJLOG
|
||||
auto mmio_w212c(uint8 value) -> void; //TM
|
||||
auto mmio_w212d(uint8 value) -> void; //TS
|
||||
auto mmio_w212e(uint8 value) -> void; //TMW
|
||||
auto mmio_w212f(uint8 value) -> void; //TSW
|
||||
auto mmio_w2130(uint8 value) -> void; //CGWSEL
|
||||
auto mmio_w2131(uint8 value) -> void; //CGADDSUB
|
||||
auto mmio_w2132(uint8 value) -> void; //COLDATA
|
||||
auto mmio_w2133(uint8 value) -> void; //SETINI
|
||||
|
||||
auto mmio_r2134() -> uint8; //MPYL
|
||||
auto mmio_r2135() -> uint8; //MPYM
|
||||
auto mmio_r2136() -> uint8; //MPYH
|
||||
auto mmio_r2137() -> uint8; //SLHV
|
||||
auto mmio_r2138() -> uint8; //OAMDATAREAD
|
||||
auto mmio_r2139() -> uint8; //VMDATALREAD
|
||||
auto mmio_r213a() -> uint8; //VMDATAHREAD
|
||||
auto mmio_r213b() -> uint8; //CGDATAREAD
|
||||
auto mmio_r213c() -> uint8; //OPHCT
|
||||
auto mmio_r213d() -> uint8; //OPVCT
|
||||
auto mmio_r213e() -> uint8; //STAT77
|
||||
auto mmio_r213f() -> uint8; //STAT78
|
||||
|
||||
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmio_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto latch_counters() -> void;
|
|
@ -1,427 +0,0 @@
|
|||
#include <sfc/sfc.hpp>
|
||||
|
||||
namespace SuperFamicom {
|
||||
|
||||
#include <sfc/ppu/video.cpp>
|
||||
PPU ppu;
|
||||
|
||||
#include "memory/memory.cpp"
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "render/render.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
PPU::PPU() {
|
||||
output = new uint32[512 * 512]();
|
||||
output += 16 * 512; //overscan offset
|
||||
|
||||
alloc_tiledata_cache();
|
||||
|
||||
for(uint l : range(16)) {
|
||||
for(uint i : range(4096)) {
|
||||
mosaic_table[l][i] = (i / (l + 1)) * (l + 1);
|
||||
}
|
||||
}
|
||||
|
||||
layer_enabled[BG1][0] = true;
|
||||
layer_enabled[BG1][1] = true;
|
||||
layer_enabled[BG2][0] = true;
|
||||
layer_enabled[BG2][1] = true;
|
||||
layer_enabled[BG3][0] = true;
|
||||
layer_enabled[BG3][1] = true;
|
||||
layer_enabled[BG4][0] = true;
|
||||
layer_enabled[BG4][1] = true;
|
||||
layer_enabled[OAM][0] = true;
|
||||
layer_enabled[OAM][1] = true;
|
||||
layer_enabled[OAM][2] = true;
|
||||
layer_enabled[OAM][3] = true;
|
||||
frameskip = 0;
|
||||
framecounter = 0;
|
||||
}
|
||||
|
||||
PPU::~PPU() {
|
||||
output -= 16 * 512;
|
||||
delete[] output;
|
||||
free_tiledata_cache();
|
||||
}
|
||||
|
||||
auto PPU::step(uint clocks) -> void {
|
||||
clock += clocks;
|
||||
}
|
||||
|
||||
auto PPU::synchronizeCPU() -> void {
|
||||
if(CPU::Threaded == true) {
|
||||
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
||||
} else {
|
||||
while(clock >= 0) cpu.main();
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), ppu.main();
|
||||
}
|
||||
|
||||
auto PPU::main() -> void {
|
||||
//H = 0 (initialize)
|
||||
scanline();
|
||||
add_clocks(10);
|
||||
|
||||
//H = 10 (cache mode7 registers + OAM address reset)
|
||||
cache.m7_hofs = regs.m7_hofs;
|
||||
cache.m7_vofs = regs.m7_vofs;
|
||||
cache.m7a = regs.m7a;
|
||||
cache.m7b = regs.m7b;
|
||||
cache.m7c = regs.m7c;
|
||||
cache.m7d = regs.m7d;
|
||||
cache.m7x = regs.m7x;
|
||||
cache.m7y = regs.m7y;
|
||||
if(vcounter() == (!overscan() ? 225 : 240)) {
|
||||
if(regs.display_disabled == false) {
|
||||
regs.oam_addr = regs.oam_baseaddr << 1;
|
||||
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
||||
}
|
||||
}
|
||||
add_clocks(502);
|
||||
|
||||
//H = 512 (render)
|
||||
render_scanline();
|
||||
add_clocks(640);
|
||||
|
||||
//H = 1152 (cache OBSEL)
|
||||
if(cache.oam_basesize != regs.oam_basesize) {
|
||||
cache.oam_basesize = regs.oam_basesize;
|
||||
sprite_list_valid = false;
|
||||
}
|
||||
cache.oam_nameselect = regs.oam_nameselect;
|
||||
cache.oam_tdaddr = regs.oam_tdaddr;
|
||||
add_clocks(lineclocks() - 1152); //seek to start of next scanline
|
||||
}
|
||||
|
||||
auto PPU::add_clocks(uint clocks) -> void {
|
||||
tick(clocks);
|
||||
step(clocks);
|
||||
synchronizeCPU();
|
||||
}
|
||||
|
||||
auto PPU::scanline() -> void {
|
||||
line = vcounter();
|
||||
|
||||
if(line == 0) {
|
||||
frame();
|
||||
|
||||
//RTO flag reset
|
||||
regs.time_over = false;
|
||||
regs.range_over = false;
|
||||
}
|
||||
|
||||
if(line == 1) {
|
||||
//mosaic reset
|
||||
for(int bg = BG1; bg <= BG4; bg++) regs.bg_y[bg] = 1;
|
||||
regs.mosaic_countdown = regs.mosaic_size + 1;
|
||||
regs.mosaic_countdown--;
|
||||
} else {
|
||||
for(int bg = BG1; bg <= BG4; bg++) {
|
||||
if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) regs.bg_y[bg] = line;
|
||||
}
|
||||
if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic_size + 1;
|
||||
regs.mosaic_countdown--;
|
||||
}
|
||||
|
||||
if(line == 241) {
|
||||
video.refresh();
|
||||
scheduler.exit(Scheduler::Event::Frame);
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::render_scanline() -> void {
|
||||
if(line >= 1 && line < (!overscan() ? 225 : 240)) {
|
||||
if(framecounter) return;
|
||||
render_line_oam_rto();
|
||||
render_line();
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::frame() -> void {
|
||||
if(field() == 0) {
|
||||
display.interlace = regs.interlace;
|
||||
regs.scanlines = (regs.overscan == false) ? 224 : 239;
|
||||
}
|
||||
|
||||
framecounter = (frameskip == 0 ? 0 : (framecounter + 1) % frameskip);
|
||||
}
|
||||
|
||||
auto PPU::enable() -> void {
|
||||
function<auto (uint, uint8) -> uint8> reader{&PPU::mmio_read, (PPU*)&ppu};
|
||||
function<auto (uint, uint8) -> void> writer{&PPU::mmio_write, (PPU*)&ppu};
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);
|
||||
}
|
||||
|
||||
auto PPU::power() -> void {
|
||||
for(auto& n : vram) n = 0x00;
|
||||
for(auto& n : oam) n = 0x00;
|
||||
for(auto& n : cgram) n = 0x00;
|
||||
flush_tiledata_cache();
|
||||
|
||||
region = (system.region() == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL
|
||||
|
||||
regs.ioamaddr = 0x0000;
|
||||
regs.icgramaddr = 0x01ff;
|
||||
|
||||
//$2100
|
||||
regs.display_disabled = true;
|
||||
regs.display_brightness = 15;
|
||||
|
||||
//$2101
|
||||
regs.oam_basesize = 0;
|
||||
regs.oam_nameselect = 0;
|
||||
regs.oam_tdaddr = 0x0000;
|
||||
|
||||
cache.oam_basesize = 0;
|
||||
cache.oam_nameselect = 0;
|
||||
cache.oam_tdaddr = 0x0000;
|
||||
|
||||
//$2102-$2103
|
||||
regs.oam_baseaddr = 0x0000;
|
||||
regs.oam_addr = 0x0000;
|
||||
regs.oam_priority = false;
|
||||
regs.oam_firstsprite = 0;
|
||||
|
||||
//$2104
|
||||
regs.oam_latchdata = 0x00;
|
||||
|
||||
//$2105
|
||||
regs.bg_tilesize[BG1] = 0;
|
||||
regs.bg_tilesize[BG2] = 0;
|
||||
regs.bg_tilesize[BG3] = 0;
|
||||
regs.bg_tilesize[BG4] = 0;
|
||||
regs.bg3_priority = 0;
|
||||
regs.bg_mode = 0;
|
||||
|
||||
//$2106
|
||||
regs.mosaic_size = 0;
|
||||
regs.mosaic_enabled[BG1] = false;
|
||||
regs.mosaic_enabled[BG2] = false;
|
||||
regs.mosaic_enabled[BG3] = false;
|
||||
regs.mosaic_enabled[BG4] = false;
|
||||
regs.mosaic_countdown = 0;
|
||||
|
||||
//$2107-$210a
|
||||
regs.bg_scaddr[BG1] = 0x0000;
|
||||
regs.bg_scaddr[BG2] = 0x0000;
|
||||
regs.bg_scaddr[BG3] = 0x0000;
|
||||
regs.bg_scaddr[BG4] = 0x0000;
|
||||
regs.bg_scsize[BG1] = SC_32x32;
|
||||
regs.bg_scsize[BG2] = SC_32x32;
|
||||
regs.bg_scsize[BG3] = SC_32x32;
|
||||
regs.bg_scsize[BG4] = SC_32x32;
|
||||
|
||||
//$210b-$210c
|
||||
regs.bg_tdaddr[BG1] = 0x0000;
|
||||
regs.bg_tdaddr[BG2] = 0x0000;
|
||||
regs.bg_tdaddr[BG3] = 0x0000;
|
||||
regs.bg_tdaddr[BG4] = 0x0000;
|
||||
|
||||
//$210d-$2114
|
||||
regs.bg_ofslatch = 0x00;
|
||||
regs.m7_hofs = regs.m7_vofs = 0x0000;
|
||||
regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000;
|
||||
regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000;
|
||||
regs.bg_hofs[BG3] = regs.bg_vofs[BG3] = 0x0000;
|
||||
regs.bg_hofs[BG4] = regs.bg_vofs[BG4] = 0x0000;
|
||||
|
||||
//$2115
|
||||
regs.vram_incmode = 1;
|
||||
regs.vram_mapping = 0;
|
||||
regs.vram_incsize = 1;
|
||||
|
||||
//$2116-$2117
|
||||
regs.vram_addr = 0x0000;
|
||||
|
||||
//$211a
|
||||
regs.mode7_repeat = 0;
|
||||
regs.mode7_vflip = false;
|
||||
regs.mode7_hflip = false;
|
||||
|
||||
//$211b-$2120
|
||||
regs.m7_latch = 0x00;
|
||||
regs.m7a = 0x0000;
|
||||
regs.m7b = 0x0000;
|
||||
regs.m7c = 0x0000;
|
||||
regs.m7d = 0x0000;
|
||||
regs.m7x = 0x0000;
|
||||
regs.m7y = 0x0000;
|
||||
|
||||
//$2121
|
||||
regs.cgram_addr = 0x0000;
|
||||
|
||||
//$2122
|
||||
regs.cgram_latchdata = 0x00;
|
||||
|
||||
//$2123-$2125
|
||||
regs.window1_enabled[BG1] = false;
|
||||
regs.window1_enabled[BG2] = false;
|
||||
regs.window1_enabled[BG3] = false;
|
||||
regs.window1_enabled[BG4] = false;
|
||||
regs.window1_enabled[OAM] = false;
|
||||
regs.window1_enabled[COL] = false;
|
||||
|
||||
regs.window1_invert [BG1] = false;
|
||||
regs.window1_invert [BG2] = false;
|
||||
regs.window1_invert [BG3] = false;
|
||||
regs.window1_invert [BG4] = false;
|
||||
regs.window1_invert [OAM] = false;
|
||||
regs.window1_invert [COL] = false;
|
||||
|
||||
regs.window2_enabled[BG1] = false;
|
||||
regs.window2_enabled[BG2] = false;
|
||||
regs.window2_enabled[BG3] = false;
|
||||
regs.window2_enabled[BG4] = false;
|
||||
regs.window2_enabled[OAM] = false;
|
||||
regs.window2_enabled[COL] = false;
|
||||
|
||||
regs.window2_invert [BG1] = false;
|
||||
regs.window2_invert [BG2] = false;
|
||||
regs.window2_invert [BG3] = false;
|
||||
regs.window2_invert [BG4] = false;
|
||||
regs.window2_invert [OAM] = false;
|
||||
regs.window2_invert [COL] = false;
|
||||
|
||||
//$2126-$2129
|
||||
regs.window1_left = 0x00;
|
||||
regs.window1_right = 0x00;
|
||||
regs.window2_left = 0x00;
|
||||
regs.window2_right = 0x00;
|
||||
|
||||
//$212a-$212b
|
||||
regs.window_mask[BG1] = 0;
|
||||
regs.window_mask[BG2] = 0;
|
||||
regs.window_mask[BG3] = 0;
|
||||
regs.window_mask[BG4] = 0;
|
||||
regs.window_mask[OAM] = 0;
|
||||
regs.window_mask[COL] = 0;
|
||||
|
||||
//$212c-$212d
|
||||
regs.bg_enabled[BG1] = false;
|
||||
regs.bg_enabled[BG2] = false;
|
||||
regs.bg_enabled[BG3] = false;
|
||||
regs.bg_enabled[BG4] = false;
|
||||
regs.bg_enabled[OAM] = false;
|
||||
regs.bgsub_enabled[BG1] = false;
|
||||
regs.bgsub_enabled[BG2] = false;
|
||||
regs.bgsub_enabled[BG3] = false;
|
||||
regs.bgsub_enabled[BG4] = false;
|
||||
regs.bgsub_enabled[OAM] = false;
|
||||
|
||||
//$212e-$212f
|
||||
regs.window_enabled[BG1] = false;
|
||||
regs.window_enabled[BG2] = false;
|
||||
regs.window_enabled[BG3] = false;
|
||||
regs.window_enabled[BG4] = false;
|
||||
regs.window_enabled[OAM] = false;
|
||||
regs.sub_window_enabled[BG1] = false;
|
||||
regs.sub_window_enabled[BG2] = false;
|
||||
regs.sub_window_enabled[BG3] = false;
|
||||
regs.sub_window_enabled[BG4] = false;
|
||||
regs.sub_window_enabled[OAM] = false;
|
||||
|
||||
//$2130
|
||||
regs.color_mask = 0;
|
||||
regs.colorsub_mask = 0;
|
||||
regs.addsub_mode = false;
|
||||
regs.direct_color = false;
|
||||
|
||||
//$2131
|
||||
regs.color_mode = 0;
|
||||
regs.color_halve = false;
|
||||
regs.color_enabled[BACK] = false;
|
||||
regs.color_enabled[OAM] = false;
|
||||
regs.color_enabled[BG4] = false;
|
||||
regs.color_enabled[BG3] = false;
|
||||
regs.color_enabled[BG2] = false;
|
||||
regs.color_enabled[BG1] = false;
|
||||
|
||||
//$2132
|
||||
regs.color_r = 0x00;
|
||||
regs.color_g = 0x00;
|
||||
regs.color_b = 0x00;
|
||||
regs.color_rgb = 0x0000;
|
||||
|
||||
//$2133
|
||||
regs.mode7_extbg = false;
|
||||
regs.pseudo_hires = false;
|
||||
regs.overscan = false;
|
||||
regs.scanlines = 224;
|
||||
regs.oam_interlace = false;
|
||||
regs.interlace = false;
|
||||
|
||||
//$2137
|
||||
regs.hcounter = 0;
|
||||
regs.vcounter = 0;
|
||||
regs.latch_hcounter = 0;
|
||||
regs.latch_vcounter = 0;
|
||||
regs.counters_latched = false;
|
||||
|
||||
//$2139-$213a
|
||||
regs.vram_readbuffer = 0x0000;
|
||||
|
||||
//$213e
|
||||
regs.time_over = false;
|
||||
regs.range_over = false;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
auto PPU::reset() -> void {
|
||||
create(Enter, system.cpuFrequency());
|
||||
PPUcounter::reset();
|
||||
memory::fill(output, 512 * 480 * sizeof(uint32));
|
||||
|
||||
frame();
|
||||
|
||||
//$2100
|
||||
regs.display_disabled = true;
|
||||
|
||||
display.interlace = false;
|
||||
display.overscan = false;
|
||||
regs.scanlines = 224;
|
||||
|
||||
memset(sprite_list, 0, sizeof(sprite_list));
|
||||
sprite_list_valid = false;
|
||||
|
||||
//open bus support
|
||||
regs.ppu1_mdr = 0xff;
|
||||
regs.ppu2_mdr = 0xff;
|
||||
|
||||
//bg line counters
|
||||
regs.bg_y[0] = 0;
|
||||
regs.bg_y[1] = 0;
|
||||
regs.bg_y[2] = 0;
|
||||
regs.bg_y[3] = 0;
|
||||
|
||||
video.reset();
|
||||
}
|
||||
|
||||
auto PPU::layer_enable(uint layer, uint priority, bool enable) -> void {
|
||||
switch(layer * 4 + priority) {
|
||||
case 0: layer_enabled[BG1][0] = enable; break;
|
||||
case 1: layer_enabled[BG1][1] = enable; break;
|
||||
case 4: layer_enabled[BG2][0] = enable; break;
|
||||
case 5: layer_enabled[BG2][1] = enable; break;
|
||||
case 8: layer_enabled[BG3][0] = enable; break;
|
||||
case 9: layer_enabled[BG3][1] = enable; break;
|
||||
case 12: layer_enabled[BG4][0] = enable; break;
|
||||
case 13: layer_enabled[BG4][1] = enable; break;
|
||||
case 16: layer_enabled[OAM][0] = enable; break;
|
||||
case 17: layer_enabled[OAM][1] = enable; break;
|
||||
case 18: layer_enabled[OAM][2] = enable; break;
|
||||
case 19: layer_enabled[OAM][3] = enable; break;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::set_frameskip(uint frameskip_) -> void {
|
||||
frameskip = frameskip_;
|
||||
framecounter = 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
#include <sfc/ppu/video.hpp>
|
||||
|
||||
struct PPU : Thread, public PPUcounter {
|
||||
enum : bool { Threaded = true };
|
||||
|
||||
PPU();
|
||||
~PPU();
|
||||
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto synchronizeCPU() -> void;
|
||||
|
||||
#include "memory/memory.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "render/render.hpp"
|
||||
|
||||
static auto Enter() -> void;
|
||||
auto add_clocks(uint clocks) -> void;
|
||||
|
||||
alwaysinline auto interlace() const -> bool { return display.interlace; }
|
||||
alwaysinline auto overscan() const -> bool { return display.overscan; }
|
||||
|
||||
auto render_line() -> void;
|
||||
auto update_oam_status() -> void;
|
||||
|
||||
auto scanline() -> void;
|
||||
auto render_scanline() -> void;
|
||||
auto frame() -> void;
|
||||
auto main() -> void;
|
||||
auto enable() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto layer_enable(uint layer, uint priority, bool enable) -> void;
|
||||
auto set_frameskip(uint frameskip) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
enum : uint { NTSC = 0, PAL = 1 };
|
||||
enum : uint { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 };
|
||||
enum : uint { SC_32x32 = 0, SC_64x32 = 1, SC_32x64 = 2, SC_64x64 = 3 };
|
||||
|
||||
uint8 vram[128 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
|
||||
uint32* output;
|
||||
|
||||
uint ppu1_version = 1;
|
||||
uint ppu2_version = 3;
|
||||
|
||||
uint8 region;
|
||||
uint line;
|
||||
|
||||
struct {
|
||||
bool interlace;
|
||||
bool overscan;
|
||||
} display;
|
||||
|
||||
struct {
|
||||
//$2101
|
||||
uint8 oam_basesize;
|
||||
uint8 oam_nameselect;
|
||||
uint16 oam_tdaddr;
|
||||
|
||||
//$210d-$210e
|
||||
uint16 m7_hofs, m7_vofs;
|
||||
|
||||
//$211b-$2120
|
||||
uint16 m7a, m7b, m7c, m7d, m7x, m7y;
|
||||
} cache;
|
||||
|
||||
uint16 mosaic_table[16][4096];
|
||||
bool layer_enabled[5][4];
|
||||
uint frameskip;
|
||||
uint framecounter;
|
||||
};
|
||||
|
||||
extern PPU ppu;
|
|
@ -1,21 +0,0 @@
|
|||
//color addition / subtraction
|
||||
//thanks go to blargg for the optimized algorithms
|
||||
inline auto PPU::addsub(uint32 x, uint32 y, bool halve) -> uint16 {
|
||||
if(!regs.color_mode) {
|
||||
if(!halve) {
|
||||
uint sum = x + y;
|
||||
uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420;
|
||||
return (sum - carry) | (carry - (carry >> 5));
|
||||
} else {
|
||||
return (x + y - ((x ^ y) & 0x0421)) >> 1;
|
||||
}
|
||||
} else {
|
||||
uint diff = x - y + 0x8420;
|
||||
uint borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420;
|
||||
if(!halve) {
|
||||
return (diff - borrow) & (borrow - (borrow >> 5));
|
||||
} else {
|
||||
return (((diff - borrow) & (borrow - (borrow >> 5))) & 0x7bde) >> 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,205 +0,0 @@
|
|||
//called once at the start of every rendered scanline
|
||||
auto PPU::update_bg_info() -> void {
|
||||
const unsigned hires = (regs.bg_mode == 5 || regs.bg_mode == 6);
|
||||
const unsigned width = (!hires ? 256 : 512);
|
||||
|
||||
for(unsigned bg = 0; bg < 4; bg++) {
|
||||
bg_info[bg].th = (regs.bg_tilesize[bg] ? 4 : 3);
|
||||
bg_info[bg].tw = (hires ? 4 : (uint)bg_info[bg].th);
|
||||
|
||||
bg_info[bg].mx = (bg_info[bg].th == 4 ? (width << 1) : width);
|
||||
bg_info[bg].my = bg_info[bg].mx;
|
||||
if(regs.bg_scsize[bg] & 0x01) bg_info[bg].mx <<= 1;
|
||||
if(regs.bg_scsize[bg] & 0x02) bg_info[bg].my <<= 1;
|
||||
bg_info[bg].mx--;
|
||||
bg_info[bg].my--;
|
||||
|
||||
bg_info[bg].scy = (regs.bg_scsize[bg] & 0x02) ? (32 << 5) : 0;
|
||||
bg_info[bg].scx = (regs.bg_scsize[bg] & 0x01) ? (32 << 5) : 0;
|
||||
if(regs.bg_scsize[bg] == 3) bg_info[bg].scy <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
template<uint bg>
|
||||
auto PPU::bg_get_tile(uint16 x, uint16 y) -> uint16 {
|
||||
x = (x & bg_info[bg].mx) >> bg_info[bg].tw;
|
||||
y = (y & bg_info[bg].my) >> bg_info[bg].th;
|
||||
|
||||
uint16 pos = ((y & 0x1f) << 5) + (x & 0x1f);
|
||||
if(y & 0x20) pos += bg_info[bg].scy;
|
||||
if(x & 0x20) pos += bg_info[bg].scx;
|
||||
|
||||
const uint16 addr = regs.bg_scaddr[bg] + (pos << 1);
|
||||
return vram[addr] + (vram[addr + 1] << 8);
|
||||
}
|
||||
|
||||
#define setpixel_main(x) \
|
||||
if(pixel_cache[x].pri_main < tile_pri) { \
|
||||
pixel_cache[x].pri_main = tile_pri; \
|
||||
pixel_cache[x].bg_main = bg; \
|
||||
pixel_cache[x].src_main = col; \
|
||||
pixel_cache[x].ce_main = false; \
|
||||
}
|
||||
|
||||
#define setpixel_sub(x) \
|
||||
if(pixel_cache[x].pri_sub < tile_pri) { \
|
||||
pixel_cache[x].pri_sub = tile_pri; \
|
||||
pixel_cache[x].bg_sub = bg; \
|
||||
pixel_cache[x].src_sub = col; \
|
||||
pixel_cache[x].ce_sub = false; \
|
||||
}
|
||||
|
||||
template<uint mode, uint bg, uint color_depth>
|
||||
auto PPU::render_line_bg(uint8 pri0_pos, uint8 pri1_pos) -> void {
|
||||
if(layer_enabled[bg][0] == false) pri0_pos = 0;
|
||||
if(layer_enabled[bg][1] == false) pri1_pos = 0;
|
||||
if(pri0_pos + pri1_pos == 0) return;
|
||||
|
||||
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) return;
|
||||
|
||||
const bool bg_enabled = regs.bg_enabled[bg];
|
||||
const bool bgsub_enabled = regs.bgsub_enabled[bg];
|
||||
|
||||
const uint16 opt_valid_bit = (bg == BG1) ? 0x2000 : (bg == BG2) ? 0x4000 : 0x0000;
|
||||
const uint8 bgpal_index = (mode == 0 ? (bg << 5) : 0);
|
||||
|
||||
const uint8 pal_size = 2 << color_depth; //<<2 (*4), <<4 (*16), <<8 (*256)
|
||||
const uint16 tile_mask = 0x0fff >> color_depth; //0x0fff, 0x07ff, 0x03ff
|
||||
//4 + color_depth = >>(4-6) -- / {16, 32, 64 } bytes/tile
|
||||
//index is a tile number count to add to base tile number
|
||||
const unsigned tiledata_index = regs.bg_tdaddr[bg] >> (4 + color_depth);
|
||||
|
||||
const uint8 *bg_td = bg_tiledata[color_depth];
|
||||
const uint8 *bg_td_state = bg_tiledata_state[color_depth];
|
||||
|
||||
const uint8 tile_width = bg_info[bg].tw;
|
||||
const uint8 tile_height = bg_info[bg].th;
|
||||
const uint16 mask_x = bg_info[bg].mx; //screen width mask
|
||||
const uint16 mask_y = bg_info[bg].my; //screen height mask
|
||||
|
||||
uint16 y = regs.bg_y[bg];
|
||||
uint16 hscroll = regs.bg_hofs[bg];
|
||||
uint16 vscroll = regs.bg_vofs[bg];
|
||||
|
||||
const unsigned hires = (mode == 5 || mode == 6);
|
||||
const unsigned width = (!hires ? 256 : 512);
|
||||
|
||||
if(hires) {
|
||||
hscroll <<= 1;
|
||||
if(regs.interlace) y = (y << 1) + field();
|
||||
}
|
||||
|
||||
uint16 hval, vval;
|
||||
uint16 tile_pri, tile_num;
|
||||
uint8 pal_index, pal_num;
|
||||
uint16 hoffset, voffset, opt_x, col;
|
||||
bool mirror_x, mirror_y;
|
||||
|
||||
const uint8* tile_ptr;
|
||||
const uint16* mtable = mosaic_table[regs.mosaic_enabled[bg] ? (uint)regs.mosaic_size : 0];
|
||||
const bool is_opt_mode = (mode == 2 || mode == 4 || mode == 6);
|
||||
const bool is_direct_color_mode = (regs.direct_color == true && bg == BG1 && (mode == 3 || mode == 4));
|
||||
|
||||
build_window_tables(bg);
|
||||
const uint8* wt_main = window[bg].main;
|
||||
const uint8* wt_sub = window[bg].sub;
|
||||
|
||||
uint16 prev_x = 0xffff, prev_y = 0xffff, prev_optx = 0xffff;
|
||||
for(uint16 x = 0; x < width; x++) {
|
||||
hoffset = mtable[x] + hscroll;
|
||||
voffset = y + vscroll;
|
||||
|
||||
if(is_opt_mode) {
|
||||
opt_x = (x + (hscroll & 7));
|
||||
|
||||
//tile 0 is unaffected by OPT mode...
|
||||
if(opt_x >= 8) {
|
||||
//cache tile data in hval, vval if possible
|
||||
if((opt_x >> 3) != (prev_optx >> 3)) {
|
||||
prev_optx = opt_x;
|
||||
|
||||
hval = bg_get_tile<BG3>((opt_x - 8) + (regs.bg_hofs[BG3] & ~7), regs.bg_vofs[BG3]);
|
||||
if(mode != 4) {
|
||||
vval = bg_get_tile<BG3>((opt_x - 8) + (regs.bg_hofs[BG3] & ~7), regs.bg_vofs[BG3] + 8);
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == 4) {
|
||||
if(hval & opt_valid_bit) {
|
||||
if(!(hval & 0x8000)) {
|
||||
hoffset = opt_x + (hval & ~7);
|
||||
} else {
|
||||
voffset = y + hval;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(hval & opt_valid_bit) {
|
||||
hoffset = opt_x + (hval & ~7);
|
||||
}
|
||||
if(vval & opt_valid_bit) {
|
||||
voffset = y + vval;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hoffset &= mask_x;
|
||||
voffset &= mask_y;
|
||||
|
||||
if((hoffset >> 3) != prev_x || (voffset >> 3) != prev_y) {
|
||||
prev_x = (hoffset >> 3);
|
||||
prev_y = (voffset >> 3);
|
||||
|
||||
tile_num = bg_get_tile<bg>(hoffset, voffset); //format = vhopppcc cccccccc
|
||||
mirror_y = (tile_num & 0x8000);
|
||||
mirror_x = (tile_num & 0x4000);
|
||||
tile_pri = (tile_num & 0x2000) ? pri1_pos : pri0_pos;
|
||||
pal_num = ((tile_num >> 10) & 7);
|
||||
pal_index = bgpal_index + (pal_num << pal_size);
|
||||
|
||||
if(tile_width == 4) { //16x16 horizontal tile mirroring
|
||||
if((bool)(hoffset & 8) != mirror_x) tile_num++;
|
||||
}
|
||||
|
||||
if(tile_height == 4) { //16x16 vertical tile mirroring
|
||||
if((bool)(voffset & 8) != mirror_y) tile_num += 16;
|
||||
}
|
||||
|
||||
tile_num &= 0x03ff;
|
||||
tile_num += tiledata_index;
|
||||
tile_num &= tile_mask;
|
||||
|
||||
if(bg_td_state[tile_num] == 1) {
|
||||
render_bg_tile<color_depth>(tile_num);
|
||||
}
|
||||
|
||||
if(mirror_y) voffset ^= 7; //invert y tile pos
|
||||
tile_ptr = bg_td + (tile_num * 64) + ((voffset & 7) * 8);
|
||||
}
|
||||
|
||||
if(mirror_x) hoffset ^= 7; //invert x tile pos
|
||||
col = *(tile_ptr + (hoffset & 7));
|
||||
if(col) {
|
||||
if(is_direct_color_mode) {
|
||||
col = get_direct_color(pal_num, col);
|
||||
} else {
|
||||
col = get_palette(col + pal_index);
|
||||
}
|
||||
|
||||
if(!hires) {
|
||||
if(bg_enabled == true && !wt_main[x]) { setpixel_main(x); }
|
||||
if(bgsub_enabled == true && !wt_sub[x]) { setpixel_sub(x); }
|
||||
} else {
|
||||
int hx = x >> 1;
|
||||
if(x & 1) {
|
||||
if(bg_enabled == true && !wt_main[hx]) { setpixel_main(hx); }
|
||||
} else {
|
||||
if(bgsub_enabled == true && !wt_sub[hx]) { setpixel_sub(hx); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef setpixel_main
|
||||
#undef setpixel_sub
|
|
@ -1,143 +0,0 @@
|
|||
#define render_bg_tile_line_2bpp(mask) \
|
||||
col = !!(d0 & mask) << 0; \
|
||||
col += !!(d1 & mask) << 1; \
|
||||
*dest++ = col
|
||||
|
||||
#define render_bg_tile_line_4bpp(mask) \
|
||||
col = !!(d0 & mask) << 0; \
|
||||
col += !!(d1 & mask) << 1; \
|
||||
col += !!(d2 & mask) << 2; \
|
||||
col += !!(d3 & mask) << 3; \
|
||||
*dest++ = col
|
||||
|
||||
#define render_bg_tile_line_8bpp(mask) \
|
||||
col = !!(d0 & mask) << 0; \
|
||||
col += !!(d1 & mask) << 1; \
|
||||
col += !!(d2 & mask) << 2; \
|
||||
col += !!(d3 & mask) << 3; \
|
||||
col += !!(d4 & mask) << 4; \
|
||||
col += !!(d5 & mask) << 5; \
|
||||
col += !!(d6 & mask) << 6; \
|
||||
col += !!(d7 & mask) << 7; \
|
||||
*dest++ = col
|
||||
|
||||
template<uint color_depth>
|
||||
auto PPU::render_bg_tile(uint16 tile_num) -> void {
|
||||
uint8 col, d0, d1, d2, d3, d4, d5, d6, d7;
|
||||
|
||||
if(color_depth == COLORDEPTH_4) {
|
||||
uint8* dest = (uint8*)bg_tiledata[TILE_2BIT] + tile_num * 64;
|
||||
unsigned pos = tile_num * 16;
|
||||
unsigned y = 8;
|
||||
while(y--) {
|
||||
d0 = vram[pos ];
|
||||
d1 = vram[pos + 1];
|
||||
render_bg_tile_line_2bpp(0x80);
|
||||
render_bg_tile_line_2bpp(0x40);
|
||||
render_bg_tile_line_2bpp(0x20);
|
||||
render_bg_tile_line_2bpp(0x10);
|
||||
render_bg_tile_line_2bpp(0x08);
|
||||
render_bg_tile_line_2bpp(0x04);
|
||||
render_bg_tile_line_2bpp(0x02);
|
||||
render_bg_tile_line_2bpp(0x01);
|
||||
pos += 2;
|
||||
}
|
||||
bg_tiledata_state[TILE_2BIT][tile_num] = 0;
|
||||
}
|
||||
|
||||
if(color_depth == COLORDEPTH_16) {
|
||||
uint8* dest = (uint8*)bg_tiledata[TILE_4BIT] + tile_num * 64;
|
||||
unsigned pos = tile_num * 32;
|
||||
unsigned y = 8;
|
||||
while(y--) {
|
||||
d0 = vram[pos ];
|
||||
d1 = vram[pos + 1];
|
||||
d2 = vram[pos + 16];
|
||||
d3 = vram[pos + 17];
|
||||
render_bg_tile_line_4bpp(0x80);
|
||||
render_bg_tile_line_4bpp(0x40);
|
||||
render_bg_tile_line_4bpp(0x20);
|
||||
render_bg_tile_line_4bpp(0x10);
|
||||
render_bg_tile_line_4bpp(0x08);
|
||||
render_bg_tile_line_4bpp(0x04);
|
||||
render_bg_tile_line_4bpp(0x02);
|
||||
render_bg_tile_line_4bpp(0x01);
|
||||
pos += 2;
|
||||
}
|
||||
bg_tiledata_state[TILE_4BIT][tile_num] = 0;
|
||||
}
|
||||
|
||||
if(color_depth == COLORDEPTH_256) {
|
||||
uint8* dest = (uint8*)bg_tiledata[TILE_8BIT] + tile_num * 64;
|
||||
unsigned pos = tile_num * 64;
|
||||
unsigned y = 8;
|
||||
while(y--) {
|
||||
d0 = vram[pos ];
|
||||
d1 = vram[pos + 1];
|
||||
d2 = vram[pos + 16];
|
||||
d3 = vram[pos + 17];
|
||||
d4 = vram[pos + 32];
|
||||
d5 = vram[pos + 33];
|
||||
d6 = vram[pos + 48];
|
||||
d7 = vram[pos + 49];
|
||||
render_bg_tile_line_8bpp(0x80);
|
||||
render_bg_tile_line_8bpp(0x40);
|
||||
render_bg_tile_line_8bpp(0x20);
|
||||
render_bg_tile_line_8bpp(0x10);
|
||||
render_bg_tile_line_8bpp(0x08);
|
||||
render_bg_tile_line_8bpp(0x04);
|
||||
render_bg_tile_line_8bpp(0x02);
|
||||
render_bg_tile_line_8bpp(0x01);
|
||||
pos += 2;
|
||||
}
|
||||
bg_tiledata_state[TILE_8BIT][tile_num] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#undef render_bg_tile_line_2bpp
|
||||
#undef render_bg_tile_line_4bpp
|
||||
#undef render_bg_tile_line_8bpp
|
||||
|
||||
auto PPU::flush_pixel_cache() -> void {
|
||||
uint16 main = get_palette(0);
|
||||
uint16 sub = (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6)
|
||||
? main
|
||||
: regs.color_rgb;
|
||||
|
||||
unsigned i = 255;
|
||||
do {
|
||||
pixel_cache[i].src_main = main;
|
||||
pixel_cache[i].src_sub = sub;
|
||||
pixel_cache[i].bg_main = BACK;
|
||||
pixel_cache[i].bg_sub = BACK;
|
||||
pixel_cache[i].ce_main = false;
|
||||
pixel_cache[i].ce_sub = false;
|
||||
pixel_cache[i].pri_main = 0;
|
||||
pixel_cache[i].pri_sub = 0;
|
||||
} while(i--);
|
||||
}
|
||||
|
||||
auto PPU::alloc_tiledata_cache() -> void {
|
||||
bg_tiledata[TILE_2BIT] = new uint8[262144]();
|
||||
bg_tiledata[TILE_4BIT] = new uint8[131072]();
|
||||
bg_tiledata[TILE_8BIT] = new uint8[ 65536]();
|
||||
bg_tiledata_state[TILE_2BIT] = new uint8[ 4096]();
|
||||
bg_tiledata_state[TILE_4BIT] = new uint8[ 2048]();
|
||||
bg_tiledata_state[TILE_8BIT] = new uint8[ 1024]();
|
||||
}
|
||||
|
||||
//marks all tiledata cache entries as dirty
|
||||
auto PPU::flush_tiledata_cache() -> void {
|
||||
for(unsigned i = 0; i < 4096; i++) bg_tiledata_state[TILE_2BIT][i] = 1;
|
||||
for(unsigned i = 0; i < 2048; i++) bg_tiledata_state[TILE_4BIT][i] = 1;
|
||||
for(unsigned i = 0; i < 1024; i++) bg_tiledata_state[TILE_8BIT][i] = 1;
|
||||
}
|
||||
|
||||
auto PPU::free_tiledata_cache() -> void {
|
||||
delete[] bg_tiledata[TILE_2BIT];
|
||||
delete[] bg_tiledata[TILE_4BIT];
|
||||
delete[] bg_tiledata[TILE_8BIT];
|
||||
delete[] bg_tiledata_state[TILE_2BIT];
|
||||
delete[] bg_tiledata_state[TILE_4BIT];
|
||||
delete[] bg_tiledata_state[TILE_8BIT];
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
inline auto PPU::get_palette(uint8 index) -> uint16 {
|
||||
const uint addr = index << 1;
|
||||
return cgram[addr] + (cgram[addr + 1] << 8);
|
||||
}
|
||||
|
||||
//p = 00000bgr <palette data>
|
||||
//t = BBGGGRRR <tilemap data>
|
||||
//r = 0BBb00GGGg0RRRr0 <return data>
|
||||
inline auto PPU::get_direct_color(uint8 p, uint8 t) -> uint16 {
|
||||
return ((t & 7) << 2) | ((p & 1) << 1) |
|
||||
(((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) |
|
||||
((t >> 6) << 13) | ((p >> 2) << 12);
|
||||
}
|
||||
|
||||
inline auto PPU::get_pixel_normal(uint32 x) -> uint16 {
|
||||
pixel_t& p = pixel_cache[x];
|
||||
uint16 src_main, src_sub;
|
||||
uint8 bg_sub;
|
||||
|
||||
src_main = p.src_main;
|
||||
|
||||
if(!regs.addsub_mode) {
|
||||
bg_sub = BACK;
|
||||
src_sub = regs.color_rgb;
|
||||
} else {
|
||||
bg_sub = p.bg_sub;
|
||||
src_sub = p.src_sub;
|
||||
}
|
||||
|
||||
if(!window[COL].main[x]) {
|
||||
if(!window[COL].sub[x]) {
|
||||
return 0x0000;
|
||||
}
|
||||
src_main = 0x0000;
|
||||
}
|
||||
|
||||
if(!p.ce_main && regs.color_enabled[p.bg_main] && window[COL].sub[x]) {
|
||||
bool halve = false;
|
||||
if(regs.color_halve && window[COL].main[x]) {
|
||||
if(regs.addsub_mode && bg_sub == BACK);
|
||||
else {
|
||||
halve = true;
|
||||
}
|
||||
}
|
||||
return addsub(src_main, src_sub, halve);
|
||||
}
|
||||
|
||||
return src_main;
|
||||
}
|
||||
|
||||
inline auto PPU::get_pixel_swap(uint32 x) -> uint16 {
|
||||
pixel_t& p = pixel_cache[x];
|
||||
uint16 src_main, src_sub;
|
||||
uint8 bg_sub;
|
||||
|
||||
src_main = p.src_sub;
|
||||
|
||||
if(!regs.addsub_mode) {
|
||||
bg_sub = BACK;
|
||||
src_sub = regs.color_rgb;
|
||||
} else {
|
||||
bg_sub = p.bg_main;
|
||||
src_sub = p.src_main;
|
||||
}
|
||||
|
||||
if(!window[COL].main[x]) {
|
||||
if(!window[COL].sub[x]) {
|
||||
return 0x0000;
|
||||
}
|
||||
src_main = 0x0000;
|
||||
}
|
||||
|
||||
if(!p.ce_sub && regs.color_enabled[p.bg_sub] && window[COL].sub[x]) {
|
||||
bool halve = false;
|
||||
if(regs.color_halve && window[COL].main[x]) {
|
||||
if(regs.addsub_mode && bg_sub == BACK);
|
||||
else {
|
||||
halve = true;
|
||||
}
|
||||
}
|
||||
return addsub(src_main, src_sub, halve);
|
||||
}
|
||||
|
||||
return src_main;
|
||||
}
|
||||
|
||||
inline auto PPU::render_line_output() -> void {
|
||||
auto ptr = (uint32*)output + (line * 1024) + ((interlace() && field()) ? 512 : 0);
|
||||
|
||||
if(!regs.pseudo_hires && regs.bg_mode != 5 && regs.bg_mode != 6) {
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
uint color = (regs.display_brightness << 15) | get_pixel_normal(x);
|
||||
*ptr++ = color;
|
||||
*ptr++ = color;
|
||||
}
|
||||
} else {
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
*ptr++ = (regs.display_brightness << 15) | get_pixel_swap(x);
|
||||
*ptr++ = (regs.display_brightness << 15) | get_pixel_normal(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline auto PPU::render_line_clear() -> void {
|
||||
auto ptr = (uint32*)output + (line * 1024) + ((interlace() && field()) ? 512 : 0);
|
||||
memory::fill(ptr, 512 * sizeof(uint32));
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
//bsnes mode7 renderer
|
||||
//
|
||||
//base algorithm written by anomie
|
||||
//bsnes implementation written by byuu
|
||||
//
|
||||
//supports mode 7 + extbg + rotate + zoom + direct color + scrolling + m7sel + windowing + mosaic
|
||||
//interlace and pseudo-hires support are automatic via main rendering routine
|
||||
|
||||
//13-bit sign extend
|
||||
//--s---vvvvvvvvvv -> ssssssvvvvvvvvvv
|
||||
#define CLIP(x) ( ((x) & 0x2000) ? ( (x) | ~0x03ff) : ((x) & 0x03ff) )
|
||||
|
||||
template<uint bg>
|
||||
auto PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) -> void {
|
||||
if(layer_enabled[bg][0] == false) pri0_pos = 0;
|
||||
if(layer_enabled[bg][1] == false) pri1_pos = 0;
|
||||
if(pri0_pos + pri1_pos == 0) return;
|
||||
|
||||
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) return;
|
||||
|
||||
int32 px, py;
|
||||
int32 tx, ty, tile, palette;
|
||||
|
||||
int32 a = sclip<16>(cache.m7a);
|
||||
int32 b = sclip<16>(cache.m7b);
|
||||
int32 c = sclip<16>(cache.m7c);
|
||||
int32 d = sclip<16>(cache.m7d);
|
||||
|
||||
int32 cx = sclip<13>(cache.m7x);
|
||||
int32 cy = sclip<13>(cache.m7y);
|
||||
int32 hofs = sclip<13>(cache.m7_hofs);
|
||||
int32 vofs = sclip<13>(cache.m7_vofs);
|
||||
|
||||
int _pri, _x;
|
||||
bool _bg_enabled = regs.bg_enabled[bg];
|
||||
bool _bgsub_enabled = regs.bgsub_enabled[bg];
|
||||
|
||||
build_window_tables(bg);
|
||||
uint8* wt_main = window[bg].main;
|
||||
uint8* wt_sub = window[bg].sub;
|
||||
|
||||
int32 y = (regs.mode7_vflip == false ? line : 255 - line);
|
||||
|
||||
uint16* mtable_x;
|
||||
uint16* mtable_y;
|
||||
if(bg == BG1) {
|
||||
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? (uint)regs.mosaic_size : 0];
|
||||
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? (uint)regs.mosaic_size : 0];
|
||||
} else { //bg == BG2
|
||||
//Mode7 EXTBG BG2 uses BG1 mosaic enable to control vertical mosaic,
|
||||
//and BG2 mosaic enable to control horizontal mosaic...
|
||||
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG2] == true) ? (uint)regs.mosaic_size : 0];
|
||||
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? (uint)regs.mosaic_size : 0];
|
||||
}
|
||||
|
||||
int32 psx = ((a * CLIP(hofs - cx)) & ~63) + ((b * CLIP(vofs - cy)) & ~63) + ((b * mtable_y[y]) & ~63) + (cx << 8);
|
||||
int32 psy = ((c * CLIP(hofs - cx)) & ~63) + ((d * CLIP(vofs - cy)) & ~63) + ((d * mtable_y[y]) & ~63) + (cy << 8);
|
||||
for(int32 x = 0; x < 256; x++) {
|
||||
px = psx + (a * mtable_x[x]);
|
||||
py = psy + (c * mtable_x[x]);
|
||||
|
||||
//mask floating-point bits (low 8 bits)
|
||||
px >>= 8;
|
||||
py >>= 8;
|
||||
|
||||
switch(regs.mode7_repeat) {
|
||||
case 0: //screen repetition outside of screen area
|
||||
case 1: { //same as case 0
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
} break;
|
||||
case 2: { //palette color 0 outside of screen area
|
||||
if((px | py) & ~1023) {
|
||||
palette = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
} break;
|
||||
case 3: { //character 0 repetition outside of screen area
|
||||
if((px | py) & ~1023) {
|
||||
tile = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
}
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
} break;
|
||||
}
|
||||
|
||||
if(bg == BG1) {
|
||||
_pri = pri0_pos;
|
||||
} else {
|
||||
_pri = (palette >> 7) ? pri1_pos : pri0_pos;
|
||||
palette &= 0x7f;
|
||||
}
|
||||
|
||||
if(!palette) continue;
|
||||
|
||||
_x = (regs.mode7_hflip == false) ? ((uint)x) : (255 - x);
|
||||
|
||||
uint32 col;
|
||||
if(regs.direct_color == true && bg == BG1) {
|
||||
//direct color mode does not apply to bg2, as it is only 128 colors...
|
||||
col = get_direct_color(0, palette);
|
||||
} else {
|
||||
col = get_palette(palette);
|
||||
}
|
||||
|
||||
if(regs.bg_enabled[bg] == true && !wt_main[_x]) {
|
||||
if(pixel_cache[_x].pri_main < _pri) {
|
||||
pixel_cache[_x].pri_main = _pri;
|
||||
pixel_cache[_x].bg_main = bg;
|
||||
pixel_cache[_x].src_main = col;
|
||||
pixel_cache[_x].ce_main = false;
|
||||
}
|
||||
}
|
||||
if(regs.bgsub_enabled[bg] == true && !wt_sub[_x]) {
|
||||
if(pixel_cache[_x].pri_sub < _pri) {
|
||||
pixel_cache[_x].pri_sub = _pri;
|
||||
pixel_cache[_x].bg_sub = bg;
|
||||
pixel_cache[_x].src_sub = col;
|
||||
pixel_cache[_x].ce_sub = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef CLIP
|
|
@ -1,233 +0,0 @@
|
|||
auto PPU::update_sprite_list(uint addr, uint8 data) -> void {
|
||||
if(addr < 0x0200) {
|
||||
unsigned i = addr >> 2;
|
||||
switch(addr & 3) {
|
||||
case 0: sprite_list[i].x = (sprite_list[i].x & 0x0100) | data; break;
|
||||
case 1: sprite_list[i].y = (data + 1) & 0xff; break;
|
||||
case 2: sprite_list[i].character = data; break;
|
||||
case 3: sprite_list[i].vflip = data & 0x80;
|
||||
sprite_list[i].hflip = data & 0x40;
|
||||
sprite_list[i].priority = (data >> 4) & 3;
|
||||
sprite_list[i].palette = (data >> 1) & 7;
|
||||
sprite_list[i].use_nameselect = data & 0x01;
|
||||
}
|
||||
} else {
|
||||
unsigned i = (addr & 0x1f) << 2;
|
||||
sprite_list[i + 0].x = ((data & 0x01) << 8) | (sprite_list[i + 0].x & 0xff);
|
||||
sprite_list[i + 0].size = data & 0x02;
|
||||
sprite_list[i + 1].x = ((data & 0x04) << 6) | (sprite_list[i + 1].x & 0xff);
|
||||
sprite_list[i + 1].size = data & 0x08;
|
||||
sprite_list[i + 2].x = ((data & 0x10) << 4) | (sprite_list[i + 2].x & 0xff);
|
||||
sprite_list[i + 2].size = data & 0x20;
|
||||
sprite_list[i + 3].x = ((data & 0x40) << 2) | (sprite_list[i + 3].x & 0xff);
|
||||
sprite_list[i + 3].size = data & 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::build_sprite_list() -> void {
|
||||
if(sprite_list_valid == true) return;
|
||||
sprite_list_valid = true;
|
||||
|
||||
for(unsigned i = 0; i < 128; i++) {
|
||||
const bool size = sprite_list[i].size;
|
||||
|
||||
switch(cache.oam_basesize) {
|
||||
case 0: sprite_list[i].width = (!size) ? 8 : 16;
|
||||
sprite_list[i].height = (!size) ? 8 : 16;
|
||||
break;
|
||||
case 1: sprite_list[i].width = (!size) ? 8 : 32;
|
||||
sprite_list[i].height = (!size) ? 8 : 32;
|
||||
break;
|
||||
case 2: sprite_list[i].width = (!size) ? 8 : 64;
|
||||
sprite_list[i].height = (!size) ? 8 : 64;
|
||||
break;
|
||||
case 3: sprite_list[i].width = (!size) ? 16 : 32;
|
||||
sprite_list[i].height = (!size) ? 16 : 32;
|
||||
break;
|
||||
case 4: sprite_list[i].width = (!size) ? 16 : 64;
|
||||
sprite_list[i].height = (!size) ? 16 : 64;
|
||||
break;
|
||||
case 5: sprite_list[i].width = (!size) ? 32 : 64;
|
||||
sprite_list[i].height = (!size) ? 32 : 64;
|
||||
break;
|
||||
case 6: sprite_list[i].width = (!size) ? 16 : 32;
|
||||
sprite_list[i].height = (!size) ? 32 : 64;
|
||||
if(regs.oam_interlace && !size) sprite_list[i].height = 16;
|
||||
//32x64 height is not affected by oam_interlace setting
|
||||
break;
|
||||
case 7: sprite_list[i].width = (!size) ? 16 : 32;
|
||||
sprite_list[i].height = (!size) ? 32 : 32;
|
||||
if(regs.oam_interlace && !size) sprite_list[i].height = 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::is_sprite_on_scanline() -> bool {
|
||||
//if sprite is entirely offscreen and doesn't wrap around to the left side of the screen,
|
||||
//then it is not counted. this *should* be 256, and not 255, even though dot 256 is offscreen.
|
||||
sprite_item* spr = &sprite_list[active_sprite];
|
||||
if(spr->x > 256 && (spr->x + spr->width - 1) < 512) return false;
|
||||
|
||||
int spr_height = (regs.oam_interlace == false) ? ((uint)spr->height) : (spr->height >> 1);
|
||||
if(line >= spr->y && line < (spr->y + spr_height)) return true;
|
||||
if((spr->y + spr_height) >= 256 && line < ((spr->y + spr_height) & 255)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto PPU::load_oam_tiles() -> void {
|
||||
sprite_item* spr = &sprite_list[active_sprite];
|
||||
uint16 tile_width = spr->width >> 3;
|
||||
int x = spr->x;
|
||||
int y = (line - spr->y) & 0xff;
|
||||
if(regs.oam_interlace == true) {
|
||||
y <<= 1;
|
||||
}
|
||||
|
||||
if(spr->vflip == true) {
|
||||
if(spr->width == spr->height) {
|
||||
y = (spr->height - 1) - y;
|
||||
} else {
|
||||
y = (y < spr->width) ? ((spr->width - 1) - y) : (spr->width + ((spr->width - 1) - (y - spr->width)));
|
||||
}
|
||||
}
|
||||
|
||||
if(regs.oam_interlace == true) {
|
||||
y = (spr->vflip == false) ? (y + field()) : (y - field());
|
||||
}
|
||||
|
||||
x &= 511;
|
||||
y &= 255;
|
||||
|
||||
uint16 tdaddr = cache.oam_tdaddr;
|
||||
uint16 chrx = (spr->character ) & 15;
|
||||
uint16 chry = (spr->character >> 4) & 15;
|
||||
if(spr->use_nameselect == true) {
|
||||
tdaddr += (256 * 32) + (cache.oam_nameselect << 13);
|
||||
}
|
||||
chry += (y >> 3);
|
||||
chry &= 15;
|
||||
chry <<= 4;
|
||||
|
||||
for(unsigned tx = 0; tx < tile_width; tx++) {
|
||||
unsigned sx = (x + (tx << 3)) & 511;
|
||||
//ignore sprites that are offscreen, x==256 is a special case that loads all tiles in OBJ
|
||||
if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;
|
||||
|
||||
if(regs.oam_tilecount++ >= 34) break;
|
||||
unsigned n = regs.oam_tilecount - 1;
|
||||
oam_tilelist[n].x = sx;
|
||||
oam_tilelist[n].y = y;
|
||||
oam_tilelist[n].pri = spr->priority;
|
||||
oam_tilelist[n].pal = 128 + (spr->palette << 4);
|
||||
oam_tilelist[n].hflip = spr->hflip;
|
||||
|
||||
unsigned mx = (spr->hflip == false) ? tx : ((tile_width - 1) - tx);
|
||||
unsigned pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5);
|
||||
oam_tilelist[n].tile = (pos >> 5) & 0x07ff;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::render_oam_tile(int tile_num) -> void {
|
||||
oam_tileitem* t = &oam_tilelist[tile_num];
|
||||
uint8* oam_td = (uint8*)bg_tiledata[COLORDEPTH_16];
|
||||
uint8* oam_td_state = (uint8*)bg_tiledata_state[COLORDEPTH_16];
|
||||
|
||||
if(oam_td_state[t->tile] == 1) {
|
||||
render_bg_tile<COLORDEPTH_16>(t->tile);
|
||||
}
|
||||
|
||||
unsigned sx = t->x;
|
||||
uint8* tile_ptr = (uint8*)oam_td + (t->tile << 6) + ((t->y & 7) << 3);
|
||||
for(unsigned x = 0; x < 8; x++) {
|
||||
sx &= 511;
|
||||
if(sx < 256) {
|
||||
unsigned col = *(tile_ptr + ((t->hflip == false) ? x : (7 - x)));
|
||||
if(col) {
|
||||
col += t->pal;
|
||||
oam_line_pal[sx] = col;
|
||||
oam_line_pri[sx] = t->pri;
|
||||
}
|
||||
}
|
||||
sx++;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::render_line_oam_rto() -> void {
|
||||
build_sprite_list();
|
||||
|
||||
regs.oam_itemcount = 0;
|
||||
regs.oam_tilecount = 0;
|
||||
memset(oam_line_pri, OAM_PRI_NONE, 256);
|
||||
memset(oam_itemlist, 0xff, 32);
|
||||
for(int s = 0; s < 34; s++) oam_tilelist[s].tile = 0xffff;
|
||||
|
||||
for(int s = 0; s < 128; s++) {
|
||||
active_sprite = (s + regs.oam_firstsprite) & 127;
|
||||
if(is_sprite_on_scanline() == false) continue;
|
||||
if(regs.oam_itemcount++ >= 32) break;
|
||||
oam_itemlist[regs.oam_itemcount - 1] = (s + regs.oam_firstsprite) & 127;
|
||||
}
|
||||
|
||||
if(regs.oam_itemcount > 0 && oam_itemlist[regs.oam_itemcount - 1] != 0xff) {
|
||||
regs.ioamaddr = 0x0200 + (oam_itemlist[regs.oam_itemcount - 1] >> 2);
|
||||
}
|
||||
|
||||
for(int s = 31; s >= 0; s--) {
|
||||
if(oam_itemlist[s] == 0xff) continue;
|
||||
active_sprite = oam_itemlist[s];
|
||||
load_oam_tiles();
|
||||
}
|
||||
|
||||
regs.time_over |= (regs.oam_tilecount > 34);
|
||||
regs.range_over |= (regs.oam_itemcount > 32);
|
||||
}
|
||||
|
||||
#define setpixel_main(x) \
|
||||
if(pixel_cache[x].pri_main < pri) { \
|
||||
pixel_cache[x].pri_main = pri; \
|
||||
pixel_cache[x].bg_main = OAM; \
|
||||
pixel_cache[x].src_main = get_palette(oam_line_pal[x]); \
|
||||
pixel_cache[x].ce_main = (oam_line_pal[x] < 192); \
|
||||
}
|
||||
#define setpixel_sub(x) \
|
||||
if(pixel_cache[x].pri_sub < pri) { \
|
||||
pixel_cache[x].pri_sub = pri; \
|
||||
pixel_cache[x].bg_sub = OAM; \
|
||||
pixel_cache[x].src_sub = get_palette(oam_line_pal[x]); \
|
||||
pixel_cache[x].ce_sub = (oam_line_pal[x] < 192); \
|
||||
}
|
||||
|
||||
auto PPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) -> void {
|
||||
if(layer_enabled[OAM][0] == false) pri0_pos = 0;
|
||||
if(layer_enabled[OAM][1] == false) pri1_pos = 0;
|
||||
if(layer_enabled[OAM][2] == false) pri2_pos = 0;
|
||||
if(layer_enabled[OAM][3] == false) pri3_pos = 0;
|
||||
if(pri0_pos + pri1_pos + pri2_pos + pri3_pos == 0) return;
|
||||
|
||||
if(regs.bg_enabled[OAM] == false && regs.bgsub_enabled[OAM] == false) return;
|
||||
|
||||
for(unsigned s = 0; s < 34; s++) {
|
||||
if(oam_tilelist[s].tile == 0xffff) continue;
|
||||
render_oam_tile(s);
|
||||
}
|
||||
|
||||
bool bg_enabled = regs.bg_enabled[OAM];
|
||||
bool bgsub_enabled = regs.bgsub_enabled[OAM];
|
||||
|
||||
build_window_tables(OAM);
|
||||
uint8* wt_main = window[OAM].main;
|
||||
uint8* wt_sub = window[OAM].sub;
|
||||
|
||||
unsigned pri_tbl[4] = { pri0_pos, pri1_pos, pri2_pos, pri3_pos };
|
||||
for(int x = 0; x < 256; x++) {
|
||||
if(oam_line_pri[x] == OAM_PRI_NONE) continue;
|
||||
|
||||
unsigned pri = pri_tbl[oam_line_pri[x]];
|
||||
if(bg_enabled == true && !wt_main[x]) { setpixel_main(x); }
|
||||
if(bgsub_enabled == true && !wt_sub[x]) { setpixel_sub(x); }
|
||||
}
|
||||
}
|
||||
|
||||
#undef setpixel_main
|
||||
#undef setpixel_sub
|
|
@ -1,125 +0,0 @@
|
|||
#include "cache.cpp"
|
||||
#include "windows.cpp"
|
||||
#include "bg.cpp"
|
||||
#include "oam.cpp"
|
||||
#include "mode7.cpp"
|
||||
#include "addsub.cpp"
|
||||
#include "line.cpp"
|
||||
|
||||
//Mode 0: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
|
||||
// BG4B, BG3B, OAM0, BG4A, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
|
||||
auto PPU::render_line_mode0() -> void {
|
||||
render_line_bg<0, BG1, COLORDEPTH_4>(8, 11);
|
||||
render_line_bg<0, BG2, COLORDEPTH_4>(7, 10);
|
||||
render_line_bg<0, BG3, COLORDEPTH_4>(2, 5);
|
||||
render_line_bg<0, BG4, COLORDEPTH_4>(1, 4);
|
||||
render_line_oam(3, 6, 9, 12);
|
||||
}
|
||||
|
||||
//Mode 1 (pri=1): ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
|
||||
// BG3B, OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3, BG3A
|
||||
//
|
||||
//Mode 1 (pri=0): ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
|
||||
// BG3B, OAM0, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
|
||||
auto PPU::render_line_mode1() -> void {
|
||||
if(regs.bg3_priority) {
|
||||
render_line_bg<1, BG1, COLORDEPTH_16>(5, 8);
|
||||
render_line_bg<1, BG2, COLORDEPTH_16>(4, 7);
|
||||
render_line_bg<1, BG3, COLORDEPTH_4 >(1, 10);
|
||||
render_line_oam(2, 3, 6, 9);
|
||||
} else {
|
||||
render_line_bg<1, BG1, COLORDEPTH_16>(6, 9);
|
||||
render_line_bg<1, BG2, COLORDEPTH_16>(5, 8);
|
||||
render_line_bg<1, BG3, COLORDEPTH_4 >(1, 3);
|
||||
render_line_oam(2, 4, 7, 10);
|
||||
}
|
||||
}
|
||||
|
||||
//Mode 2: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8
|
||||
// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3
|
||||
auto PPU::render_line_mode2() -> void {
|
||||
render_line_bg<2, BG1, COLORDEPTH_16>(3, 7);
|
||||
render_line_bg<2, BG2, COLORDEPTH_16>(1, 5);
|
||||
render_line_oam(2, 4, 6, 8);
|
||||
}
|
||||
|
||||
//Mode 3: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8
|
||||
// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3
|
||||
auto PPU::render_line_mode3() -> void {
|
||||
render_line_bg<3, BG1, COLORDEPTH_256>(3, 7);
|
||||
render_line_bg<3, BG2, COLORDEPTH_16 >(1, 5);
|
||||
render_line_oam(2, 4, 6, 8);
|
||||
}
|
||||
|
||||
//Mode 4: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8
|
||||
// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3
|
||||
auto PPU::render_line_mode4() -> void {
|
||||
render_line_bg<4, BG1, COLORDEPTH_256>(3, 7);
|
||||
render_line_bg<4, BG2, COLORDEPTH_4 >(1, 5);
|
||||
render_line_oam(2, 4, 6, 8);
|
||||
}
|
||||
|
||||
//Mode 5: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8
|
||||
// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3
|
||||
auto PPU::render_line_mode5() -> void {
|
||||
render_line_bg<5, BG1, COLORDEPTH_16>(3, 7);
|
||||
render_line_bg<5, BG2, COLORDEPTH_4 >(1, 5);
|
||||
render_line_oam(2, 4, 6, 8);
|
||||
}
|
||||
|
||||
//Mode 6: ->
|
||||
// 1, 2, 3, 4, 5, 6
|
||||
// OAM0, BG1B, OAM1, OAM2, BG1A, OAM3
|
||||
auto PPU::render_line_mode6() -> void {
|
||||
render_line_bg<6, BG1, COLORDEPTH_16>(2, 5);
|
||||
render_line_oam(1, 3, 4, 6);
|
||||
}
|
||||
|
||||
//Mode7: ->
|
||||
// 1, 2, 3, 4, 5
|
||||
// OAM0, BG1n, OAM1, OAM2, OAM3
|
||||
|
||||
//Mode 7 EXTBG: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7
|
||||
// BG2B, OAM0, BG1n, OAM1, BG2A, OAM2, OAM3
|
||||
auto PPU::render_line_mode7() -> void {
|
||||
if(regs.mode7_extbg == false) {
|
||||
render_line_mode7<BG1>(2, 2);
|
||||
render_line_oam(1, 3, 4, 5);
|
||||
} else {
|
||||
render_line_mode7<BG1>(3, 3);
|
||||
render_line_mode7<BG2>(1, 5);
|
||||
render_line_oam(2, 4, 6, 7);
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::render_line() -> void {
|
||||
if(regs.display_disabled == true) {
|
||||
render_line_clear();
|
||||
return;
|
||||
}
|
||||
|
||||
flush_pixel_cache();
|
||||
build_window_tables(COL);
|
||||
update_bg_info();
|
||||
|
||||
switch(regs.bg_mode) {
|
||||
case 0: render_line_mode0(); break;
|
||||
case 1: render_line_mode1(); break;
|
||||
case 2: render_line_mode2(); break;
|
||||
case 3: render_line_mode3(); break;
|
||||
case 4: render_line_mode4(); break;
|
||||
case 5: render_line_mode5(); break;
|
||||
case 6: render_line_mode6(); break;
|
||||
case 7: render_line_mode7(); break;
|
||||
}
|
||||
|
||||
render_line_output();
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
//render.cpp
|
||||
inline auto render_line_mode0() -> void;
|
||||
inline auto render_line_mode1() -> void;
|
||||
inline auto render_line_mode2() -> void;
|
||||
inline auto render_line_mode3() -> void;
|
||||
inline auto render_line_mode4() -> void;
|
||||
inline auto render_line_mode5() -> void;
|
||||
inline auto render_line_mode6() -> void;
|
||||
inline auto render_line_mode7() -> void;
|
||||
|
||||
//cache.cpp
|
||||
enum : uint { COLORDEPTH_4 = 0, COLORDEPTH_16 = 1, COLORDEPTH_256 = 2 };
|
||||
enum : uint { TILE_2BIT = 0, TILE_4BIT = 1, TILE_8BIT = 2 };
|
||||
|
||||
struct pixel_t {
|
||||
//bgr555 color data for main/subscreen pixels: 0x0000 = transparent / use palette color # 0
|
||||
//needs to be bgr555 instead of palette index for direct color mode ($2130 bit 0) to work
|
||||
uint16 src_main, src_sub;
|
||||
//indicates source of palette # for main/subscreen (BG1-4, OAM, or back)
|
||||
uint8 bg_main, bg_sub;
|
||||
//color_exemption -- true when bg == OAM && palette index >= 192, disables color add/sub effects
|
||||
uint8 ce_main, ce_sub;
|
||||
//priority level of src_n. to set src_n,
|
||||
//the priority of the pixel must be >pri_n
|
||||
uint8 pri_main, pri_sub;
|
||||
} pixel_cache[256];
|
||||
|
||||
uint8* bg_tiledata[3];
|
||||
uint8* bg_tiledata_state[3]; //0 = valid, 1 = dirty
|
||||
|
||||
template<uint color_depth> auto render_bg_tile(uint16 tile_num) -> void;
|
||||
inline auto flush_pixel_cache() -> void;
|
||||
auto alloc_tiledata_cache() -> void;
|
||||
auto flush_tiledata_cache() -> void;
|
||||
auto free_tiledata_cache() -> void;
|
||||
|
||||
//windows.cpp
|
||||
struct window_t {
|
||||
uint8 main[256], sub[256];
|
||||
} window[6];
|
||||
|
||||
auto build_window_table(uint8 bg, bool mainscreen) -> void;
|
||||
auto build_window_tables(uint8 bg) -> void;
|
||||
|
||||
//bg.cpp
|
||||
struct {
|
||||
uint16 tw, th; //tile width, height
|
||||
uint16 mx, my; //screen mask x, y
|
||||
uint16 scx, scy; //sc index offsets
|
||||
} bg_info[4];
|
||||
auto update_bg_info() -> void;
|
||||
|
||||
template<uint bg> auto bg_get_tile(uint16 x, uint16 y) -> uint16;
|
||||
template<uint mode, uint bg, uint color_depth> auto render_line_bg(uint8 pri0_pos, uint8 pri1_pos) -> void;
|
||||
|
||||
//oam.cpp
|
||||
struct sprite_item {
|
||||
uint8 width, height;
|
||||
uint16 x, y;
|
||||
uint8 character;
|
||||
bool use_nameselect;
|
||||
bool vflip, hflip;
|
||||
uint8 palette;
|
||||
uint8 priority;
|
||||
bool size;
|
||||
} sprite_list[128];
|
||||
bool sprite_list_valid;
|
||||
uint active_sprite;
|
||||
|
||||
uint8 oam_itemlist[32];
|
||||
struct oam_tileitem {
|
||||
uint16 x, y, pri, pal, tile;
|
||||
bool hflip;
|
||||
} oam_tilelist[34];
|
||||
|
||||
enum : uint { OAM_PRI_NONE = 4 };
|
||||
uint8 oam_line_pal[256], oam_line_pri[256];
|
||||
|
||||
auto update_sprite_list(unsigned addr, uint8 data) -> void;
|
||||
auto build_sprite_list() -> void;
|
||||
auto is_sprite_on_scanline() -> bool;
|
||||
auto load_oam_tiles() -> void;
|
||||
auto render_oam_tile(int tile_num) -> void;
|
||||
auto render_line_oam_rto() -> void;
|
||||
auto render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) -> void;
|
||||
|
||||
//mode7.cpp
|
||||
template<uint bg> auto render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) -> void;
|
||||
|
||||
//addsub.cpp
|
||||
inline auto addsub(uint32 x, uint32 y, bool halve) -> uint16;
|
||||
|
||||
//line.cpp
|
||||
inline auto get_palette(uint8 index) -> uint16;
|
||||
inline auto get_direct_color(uint8 p, uint8 t) -> uint16;
|
||||
inline auto get_pixel_normal(uint32 x) -> uint16;
|
||||
inline auto get_pixel_swap(uint32 x) -> uint16;
|
||||
auto render_line_output() -> void;
|
||||
auto render_line_clear() -> void;
|
|
@ -1,66 +0,0 @@
|
|||
//screen: 0 = main, 1 = sub
|
||||
auto PPU::build_window_table(uint8 bg, bool screen) -> void {
|
||||
bool set = 1, clr = 0;
|
||||
uint8* table = (screen == 0 ? window[bg].main : window[bg].sub);
|
||||
|
||||
if(bg != COL) {
|
||||
if(screen == 0 && regs.window_enabled[bg] == false) {
|
||||
memset(table, 0, 256);
|
||||
return;
|
||||
}
|
||||
if(screen == 1 && regs.sub_window_enabled[bg] == false) {
|
||||
memset(table, 0, 256);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
switch(screen == 0 ? regs.color_mask : regs.colorsub_mask) {
|
||||
case 0: memset(table, 1, 256); return; //always
|
||||
case 3: memset(table, 0, 256); return; //never
|
||||
case 1: set = 1, clr = 0; break; //inside window only
|
||||
case 2: set = 0, clr = 1; break; //outside window only
|
||||
}
|
||||
}
|
||||
|
||||
const uint16 window1_left = regs.window1_left;
|
||||
const uint16 window1_right = regs.window1_right;
|
||||
const uint16 window2_left = regs.window2_left;
|
||||
const uint16 window2_right = regs.window2_right;
|
||||
|
||||
if(regs.window1_enabled[bg] == false && regs.window2_enabled[bg] == false) {
|
||||
memset(table, clr, 256);
|
||||
return;
|
||||
}
|
||||
|
||||
if(regs.window1_enabled[bg] == true && regs.window2_enabled[bg] == false) {
|
||||
if(regs.window1_invert[bg] == true) set ^= clr ^= set ^= clr;
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
table[x] = (x >= window1_left && x <= window1_right) ? set : clr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(regs.window1_enabled[bg] == false && regs.window2_enabled[bg] == true) {
|
||||
if(regs.window2_invert[bg] == true) set ^= clr ^= set ^= clr;
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
table[x] = (x >= window2_left && x <= window2_right) ? set : clr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
bool w1_mask = (x >= window1_left && x <= window1_right) ^ regs.window1_invert[bg];
|
||||
bool w2_mask = (x >= window2_left && x <= window2_right) ^ regs.window2_invert[bg];
|
||||
|
||||
switch(regs.window_mask[bg]) {
|
||||
case 0: table[x] = (w1_mask | w2_mask) == 1 ? set : clr; break; //or
|
||||
case 1: table[x] = (w1_mask & w2_mask) == 1 ? set : clr; break; //and
|
||||
case 2: table[x] = (w1_mask ^ w2_mask) == 1 ? set : clr; break; //xor
|
||||
case 3: table[x] = (w1_mask ^ w2_mask) == 0 ? set : clr; break; //xnor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::build_window_tables(uint8 bg) -> void {
|
||||
build_window_table(bg, 0);
|
||||
build_window_table(bg, 1);
|
||||
}
|
|
@ -1,203 +0,0 @@
|
|||
auto PPUcounter::serialize(serializer& s) -> void {
|
||||
s.integer(status.interlace);
|
||||
s.integer(status.field);
|
||||
s.integer(status.vcounter);
|
||||
s.integer(status.hcounter);
|
||||
|
||||
s.array(history.field);
|
||||
s.array(history.vcounter);
|
||||
s.array(history.hcounter);
|
||||
s.integer(history.index);
|
||||
}
|
||||
|
||||
auto PPU::serialize(serializer& s) -> void {
|
||||
Thread::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram);
|
||||
s.array(oam);
|
||||
s.array(cgram);
|
||||
|
||||
s.integer(ppu1_version);
|
||||
s.integer(ppu2_version);
|
||||
|
||||
s.integer(region);
|
||||
s.integer(line);
|
||||
|
||||
s.integer(display.interlace);
|
||||
s.integer(display.overscan);
|
||||
|
||||
s.integer(cache.oam_basesize);
|
||||
s.integer(cache.oam_nameselect);
|
||||
s.integer(cache.oam_tdaddr);
|
||||
|
||||
s.integer(regs.ppu1_mdr);
|
||||
s.integer(regs.ppu2_mdr);
|
||||
for(uint n = 0; n < 4; n++) s.integer(regs.bg_y[n]);
|
||||
|
||||
s.integer(regs.ioamaddr);
|
||||
s.integer(regs.icgramaddr);
|
||||
|
||||
s.integer(regs.display_disabled);
|
||||
s.integer(regs.display_brightness);
|
||||
|
||||
s.integer(regs.oam_basesize);
|
||||
s.integer(regs.oam_nameselect);
|
||||
s.integer(regs.oam_tdaddr);
|
||||
|
||||
s.integer(regs.oam_baseaddr);
|
||||
s.integer(regs.oam_addr);
|
||||
s.integer(regs.oam_priority);
|
||||
s.integer(regs.oam_firstsprite);
|
||||
|
||||
s.integer(regs.oam_latchdata);
|
||||
|
||||
for(uint n = 0; n < 4; n++) s.integer(regs.bg_tilesize[n]);
|
||||
s.integer(regs.bg3_priority);
|
||||
s.integer(regs.bg_mode);
|
||||
|
||||
s.integer(regs.mosaic_size);
|
||||
for(uint n = 0; n < 4; n++) s.integer(regs.mosaic_enabled[n]);
|
||||
s.integer(regs.mosaic_countdown);
|
||||
|
||||
for(uint n = 0; n < 4; n++) s.integer(regs.bg_scaddr[n]);
|
||||
for(uint n = 0; n < 4; n++) s.integer(regs.bg_scsize[n]);
|
||||
|
||||
for(uint n = 0; n < 4; n++) s.integer(regs.bg_tdaddr[n]);
|
||||
|
||||
s.integer(regs.bg_ofslatch);
|
||||
s.integer(regs.m7_hofs);
|
||||
s.integer(regs.m7_vofs);
|
||||
for(uint n = 0; n < 4; n++) s.integer(regs.bg_hofs[n]);
|
||||
for(uint n = 0; n < 4; n++) s.integer(regs.bg_vofs[n]);
|
||||
|
||||
s.integer(regs.vram_incmode);
|
||||
s.integer(regs.vram_mapping);
|
||||
s.integer(regs.vram_incsize);
|
||||
|
||||
s.integer(regs.vram_addr);
|
||||
|
||||
s.integer(regs.mode7_repeat);
|
||||
s.integer(regs.mode7_vflip);
|
||||
s.integer(regs.mode7_hflip);
|
||||
|
||||
s.integer(regs.m7_latch);
|
||||
s.integer(regs.m7a);
|
||||
s.integer(regs.m7b);
|
||||
s.integer(regs.m7c);
|
||||
s.integer(regs.m7d);
|
||||
s.integer(regs.m7x);
|
||||
s.integer(regs.m7y);
|
||||
|
||||
s.integer(regs.cgram_addr);
|
||||
|
||||
s.integer(regs.cgram_latchdata);
|
||||
|
||||
for(uint n = 0; n < 6; n++) s.integer(regs.window1_enabled[n]);
|
||||
for(uint n = 0; n < 6; n++) s.integer(regs.window1_invert [n]);
|
||||
for(uint n = 0; n < 6; n++) s.integer(regs.window2_enabled[n]);
|
||||
for(uint n = 0; n < 6; n++) s.integer(regs.window2_invert [n]);
|
||||
|
||||
s.integer(regs.window1_left);
|
||||
s.integer(regs.window1_right);
|
||||
s.integer(regs.window2_left);
|
||||
s.integer(regs.window2_right);
|
||||
|
||||
for(uint n = 0; n < 6; n++) s.integer(regs.window_mask[n]);
|
||||
for(uint n = 0; n < 5; n++) s.integer(regs.bg_enabled[n]);
|
||||
for(uint n = 0; n < 5; n++) s.integer(regs.bgsub_enabled[n]);
|
||||
for(uint n = 0; n < 5; n++) s.integer(regs.window_enabled[n]);
|
||||
for(uint n = 0; n < 5; n++) s.integer(regs.sub_window_enabled[n]);
|
||||
|
||||
s.integer(regs.color_mask);
|
||||
s.integer(regs.colorsub_mask);
|
||||
s.integer(regs.addsub_mode);
|
||||
s.integer(regs.direct_color);
|
||||
|
||||
s.integer(regs.color_mode);
|
||||
s.integer(regs.color_halve);
|
||||
for(uint n = 0; n < 6; n++) s.integer(regs.color_enabled[n]);
|
||||
|
||||
s.integer(regs.color_r);
|
||||
s.integer(regs.color_g);
|
||||
s.integer(regs.color_b);
|
||||
s.integer(regs.color_rgb);
|
||||
|
||||
s.integer(regs.mode7_extbg);
|
||||
s.integer(regs.pseudo_hires);
|
||||
s.integer(regs.overscan);
|
||||
s.integer(regs.scanlines);
|
||||
s.integer(regs.oam_interlace);
|
||||
s.integer(regs.interlace);
|
||||
|
||||
s.integer(regs.hcounter);
|
||||
s.integer(regs.vcounter);
|
||||
s.integer(regs.latch_hcounter);
|
||||
s.integer(regs.latch_vcounter);
|
||||
s.integer(regs.counters_latched);
|
||||
|
||||
s.integer(regs.vram_readbuffer);
|
||||
|
||||
s.integer(regs.time_over);
|
||||
s.integer(regs.range_over);
|
||||
s.integer(regs.oam_itemcount);
|
||||
s.integer(regs.oam_tilecount);
|
||||
|
||||
for(uint n = 0; n < 256; n++) {
|
||||
s.integer(pixel_cache[n].src_main);
|
||||
s.integer(pixel_cache[n].src_sub);
|
||||
s.integer(pixel_cache[n].bg_main);
|
||||
s.integer(pixel_cache[n].bg_sub);
|
||||
s.integer(pixel_cache[n].ce_main);
|
||||
s.integer(pixel_cache[n].ce_sub);
|
||||
s.integer(pixel_cache[n].pri_main);
|
||||
s.integer(pixel_cache[n].pri_sub);
|
||||
}
|
||||
|
||||
//better to just take a small speed hit than store all of bg_tiledata[3][] ...
|
||||
flush_tiledata_cache();
|
||||
|
||||
for(uint n = 0; n < 6; n++) {
|
||||
s.array(window[n].main, 256);
|
||||
s.array(window[n].sub, 256);
|
||||
}
|
||||
|
||||
for(uint n = 0; n < 4; n++) {
|
||||
s.integer(bg_info[n].tw);
|
||||
s.integer(bg_info[n].th);
|
||||
s.integer(bg_info[n].mx);
|
||||
s.integer(bg_info[n].my);
|
||||
s.integer(bg_info[n].scx);
|
||||
s.integer(bg_info[n].scy);
|
||||
}
|
||||
|
||||
for(uint n = 0; n < 128; n++) {
|
||||
s.integer(sprite_list[n].width);
|
||||
s.integer(sprite_list[n].height);
|
||||
s.integer(sprite_list[n].x);
|
||||
s.integer(sprite_list[n].y);
|
||||
s.integer(sprite_list[n].character);
|
||||
s.integer(sprite_list[n].use_nameselect);
|
||||
s.integer(sprite_list[n].vflip);
|
||||
s.integer(sprite_list[n].hflip);
|
||||
s.integer(sprite_list[n].palette);
|
||||
s.integer(sprite_list[n].priority);
|
||||
s.integer(sprite_list[n].size);
|
||||
}
|
||||
s.integer(sprite_list_valid);
|
||||
s.integer(active_sprite);
|
||||
|
||||
s.array(oam_itemlist, 32);
|
||||
|
||||
for(uint n = 0; n < 34; n++) {
|
||||
s.integer(oam_tilelist[n].x);
|
||||
s.integer(oam_tilelist[n].y);
|
||||
s.integer(oam_tilelist[n].pri);
|
||||
s.integer(oam_tilelist[n].pal);
|
||||
s.integer(oam_tilelist[n].tile);
|
||||
s.integer(oam_tilelist[n].hflip);
|
||||
}
|
||||
|
||||
s.array(oam_line_pal, 256);
|
||||
s.array(oam_line_pri, 256);
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
#include "mode7.cpp"
|
||||
|
||||
PPU::Background::Background(PPU& self, uint id) : self(self), id(id) {
|
||||
priority0_enable = true;
|
||||
priority1_enable = true;
|
||||
|
||||
opt_valid_bit = (id == ID::BG1 ? 0x2000 : id == ID::BG2 ? 0x4000 : 0x0000);
|
||||
|
||||
mosaic_table = new uint16*[16];
|
||||
for(uint m = 0; m < 16; m++) {
|
||||
mosaic_table[m] = new uint16[4096];
|
||||
for(uint x = 0; x < 4096; x++) {
|
||||
mosaic_table[m][x] = (x / (m + 1)) * (m + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PPU::Background::~Background() {
|
||||
for(uint m = 0; m < 16; m++) delete[] mosaic_table[m];
|
||||
delete[] mosaic_table;
|
||||
}
|
||||
|
||||
auto PPU::Background::get_tile(uint hoffset, uint voffset) -> uint {
|
||||
uint tile_x = (hoffset & mask_x) >> tile_width;
|
||||
uint tile_y = (voffset & mask_y) >> tile_height;
|
||||
|
||||
uint tile_pos = ((tile_y & 0x1f) << 5) + (tile_x & 0x1f);
|
||||
if(tile_y & 0x20) tile_pos += scy;
|
||||
if(tile_x & 0x20) tile_pos += scx;
|
||||
|
||||
const uint16 tiledata_addr = regs.screen_addr + (tile_pos << 1);
|
||||
return (ppu.vram[tiledata_addr + 0] << 0) + (ppu.vram[tiledata_addr + 1] << 8);
|
||||
}
|
||||
|
||||
auto PPU::Background::offset_per_tile(uint x, uint y, uint& hoffset, uint& voffset) -> void {
|
||||
uint opt_x = (x + (hscroll & 7)), hval, vval;
|
||||
if(opt_x >= 8) {
|
||||
hval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0);
|
||||
if(self.regs.bgmode != 4)
|
||||
vval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 8);
|
||||
|
||||
if(self.regs.bgmode == 4) {
|
||||
if(hval & opt_valid_bit) {
|
||||
if(!(hval & 0x8000)) {
|
||||
hoffset = opt_x + (hval & ~7);
|
||||
} else {
|
||||
voffset = y + hval;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(hval & opt_valid_bit) {
|
||||
hoffset = opt_x + (hval & ~7);
|
||||
}
|
||||
if(vval & opt_valid_bit) {
|
||||
voffset = y + vval;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Background::scanline() -> void {
|
||||
if(self.vcounter() == 1) {
|
||||
mosaic_vcounter = regs.mosaic + 1;
|
||||
mosaic_voffset = 1;
|
||||
} else if(--mosaic_vcounter == 0) {
|
||||
mosaic_vcounter = regs.mosaic + 1;
|
||||
mosaic_voffset += regs.mosaic + 1;
|
||||
}
|
||||
if(self.regs.display_disable) return;
|
||||
|
||||
hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
|
||||
width = !hires ? 256 : 512;
|
||||
|
||||
tile_height = regs.tile_size ? 4 : 3;
|
||||
tile_width = hires ? 4 : tile_height;
|
||||
|
||||
mask_x = (tile_height == 4 ? width << 1 : width);
|
||||
mask_y = mask_x;
|
||||
if(regs.screen_size & 1) mask_x <<= 1;
|
||||
if(regs.screen_size & 2) mask_y <<= 1;
|
||||
mask_x--;
|
||||
mask_y--;
|
||||
|
||||
scx = (regs.screen_size & 1 ? 32 << 5 : 0);
|
||||
scy = (regs.screen_size & 2 ? 32 << 5 : 0);
|
||||
if(regs.screen_size == 3) scy <<= 1;
|
||||
}
|
||||
|
||||
auto PPU::Background::render() -> void {
|
||||
if(regs.mode == Mode::Inactive) return;
|
||||
if(regs.main_enable == false && regs.sub_enable == false) return;
|
||||
|
||||
if(regs.main_enable) window.render(0);
|
||||
if(regs.sub_enable) window.render(1);
|
||||
if(regs.mode == Mode::Mode7) return render_mode7();
|
||||
|
||||
uint priority0 = (priority0_enable ? regs.priority0 : 0);
|
||||
uint priority1 = (priority1_enable ? regs.priority1 : 0);
|
||||
if(priority0 + priority1 == 0) return;
|
||||
|
||||
uint mosaic_hcounter = 1;
|
||||
uint mosaic_palette = 0;
|
||||
uint mosaic_priority = 0;
|
||||
uint mosaic_color = 0;
|
||||
|
||||
const uint bgpal_index = (self.regs.bgmode == 0 ? id << 5 : 0);
|
||||
const uint pal_size = 2 << regs.mode;
|
||||
const uint tile_mask = 0x0fff >> regs.mode;
|
||||
const uint tiledata_index = regs.tiledata_addr >> (4 + regs.mode);
|
||||
|
||||
hscroll = regs.hoffset;
|
||||
vscroll = regs.voffset;
|
||||
|
||||
uint y = (regs.mosaic == 0 ? (uint)self.vcounter() : mosaic_voffset);
|
||||
if(hires) {
|
||||
hscroll <<= 1;
|
||||
if(self.regs.interlace) y = (y << 1) + self.field();
|
||||
}
|
||||
|
||||
uint tile_pri, tile_num;
|
||||
uint pal_index, pal_num;
|
||||
uint hoffset, voffset, col;
|
||||
bool mirror_x, mirror_y;
|
||||
|
||||
const bool is_opt_mode = (self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6);
|
||||
const bool is_direct_color_mode = (self.screen.regs.direct_color == true && id == ID::BG1 && (self.regs.bgmode == 3 || self.regs.bgmode == 4));
|
||||
|
||||
int x = 0 - (hscroll & 7);
|
||||
while(x < width) {
|
||||
hoffset = x + hscroll;
|
||||
voffset = y + vscroll;
|
||||
if(is_opt_mode) offset_per_tile(x, y, hoffset, voffset);
|
||||
hoffset &= mask_x;
|
||||
voffset &= mask_y;
|
||||
|
||||
tile_num = get_tile(hoffset, voffset);
|
||||
mirror_y = tile_num & 0x8000;
|
||||
mirror_x = tile_num & 0x4000;
|
||||
tile_pri = tile_num & 0x2000 ? priority1 : priority0;
|
||||
pal_num = (tile_num >> 10) & 7;
|
||||
pal_index = (bgpal_index + (pal_num << pal_size)) & 0xff;
|
||||
|
||||
if(tile_width == 4 && (bool)(hoffset & 8) != mirror_x) tile_num += 1;
|
||||
if(tile_height == 4 && (bool)(voffset & 8) != mirror_y) tile_num += 16;
|
||||
tile_num = ((tile_num & 0x03ff) + tiledata_index) & tile_mask;
|
||||
|
||||
if(mirror_y) voffset ^= 7;
|
||||
uint mirror_xmask = !mirror_x ? 0 : 7;
|
||||
|
||||
uint8* tiledata = self.cache.tile(regs.mode, tile_num);
|
||||
tiledata += ((voffset & 7) * 8);
|
||||
|
||||
for(uint n = 0; n < 8; n++, x++) {
|
||||
if(x & width) continue;
|
||||
if(--mosaic_hcounter == 0) {
|
||||
mosaic_hcounter = regs.mosaic + 1;
|
||||
mosaic_palette = tiledata[n ^ mirror_xmask];
|
||||
mosaic_priority = tile_pri;
|
||||
if(is_direct_color_mode) {
|
||||
mosaic_color = self.screen.get_direct_color(pal_num, mosaic_palette);
|
||||
} else {
|
||||
mosaic_color = self.screen.get_palette(pal_index + mosaic_palette);
|
||||
}
|
||||
}
|
||||
if(mosaic_palette == 0) continue;
|
||||
|
||||
if(hires == false) {
|
||||
if(regs.main_enable && !window.main[x]) self.screen.output.plot_main(x, mosaic_color, mosaic_priority, id);
|
||||
if(regs.sub_enable && !window.sub[x]) self.screen.output.plot_sub(x, mosaic_color, mosaic_priority, id);
|
||||
} else {
|
||||
int half_x = x >> 1;
|
||||
if(x & 1) {
|
||||
if(regs.main_enable && !window.main[half_x]) self.screen.output.plot_main(half_x, mosaic_color, mosaic_priority, id);
|
||||
} else {
|
||||
if(regs.sub_enable && !window.sub[half_x]) self.screen.output.plot_sub(half_x, mosaic_color, mosaic_priority, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
class Background {
|
||||
struct ID { enum : uint { BG1, BG2, BG3, BG4 }; };
|
||||
struct Mode { enum : uint { BPP2, BPP4, BPP8, Mode7, Inactive }; };
|
||||
struct ScreenSize { enum : uint { Size32x32, Size32x64, Size64x32, Size64x64 }; };
|
||||
struct TileSize { enum : uint { Size8x8, Size16x16 }; };
|
||||
|
||||
Background(PPU& self, uint id);
|
||||
~Background();
|
||||
|
||||
alwaysinline auto get_tile(uint hoffset, uint voffset) -> uint;
|
||||
auto offset_per_tile(uint x, uint y, uint& hoffset, uint& voffset) -> void;
|
||||
auto scanline() -> void;
|
||||
auto render() -> void;
|
||||
auto render_mode7() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
PPU& self;
|
||||
|
||||
bool priority0_enable;
|
||||
bool priority1_enable;
|
||||
|
||||
struct Regs {
|
||||
uint mode;
|
||||
uint priority0;
|
||||
uint priority1;
|
||||
|
||||
bool tile_size;
|
||||
uint mosaic;
|
||||
|
||||
uint screen_addr;
|
||||
uint screen_size;
|
||||
uint tiledata_addr;
|
||||
|
||||
uint hoffset;
|
||||
uint voffset;
|
||||
|
||||
bool main_enable;
|
||||
bool sub_enable;
|
||||
} regs;
|
||||
|
||||
uint16** mosaic_table;
|
||||
|
||||
const uint id;
|
||||
uint opt_valid_bit;
|
||||
|
||||
bool hires;
|
||||
signed width;
|
||||
|
||||
uint tile_width;
|
||||
uint tile_height;
|
||||
|
||||
uint mask_x;
|
||||
uint mask_y;
|
||||
|
||||
uint scx;
|
||||
uint scy;
|
||||
|
||||
uint hscroll;
|
||||
uint vscroll;
|
||||
|
||||
uint mosaic_vcounter;
|
||||
uint mosaic_voffset;
|
||||
|
||||
LayerWindow window;
|
||||
|
||||
friend class PPU;
|
||||
};
|
|
@ -1,102 +0,0 @@
|
|||
#define Clip(x) (((x) & 0x2000) ? ((x) | ~0x03ff) : ((x) & 0x03ff))
|
||||
|
||||
auto PPU::Background::render_mode7() -> void {
|
||||
int px, py;
|
||||
int tx, ty, tile, palette;
|
||||
|
||||
int a = sclip<16>(self.regs.m7a);
|
||||
int b = sclip<16>(self.regs.m7b);
|
||||
int c = sclip<16>(self.regs.m7c);
|
||||
int d = sclip<16>(self.regs.m7d);
|
||||
|
||||
int cx = sclip<13>(self.regs.m7x);
|
||||
int cy = sclip<13>(self.regs.m7y);
|
||||
int hofs = sclip<13>(self.regs.mode7_hoffset);
|
||||
int vofs = sclip<13>(self.regs.mode7_voffset);
|
||||
|
||||
int y = (self.regs.mode7_vflip == false ? (uint)self.vcounter() : 255 - self.vcounter());
|
||||
|
||||
uint16* mosaic_x;
|
||||
uint16* mosaic_y;
|
||||
if(id == ID::BG1) {
|
||||
mosaic_x = mosaic_table[self.bg1.regs.mosaic];
|
||||
mosaic_y = mosaic_table[self.bg1.regs.mosaic];
|
||||
} else {
|
||||
mosaic_x = mosaic_table[self.bg2.regs.mosaic];
|
||||
mosaic_y = mosaic_table[self.bg1.regs.mosaic];
|
||||
}
|
||||
|
||||
uint priority0 = (priority0_enable ? regs.priority0 : 0);
|
||||
uint priority1 = (priority1_enable ? regs.priority1 : 0);
|
||||
if(priority0 + priority1 == 0) return;
|
||||
|
||||
int psx = ((a * Clip(hofs - cx)) & ~63) + ((b * Clip(vofs - cy)) & ~63) + ((b * mosaic_y[y]) & ~63) + (cx << 8);
|
||||
int psy = ((c * Clip(hofs - cx)) & ~63) + ((d * Clip(vofs - cy)) & ~63) + ((d * mosaic_y[y]) & ~63) + (cy << 8);
|
||||
for(int x = 0; x < 256; x++) {
|
||||
px = (psx + (a * mosaic_x[x])) >> 8;
|
||||
py = (psy + (c * mosaic_x[x])) >> 8;
|
||||
|
||||
switch(self.regs.mode7_repeat) {
|
||||
case 0: case 1: {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = ppu.vram[(ty * 128 + tx) << 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
if((px | py) & ~1023) {
|
||||
palette = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = ppu.vram[(ty * 128 + tx) << 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
if((px | py) & ~1023) {
|
||||
tile = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = ppu.vram[(ty * 128 + tx) << 1];
|
||||
}
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint priority;
|
||||
if(id == ID::BG1) {
|
||||
priority = priority0;
|
||||
} else {
|
||||
priority = (palette & 0x80 ? priority1 : priority0);
|
||||
palette &= 0x7f;
|
||||
}
|
||||
|
||||
if(palette == 0) continue;
|
||||
uint plot_x = (self.regs.mode7_hflip == false ? x : 255 - x);
|
||||
|
||||
uint color;
|
||||
if(self.screen.regs.direct_color && id == ID::BG1) {
|
||||
color = self.screen.get_direct_color(0, palette);
|
||||
} else {
|
||||
color = self.screen.get_palette(palette);
|
||||
}
|
||||
|
||||
if(regs.main_enable && !window.main[plot_x]) self.screen.output.plot_main(plot_x, color, priority, id);
|
||||
if(regs.sub_enable && !window.sub[plot_x]) self.screen.output.plot_sub(plot_x, color, priority, id);
|
||||
}
|
||||
}
|
||||
|
||||
#undef Clip
|
|
@ -1,119 +0,0 @@
|
|||
PPU::Cache::Cache(PPU& self) : self(self) {
|
||||
tiledata[0] = new uint8[262144]();
|
||||
tiledata[1] = new uint8[131072]();
|
||||
tiledata[2] = new uint8[ 65536]();
|
||||
tilevalid[0] = new uint8[ 4096]();
|
||||
tilevalid[1] = new uint8[ 2048]();
|
||||
tilevalid[2] = new uint8[ 1024]();
|
||||
}
|
||||
|
||||
auto PPU::Cache::tile_2bpp(uint tile) -> uint8* {
|
||||
if(tilevalid[0][tile] == 0) {
|
||||
tilevalid[0][tile] = 1;
|
||||
uint8* output = (uint8*)tiledata[0] + (tile << 6);
|
||||
uint offset = tile << 4;
|
||||
uint y = 8;
|
||||
uint color, d0, d1;
|
||||
while(y--) {
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
#define render_line(mask) \
|
||||
color = !!(d0 & mask) << 0; \
|
||||
color |= !!(d1 & mask) << 1; \
|
||||
*output++ = color
|
||||
render_line(0x80);
|
||||
render_line(0x40);
|
||||
render_line(0x20);
|
||||
render_line(0x10);
|
||||
render_line(0x08);
|
||||
render_line(0x04);
|
||||
render_line(0x02);
|
||||
render_line(0x01);
|
||||
#undef render_line
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
return tiledata[0] + (tile << 6);
|
||||
}
|
||||
|
||||
auto PPU::Cache::tile_4bpp(uint tile) -> uint8* {
|
||||
if(tilevalid[1][tile] == 0) {
|
||||
tilevalid[1][tile] = 1;
|
||||
uint8* output = (uint8*)tiledata[1] + (tile << 6);
|
||||
uint offset = tile << 5;
|
||||
uint y = 8;
|
||||
uint color, d0, d1, d2, d3;
|
||||
while(y--) {
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
d2 = ppu.vram[offset + 16];
|
||||
d3 = ppu.vram[offset + 17];
|
||||
#define render_line(mask) \
|
||||
color = !!(d0 & mask) << 0; \
|
||||
color |= !!(d1 & mask) << 1; \
|
||||
color |= !!(d2 & mask) << 2; \
|
||||
color |= !!(d3 & mask) << 3; \
|
||||
*output++ = color
|
||||
render_line(0x80);
|
||||
render_line(0x40);
|
||||
render_line(0x20);
|
||||
render_line(0x10);
|
||||
render_line(0x08);
|
||||
render_line(0x04);
|
||||
render_line(0x02);
|
||||
render_line(0x01);
|
||||
#undef render_line
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
return tiledata[1] + (tile << 6);
|
||||
}
|
||||
|
||||
auto PPU::Cache::tile_8bpp(uint tile) -> uint8* {
|
||||
if(tilevalid[2][tile] == 0) {
|
||||
tilevalid[2][tile] = 1;
|
||||
uint8* output = (uint8*)tiledata[2] + (tile << 6);
|
||||
uint offset = tile << 6;
|
||||
uint y = 8;
|
||||
uint color, d0, d1, d2, d3, d4, d5, d6, d7;
|
||||
while(y--) {
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
d2 = ppu.vram[offset + 16];
|
||||
d3 = ppu.vram[offset + 17];
|
||||
d4 = ppu.vram[offset + 32];
|
||||
d5 = ppu.vram[offset + 33];
|
||||
d6 = ppu.vram[offset + 48];
|
||||
d7 = ppu.vram[offset + 49];
|
||||
#define render_line(mask) \
|
||||
color = !!(d0 & mask) << 0; \
|
||||
color |= !!(d1 & mask) << 1; \
|
||||
color |= !!(d2 & mask) << 2; \
|
||||
color |= !!(d3 & mask) << 3; \
|
||||
color |= !!(d4 & mask) << 4; \
|
||||
color |= !!(d5 & mask) << 5; \
|
||||
color |= !!(d6 & mask) << 6; \
|
||||
color |= !!(d7 & mask) << 7; \
|
||||
*output++ = color
|
||||
render_line(0x80);
|
||||
render_line(0x40);
|
||||
render_line(0x20);
|
||||
render_line(0x10);
|
||||
render_line(0x08);
|
||||
render_line(0x04);
|
||||
render_line(0x02);
|
||||
render_line(0x01);
|
||||
#undef render_line
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
return tiledata[2] + (tile << 6);
|
||||
}
|
||||
|
||||
auto PPU::Cache::tile(uint bpp, uint tile) -> uint8* {
|
||||
switch(bpp) {
|
||||
case 0: return tile_2bpp(tile);
|
||||
case 1: return tile_4bpp(tile);
|
||||
case 2: return tile_8bpp(tile);
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
struct Cache {
|
||||
Cache(PPU& self);
|
||||
|
||||
auto tile_2bpp(uint tile) -> uint8*;
|
||||
auto tile_4bpp(uint tile) -> uint8*;
|
||||
auto tile_8bpp(uint tile) -> uint8*;
|
||||
auto tile(uint bpp, uint tile) -> uint8*;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
PPU& self;
|
||||
uint8* tiledata[3];
|
||||
uint8* tilevalid[3];
|
||||
|
||||
friend class PPU;
|
||||
};
|
|
@ -1,886 +0,0 @@
|
|||
auto PPU::latch_counters() -> void {
|
||||
regs.hcounter = cpu.hdot();
|
||||
regs.vcounter = cpu.vcounter();
|
||||
regs.counters_latched = true;
|
||||
}
|
||||
|
||||
auto PPU::interlace() const -> bool { return display.interlace; }
|
||||
auto PPU::overscan() const -> bool { return display.overscan; }
|
||||
|
||||
auto PPU::get_vram_addr() -> uint16 {
|
||||
uint16 addr = regs.vram_addr;
|
||||
switch(regs.vram_mapping) {
|
||||
case 0: break;
|
||||
case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break;
|
||||
case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break;
|
||||
case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break;
|
||||
}
|
||||
return (addr << 1);
|
||||
}
|
||||
|
||||
auto PPU::vram_read(uint addr) -> uint8 {
|
||||
if(regs.display_disable) return vram[addr];
|
||||
if(cpu.vcounter() >= display.height) return vram[addr];
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto PPU::vram_write(uint addr, uint8 data) -> void {
|
||||
if(regs.display_disable || cpu.vcounter() >= display.height) {
|
||||
vram[addr] = data;
|
||||
cache.tilevalid[0][addr >> 4] = false;
|
||||
cache.tilevalid[1][addr >> 5] = false;
|
||||
cache.tilevalid[2][addr >> 6] = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::oam_read(uint addr) -> uint8 {
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
if(regs.display_disable) return oam[addr];
|
||||
if(cpu.vcounter() >= display.height) return oam[addr];
|
||||
return oam[0x0218];
|
||||
}
|
||||
|
||||
auto PPU::oam_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
if(!regs.display_disable && cpu.vcounter() < display.height) addr = 0x0218;
|
||||
oam[addr] = data;
|
||||
sprite.update_list(addr, data);
|
||||
}
|
||||
|
||||
auto PPU::cgram_read(uint addr) -> uint8 {
|
||||
return cgram[addr];
|
||||
}
|
||||
|
||||
auto PPU::cgram_write(uint addr, uint8 data) -> void {
|
||||
cgram[addr] = data;
|
||||
}
|
||||
|
||||
auto PPU::mmio_update_video_mode() -> void {
|
||||
switch(regs.bgmode) {
|
||||
case 0: {
|
||||
bg1.regs.mode = Background::Mode::BPP2; bg1.regs.priority0 = 8; bg1.regs.priority1 = 11;
|
||||
bg2.regs.mode = Background::Mode::BPP2; bg2.regs.priority0 = 7; bg2.regs.priority1 = 10;
|
||||
bg3.regs.mode = Background::Mode::BPP2; bg3.regs.priority0 = 2; bg3.regs.priority1 = 5;
|
||||
bg4.regs.mode = Background::Mode::BPP2; bg4.regs.priority0 = 1; bg4.regs.priority1 = 4;
|
||||
sprite.regs.priority0 = 3; sprite.regs.priority1 = 6; sprite.regs.priority2 = 9; sprite.regs.priority3 = 12;
|
||||
} break;
|
||||
|
||||
case 1: {
|
||||
bg1.regs.mode = Background::Mode::BPP4;
|
||||
bg2.regs.mode = Background::Mode::BPP4;
|
||||
bg3.regs.mode = Background::Mode::BPP2;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
if(regs.bg3_priority) {
|
||||
bg1.regs.priority0 = 5; bg1.regs.priority1 = 8;
|
||||
bg2.regs.priority0 = 4; bg2.regs.priority1 = 7;
|
||||
bg3.regs.priority0 = 1; bg3.regs.priority1 = 10;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 3; sprite.regs.priority2 = 6; sprite.regs.priority3 = 9;
|
||||
} else {
|
||||
bg1.regs.priority0 = 6; bg1.regs.priority1 = 9;
|
||||
bg2.regs.priority0 = 5; bg2.regs.priority1 = 8;
|
||||
bg3.regs.priority0 = 1; bg3.regs.priority1 = 3;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 7; sprite.regs.priority3 = 10;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 2: {
|
||||
bg1.regs.mode = Background::Mode::BPP4;
|
||||
bg2.regs.mode = Background::Mode::BPP4;
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 3: {
|
||||
bg1.regs.mode = Background::Mode::BPP8;
|
||||
bg2.regs.mode = Background::Mode::BPP4;
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 4: {
|
||||
bg1.regs.mode = Background::Mode::BPP8;
|
||||
bg2.regs.mode = Background::Mode::BPP2;
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 5: {
|
||||
bg1.regs.mode = Background::Mode::BPP4;
|
||||
bg2.regs.mode = Background::Mode::BPP2;
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 6: {
|
||||
bg1.regs.mode = Background::Mode::BPP4;
|
||||
bg2.regs.mode = Background::Mode::Inactive;
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 2; bg1.regs.priority1 = 5;
|
||||
sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 6;
|
||||
} break;
|
||||
|
||||
case 7: {
|
||||
if(regs.mode7_extbg == false) {
|
||||
bg1.regs.mode = Background::Mode::Mode7;
|
||||
bg2.regs.mode = Background::Mode::Inactive;
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 2; bg1.regs.priority1 = 2;
|
||||
sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 5;
|
||||
} else {
|
||||
bg1.regs.mode = Background::Mode::Mode7;
|
||||
bg2.regs.mode = Background::Mode::Mode7;
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 3;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 7;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::mmio_read(uint addr, uint8 data) -> uint8 {
|
||||
cpu.synchronizePPU();
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
case 0x2104: case 0x2105: case 0x2106: case 0x2108: case 0x2109: case 0x210a:
|
||||
case 0x2114: case 0x2115: case 0x2116: case 0x2118: case 0x2119: case 0x211a:
|
||||
case 0x2124: case 0x2125: case 0x2126: case 0x2128: case 0x2129: case 0x212a: {
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
case 0x2134: { //MPYL
|
||||
unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
regs.ppu1_mdr = result >> 0;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
case 0x2135: { //MPYM
|
||||
unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
regs.ppu1_mdr = result >> 8;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
case 0x2136: { //MPYH
|
||||
unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
regs.ppu1_mdr = result >> 16;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
case 0x2137: { //SLHV
|
||||
if(cpu.pio() & 0x80) latch_counters();
|
||||
return data;
|
||||
}
|
||||
|
||||
case 0x2138: { //OAMDATAREAD
|
||||
regs.ppu1_mdr = oam_read(regs.oam_addr);
|
||||
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
|
||||
sprite.set_first();
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
case 0x2139: { //VMDATALREAD
|
||||
regs.ppu1_mdr = regs.vram_readbuffer >> 0;
|
||||
if(regs.vram_incmode == 0) {
|
||||
uint16 addr = get_vram_addr();
|
||||
regs.vram_readbuffer = vram_read(addr + 0) << 0;
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
case 0x213a: { //VMDATAHREAD
|
||||
regs.ppu1_mdr = regs.vram_readbuffer >> 8;
|
||||
if(regs.vram_incmode == 1) {
|
||||
uint16 addr = get_vram_addr();
|
||||
regs.vram_readbuffer = vram_read(addr + 0) << 0;
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
case 0x213b: { //CGDATAREAD
|
||||
if((regs.cgram_addr & 1) == 0) {
|
||||
regs.ppu2_mdr = cgram_read(regs.cgram_addr);
|
||||
} else {
|
||||
regs.ppu2_mdr = (regs.ppu2_mdr & 0x80) | (cgram_read(regs.cgram_addr) & 0x7f);
|
||||
}
|
||||
regs.cgram_addr = (regs.cgram_addr + 1) & 0x01ff;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
case 0x213c: { //OPHCT
|
||||
if(regs.latch_hcounter == 0) {
|
||||
regs.ppu2_mdr = regs.hcounter & 0xff;
|
||||
} else {
|
||||
regs.ppu2_mdr = (regs.ppu2_mdr & 0xfe) | (regs.hcounter >> 8);
|
||||
}
|
||||
regs.latch_hcounter ^= 1;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
case 0x213d: { //OPVCT
|
||||
if(regs.latch_vcounter == 0) {
|
||||
regs.ppu2_mdr = regs.vcounter & 0xff;
|
||||
} else {
|
||||
regs.ppu2_mdr = (regs.ppu2_mdr & 0xfe) | (regs.vcounter >> 8);
|
||||
}
|
||||
regs.latch_vcounter ^= 1;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
case 0x213e: { //STAT77
|
||||
regs.ppu1_mdr &= 0x10;
|
||||
regs.ppu1_mdr |= sprite.regs.time_over << 7;
|
||||
regs.ppu1_mdr |= sprite.regs.range_over << 6;
|
||||
regs.ppu1_mdr |= 0x01; //version
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
case 0x213f: { //STAT78
|
||||
regs.latch_hcounter = 0;
|
||||
regs.latch_vcounter = 0;
|
||||
|
||||
regs.ppu2_mdr &= 0x20;
|
||||
regs.ppu2_mdr |= cpu.field() << 7;
|
||||
if((cpu.pio() & 0x80) == 0) {
|
||||
regs.ppu2_mdr |= 0x40;
|
||||
} else if(regs.counters_latched) {
|
||||
regs.ppu2_mdr |= 0x40;
|
||||
regs.counters_latched = false;
|
||||
}
|
||||
regs.ppu2_mdr |= (system.region() == System::Region::NTSC ? 0 : 1) << 4;
|
||||
regs.ppu2_mdr |= 0x03; //version
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto PPU::mmio_write(uint addr, uint8 data) -> void {
|
||||
cpu.synchronizePPU();
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
case 0x2100: { //INIDISP
|
||||
if(regs.display_disable && cpu.vcounter() == display.height) sprite.address_reset();
|
||||
regs.display_disable = data & 0x80;
|
||||
regs.display_brightness = data & 0x0f;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2101: { //OBSEL
|
||||
sprite.regs.base_size = (data >> 5) & 7;
|
||||
sprite.regs.nameselect = (data >> 3) & 3;
|
||||
sprite.regs.tiledata_addr = (data & 3) << 14;
|
||||
sprite.list_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2102: { //OAMADDL
|
||||
regs.oam_baseaddr = (regs.oam_baseaddr & 0x0100) | (data << 0);
|
||||
sprite.address_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2103: { //OAMADDH
|
||||
regs.oam_priority = data & 0x80;
|
||||
regs.oam_baseaddr = ((data & 1) << 8) | (regs.oam_baseaddr & 0x00ff);
|
||||
sprite.address_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2104: { //OAMDATA
|
||||
if((regs.oam_addr & 1) == 0) regs.oam_latchdata = data;
|
||||
if(regs.oam_addr & 0x0200) {
|
||||
oam_write(regs.oam_addr, data);
|
||||
} else if((regs.oam_addr & 1) == 1) {
|
||||
oam_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
|
||||
oam_write((regs.oam_addr & ~1) + 1, data);
|
||||
}
|
||||
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
|
||||
sprite.set_first();
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2105: { //BGMODE
|
||||
bg4.regs.tile_size = data & 0x80;
|
||||
bg3.regs.tile_size = data & 0x40;
|
||||
bg2.regs.tile_size = data & 0x20;
|
||||
bg1.regs.tile_size = data & 0x10;
|
||||
regs.bg3_priority = data & 0x08;
|
||||
regs.bgmode = data & 0x07;
|
||||
mmio_update_video_mode();
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2106: { //MOSAIC
|
||||
unsigned mosaic_size = (data >> 4) & 15;
|
||||
bg4.regs.mosaic = (data & 0x08 ? mosaic_size : 0);
|
||||
bg3.regs.mosaic = (data & 0x04 ? mosaic_size : 0);
|
||||
bg2.regs.mosaic = (data & 0x02 ? mosaic_size : 0);
|
||||
bg1.regs.mosaic = (data & 0x01 ? mosaic_size : 0);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2107: { //BG1SC
|
||||
bg1.regs.screen_addr = (data & 0x7c) << 9;
|
||||
bg1.regs.screen_size = data & 3;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2108: { //BG2SC
|
||||
bg2.regs.screen_addr = (data & 0x7c) << 9;
|
||||
bg2.regs.screen_size = data & 3;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2109: { //BG3SC
|
||||
bg3.regs.screen_addr = (data & 0x7c) << 9;
|
||||
bg3.regs.screen_size = data & 3;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x210a: { //BG4SC
|
||||
bg4.regs.screen_addr = (data & 0x7c) << 9;
|
||||
bg4.regs.screen_size = data & 3;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x210b: { //BG12NBA
|
||||
bg1.regs.tiledata_addr = (data & 0x07) << 13;
|
||||
bg2.regs.tiledata_addr = (data & 0x70) << 9;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x210c: { //BG34NBA
|
||||
bg3.regs.tiledata_addr = (data & 0x07) << 13;
|
||||
bg4.regs.tiledata_addr = (data & 0x70) << 9;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x210d: { //BG1HOFS
|
||||
regs.mode7_hoffset = (data << 8) | regs.mode7_latchdata;
|
||||
regs.mode7_latchdata = data;
|
||||
|
||||
bg1.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg1.regs.hoffset >> 8) & 7);
|
||||
regs.bgofs_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x210e: { //BG1VOFS
|
||||
regs.mode7_voffset = (data << 8) | regs.mode7_latchdata;
|
||||
regs.mode7_latchdata = data;
|
||||
|
||||
bg1.regs.voffset = (data << 8) | regs.bgofs_latchdata;
|
||||
regs.bgofs_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x210f: { //BG2HOFS
|
||||
bg2.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg2.regs.hoffset >> 8) & 7);
|
||||
regs.bgofs_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2110: { //BG2VOFS
|
||||
bg2.regs.voffset = (data << 8) | regs.bgofs_latchdata;
|
||||
regs.bgofs_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2111: { //BG3HOFS
|
||||
bg3.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg3.regs.hoffset >> 8) & 7);
|
||||
regs.bgofs_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2112: { //BG3VOFS
|
||||
bg3.regs.voffset = (data << 8) | regs.bgofs_latchdata;
|
||||
regs.bgofs_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2113: { //BG4HOFS
|
||||
bg4.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg4.regs.hoffset >> 8) & 7);
|
||||
regs.bgofs_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2114: { //BG4VOFS
|
||||
bg4.regs.voffset = (data << 8) | regs.bgofs_latchdata;
|
||||
regs.bgofs_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2115: { //VMAIN
|
||||
regs.vram_incmode = data & 0x80;
|
||||
regs.vram_mapping = (data >> 2) & 3;
|
||||
switch(data & 3) {
|
||||
case 0: regs.vram_incsize = 1; break;
|
||||
case 1: regs.vram_incsize = 32; break;
|
||||
case 2: regs.vram_incsize = 128; break;
|
||||
case 3: regs.vram_incsize = 128; break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2116: { //VMADDL
|
||||
regs.vram_addr = (regs.vram_addr & 0xff00) | (data << 0);
|
||||
uint16 addr = get_vram_addr();
|
||||
regs.vram_readbuffer = vram_read(addr + 0) << 0;
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2117: { //VMADDH
|
||||
regs.vram_addr = (data << 8) | (regs.vram_addr & 0x00ff);
|
||||
uint16 addr = get_vram_addr();
|
||||
regs.vram_readbuffer = vram_read(addr + 0) << 0;
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2118: { //VMDATAL
|
||||
vram_write(get_vram_addr() + 0, data);
|
||||
if(regs.vram_incmode == 0) regs.vram_addr += regs.vram_incsize;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2119: { //VMDATAH
|
||||
vram_write(get_vram_addr() + 1, data);
|
||||
if(regs.vram_incmode == 1) regs.vram_addr += regs.vram_incsize;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x211a: { //M7SEL
|
||||
regs.mode7_repeat = (data >> 6) & 3;
|
||||
regs.mode7_vflip = data & 0x02;
|
||||
regs.mode7_hflip = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x211b: { //M7A
|
||||
regs.m7a = (data << 8) | regs.mode7_latchdata;
|
||||
regs.mode7_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x211c: { //M7B
|
||||
regs.m7b = (data << 8) | regs.mode7_latchdata;
|
||||
regs.mode7_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x211d: { //M7C
|
||||
regs.m7c = (data << 8) | regs.mode7_latchdata;
|
||||
regs.mode7_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x211e: { //M7D
|
||||
regs.m7d = (data << 8) | regs.mode7_latchdata;
|
||||
regs.mode7_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x211f: { //M7X
|
||||
regs.m7x = (data << 8) | regs.mode7_latchdata;
|
||||
regs.mode7_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2120: { //M7Y
|
||||
regs.m7y = (data << 8) | regs.mode7_latchdata;
|
||||
regs.mode7_latchdata = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2121: { //CGADD
|
||||
regs.cgram_addr = data << 1;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2122: { //CGDATA
|
||||
if((regs.cgram_addr & 1) == 0) {
|
||||
regs.cgram_latchdata = data;
|
||||
} else {
|
||||
cgram_write((regs.cgram_addr & ~1) + 0, regs.cgram_latchdata);
|
||||
cgram_write((regs.cgram_addr & ~1) + 1, data & 0x7f);
|
||||
}
|
||||
regs.cgram_addr = (regs.cgram_addr + 1) & 0x01ff;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2123: { //W12SEL
|
||||
bg2.window.two_enable = data & 0x80;
|
||||
bg2.window.two_invert = data & 0x40;
|
||||
bg2.window.one_enable = data & 0x20;
|
||||
bg2.window.one_invert = data & 0x10;
|
||||
bg1.window.two_enable = data & 0x08;
|
||||
bg1.window.two_invert = data & 0x04;
|
||||
bg1.window.one_enable = data & 0x02;
|
||||
bg1.window.one_invert = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2124: { //W34SEL
|
||||
bg4.window.two_enable = data & 0x80;
|
||||
bg4.window.two_invert = data & 0x40;
|
||||
bg4.window.one_enable = data & 0x20;
|
||||
bg4.window.one_invert = data & 0x10;
|
||||
bg3.window.two_enable = data & 0x08;
|
||||
bg3.window.two_invert = data & 0x04;
|
||||
bg3.window.one_enable = data & 0x02;
|
||||
bg3.window.one_invert = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2125: { //WOBJSEL
|
||||
screen.window.two_enable = data & 0x80;
|
||||
screen.window.two_invert = data & 0x40;
|
||||
screen.window.one_enable = data & 0x20;
|
||||
screen.window.one_invert = data & 0x10;
|
||||
sprite.window.two_enable = data & 0x08;
|
||||
sprite.window.two_invert = data & 0x04;
|
||||
sprite.window.one_enable = data & 0x02;
|
||||
sprite.window.one_invert = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2126: { //WH0
|
||||
regs.window_one_left = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2127: { //WH1
|
||||
regs.window_one_right = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2128: { //WH2
|
||||
regs.window_two_left = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2129: { //WH3
|
||||
regs.window_two_right = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x212a: { //WBGLOG
|
||||
bg4.window.mask = (data >> 6) & 3;
|
||||
bg3.window.mask = (data >> 4) & 3;
|
||||
bg2.window.mask = (data >> 2) & 3;
|
||||
bg1.window.mask = (data >> 0) & 3;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x212b: { //WOBJLOG
|
||||
screen.window.mask = (data >> 2) & 3;
|
||||
sprite.window.mask = (data >> 0) & 3;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x212c: { //TM
|
||||
sprite.regs.main_enable = data & 0x10;
|
||||
bg4.regs.main_enable = data & 0x08;
|
||||
bg3.regs.main_enable = data & 0x04;
|
||||
bg2.regs.main_enable = data & 0x02;
|
||||
bg1.regs.main_enable = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x212d: { //TS
|
||||
sprite.regs.sub_enable = data & 0x10;
|
||||
bg4.regs.sub_enable = data & 0x08;
|
||||
bg3.regs.sub_enable = data & 0x04;
|
||||
bg2.regs.sub_enable = data & 0x02;
|
||||
bg1.regs.sub_enable = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x212e: { //TMW
|
||||
sprite.window.main_enable = data & 0x10;
|
||||
bg4.window.main_enable = data & 0x08;
|
||||
bg3.window.main_enable = data & 0x04;
|
||||
bg2.window.main_enable = data & 0x02;
|
||||
bg1.window.main_enable = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x212f: { //TSW
|
||||
sprite.window.sub_enable = data & 0x10;
|
||||
bg4.window.sub_enable = data & 0x08;
|
||||
bg3.window.sub_enable = data & 0x04;
|
||||
bg2.window.sub_enable = data & 0x02;
|
||||
bg1.window.sub_enable = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2130: { //CGWSEL
|
||||
screen.window.main_mask = (data >> 6) & 3;
|
||||
screen.window.sub_mask = (data >> 4) & 3;
|
||||
screen.regs.addsub_mode = data & 0x02;
|
||||
screen.regs.direct_color = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2131: { //CGADDSUB
|
||||
screen.regs.color_mode = data & 0x80;
|
||||
screen.regs.color_halve = data & 0x40;
|
||||
screen.regs.color_enable[6] = data & 0x20;
|
||||
screen.regs.color_enable[5] = data & 0x10;
|
||||
screen.regs.color_enable[4] = data & 0x10;
|
||||
screen.regs.color_enable[3] = data & 0x08;
|
||||
screen.regs.color_enable[2] = data & 0x04;
|
||||
screen.regs.color_enable[1] = data & 0x02;
|
||||
screen.regs.color_enable[0] = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2132: { //COLDATA
|
||||
if(data & 0x80) screen.regs.color_b = data & 0x1f;
|
||||
if(data & 0x40) screen.regs.color_g = data & 0x1f;
|
||||
if(data & 0x20) screen.regs.color_r = data & 0x1f;
|
||||
screen.regs.color = (screen.regs.color_b << 10) | (screen.regs.color_g << 5) | (screen.regs.color_r << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2133: { //SETINI
|
||||
regs.mode7_extbg = data & 0x40;
|
||||
regs.pseudo_hires = data & 0x08;
|
||||
regs.overscan = data & 0x04;
|
||||
sprite.regs.interlace = data & 0x02;
|
||||
regs.interlace = data & 0x01;
|
||||
mmio_update_video_mode();
|
||||
sprite.list_valid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::mmio_reset() -> void {
|
||||
//internal
|
||||
regs.ppu1_mdr = 0;
|
||||
regs.ppu2_mdr = 0;
|
||||
|
||||
regs.vram_readbuffer = 0;
|
||||
regs.oam_latchdata = 0;
|
||||
regs.cgram_latchdata = 0;
|
||||
regs.bgofs_latchdata = 0;
|
||||
regs.mode7_latchdata = 0;
|
||||
|
||||
regs.counters_latched = 0;
|
||||
regs.latch_hcounter = 0;
|
||||
regs.latch_vcounter = 0;
|
||||
|
||||
sprite.regs.first_sprite = 0;
|
||||
sprite.list_valid = false;
|
||||
|
||||
//$2100
|
||||
regs.display_disable = true;
|
||||
regs.display_brightness = 0;
|
||||
|
||||
//$2101
|
||||
sprite.regs.base_size = 0;
|
||||
sprite.regs.nameselect = 0;
|
||||
sprite.regs.tiledata_addr = 0;
|
||||
|
||||
//$2102-$2103
|
||||
regs.oam_baseaddr = 0;
|
||||
regs.oam_addr = 0;
|
||||
regs.oam_priority = 0;
|
||||
|
||||
//$2105
|
||||
bg4.regs.tile_size = 0;
|
||||
bg3.regs.tile_size = 0;
|
||||
bg2.regs.tile_size = 0;
|
||||
bg1.regs.tile_size = 0;
|
||||
regs.bg3_priority = 0;
|
||||
regs.bgmode = 0;
|
||||
|
||||
//$2106
|
||||
bg4.regs.mosaic = 0;
|
||||
bg3.regs.mosaic = 0;
|
||||
bg2.regs.mosaic = 0;
|
||||
bg1.regs.mosaic = 0;
|
||||
|
||||
//$2107-$210a
|
||||
bg1.regs.screen_addr = 0;
|
||||
bg1.regs.screen_size = 0;
|
||||
bg2.regs.screen_addr = 0;
|
||||
bg2.regs.screen_size = 0;
|
||||
bg3.regs.screen_addr = 0;
|
||||
bg3.regs.screen_size = 0;
|
||||
bg4.regs.screen_addr = 0;
|
||||
bg4.regs.screen_size = 0;
|
||||
|
||||
//$210b-$210c
|
||||
bg1.regs.tiledata_addr = 0;
|
||||
bg2.regs.tiledata_addr = 0;
|
||||
bg3.regs.tiledata_addr = 0;
|
||||
bg4.regs.tiledata_addr = 0;
|
||||
|
||||
//$210d-$2114
|
||||
regs.mode7_hoffset = 0;
|
||||
regs.mode7_voffset = 0;
|
||||
bg1.regs.hoffset = 0;
|
||||
bg1.regs.voffset = 0;
|
||||
bg2.regs.hoffset = 0;
|
||||
bg2.regs.voffset = 0;
|
||||
bg3.regs.hoffset = 0;
|
||||
bg3.regs.voffset = 0;
|
||||
bg4.regs.hoffset = 0;
|
||||
bg4.regs.voffset = 0;
|
||||
|
||||
//$2115
|
||||
regs.vram_incmode = 0;
|
||||
regs.vram_mapping = 0;
|
||||
regs.vram_incsize = 1;
|
||||
|
||||
//$2116-$2117
|
||||
regs.vram_addr = 0;
|
||||
|
||||
//$211a
|
||||
regs.mode7_repeat = 0;
|
||||
regs.mode7_vflip = 0;
|
||||
regs.mode7_hflip = 0;
|
||||
|
||||
//$211b-$2120
|
||||
regs.m7a = 0;
|
||||
regs.m7b = 0;
|
||||
regs.m7c = 0;
|
||||
regs.m7d = 0;
|
||||
regs.m7x = 0;
|
||||
regs.m7y = 0;
|
||||
|
||||
//$2121
|
||||
regs.cgram_addr = 0;
|
||||
|
||||
//$2123-$2125
|
||||
bg1.window.one_enable = 0;
|
||||
bg1.window.one_invert = 0;
|
||||
bg1.window.two_enable = 0;
|
||||
bg1.window.two_invert = 0;
|
||||
|
||||
bg2.window.one_enable = 0;
|
||||
bg2.window.one_invert = 0;
|
||||
bg2.window.two_enable = 0;
|
||||
bg2.window.two_invert = 0;
|
||||
|
||||
bg3.window.one_enable = 0;
|
||||
bg3.window.one_invert = 0;
|
||||
bg3.window.two_enable = 0;
|
||||
bg3.window.two_invert = 0;
|
||||
|
||||
bg4.window.one_enable = 0;
|
||||
bg4.window.one_invert = 0;
|
||||
bg4.window.two_enable = 0;
|
||||
bg4.window.two_invert = 0;
|
||||
|
||||
sprite.window.one_enable = 0;
|
||||
sprite.window.one_invert = 0;
|
||||
sprite.window.two_enable = 0;
|
||||
sprite.window.two_invert = 0;
|
||||
|
||||
screen.window.one_enable = 0;
|
||||
screen.window.one_invert = 0;
|
||||
screen.window.two_enable = 0;
|
||||
screen.window.two_invert = 0;
|
||||
|
||||
//$2126-$2129
|
||||
regs.window_one_left = 0;
|
||||
regs.window_one_right = 0;
|
||||
regs.window_two_left = 0;
|
||||
regs.window_two_right = 0;
|
||||
|
||||
//$212a-$212b
|
||||
bg1.window.mask = 0;
|
||||
bg2.window.mask = 0;
|
||||
bg3.window.mask = 0;
|
||||
bg4.window.mask = 0;
|
||||
sprite.window.mask = 0;
|
||||
screen.window.mask = 0;
|
||||
|
||||
//$212c
|
||||
bg1.regs.main_enable = 0;
|
||||
bg2.regs.main_enable = 0;
|
||||
bg3.regs.main_enable = 0;
|
||||
bg4.regs.main_enable = 0;
|
||||
sprite.regs.main_enable = 0;
|
||||
|
||||
//$212d
|
||||
bg1.regs.sub_enable = 0;
|
||||
bg2.regs.sub_enable = 0;
|
||||
bg3.regs.sub_enable = 0;
|
||||
bg4.regs.sub_enable = 0;
|
||||
sprite.regs.sub_enable = 0;
|
||||
|
||||
//$212e
|
||||
bg1.window.main_enable = 0;
|
||||
bg2.window.main_enable = 0;
|
||||
bg3.window.main_enable = 0;
|
||||
bg4.window.main_enable = 0;
|
||||
sprite.window.main_enable = 0;
|
||||
|
||||
//$212f
|
||||
bg1.window.sub_enable = 0;
|
||||
bg2.window.sub_enable = 0;
|
||||
bg3.window.sub_enable = 0;
|
||||
bg4.window.sub_enable = 0;
|
||||
sprite.window.sub_enable = 0;
|
||||
|
||||
//$2130
|
||||
screen.window.main_mask = 0;
|
||||
screen.window.sub_mask = 0;
|
||||
screen.regs.addsub_mode = 0;
|
||||
screen.regs.direct_color = 0;
|
||||
|
||||
//$2131
|
||||
screen.regs.color_mode = 0;
|
||||
screen.regs.color_halve = 0;
|
||||
screen.regs.color_enable[6] = 0;
|
||||
screen.regs.color_enable[5] = 0;
|
||||
screen.regs.color_enable[4] = 0;
|
||||
screen.regs.color_enable[3] = 0;
|
||||
screen.regs.color_enable[2] = 0;
|
||||
screen.regs.color_enable[1] = 0;
|
||||
screen.regs.color_enable[0] = 0;
|
||||
|
||||
//$2132
|
||||
screen.regs.color_b = 0;
|
||||
screen.regs.color_g = 0;
|
||||
screen.regs.color_r = 0;
|
||||
screen.regs.color = 0;
|
||||
|
||||
//$2133
|
||||
regs.mode7_extbg = 0;
|
||||
regs.pseudo_hires = 0;
|
||||
regs.overscan = 0;
|
||||
sprite.regs.interlace = 0;
|
||||
regs.interlace = 0;
|
||||
|
||||
//$213e
|
||||
sprite.regs.time_over = 0;
|
||||
sprite.regs.range_over = 0;
|
||||
|
||||
mmio_update_video_mode();
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
public:
|
||||
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmio_write(uint addr, uint8 data) -> void;
|
||||
|
||||
private:
|
||||
|
||||
struct Regs {
|
||||
//internal
|
||||
uint8 ppu1_mdr;
|
||||
uint8 ppu2_mdr;
|
||||
|
||||
uint16 vram_readbuffer;
|
||||
uint8 oam_latchdata;
|
||||
uint8 cgram_latchdata;
|
||||
uint8 bgofs_latchdata;
|
||||
uint8 mode7_latchdata;
|
||||
|
||||
bool counters_latched;
|
||||
bool latch_hcounter;
|
||||
bool latch_vcounter;
|
||||
|
||||
//$2100
|
||||
bool display_disable;
|
||||
uint display_brightness;
|
||||
|
||||
//$2102-$2103
|
||||
uint16 oam_baseaddr;
|
||||
uint16 oam_addr;
|
||||
bool oam_priority;
|
||||
|
||||
//$2105
|
||||
bool bg3_priority;
|
||||
uint bgmode;
|
||||
|
||||
//$210d
|
||||
uint16 mode7_hoffset;
|
||||
|
||||
//$210e
|
||||
uint16 mode7_voffset;
|
||||
|
||||
//$2115
|
||||
bool vram_incmode;
|
||||
uint vram_mapping;
|
||||
uint vram_incsize;
|
||||
|
||||
//$2116-$2117
|
||||
uint16 vram_addr;
|
||||
|
||||
//$211a
|
||||
uint mode7_repeat;
|
||||
bool mode7_vflip;
|
||||
bool mode7_hflip;
|
||||
|
||||
//$211b-$2120
|
||||
uint16 m7a;
|
||||
uint16 m7b;
|
||||
uint16 m7c;
|
||||
uint16 m7d;
|
||||
uint16 m7x;
|
||||
uint16 m7y;
|
||||
|
||||
//$2121
|
||||
uint16 cgram_addr;
|
||||
|
||||
//$2126-$212a
|
||||
uint window_one_left;
|
||||
uint window_one_right;
|
||||
uint window_two_left;
|
||||
uint window_two_right;
|
||||
|
||||
//$2133
|
||||
bool mode7_extbg;
|
||||
bool pseudo_hires;
|
||||
bool overscan;
|
||||
bool interlace;
|
||||
|
||||
//$213c
|
||||
uint16 hcounter;
|
||||
|
||||
//$213d
|
||||
uint16 vcounter;
|
||||
} regs;
|
||||
|
||||
auto get_vram_addr() -> uint16;
|
||||
auto vram_read(uint addr) -> uint8;
|
||||
auto vram_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto oam_read(uint addr) -> uint8;
|
||||
auto oam_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto cgram_read(uint addr) -> uint8;
|
||||
auto cgram_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto mmio_update_video_mode() -> void;
|
||||
auto mmio_reset() -> void;
|
|
@ -1,152 +0,0 @@
|
|||
#include <sfc/sfc.hpp>
|
||||
|
||||
namespace SuperFamicom {
|
||||
|
||||
#include <sfc/ppu/video.cpp>
|
||||
PPU ppu;
|
||||
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "window/window.cpp"
|
||||
#include "cache/cache.cpp"
|
||||
#include "background/background.cpp"
|
||||
#include "sprite/sprite.cpp"
|
||||
#include "screen/screen.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
PPU::PPU() :
|
||||
cache(*this),
|
||||
bg1(*this, Background::ID::BG1),
|
||||
bg2(*this, Background::ID::BG2),
|
||||
bg3(*this, Background::ID::BG3),
|
||||
bg4(*this, Background::ID::BG4),
|
||||
sprite(*this),
|
||||
screen(*this) {
|
||||
output = new uint32[512 * 512]();
|
||||
output += 16 * 512; //overscan offset
|
||||
display.width = 256;
|
||||
display.height = 224;
|
||||
display.frameskip = 0;
|
||||
display.framecounter = 0;
|
||||
}
|
||||
|
||||
PPU::~PPU() {
|
||||
output -= 16 * 512;
|
||||
delete[] output;
|
||||
}
|
||||
|
||||
auto PPU::step(uint clocks) -> void {
|
||||
clock += clocks;
|
||||
}
|
||||
|
||||
auto PPU::synchronizeCPU() -> void {
|
||||
if(CPU::Threaded == true) {
|
||||
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
||||
} else {
|
||||
while(clock >= 0) cpu.main();
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), ppu.main();
|
||||
}
|
||||
|
||||
auto PPU::main() -> void {
|
||||
scanline();
|
||||
if(vcounter() < display.height && vcounter()) {
|
||||
add_clocks(512);
|
||||
render_scanline();
|
||||
add_clocks(lineclocks() - 512);
|
||||
} else {
|
||||
add_clocks(lineclocks());
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::add_clocks(uint clocks) -> void {
|
||||
tick(clocks);
|
||||
step(clocks);
|
||||
synchronizeCPU();
|
||||
}
|
||||
|
||||
auto PPU::render_scanline() -> void {
|
||||
if(display.framecounter) return; //skip this frame?
|
||||
bg1.scanline();
|
||||
bg2.scanline();
|
||||
bg3.scanline();
|
||||
bg4.scanline();
|
||||
if(regs.display_disable) return screen.render_black();
|
||||
screen.scanline();
|
||||
bg1.render();
|
||||
bg2.render();
|
||||
bg3.render();
|
||||
bg4.render();
|
||||
sprite.render();
|
||||
screen.render();
|
||||
}
|
||||
|
||||
auto PPU::scanline() -> void {
|
||||
display.width = 512;
|
||||
display.height = !overscan() ? 225 : 240;
|
||||
if(vcounter() == 0) frame();
|
||||
if(vcounter() == display.height && regs.display_disable == false) sprite.address_reset();
|
||||
|
||||
if(vcounter() == 241) {
|
||||
video.refresh();
|
||||
scheduler.exit(Scheduler::Event::Frame);
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::frame() -> void {
|
||||
sprite.frame();
|
||||
display.interlace = regs.interlace;
|
||||
display.overscan = regs.overscan;
|
||||
display.framecounter = display.frameskip == 0 ? 0 : (display.framecounter + 1) % display.frameskip;
|
||||
}
|
||||
|
||||
auto PPU::enable() -> void {
|
||||
function<auto (uint, uint8) -> uint8> reader{&PPU::mmio_read, (PPU*)&ppu};
|
||||
function<auto (uint, uint8) -> void> writer{&PPU::mmio_write, (PPU*)&ppu};
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);
|
||||
}
|
||||
|
||||
auto PPU::power() -> void {
|
||||
for(auto& n : vram) n = 0;
|
||||
for(auto& n : oam) n = 0;
|
||||
for(auto& n : cgram) n = 0;
|
||||
reset();
|
||||
}
|
||||
|
||||
auto PPU::reset() -> void {
|
||||
create(Enter, system.cpuFrequency());
|
||||
PPUcounter::reset();
|
||||
memset(output, 0, 512 * 480 * sizeof(uint32));
|
||||
mmio_reset();
|
||||
display.interlace = false;
|
||||
display.overscan = false;
|
||||
video.reset();
|
||||
}
|
||||
|
||||
auto PPU::layer_enable(uint layer, uint priority, bool enable) -> void {
|
||||
switch(layer * 4 + priority) {
|
||||
case 0: bg1.priority0_enable = enable; break;
|
||||
case 1: bg1.priority1_enable = enable; break;
|
||||
case 4: bg2.priority0_enable = enable; break;
|
||||
case 5: bg2.priority1_enable = enable; break;
|
||||
case 8: bg3.priority0_enable = enable; break;
|
||||
case 9: bg3.priority1_enable = enable; break;
|
||||
case 12: bg4.priority0_enable = enable; break;
|
||||
case 13: bg4.priority1_enable = enable; break;
|
||||
case 16: sprite.priority0_enable = enable; break;
|
||||
case 17: sprite.priority1_enable = enable; break;
|
||||
case 18: sprite.priority2_enable = enable; break;
|
||||
case 19: sprite.priority3_enable = enable; break;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::set_frameskip(uint frameskip) -> void {
|
||||
display.frameskip = frameskip;
|
||||
display.framecounter = 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
#include <sfc/ppu/video.hpp>
|
||||
|
||||
struct PPU : Thread, public PPUcounter {
|
||||
enum : bool { Threaded = true };
|
||||
|
||||
PPU();
|
||||
~PPU();
|
||||
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto synchronizeCPU() -> void;
|
||||
|
||||
auto latch_counters() -> void;
|
||||
auto interlace() const -> bool;
|
||||
auto overscan() const -> bool;
|
||||
|
||||
auto main() -> void;
|
||||
auto enable() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
auto scanline() -> void;
|
||||
auto frame() -> void;
|
||||
|
||||
auto layer_enable(uint layer, uint priority, bool enable) -> void;
|
||||
auto set_frameskip(uint frameskip) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint8 vram[64 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
|
||||
private:
|
||||
uint32* output;
|
||||
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "window/window.hpp"
|
||||
#include "cache/cache.hpp"
|
||||
#include "background/background.hpp"
|
||||
#include "sprite/sprite.hpp"
|
||||
#include "screen/screen.hpp"
|
||||
|
||||
Cache cache;
|
||||
Background bg1;
|
||||
Background bg2;
|
||||
Background bg3;
|
||||
Background bg4;
|
||||
Sprite sprite;
|
||||
Screen screen;
|
||||
|
||||
struct Display {
|
||||
bool interlace;
|
||||
bool overscan;
|
||||
uint width;
|
||||
uint height;
|
||||
uint frameskip;
|
||||
uint framecounter;
|
||||
} display;
|
||||
|
||||
static auto Enter() -> void;
|
||||
auto add_clocks(uint clocks) -> void;
|
||||
auto render_scanline() -> void;
|
||||
|
||||
friend class PPU::Cache;
|
||||
friend class PPU::Background;
|
||||
friend class PPU::Sprite;
|
||||
friend class PPU::Screen;
|
||||
friend class Video;
|
||||
};
|
||||
|
||||
extern PPU ppu;
|
|
@ -1,150 +0,0 @@
|
|||
PPU::Screen::Screen(PPU& self) : self(self) {
|
||||
}
|
||||
|
||||
auto PPU::Screen::get_palette(uint color) -> uint {
|
||||
#if defined(ENDIAN_LSB)
|
||||
return ((uint16*)ppu.cgram)[color];
|
||||
#else
|
||||
color <<= 1;
|
||||
return (ppu.cgram[color + 0] << 0) + (ppu.cgram[color + 1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
auto PPU::Screen::get_direct_color(uint p, uint t) -> uint {
|
||||
return ((t & 7) << 2) | ((p & 1) << 1) |
|
||||
(((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) |
|
||||
((t >> 6) << 13) | ((p >> 2) << 12);
|
||||
}
|
||||
|
||||
auto PPU::Screen::addsub(uint x, uint y, bool halve) -> uint16 {
|
||||
if(!regs.color_mode) {
|
||||
if(!halve) {
|
||||
uint sum = x + y;
|
||||
uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420;
|
||||
return (sum - carry) | (carry - (carry >> 5));
|
||||
} else {
|
||||
return (x + y - ((x ^ y) & 0x0421)) >> 1;
|
||||
}
|
||||
} else {
|
||||
uint diff = x - y + 0x8420;
|
||||
uint borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420;
|
||||
if(!halve) {
|
||||
return (diff - borrow) & (borrow - (borrow >> 5));
|
||||
} else {
|
||||
return (((diff - borrow) & (borrow - (borrow >> 5))) & 0x7bde) >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Screen::scanline() -> void {
|
||||
uint main_color = get_palette(0);
|
||||
uint sub_color = (self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6)
|
||||
? regs.color : main_color;
|
||||
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
output.main[x].color = main_color;
|
||||
output.main[x].priority = 0;
|
||||
output.main[x].source = 6;
|
||||
|
||||
output.sub[x].color = sub_color;
|
||||
output.sub[x].priority = 0;
|
||||
output.sub[x].source = 6;
|
||||
}
|
||||
|
||||
window.render(0);
|
||||
window.render(1);
|
||||
}
|
||||
|
||||
auto PPU::Screen::render_black() -> void {
|
||||
auto data = self.output + self.vcounter() * 1024;
|
||||
if(self.interlace() && self.field()) data += 512;
|
||||
memory::fill(data, 512 * sizeof(uint32));
|
||||
}
|
||||
|
||||
auto PPU::Screen::get_pixel_main(uint x) -> uint16 {
|
||||
auto main = output.main[x];
|
||||
auto sub = output.sub[x];
|
||||
|
||||
if(!regs.addsub_mode) {
|
||||
sub.source = 6;
|
||||
sub.color = regs.color;
|
||||
}
|
||||
|
||||
if(!window.main[x]) {
|
||||
if(!window.sub[x]) {
|
||||
return 0x0000;
|
||||
}
|
||||
main.color = 0x0000;
|
||||
}
|
||||
|
||||
if(main.source != 5 && regs.color_enable[main.source] && window.sub[x]) {
|
||||
bool halve = false;
|
||||
if(regs.color_halve && window.main[x]) {
|
||||
if(!regs.addsub_mode || sub.source != 6) halve = true;
|
||||
}
|
||||
return addsub(main.color, sub.color, halve);
|
||||
}
|
||||
|
||||
return main.color;
|
||||
}
|
||||
|
||||
auto PPU::Screen::get_pixel_sub(uint x) -> uint16 {
|
||||
auto main = output.sub[x];
|
||||
auto sub = output.main[x];
|
||||
|
||||
if(!regs.addsub_mode) {
|
||||
sub.source = 6;
|
||||
sub.color = regs.color;
|
||||
}
|
||||
|
||||
if(!window.main[x]) {
|
||||
if(!window.sub[x]) {
|
||||
return 0x0000;
|
||||
}
|
||||
main.color = 0x0000;
|
||||
}
|
||||
|
||||
if(main.source != 5 && regs.color_enable[main.source] && window.sub[x]) {
|
||||
bool halve = false;
|
||||
if(regs.color_halve && window.main[x]) {
|
||||
if(!regs.addsub_mode || sub.source != 6) halve = true;
|
||||
}
|
||||
return addsub(main.color, sub.color, halve);
|
||||
}
|
||||
|
||||
return main.color;
|
||||
}
|
||||
|
||||
auto PPU::Screen::render() -> void {
|
||||
auto data = self.output + self.vcounter() * 1024;
|
||||
if(self.interlace() && self.field()) data += 512;
|
||||
|
||||
if(!self.regs.pseudo_hires && self.regs.bgmode != 5 && self.regs.bgmode != 6) {
|
||||
for(uint i = 0; i < 256; i++) {
|
||||
uint32 color = self.regs.display_brightness << 15 | get_pixel_main(i);
|
||||
*data++ = color;
|
||||
*data++ = color;
|
||||
}
|
||||
} else {
|
||||
for(uint i = 0; i < 256; i++) {
|
||||
*data++ = self.regs.display_brightness << 15 | get_pixel_sub(i);
|
||||
*data++ = self.regs.display_brightness << 15 | get_pixel_main(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Screen::Output::plot_main(uint x, uint color, uint priority, uint source) -> void {
|
||||
if(priority > main[x].priority) {
|
||||
main[x].color = color;
|
||||
main[x].priority = priority;
|
||||
main[x].source = source;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Screen::Output::plot_sub(uint x, uint color, uint priority, uint source) -> void {
|
||||
if(priority > sub[x].priority) {
|
||||
sub[x].color = color;
|
||||
sub[x].priority = priority;
|
||||
sub[x].source = source;
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
class Screen {
|
||||
Screen(PPU& self);
|
||||
|
||||
alwaysinline auto get_palette(uint color) -> uint;
|
||||
auto get_direct_color(uint palette, uint tile) -> uint;
|
||||
alwaysinline auto addsub(uint x, uint y, bool halve) -> uint16;
|
||||
auto scanline() -> void;
|
||||
auto render_black() -> void;
|
||||
alwaysinline auto get_pixel_main(uint x) -> uint16;
|
||||
alwaysinline auto get_pixel_sub(uint x) -> uint16;
|
||||
auto render() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
PPU& self;
|
||||
|
||||
struct Regs {
|
||||
bool addsub_mode;
|
||||
bool direct_color;
|
||||
|
||||
bool color_mode;
|
||||
bool color_halve;
|
||||
bool color_enable[7];
|
||||
|
||||
uint color_b;
|
||||
uint color_g;
|
||||
uint color_r;
|
||||
uint color;
|
||||
} regs;
|
||||
|
||||
struct Output {
|
||||
alwaysinline auto plot_main(uint x, uint color, uint priority, uint source) -> void;
|
||||
alwaysinline auto plot_sub(uint x, uint color, uint priority, uint source) -> void;
|
||||
|
||||
struct Pixel {
|
||||
uint color;
|
||||
uint priority;
|
||||
uint source;
|
||||
} main[256], sub[256];
|
||||
} output;
|
||||
|
||||
ColorWindow window;
|
||||
|
||||
friend class PPU;
|
||||
};
|
|
@ -1,245 +0,0 @@
|
|||
auto PPUcounter::serialize(serializer& s) -> void {
|
||||
s.integer(status.interlace);
|
||||
s.integer(status.field);
|
||||
s.integer(status.vcounter);
|
||||
s.integer(status.hcounter);
|
||||
|
||||
s.array(history.field);
|
||||
s.array(history.vcounter);
|
||||
s.array(history.hcounter);
|
||||
s.integer(history.index);
|
||||
}
|
||||
|
||||
auto PPU::serialize(serializer& s) -> void {
|
||||
Thread::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram);
|
||||
s.array(oam);
|
||||
s.array(cgram);
|
||||
|
||||
cache.serialize(s);
|
||||
bg1.serialize(s);
|
||||
bg2.serialize(s);
|
||||
bg3.serialize(s);
|
||||
bg4.serialize(s);
|
||||
sprite.serialize(s);
|
||||
screen.serialize(s);
|
||||
|
||||
s.integer(display.interlace);
|
||||
s.integer(display.overscan);
|
||||
s.integer(display.width);
|
||||
s.integer(display.height);
|
||||
|
||||
s.integer(regs.ppu1_mdr);
|
||||
s.integer(regs.ppu2_mdr);
|
||||
|
||||
s.integer(regs.vram_readbuffer);
|
||||
s.integer(regs.oam_latchdata);
|
||||
s.integer(regs.cgram_latchdata);
|
||||
s.integer(regs.bgofs_latchdata);
|
||||
s.integer(regs.mode7_latchdata);
|
||||
|
||||
s.integer(regs.counters_latched);
|
||||
s.integer(regs.latch_hcounter);
|
||||
s.integer(regs.latch_vcounter);
|
||||
|
||||
s.integer(regs.display_disable);
|
||||
s.integer(regs.display_brightness);
|
||||
|
||||
s.integer(regs.oam_baseaddr);
|
||||
s.integer(regs.oam_addr);
|
||||
s.integer(regs.oam_priority);
|
||||
|
||||
s.integer(regs.bg3_priority);
|
||||
s.integer(regs.bgmode);
|
||||
|
||||
s.integer(regs.mode7_hoffset);
|
||||
|
||||
s.integer(regs.mode7_voffset);
|
||||
|
||||
s.integer(regs.vram_incmode);
|
||||
s.integer(regs.vram_mapping);
|
||||
s.integer(regs.vram_incsize);
|
||||
|
||||
s.integer(regs.vram_addr);
|
||||
|
||||
s.integer(regs.mode7_repeat);
|
||||
s.integer(regs.mode7_vflip);
|
||||
s.integer(regs.mode7_hflip);
|
||||
|
||||
s.integer(regs.m7a);
|
||||
s.integer(regs.m7b);
|
||||
s.integer(regs.m7c);
|
||||
s.integer(regs.m7d);
|
||||
s.integer(regs.m7x);
|
||||
s.integer(regs.m7y);
|
||||
|
||||
s.integer(regs.cgram_addr);
|
||||
|
||||
s.integer(regs.window_one_left);
|
||||
s.integer(regs.window_one_right);
|
||||
s.integer(regs.window_two_left);
|
||||
s.integer(regs.window_two_right);
|
||||
|
||||
s.integer(regs.mode7_extbg);
|
||||
s.integer(regs.pseudo_hires);
|
||||
s.integer(regs.overscan);
|
||||
s.integer(regs.interlace);
|
||||
|
||||
s.integer(regs.hcounter);
|
||||
|
||||
s.integer(regs.vcounter);
|
||||
}
|
||||
|
||||
auto PPU::Cache::serialize(serializer& s) -> void {
|
||||
//rather than save ~512KB worth of cached tiledata, invalidate it all
|
||||
for(uint i = 0; i < 4096; i++) tilevalid[0][i] = false;
|
||||
for(uint i = 0; i < 2048; i++) tilevalid[1][i] = false;
|
||||
for(uint i = 0; i < 1024; i++) tilevalid[2][i] = false;
|
||||
}
|
||||
|
||||
auto PPU::Background::serialize(serializer& s) -> void {
|
||||
s.integer(regs.mode);
|
||||
s.integer(regs.priority0);
|
||||
s.integer(regs.priority1);
|
||||
|
||||
s.integer(regs.tile_size);
|
||||
s.integer(regs.mosaic);
|
||||
|
||||
s.integer(regs.screen_addr);
|
||||
s.integer(regs.screen_size);
|
||||
s.integer(regs.tiledata_addr);
|
||||
|
||||
s.integer(regs.hoffset);
|
||||
s.integer(regs.voffset);
|
||||
|
||||
s.integer(regs.main_enable);
|
||||
s.integer(regs.sub_enable);
|
||||
|
||||
s.integer(hires);
|
||||
s.integer(width);
|
||||
|
||||
s.integer(tile_width);
|
||||
s.integer(tile_height);
|
||||
|
||||
s.integer(mask_x);
|
||||
s.integer(mask_y);
|
||||
|
||||
s.integer(scx);
|
||||
s.integer(scy);
|
||||
|
||||
s.integer(hscroll);
|
||||
s.integer(vscroll);
|
||||
|
||||
s.integer(mosaic_vcounter);
|
||||
s.integer(mosaic_voffset);
|
||||
|
||||
window.serialize(s);
|
||||
}
|
||||
|
||||
auto PPU::Sprite::serialize(serializer& s) -> void {
|
||||
s.integer(regs.priority0);
|
||||
s.integer(regs.priority1);
|
||||
s.integer(regs.priority2);
|
||||
s.integer(regs.priority3);
|
||||
|
||||
s.integer(regs.base_size);
|
||||
s.integer(regs.nameselect);
|
||||
s.integer(regs.tiledata_addr);
|
||||
s.integer(regs.first_sprite);
|
||||
|
||||
s.integer(regs.main_enable);
|
||||
s.integer(regs.sub_enable);
|
||||
|
||||
s.integer(regs.interlace);
|
||||
|
||||
s.integer(regs.time_over);
|
||||
s.integer(regs.range_over);
|
||||
|
||||
for(uint i = 0; i < 128; i++) {
|
||||
s.integer(list[i].width);
|
||||
s.integer(list[i].height);
|
||||
s.integer(list[i].x);
|
||||
s.integer(list[i].y);
|
||||
s.integer(list[i].character);
|
||||
s.integer(list[i].use_nameselect);
|
||||
s.integer(list[i].vflip);
|
||||
s.integer(list[i].hflip);
|
||||
s.integer(list[i].palette);
|
||||
s.integer(list[i].priority);
|
||||
s.integer(list[i].size);
|
||||
}
|
||||
s.integer(list_valid);
|
||||
|
||||
s.array(itemlist);
|
||||
for(uint i = 0; i < 34; i++) {
|
||||
s.integer(tilelist[i].x);
|
||||
s.integer(tilelist[i].y);
|
||||
s.integer(tilelist[i].priority);
|
||||
s.integer(tilelist[i].palette);
|
||||
s.integer(tilelist[i].tile);
|
||||
s.integer(tilelist[i].hflip);
|
||||
}
|
||||
|
||||
s.array(output.palette);
|
||||
s.array(output.priority);
|
||||
|
||||
window.serialize(s);
|
||||
}
|
||||
|
||||
auto PPU::Screen::serialize(serializer& s) -> void {
|
||||
s.integer(regs.addsub_mode);
|
||||
s.integer(regs.direct_color);
|
||||
|
||||
s.integer(regs.color_mode);
|
||||
s.integer(regs.color_halve);
|
||||
s.array(regs.color_enable);
|
||||
|
||||
s.integer(regs.color_b);
|
||||
s.integer(regs.color_g);
|
||||
s.integer(regs.color_r);
|
||||
s.integer(regs.color);
|
||||
|
||||
for(uint i = 0; i < 256; i++) {
|
||||
s.integer(output.main[i].color);
|
||||
s.integer(output.main[i].priority);
|
||||
s.integer(output.main[i].source);
|
||||
|
||||
s.integer(output.sub[i].color);
|
||||
s.integer(output.sub[i].priority);
|
||||
s.integer(output.sub[i].source);
|
||||
}
|
||||
|
||||
window.serialize(s);
|
||||
}
|
||||
|
||||
auto PPU::LayerWindow::serialize(serializer& s) -> void {
|
||||
s.integer(one_enable);
|
||||
s.integer(one_invert);
|
||||
s.integer(two_enable);
|
||||
s.integer(two_invert);
|
||||
|
||||
s.integer(mask);
|
||||
|
||||
s.integer(main_enable);
|
||||
s.integer(sub_enable);
|
||||
|
||||
s.array(main);
|
||||
s.array(sub);
|
||||
}
|
||||
|
||||
auto PPU::ColorWindow::serialize(serializer& s) -> void {
|
||||
s.integer(one_enable);
|
||||
s.integer(one_invert);
|
||||
s.integer(two_enable);
|
||||
s.integer(two_invert);
|
||||
|
||||
s.integer(mask);
|
||||
|
||||
s.integer(main_mask);
|
||||
s.integer(sub_mask);
|
||||
|
||||
s.array(main);
|
||||
s.array(sub);
|
||||
}
|
|
@ -1,186 +0,0 @@
|
|||
PPU::Sprite::Sprite(PPU& self) : self(self) {
|
||||
priority0_enable = true;
|
||||
priority1_enable = true;
|
||||
priority2_enable = true;
|
||||
priority3_enable = true;
|
||||
}
|
||||
|
||||
auto PPU::Sprite::frame() -> void {
|
||||
regs.time_over = false;
|
||||
regs.range_over = false;
|
||||
}
|
||||
|
||||
auto PPU::Sprite::update_list(uint addr, uint8 data) -> void {
|
||||
if(addr < 0x0200) {
|
||||
uint i = addr >> 2;
|
||||
switch(addr & 3) {
|
||||
case 0: list[i].x = (list[i].x & 0x0100) | data; break;
|
||||
case 1: list[i].y = (data + 1) & 0xff; break;
|
||||
case 2: list[i].character = data; break;
|
||||
case 3: list[i].vflip = data & 0x80;
|
||||
list[i].hflip = data & 0x40;
|
||||
list[i].priority = (data >> 4) & 3;
|
||||
list[i].palette = (data >> 1) & 7;
|
||||
list[i].use_nameselect = data & 0x01;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
uint i = (addr & 0x1f) << 2;
|
||||
list[i + 0].x = ((data & 0x01) << 8) | (list[i + 0].x & 0xff);
|
||||
list[i + 0].size = data & 0x02;
|
||||
list[i + 1].x = ((data & 0x04) << 6) | (list[i + 1].x & 0xff);
|
||||
list[i + 1].size = data & 0x08;
|
||||
list[i + 2].x = ((data & 0x10) << 4) | (list[i + 2].x & 0xff);
|
||||
list[i + 2].size = data & 0x20;
|
||||
list[i + 3].x = ((data & 0x40) << 2) | (list[i + 3].x & 0xff);
|
||||
list[i + 3].size = data & 0x80;
|
||||
list_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Sprite::address_reset() -> void {
|
||||
self.regs.oam_addr = self.regs.oam_baseaddr << 1;
|
||||
set_first();
|
||||
}
|
||||
|
||||
auto PPU::Sprite::set_first() -> void {
|
||||
regs.first_sprite = (self.regs.oam_priority == false ? 0 : (self.regs.oam_addr >> 2) & 127);
|
||||
}
|
||||
|
||||
auto PPU::Sprite::on_scanline(uint sprite) -> bool {
|
||||
auto& s = list[sprite];
|
||||
if(s.x > 256 && (s.x + s.width - 1) < 512) return false;
|
||||
int height = (regs.interlace == false ? s.height : s.height >> 1);
|
||||
if(self.vcounter() >= s.y && self.vcounter() < (s.y + height)) return true;
|
||||
if((s.y + height) >= 256 && self.vcounter() < ((s.y + height) & 255)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto PPU::Sprite::render() -> void {
|
||||
if(list_valid == false) {
|
||||
list_valid = true;
|
||||
for(uint i = 0; i < 128; i++) {
|
||||
if(list[i].size == 0) {
|
||||
static uint width[] = {8, 8, 8, 16, 16, 32, 16, 16};
|
||||
static uint height[] = {8, 8, 8, 16, 16, 32, 32, 32};
|
||||
list[i].width = width[regs.base_size];
|
||||
list[i].height = height[regs.base_size];
|
||||
} else {
|
||||
static uint width[] = {16, 32, 64, 32, 64, 64, 32, 32};
|
||||
static uint height[] = {16, 32, 64, 32, 64, 64, 64, 32};
|
||||
list[i].width = width[regs.base_size];
|
||||
list[i].height = height[regs.base_size];
|
||||
if(regs.interlace && regs.base_size >= 6) list[i].height = 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint itemcount = 0;
|
||||
uint tilecount = 0;
|
||||
memset(output.priority, 0xff, 256);
|
||||
memset(itemlist, 0xff, 32);
|
||||
for(uint i = 0; i < 34; i++) tilelist[i].tile = 0xffff;
|
||||
|
||||
for(uint i = 0; i < 128; i++) {
|
||||
uint s = (regs.first_sprite + i) & 127;
|
||||
if(on_scanline(s) == false) continue;
|
||||
if(itemcount++ >= 32) break;
|
||||
itemlist[itemcount - 1] = s;
|
||||
}
|
||||
|
||||
for(int i = 31; i >= 0; i--) {
|
||||
if(itemlist[i] == 0xff) continue;
|
||||
auto& s = list[itemlist[i]];
|
||||
uint tile_width = s.width >> 3;
|
||||
int x = s.x;
|
||||
int y = (self.vcounter() - s.y) & 0xff;
|
||||
if(regs.interlace) y <<= 1;
|
||||
|
||||
if(s.vflip) {
|
||||
if(s.width == s.height) {
|
||||
y = (s.height - 1) - y;
|
||||
} else {
|
||||
y = (y < s.width) ? ((s.width - 1) - y) : (s.width + ((s.width - 1) - (y - s.width)));
|
||||
}
|
||||
}
|
||||
|
||||
if(regs.interlace) {
|
||||
y = (s.vflip == false) ? (y + self.field()) : (y - self.field());
|
||||
}
|
||||
|
||||
x &= 511;
|
||||
y &= 255;
|
||||
|
||||
uint16 tdaddr = regs.tiledata_addr;
|
||||
uint16 chrx = (s.character >> 0) & 15;
|
||||
uint16 chry = (s.character >> 4) & 15;
|
||||
if(s.use_nameselect) {
|
||||
tdaddr += (256 * 32) + (regs.nameselect << 13);
|
||||
}
|
||||
chry += (y >> 3);
|
||||
chry &= 15;
|
||||
chry <<= 4;
|
||||
|
||||
for(uint tx = 0; tx < tile_width; tx++) {
|
||||
uint sx = (x + (tx << 3)) & 511;
|
||||
if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;
|
||||
if(tilecount++ >= 34) break;
|
||||
|
||||
uint n = tilecount - 1;
|
||||
tilelist[n].x = sx;
|
||||
tilelist[n].y = y;
|
||||
tilelist[n].priority = s.priority;
|
||||
tilelist[n].palette = 128 + (s.palette << 4);
|
||||
tilelist[n].hflip = s.hflip;
|
||||
|
||||
uint mx = (s.hflip == false) ? tx : ((tile_width - 1) - tx);
|
||||
uint pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5);
|
||||
tilelist[n].tile = (pos >> 5) & 0x07ff;
|
||||
}
|
||||
}
|
||||
|
||||
regs.time_over |= (tilecount > 34);
|
||||
regs.range_over |= (itemcount > 32);
|
||||
|
||||
if(regs.main_enable == false && regs.sub_enable == false) return;
|
||||
|
||||
for(uint i = 0; i < 34; i++) {
|
||||
if(tilelist[i].tile == 0xffff) continue;
|
||||
|
||||
auto& t = tilelist[i];
|
||||
uint8* tiledata = self.cache.tile_4bpp(t.tile);
|
||||
tiledata += (t.y & 7) << 3;
|
||||
uint sx = t.x;
|
||||
for(uint x = 0; x < 8; x++) {
|
||||
sx &= 511;
|
||||
if(sx < 256) {
|
||||
uint color = *(tiledata + (t.hflip == false ? x : 7 - x));
|
||||
if(color) {
|
||||
color += t.palette;
|
||||
output.palette[sx] = color;
|
||||
output.priority[sx] = t.priority;
|
||||
}
|
||||
}
|
||||
sx++;
|
||||
}
|
||||
}
|
||||
|
||||
if(regs.main_enable) window.render(0);
|
||||
if(regs.sub_enable) window.render(1);
|
||||
|
||||
uint priority0 = (priority0_enable ? regs.priority0 : 0);
|
||||
uint priority1 = (priority1_enable ? regs.priority1 : 0);
|
||||
uint priority2 = (priority2_enable ? regs.priority2 : 0);
|
||||
uint priority3 = (priority3_enable ? regs.priority3 : 0);
|
||||
if(priority0 + priority1 + priority2 + priority3 == 0) return;
|
||||
const uint priority_table[] = {priority0, priority1, priority2, priority3};
|
||||
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
if(output.priority[x] == 0xff) continue;
|
||||
uint priority = priority_table[output.priority[x]];
|
||||
uint palette = output.palette[x];
|
||||
uint color = self.screen.get_palette(output.palette[x]);
|
||||
if(regs.main_enable && !window.main[x]) self.screen.output.plot_main(x, color, priority, 4 + (palette < 192));
|
||||
if(regs.sub_enable && !window.sub[x]) self.screen.output.plot_sub(x, color, priority, 4 + (palette < 192));
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
class Sprite {
|
||||
Sprite(PPU& self);
|
||||
|
||||
auto frame() -> void;
|
||||
auto update_list(uint addr, uint8 data) -> void;
|
||||
auto address_reset() -> void;
|
||||
auto set_first() -> void;
|
||||
alwaysinline auto on_scanline(uint sprite) -> bool;
|
||||
auto render() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
PPU& self;
|
||||
|
||||
bool priority0_enable;
|
||||
bool priority1_enable;
|
||||
bool priority2_enable;
|
||||
bool priority3_enable;
|
||||
|
||||
struct Regs {
|
||||
uint priority0;
|
||||
uint priority1;
|
||||
uint priority2;
|
||||
uint priority3;
|
||||
|
||||
uint base_size;
|
||||
uint nameselect;
|
||||
uint tiledata_addr;
|
||||
uint first_sprite;
|
||||
|
||||
bool main_enable;
|
||||
bool sub_enable;
|
||||
|
||||
bool interlace;
|
||||
|
||||
bool time_over;
|
||||
bool range_over;
|
||||
} regs;
|
||||
|
||||
struct List {
|
||||
uint width;
|
||||
uint height;
|
||||
uint x;
|
||||
uint y;
|
||||
uint character;
|
||||
bool use_nameselect;
|
||||
bool vflip;
|
||||
bool hflip;
|
||||
uint palette;
|
||||
uint priority;
|
||||
bool size;
|
||||
} list[128];
|
||||
bool list_valid;
|
||||
|
||||
uint8 itemlist[32];
|
||||
struct TileList {
|
||||
uint x;
|
||||
uint y;
|
||||
uint priority;
|
||||
uint palette;
|
||||
uint tile;
|
||||
bool hflip;
|
||||
} tilelist[34];
|
||||
|
||||
struct Output {
|
||||
uint8 palette[256];
|
||||
uint8 priority[256];
|
||||
} output;
|
||||
|
||||
LayerWindow window;
|
||||
|
||||
friend class PPU;
|
||||
};
|
|
@ -1,94 +0,0 @@
|
|||
auto PPU::LayerWindow::render(bool screen) -> void {
|
||||
uint8* output;
|
||||
if(screen == 0) {
|
||||
output = main;
|
||||
if(main_enable == false) {
|
||||
memset(output, 0, 256);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
output = sub;
|
||||
if(sub_enable == false) {
|
||||
memset(output, 0, 256);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(one_enable == false && two_enable == false) {
|
||||
memset(output, 0, 256);
|
||||
return;
|
||||
}
|
||||
|
||||
if(one_enable == true && two_enable == false) {
|
||||
bool set = 1 ^ one_invert, clr = !set;
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
output[x] = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ? set : clr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(one_enable == false && two_enable == true) {
|
||||
bool set = 1 ^ two_invert, clr = !set;
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
output[x] = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ? set : clr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
bool one_mask = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ^ one_invert;
|
||||
bool two_mask = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ^ two_invert;
|
||||
switch(mask) {
|
||||
case 0: output[x] = one_mask | two_mask == 1; break;
|
||||
case 1: output[x] = one_mask & two_mask == 1; break;
|
||||
case 2: output[x] = one_mask ^ two_mask == 1; break;
|
||||
case 3: output[x] = one_mask ^ two_mask == 0; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto PPU::ColorWindow::render(bool screen) -> void {
|
||||
uint8* output = (screen == 0 ? main : sub);
|
||||
bool set = 1, clr = 0;
|
||||
|
||||
switch(screen == 0 ? main_mask : sub_mask) {
|
||||
case 0: memset(output, 1, 256); return; //always
|
||||
case 1: set = 1, clr = 0; break; //inside window only
|
||||
case 2: set = 0, clr = 1; break; //outside window only
|
||||
case 3: memset(output, 0, 256); return; //never
|
||||
}
|
||||
|
||||
if(one_enable == false && two_enable == false) {
|
||||
memset(output, clr, 256);
|
||||
return;
|
||||
}
|
||||
|
||||
if(one_enable == true && two_enable == false) {
|
||||
if(one_invert) { set ^= 1; clr ^= 1; }
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
output[x] = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ? set : clr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(one_enable == false && two_enable == true) {
|
||||
if(two_invert) { set ^= 1; clr ^= 1; }
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
output[x] = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ? set : clr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
bool one_mask = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ^ one_invert;
|
||||
bool two_mask = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ^ two_invert;
|
||||
switch(mask) {
|
||||
case 0: output[x] = one_mask | two_mask == 1 ? set : clr; break;
|
||||
case 1: output[x] = one_mask & two_mask == 1 ? set : clr; break;
|
||||
case 2: output[x] = one_mask ^ two_mask == 1 ? set : clr; break;
|
||||
case 3: output[x] = one_mask ^ two_mask == 0 ? set : clr; break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
struct LayerWindow {
|
||||
auto render(bool screen) -> void;
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool one_enable;
|
||||
bool one_invert;
|
||||
bool two_enable;
|
||||
bool two_invert;
|
||||
|
||||
uint mask;
|
||||
|
||||
bool main_enable;
|
||||
bool sub_enable;
|
||||
|
||||
uint8 main[256];
|
||||
uint8 sub[256];
|
||||
};
|
||||
|
||||
struct ColorWindow {
|
||||
auto render(bool screen) -> void;
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool one_enable;
|
||||
bool one_invert;
|
||||
bool two_enable;
|
||||
bool two_invert;
|
||||
|
||||
uint mask;
|
||||
|
||||
uint main_mask;
|
||||
uint sub_mask;
|
||||
|
||||
uint8 main[256];
|
||||
uint8 sub[256];
|
||||
};
|
|
@ -1,122 +0,0 @@
|
|||
auto SMP::op_adc(uint8 x, uint8 y) -> uint8 {
|
||||
int r = x + y + regs.p.c;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.v = ~(x ^ y) & (x ^ r) & 0x80;
|
||||
regs.p.h = (x ^ y ^ r) & 0x10;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r > 0xff;
|
||||
return r;
|
||||
}
|
||||
|
||||
auto SMP::op_addw(uint16 x, uint16 y) -> uint16 {
|
||||
uint16 r;
|
||||
regs.p.c = 0;
|
||||
r = op_adc(x, y);
|
||||
r |= op_adc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = r == 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
auto SMP::op_and(uint8 x, uint8 y) -> uint8 {
|
||||
x &= y;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto SMP::op_cmp(uint8 x, uint8 y) -> uint8 {
|
||||
int r = x - y;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto SMP::op_cmpw(uint16 x, uint16 y) -> uint16 {
|
||||
int r = x - y;
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto SMP::op_eor(uint8 x, uint8 y) -> uint8 {
|
||||
x ^= y;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto SMP::op_or(uint8 x, uint8 y) -> uint8 {
|
||||
x |= y;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto SMP::op_sbc(uint8 x, uint8 y) -> uint8 {
|
||||
int r = x - y - !regs.p.c;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.v = (x ^ y) & (x ^ r) & 0x80;
|
||||
regs.p.h = !((x ^ y ^ r) & 0x10);
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
auto SMP::op_subw(uint16 x, uint16 y) -> uint16 {
|
||||
uint16 r;
|
||||
regs.p.c = 1;
|
||||
r = op_sbc(x, y);
|
||||
r |= op_sbc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = r == 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
auto SMP::op_inc(uint8 x) -> uint8 {
|
||||
x++;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto SMP::op_dec(uint8 x) -> uint8 {
|
||||
x--;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto SMP::op_asl(uint8 x) -> uint8 {
|
||||
regs.p.c = x & 0x80;
|
||||
x <<= 1;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto SMP::op_lsr(uint8 x) -> uint8 {
|
||||
regs.p.c = x & 0x01;
|
||||
x >>= 1;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto SMP::op_rol(uint8 x) -> uint8 {
|
||||
auto carry = (uint)regs.p.c;
|
||||
regs.p.c = x & 0x80;
|
||||
x = (x << 1) | carry;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto SMP::op_ror(uint8 x) -> uint8 {
|
||||
auto carry = (uint)regs.p.c << 7;
|
||||
regs.p.c = x & 0x01;
|
||||
x = carry | (x >> 1);
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
auto SMP::tick() -> void {
|
||||
timer0.tick();
|
||||
timer1.tick();
|
||||
timer2.tick();
|
||||
|
||||
clock += cycle_step_cpu;
|
||||
dsp.clock -= 24;
|
||||
synchronizeDSP();
|
||||
}
|
||||
|
||||
auto SMP::op_io() -> void {
|
||||
#if defined(CYCLE_ACCURATE)
|
||||
tick();
|
||||
#endif
|
||||
}
|
||||
|
||||
auto SMP::op_read(uint16 addr) -> uint8 {
|
||||
#if defined(CYCLE_ACCURATE)
|
||||
tick();
|
||||
#endif
|
||||
if((addr & 0xfff0) == 0x00f0) return mmio_read(addr);
|
||||
if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f];
|
||||
return apuram[addr];
|
||||
}
|
||||
|
||||
auto SMP::op_write(uint16 addr, uint8 data) -> void {
|
||||
#if defined(CYCLE_ACCURATE)
|
||||
tick();
|
||||
#endif
|
||||
if((addr & 0xfff0) == 0x00f0) mmio_write(addr, data);
|
||||
apuram[addr] = data; //all writes go to RAM, even MMIO writes
|
||||
}
|
||||
|
||||
auto SMP::op_step() -> void {
|
||||
#define op_readpc() op_read(regs.pc++)
|
||||
#define op_readdp(addr) op_read((regs.p.p << 8) + addr)
|
||||
#define op_writedp(addr, data) op_write((regs.p.p << 8) + addr, data)
|
||||
#define op_readaddr(addr) op_read(addr)
|
||||
#define op_writeaddr(addr, data) op_write(addr, data)
|
||||
#define op_readstack() op_read(0x0100 | ++regs.sp)
|
||||
#define op_writestack(data) op_write(0x0100 | regs.sp--, data)
|
||||
|
||||
#if defined(CYCLE_ACCURATE)
|
||||
|
||||
if(opcode_cycle == 0) {
|
||||
opcode_number = op_readpc();
|
||||
opcode_cycle++;
|
||||
} else switch(opcode_number) {
|
||||
#include "core/opcycle_misc.cpp"
|
||||
#include "core/opcycle_mov.cpp"
|
||||
#include "core/opcycle_pc.cpp"
|
||||
#include "core/opcycle_read.cpp"
|
||||
#include "core/opcycle_rmw.cpp"
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
uint opcode = op_readpc();
|
||||
switch(opcode) {
|
||||
#include "core/op_misc.cpp"
|
||||
#include "core/op_mov.cpp"
|
||||
#include "core/op_pc.cpp"
|
||||
#include "core/op_read.cpp"
|
||||
#include "core/op_rmw.cpp"
|
||||
}
|
||||
|
||||
//TODO: untaken branches should consume less cycles
|
||||
|
||||
timer0.tick(cycle_count_table[opcode]);
|
||||
timer1.tick(cycle_count_table[opcode]);
|
||||
timer2.tick(cycle_count_table[opcode]);
|
||||
|
||||
clock += cycle_table_cpu[opcode];
|
||||
dsp.clock -= cycle_table_dsp[opcode];
|
||||
synchronize_dsp();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
const uint SMP::cycle_count_table[256] = {
|
||||
#define c 12
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,6,8, //0
|
||||
4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,4,6, //1
|
||||
2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,7,4, //2
|
||||
4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,3,8, //3
|
||||
|
||||
2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,6,6, //4
|
||||
4,8,4,7, 4,5,5,6, 5,5,4,5, 2,2,4,3, //5
|
||||
2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,7,5, //6
|
||||
4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,6, //7
|
||||
|
||||
2,8,4,7, 3,4,3,6, 2,6,5,4, 5,2,4,5, //8
|
||||
4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,c,5, //9
|
||||
3,8,4,7, 3,4,3,6, 2,6,4,4, 5,2,4,4, //A
|
||||
4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,4, //B
|
||||
|
||||
3,8,4,7, 4,5,4,7, 2,5,6,4, 5,2,4,9, //C
|
||||
4,8,4,7, 5,6,6,7, 4,5,5,5, 2,2,8,3, //D
|
||||
2,8,4,7, 3,4,3,6, 2,4,5,3, 4,3,4,1, //E
|
||||
4,8,4,7, 4,5,5,6, 3,4,5,4, 2,2,6,1, //F
|
||||
|
||||
#undef c
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
g++-4.5 -std=gnu++0x -I../../../.. -o generate generate.cpp
|
|
@ -1,154 +0,0 @@
|
|||
#include <nall/file.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
using namespace nall;
|
||||
|
||||
static bool cycle_accurate;
|
||||
|
||||
struct opcode_t {
|
||||
string name;
|
||||
lstring args;
|
||||
uint opcode;
|
||||
};
|
||||
|
||||
auto generate(const char* sourceFilename, const char* targetFilename) -> void {
|
||||
file fp;
|
||||
fp.open(targetFilename, file::mode::write);
|
||||
|
||||
string filedata;
|
||||
filedata.readfile(sourceFilename);
|
||||
filedata.replace("\r", "");
|
||||
|
||||
lstring block;
|
||||
block.split("\n\n", filedata);
|
||||
|
||||
foreach(data, block) {
|
||||
lstring lines;
|
||||
lines.split("\n", data);
|
||||
|
||||
linear_vector<opcode_t> array;
|
||||
|
||||
uint sourceStart = 0;
|
||||
foreach(line, lines, currentLine) {
|
||||
line.transform("()", "``");
|
||||
lstring part;
|
||||
part.split("`", line);
|
||||
lstring arguments;
|
||||
arguments.split(", ", part[1]);
|
||||
|
||||
opcode_t opcode;
|
||||
opcode.name = part[0];
|
||||
opcode.args = arguments;
|
||||
opcode.opcode = hex(arguments[0]);
|
||||
array.append(opcode);
|
||||
|
||||
line.rtrim(",", 1L);
|
||||
if(line.endswith(" {")) {
|
||||
line.rtrim("{ ", 1L);
|
||||
sourceStart = currentLine + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(cycle_accurate == false) {
|
||||
foreach(opcode, array) {
|
||||
fp.print("case 0x", hex(opcode.opcode, 2L), ": {\n");
|
||||
|
||||
for(uint n = sourceStart; n < lines.size(); n++) {
|
||||
if(lines[n] == "}") break;
|
||||
|
||||
string output;
|
||||
|
||||
if(lines[n].beginswith(" ")) {
|
||||
output = lines[n];
|
||||
} else {
|
||||
lstring part;
|
||||
part.split<1>(":", lines[n]);
|
||||
output = { " ", part[1] };
|
||||
}
|
||||
|
||||
output.replace("$1", opcode.args[1]);
|
||||
output.replace("$2", opcode.args[2]);
|
||||
output.replace("$3", opcode.args[3]);
|
||||
output.replace("$4", opcode.args[4]);
|
||||
output.replace("$5", opcode.args[5]);
|
||||
output.replace("$6", opcode.args[6]);
|
||||
output.replace("$7", opcode.args[7]);
|
||||
output.replace("$8", opcode.args[8]);
|
||||
output.replace("end;", "break;");
|
||||
|
||||
fp.print(output, "\n");
|
||||
}
|
||||
|
||||
fp.print(" break;\n");
|
||||
fp.print("}\n\n");
|
||||
}
|
||||
} else {
|
||||
foreach(opcode, array) {
|
||||
fp.print("case 0x", hex(opcode.opcode, 2L), ": {\n");
|
||||
fp.print(" switch(opcode_cycle++) {\n");
|
||||
|
||||
for(uint n = sourceStart; n < lines.size(); n++) {
|
||||
if(lines[n] == "}") break;
|
||||
|
||||
bool nextLineEndsCycle = false;
|
||||
if(lines[n + 1] == "}") nextLineEndsCycle = true;
|
||||
if(lines[n + 1].beginswith(" ") == false) nextLineEndsCycle = true;
|
||||
|
||||
string output;
|
||||
|
||||
if(lines[n].beginswith(" ")) {
|
||||
output = { " ", lines[n] };
|
||||
} else {
|
||||
lstring part;
|
||||
part.split(":", lines[n], 1L);
|
||||
fp.print(" case ", (unsigned)decimal(part[0]), ":\n");
|
||||
output = { " ", part[1] };
|
||||
}
|
||||
|
||||
output.replace("$1", opcode.args[1]);
|
||||
output.replace("$2", opcode.args[2]);
|
||||
output.replace("$3", opcode.args[3]);
|
||||
output.replace("$4", opcode.args[4]);
|
||||
output.replace("$5", opcode.args[5]);
|
||||
output.replace("$6", opcode.args[6]);
|
||||
output.replace("$7", opcode.args[7]);
|
||||
output.replace("$8", opcode.args[8]);
|
||||
output.replace("end;", "{ opcode_cycle = 0; break; }");
|
||||
|
||||
fp.print(output, "\n");
|
||||
if(nextLineEndsCycle) {
|
||||
if(lines[n + 1].beginswith("}")) {
|
||||
fp.print(" opcode_cycle = 0;\n");
|
||||
}
|
||||
fp.print(" break;\n");
|
||||
}
|
||||
}
|
||||
|
||||
fp.print(" }\n");
|
||||
fp.print(" break;\n");
|
||||
fp.print("}\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fp.close();
|
||||
}
|
||||
|
||||
auto main() -> int {
|
||||
cycle_accurate = false;
|
||||
generate("op_misc.b", "op_misc.cpp");
|
||||
generate("op_mov.b", "op_mov.cpp" );
|
||||
generate("op_pc.b", "op_pc.cpp" );
|
||||
generate("op_read.b", "op_read.cpp");
|
||||
generate("op_rmw.b", "op_rmw.cpp" );
|
||||
|
||||
cycle_accurate = true;
|
||||
generate("op_misc.b", "opcycle_misc.cpp");
|
||||
generate("op_mov.b", "opcycle_mov.cpp" );
|
||||
generate("op_pc.b", "opcycle_pc.cpp" );
|
||||
generate("op_read.b", "opcycle_read.cpp");
|
||||
generate("op_rmw.b", "opcycle_rmw.cpp" );
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
nop(0x00) {
|
||||
1:op_io();
|
||||
}
|
||||
|
||||
sleep(0xef),
|
||||
stop(0xff) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
regs.pc--;
|
||||
}
|
||||
|
||||
xcn(0x9f) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
regs.a = (regs.a >> 4) | (regs.a << 4);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
daa(0xdf) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
if(regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a += 0x60;
|
||||
regs.p.c = 1;
|
||||
}
|
||||
if(regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a += 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
das(0xbe) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
if(!regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a -= 0x60;
|
||||
regs.p.c = 0;
|
||||
}
|
||||
if(!regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a -= 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
clrc(0x60, regs.p.c = 0),
|
||||
clrp(0x20, regs.p.p = 0),
|
||||
setc(0x80, regs.p.c = 1),
|
||||
setp(0x40, regs.p.p = 1) {
|
||||
1:op_io();
|
||||
$1;
|
||||
}
|
||||
|
||||
clrv(0xe0) {
|
||||
1:op_io();
|
||||
regs.p.v = 0;
|
||||
regs.p.h = 0;
|
||||
}
|
||||
|
||||
notc(0xed) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
regs.p.c = !regs.p.c;
|
||||
}
|
||||
|
||||
ei(0xa0, 1),
|
||||
di(0xc0, 0) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
regs.p.i = $1;
|
||||
}
|
||||
|
||||
set0_dp(0x02, rd |= 0x01),
|
||||
clr0_dp(0x12, rd &= ~0x01),
|
||||
set1_dp(0x22, rd |= 0x02),
|
||||
clr1_dp(0x32, rd &= ~0x02),
|
||||
set2_dp(0x42, rd |= 0x04),
|
||||
clr2_dp(0x52, rd &= ~0x04),
|
||||
set3_dp(0x62, rd |= 0x08),
|
||||
clr3_dp(0x72, rd &= ~0x08),
|
||||
set4_dp(0x82, rd |= 0x10),
|
||||
clr4_dp(0x92, rd &= ~0x10),
|
||||
set5_dp(0xa2, rd |= 0x20),
|
||||
clr5_dp(0xb2, rd &= ~0x20),
|
||||
set6_dp(0xc2, rd |= 0x40),
|
||||
clr6_dp(0xd2, rd &= ~0x40),
|
||||
set7_dp(0xe2, rd |= 0x80),
|
||||
clr7_dp(0xf2, rd &= ~0x80) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
3:$1;
|
||||
op_writedp(dp, rd);
|
||||
}
|
||||
|
||||
push_a(0x2d, a),
|
||||
push_x(0x4d, x),
|
||||
push_y(0x6d, y),
|
||||
push_p(0x0d, p) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:op_writestack(regs.$1);
|
||||
}
|
||||
|
||||
pop_a(0xae, a),
|
||||
pop_x(0xce, x),
|
||||
pop_y(0xee, y),
|
||||
pop_p(0x8e, p) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:regs.$1 = op_readstack();
|
||||
}
|
||||
|
||||
mul_ya(0xcf) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
6:op_io();
|
||||
7:op_io();
|
||||
8:op_io();
|
||||
ya = regs.y * regs.a;
|
||||
regs.a = ya;
|
||||
regs.y = ya >> 8;
|
||||
//result is set based on y (high-byte) only
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
}
|
||||
|
||||
div_ya_x(0x9e) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
6:op_io();
|
||||
7:op_io();
|
||||
8:op_io();
|
||||
9:op_io();
|
||||
10:op_io();
|
||||
11:op_io();
|
||||
ya = regs.ya;
|
||||
//overflow set if quotient >= 256
|
||||
regs.p.v = !!(regs.y >= regs.x);
|
||||
regs.p.h = !!((regs.y & 15) >= (regs.x & 15));
|
||||
if(regs.y < (regs.x << 1)) {
|
||||
//if quotient is <= 511 (will fit into 9-bit result)
|
||||
regs.a = ya / regs.x;
|
||||
regs.y = ya % regs.x;
|
||||
} else {
|
||||
//otherwise, the quotient won't fit into regs.p.v + regs.a
|
||||
//this emulates the odd behavior of the S-SMP in this case
|
||||
regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x);
|
||||
regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x);
|
||||
}
|
||||
//result is set based on a (quotient) only
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
|
@ -1,346 +0,0 @@
|
|||
case 0x00: {
|
||||
op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xef: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc--;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xff: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc--;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9f: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
regs.a = (regs.a >> 4) | (regs.a << 4);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xdf: {
|
||||
op_io();
|
||||
op_io();
|
||||
if(regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a += 0x60;
|
||||
regs.p.c = 1;
|
||||
}
|
||||
if(regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a += 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xbe: {
|
||||
op_io();
|
||||
op_io();
|
||||
if(!regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a -= 0x60;
|
||||
regs.p.c = 0;
|
||||
}
|
||||
if(!regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a -= 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x60: {
|
||||
op_io();
|
||||
regs.p.c = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x20: {
|
||||
op_io();
|
||||
regs.p.p = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x80: {
|
||||
op_io();
|
||||
regs.p.c = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x40: {
|
||||
op_io();
|
||||
regs.p.p = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe0: {
|
||||
op_io();
|
||||
regs.p.v = 0;
|
||||
regs.p.h = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xed: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p.c = !regs.p.c;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa0: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p.i = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc0: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p.i = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x02: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x01;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x12: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x01;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x22: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x02;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x32: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x02;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x42: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x04;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x52: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x04;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x62: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x08;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x72: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x08;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x82: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x10;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x92: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x10;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x20;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x20;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x40;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x40;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x80;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x80;
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2d: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4d: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.x);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x6d: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0d: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.p);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xae: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.a = op_readstack();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xce: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.x = op_readstack();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xee: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.y = op_readstack();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8e: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p = op_readstack();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xcf: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
ya = regs.y * regs.a;
|
||||
regs.a = ya;
|
||||
regs.y = ya >> 8;
|
||||
//result is set based on y (high-byte) only
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9e: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
ya = regs.ya;
|
||||
//overflow set if quotient >= 256
|
||||
regs.p.v = !!(regs.y >= regs.x);
|
||||
regs.p.h = !!((regs.y & 15) >= (regs.x & 15));
|
||||
if(regs.y < (regs.x << 1)) {
|
||||
//if quotient is <= 511 (will fit into 9-bit result)
|
||||
regs.a = ya / regs.x;
|
||||
regs.y = ya % regs.x;
|
||||
} else {
|
||||
//otherwise, the quotient won't fit into regs.p.v + regs.a
|
||||
//this emulates the odd behavior of the S-SMP in this case
|
||||
regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x);
|
||||
regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x);
|
||||
}
|
||||
//result is set based on a (quotient) only
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1,217 +0,0 @@
|
|||
mov_a_x(0x7d, a, x),
|
||||
mov_a_y(0xdd, a, y),
|
||||
mov_x_a(0x5d, x, a),
|
||||
mov_y_a(0xfd, y, a),
|
||||
mov_x_sp(0x9d, x, sp) {
|
||||
1:op_io();
|
||||
regs.$1 = regs.$2;
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_sp_x(0xbd, sp, x) {
|
||||
1:op_io();
|
||||
regs.$1 = regs.$2;
|
||||
}
|
||||
|
||||
mov_a_const(0xe8, a),
|
||||
mov_x_const(0xcd, x),
|
||||
mov_y_const(0x8d, y) {
|
||||
1:regs.$1 = op_readpc();
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_ix(0xe6) {
|
||||
1:op_io();
|
||||
2:regs.a = op_readdp(regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_ixinc(0xbf) {
|
||||
1:op_io();
|
||||
2:regs.a = op_readdp(regs.x++);
|
||||
3:op_io();
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_dp(0xe4, a),
|
||||
mov_x_dp(0xf8, x),
|
||||
mov_y_dp(0xeb, y) {
|
||||
1:sp = op_readpc();
|
||||
2:regs.$1 = op_readdp(sp);
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_dpx(0xf4, a, x),
|
||||
mov_x_dpy(0xf9, x, y),
|
||||
mov_y_dpx(0xfb, y, x) {
|
||||
1:sp = op_readpc();
|
||||
2:op_io();
|
||||
3:regs.$1 = op_readdp(sp + regs.$2);
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_addr(0xe5, a),
|
||||
mov_x_addr(0xe9, x),
|
||||
mov_y_addr(0xec, y) {
|
||||
1:sp = op_readpc();
|
||||
2:sp |= op_readpc() << 8;
|
||||
3:regs.$1 = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_addrx(0xf5, x),
|
||||
mov_a_addry(0xf6, y) {
|
||||
1:sp = op_readpc();
|
||||
2:sp |= op_readpc() << 8;
|
||||
3:op_io();
|
||||
4:regs.a = op_readaddr(sp + regs.$1);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_idpx(0xe7) {
|
||||
1:dp = op_readpc() + regs.x;
|
||||
2:op_io();
|
||||
3:sp = op_readdp(dp);
|
||||
4:sp |= op_readdp(dp + 1) << 8;
|
||||
5:regs.a = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_idpy(0xf7) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:sp = op_readdp(dp);
|
||||
4:sp |= op_readdp(dp + 1) << 8;
|
||||
5:regs.a = op_readaddr(sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_dp_dp(0xfa) {
|
||||
1:sp = op_readpc();
|
||||
2:rd = op_readdp(sp);
|
||||
3:dp = op_readpc();
|
||||
4:op_writedp(dp, rd);
|
||||
}
|
||||
|
||||
mov_dp_const(0x8f) {
|
||||
1:rd = op_readpc();
|
||||
2:dp = op_readpc();
|
||||
3:op_readdp(dp);
|
||||
4:op_writedp(dp, rd);
|
||||
}
|
||||
|
||||
mov_ix_a(0xc6) {
|
||||
1:op_io();
|
||||
2:op_readdp(regs.x);
|
||||
3:op_writedp(regs.x, regs.a);
|
||||
}
|
||||
|
||||
mov_ixinc_a(0xaf) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:op_writedp(regs.x++, regs.a);
|
||||
}
|
||||
|
||||
mov_dp_a(0xc4, a),
|
||||
mov_dp_x(0xd8, x),
|
||||
mov_dp_y(0xcb, y) {
|
||||
1:dp = op_readpc();
|
||||
2:op_readdp(dp);
|
||||
3:op_writedp(dp, regs.$1);
|
||||
}
|
||||
|
||||
mov_dpx_a(0xd4, x, a),
|
||||
mov_dpy_x(0xd9, y, x),
|
||||
mov_dpx_y(0xdb, x, y) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
dp += regs.$1;
|
||||
3:op_readdp(dp);
|
||||
4:op_writedp(dp, regs.$2);
|
||||
}
|
||||
|
||||
mov_addr_a(0xc5, a),
|
||||
mov_addr_x(0xc9, x),
|
||||
mov_addr_y(0xcc, y) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:op_readaddr(dp);
|
||||
4:op_writeaddr(dp, regs.$1);
|
||||
}
|
||||
|
||||
mov_addrx_a(0xd5, x),
|
||||
mov_addry_a(0xd6, y) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:op_io();
|
||||
dp += regs.$1;
|
||||
4:op_readaddr(dp);
|
||||
5:op_writeaddr(dp, regs.a);
|
||||
}
|
||||
|
||||
mov_idpx_a(0xc7) {
|
||||
1:sp = op_readpc();
|
||||
2:op_io();
|
||||
sp += regs.x;
|
||||
3:dp = op_readdp(sp);
|
||||
4:dp |= op_readdp(sp + 1) << 8;
|
||||
5:op_readaddr(dp);
|
||||
6:op_writeaddr(dp, regs.a);
|
||||
}
|
||||
|
||||
mov_idpy_a(0xd7) {
|
||||
1:sp = op_readpc();
|
||||
2:dp = op_readdp(sp);
|
||||
3:dp |= op_readdp(sp + 1) << 8;
|
||||
4:op_io();
|
||||
dp += regs.y;
|
||||
5:op_readaddr(dp);
|
||||
6:op_writeaddr(dp, regs.a);
|
||||
}
|
||||
|
||||
movw_ya_dp(0xba) {
|
||||
1:sp = op_readpc();
|
||||
2:regs.a = op_readdp(sp);
|
||||
3:op_io();
|
||||
4:regs.y = op_readdp(sp + 1);
|
||||
regs.p.n = !!(regs.ya & 0x8000);
|
||||
regs.p.z = (regs.ya == 0);
|
||||
}
|
||||
|
||||
movw_dp_ya(0xda) {
|
||||
1:dp = op_readpc();
|
||||
2:op_readdp(dp);
|
||||
3:op_writedp(dp, regs.a);
|
||||
4:op_writedp(dp + 1, regs.y);
|
||||
}
|
||||
|
||||
mov1_c_bit(0xaa) {
|
||||
1:sp = op_readpc();
|
||||
2:sp |= op_readpc() << 8;
|
||||
3:bit = sp >> 13;
|
||||
sp &= 0x1fff;
|
||||
rd = op_readaddr(sp);
|
||||
regs.p.c = !!(rd & (1 << bit));
|
||||
}
|
||||
|
||||
mov1_bit_c(0xca) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
if(regs.p.c)rd |= (1 << bit);
|
||||
else rd &= ~(1 << bit);
|
||||
4:op_io();
|
||||
5:op_writeaddr(dp, rd);
|
||||
}
|
|
@ -1,389 +0,0 @@
|
|||
case 0x7d: {
|
||||
op_io();
|
||||
regs.a = regs.x;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xdd: {
|
||||
op_io();
|
||||
regs.a = regs.y;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x5d: {
|
||||
op_io();
|
||||
regs.x = regs.a;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xfd: {
|
||||
op_io();
|
||||
regs.y = regs.a;
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9d: {
|
||||
op_io();
|
||||
regs.x = regs.sp;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xbd: {
|
||||
op_io();
|
||||
regs.sp = regs.x;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe8: {
|
||||
regs.a = op_readpc();
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xcd: {
|
||||
regs.x = op_readpc();
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8d: {
|
||||
regs.y = op_readpc();
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe6: {
|
||||
op_io();
|
||||
regs.a = op_readdp(regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xbf: {
|
||||
op_io();
|
||||
regs.a = op_readdp(regs.x++);
|
||||
op_io();
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe4: {
|
||||
sp = op_readpc();
|
||||
regs.a = op_readdp(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf8: {
|
||||
sp = op_readpc();
|
||||
regs.x = op_readdp(sp);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xeb: {
|
||||
sp = op_readpc();
|
||||
regs.y = op_readdp(sp);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf4: {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
regs.a = op_readdp(sp + regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf9: {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
regs.x = op_readdp(sp + regs.y);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xfb: {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
regs.y = op_readdp(sp + regs.x);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe5: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
regs.a = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe9: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
regs.x = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xec: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
regs.y = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf5: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
op_io();
|
||||
regs.a = op_readaddr(sp + regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf6: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
op_io();
|
||||
regs.a = op_readaddr(sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe7: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
regs.a = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf7: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
regs.a = op_readaddr(sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xfa: {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8f: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc6: {
|
||||
op_io();
|
||||
op_readdp(regs.x);
|
||||
op_writedp(regs.x, regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xaf: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writedp(regs.x++, regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc4: {
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd8: {
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.x);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xcb: {
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd4: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
dp += regs.x;
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd9: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
dp += regs.y;
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.x);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xdb: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
dp += regs.x;
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc5: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc9: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.x);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xcc: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd5: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
dp += regs.x;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd6: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
dp += regs.y;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc7: {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
sp += regs.x;
|
||||
dp = op_readdp(sp);
|
||||
dp |= op_readdp(sp + 1) << 8;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd7: {
|
||||
sp = op_readpc();
|
||||
dp = op_readdp(sp);
|
||||
dp |= op_readdp(sp + 1) << 8;
|
||||
op_io();
|
||||
dp += regs.y;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xba: {
|
||||
sp = op_readpc();
|
||||
regs.a = op_readdp(sp);
|
||||
op_io();
|
||||
regs.y = op_readdp(sp + 1);
|
||||
regs.p.n = !!(regs.ya & 0x8000);
|
||||
regs.p.z = (regs.ya == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xda: {
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.a);
|
||||
op_writedp(dp + 1, regs.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xaa: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
bit = sp >> 13;
|
||||
sp &= 0x1fff;
|
||||
rd = op_readaddr(sp);
|
||||
regs.p.c = !!(rd & (1 << bit));
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xca: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
if(regs.p.c)rd |= (1 << bit);
|
||||
else rd &= ~(1 << bit);
|
||||
op_io();
|
||||
op_writeaddr(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
bra(0x2f, 0),
|
||||
beq(0xf0, !regs.p.z),
|
||||
bne(0xd0, regs.p.z),
|
||||
bcs(0xb0, !regs.p.c),
|
||||
bcc(0x90, regs.p.c),
|
||||
bvs(0x70, !regs.p.v),
|
||||
bvc(0x50, regs.p.v),
|
||||
bmi(0x30, !regs.p.n),
|
||||
bpl(0x10, regs.p.n) {
|
||||
1:rd = op_readpc();
|
||||
if($1)end;
|
||||
2:op_io();
|
||||
3:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
bbs0(0x03, 0x01, !=),
|
||||
bbc0(0x13, 0x01, ==),
|
||||
bbs1(0x23, 0x02, !=),
|
||||
bbc1(0x33, 0x02, ==),
|
||||
bbs2(0x43, 0x04, !=),
|
||||
bbc2(0x53, 0x04, ==),
|
||||
bbs3(0x63, 0x08, !=),
|
||||
bbc3(0x73, 0x08, ==),
|
||||
bbs4(0x83, 0x10, !=),
|
||||
bbc4(0x93, 0x10, ==),
|
||||
bbs5(0xa3, 0x20, !=),
|
||||
bbc5(0xb3, 0x20, ==),
|
||||
bbs6(0xc3, 0x40, !=),
|
||||
bbc6(0xd3, 0x40, ==),
|
||||
bbs7(0xe3, 0x80, !=),
|
||||
bbc7(0xf3, 0x80, ==) {
|
||||
1:dp = op_readpc();
|
||||
2:sp = op_readdp(dp);
|
||||
3:rd = op_readpc();
|
||||
4:op_io();
|
||||
if((sp & $1) $2 $1)end;
|
||||
5:op_io();
|
||||
6:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dp(0x2e) {
|
||||
1:dp = op_readpc();
|
||||
2:sp = op_readdp(dp);
|
||||
3:rd = op_readpc();
|
||||
4:op_io();
|
||||
if(regs.a == sp)end;
|
||||
5:op_io();
|
||||
6:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dpx(0xde) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:sp = op_readdp(dp + regs.x);
|
||||
4:rd = op_readpc();
|
||||
5:op_io();
|
||||
if(regs.a == sp)end;
|
||||
6:op_io();
|
||||
7:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
dbnz_dp(0x6e) {
|
||||
1:dp = op_readpc();
|
||||
2:wr = op_readdp(dp);
|
||||
3:op_writedp(dp, --wr);
|
||||
4:rd = op_readpc();
|
||||
if(wr == 0x00)end;
|
||||
5:op_io();
|
||||
6:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
dbnz_y(0xfe) {
|
||||
1:rd = op_readpc();
|
||||
2:op_io();
|
||||
regs.y--;
|
||||
3:op_io();
|
||||
if(regs.y == 0x00)end;
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
jmp_addr(0x5f) {
|
||||
1:rd = op_readpc();
|
||||
2:rd |= op_readpc() << 8;
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
jmp_iaddrx(0x1f) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:op_io();
|
||||
dp += regs.x;
|
||||
4:rd = op_readaddr(dp);
|
||||
5:rd |= op_readaddr(dp + 1) << 8;
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
call(0x3f) {
|
||||
1:rd = op_readpc();
|
||||
2:rd |= op_readpc() << 8;
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
6:op_writestack(regs.pc >> 8);
|
||||
7:op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
pcall(0x4f) {
|
||||
1:rd = op_readpc();
|
||||
2:op_io();
|
||||
3:op_io();
|
||||
4:op_writestack(regs.pc >> 8);
|
||||
5:op_writestack(regs.pc);
|
||||
regs.pc = 0xff00 | rd;
|
||||
}
|
||||
|
||||
tcall_0(0x01, 0),
|
||||
tcall_1(0x11, 1),
|
||||
tcall_2(0x21, 2),
|
||||
tcall_3(0x31, 3),
|
||||
tcall_4(0x41, 4),
|
||||
tcall_5(0x51, 5),
|
||||
tcall_6(0x61, 6),
|
||||
tcall_7(0x71, 7),
|
||||
tcall_8(0x81, 8),
|
||||
tcall_9(0x91, 9),
|
||||
tcall_10(0xa1, 10),
|
||||
tcall_11(0xb1, 11),
|
||||
tcall_12(0xc1, 12),
|
||||
tcall_13(0xd1, 13),
|
||||
tcall_14(0xe1, 14),
|
||||
tcall_15(0xf1, 15) {
|
||||
1:dp = 0xffde - ($1 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
2:rd |= op_readaddr(dp + 1) << 8;
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
6:op_writestack(regs.pc >> 8);
|
||||
7:op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
brk(0x0f) {
|
||||
1:rd = op_readaddr(0xffde);
|
||||
2:rd |= op_readaddr(0xffdf) << 8;
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
5:op_writestack(regs.pc >> 8);
|
||||
6:op_writestack(regs.pc);
|
||||
7:op_writestack(regs.p);
|
||||
regs.pc = rd;
|
||||
regs.p.b = 1;
|
||||
regs.p.i = 0;
|
||||
}
|
||||
|
||||
ret(0x6f) {
|
||||
1:rd = op_readstack();
|
||||
2:rd |= op_readstack() << 8;
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
reti(0x7f) {
|
||||
1:regs.p = op_readstack();
|
||||
2:rd = op_readstack();
|
||||
3:rd |= op_readstack() << 8;
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
regs.pc = rd;
|
||||
}
|
|
@ -1,603 +0,0 @@
|
|||
case 0x2f: {
|
||||
rd = op_readpc();
|
||||
if(0)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf0: {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.z)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd0: {
|
||||
rd = op_readpc();
|
||||
if(regs.p.z)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb0: {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.c)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x90: {
|
||||
rd = op_readpc();
|
||||
if(regs.p.c)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x70: {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.v)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x50: {
|
||||
rd = op_readpc();
|
||||
if(regs.p.v)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x30: {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.n)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x10: {
|
||||
rd = op_readpc();
|
||||
if(regs.p.n)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x03: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x01) != 0x01)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x13: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x01) == 0x01)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x23: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x02) != 0x02)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x33: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x02) == 0x02)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x43: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x04) != 0x04)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x53: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x04) == 0x04)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x63: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x08) != 0x08)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x73: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x08) == 0x08)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x83: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x10) != 0x10)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x93: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x10) == 0x10)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa3: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x20) != 0x20)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb3: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x20) == 0x20)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc3: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x40) != 0x40)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd3: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x40) == 0x40)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe3: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x80) != 0x80)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf3: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x80) == 0x80)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2e: {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if(regs.a == sp)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xde: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp + regs.x);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if(regs.a == sp)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x6e: {
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
op_writedp(dp, --wr);
|
||||
rd = op_readpc();
|
||||
if(wr == 0x00)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xfe: {
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
regs.y--;
|
||||
op_io();
|
||||
if(regs.y == 0x00)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x5f: {
|
||||
rd = op_readpc();
|
||||
rd |= op_readpc() << 8;
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x1f: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
dp += regs.x;
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3f: {
|
||||
rd = op_readpc();
|
||||
rd |= op_readpc() << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4f: {
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = 0xff00 | rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x01: {
|
||||
dp = 0xffde - (0 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x11: {
|
||||
dp = 0xffde - (1 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x21: {
|
||||
dp = 0xffde - (2 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x31: {
|
||||
dp = 0xffde - (3 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x41: {
|
||||
dp = 0xffde - (4 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x51: {
|
||||
dp = 0xffde - (5 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x61: {
|
||||
dp = 0xffde - (6 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x71: {
|
||||
dp = 0xffde - (7 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x81: {
|
||||
dp = 0xffde - (8 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x91: {
|
||||
dp = 0xffde - (9 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa1: {
|
||||
dp = 0xffde - (10 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb1: {
|
||||
dp = 0xffde - (11 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc1: {
|
||||
dp = 0xffde - (12 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd1: {
|
||||
dp = 0xffde - (13 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe1: {
|
||||
dp = 0xffde - (14 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf1: {
|
||||
dp = 0xffde - (15 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0f: {
|
||||
rd = op_readaddr(0xffde);
|
||||
rd |= op_readaddr(0xffdf) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
op_writestack(regs.p);
|
||||
regs.pc = rd;
|
||||
regs.p.b = 1;
|
||||
regs.p.i = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x6f: {
|
||||
rd = op_readstack();
|
||||
rd |= op_readstack() << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x7f: {
|
||||
regs.p = op_readstack();
|
||||
rd = op_readstack();
|
||||
rd |= op_readstack() << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc = rd;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1,205 +0,0 @@
|
|||
adc_a_const(0x88, adc, a),
|
||||
and_a_const(0x28, and, a),
|
||||
cmp_a_const(0x68, cmp, a),
|
||||
cmp_x_const(0xc8, cmp, x),
|
||||
cmp_y_const(0xad, cmp, y),
|
||||
eor_a_const(0x48, eor, a),
|
||||
or_a_const(0x08, or, a),
|
||||
sbc_a_const(0xa8, sbc, a) {
|
||||
1:rd = op_readpc();
|
||||
regs.$2 = op_$1(regs.$2, rd);
|
||||
}
|
||||
|
||||
adc_a_ix(0x86, adc),
|
||||
and_a_ix(0x26, and),
|
||||
cmp_a_ix(0x66, cmp),
|
||||
eor_a_ix(0x46, eor),
|
||||
or_a_ix(0x06, or),
|
||||
sbc_a_ix(0xa6, sbc) {
|
||||
1:op_io();
|
||||
2:rd = op_readdp(regs.x);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_dp(0x84, adc, a),
|
||||
and_a_dp(0x24, and, a),
|
||||
cmp_a_dp(0x64, cmp, a),
|
||||
cmp_x_dp(0x3e, cmp, x),
|
||||
cmp_y_dp(0x7e, cmp, y),
|
||||
eor_a_dp(0x44, eor, a),
|
||||
or_a_dp(0x04, or, a),
|
||||
sbc_a_dp(0xa4, sbc, a) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
regs.$2 = op_$1(regs.$2, rd);
|
||||
}
|
||||
|
||||
adc_a_dpx(0x94, adc),
|
||||
and_a_dpx(0x34, and),
|
||||
cmp_a_dpx(0x74, cmp),
|
||||
eor_a_dpx(0x54, eor),
|
||||
or_a_dpx(0x14, or),
|
||||
sbc_a_dpx(0xb4, sbc) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_addr(0x85, adc, a),
|
||||
and_a_addr(0x25, and, a),
|
||||
cmp_a_addr(0x65, cmp, a),
|
||||
cmp_x_addr(0x1e, cmp, x),
|
||||
cmp_y_addr(0x5e, cmp, y),
|
||||
eor_a_addr(0x45, eor, a),
|
||||
or_a_addr(0x05, or, a),
|
||||
sbc_a_addr(0xa5, sbc, a) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:rd = op_readaddr(dp);
|
||||
regs.$2 = op_$1(regs.$2, rd);
|
||||
}
|
||||
|
||||
adc_a_addrx(0x95, adc, x),
|
||||
adc_a_addry(0x96, adc, y),
|
||||
and_a_addrx(0x35, and, x),
|
||||
and_a_addry(0x36, and, y),
|
||||
cmp_a_addrx(0x75, cmp, x),
|
||||
cmp_a_addry(0x76, cmp, y),
|
||||
eor_a_addrx(0x55, eor, x),
|
||||
eor_a_addry(0x56, eor, y),
|
||||
or_a_addrx(0x15, or, x),
|
||||
or_a_addry(0x16, or, y),
|
||||
sbc_a_addrx(0xb5, sbc, x),
|
||||
sbc_a_addry(0xb6, sbc, y) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:op_io();
|
||||
4:rd = op_readaddr(dp + regs.$2);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_idpx(0x87, adc),
|
||||
and_a_idpx(0x27, and),
|
||||
cmp_a_idpx(0x67, cmp),
|
||||
eor_a_idpx(0x47, eor),
|
||||
or_a_idpx(0x07, or),
|
||||
sbc_a_idpx(0xa7, sbc) {
|
||||
1:dp = op_readpc() + regs.x;
|
||||
2:op_io();
|
||||
3:sp = op_readdp(dp);
|
||||
4:sp |= op_readdp(dp + 1) << 8;
|
||||
5:rd = op_readaddr(sp);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_idpy(0x97, adc),
|
||||
and_a_idpy(0x37, and),
|
||||
cmp_a_idpy(0x77, cmp),
|
||||
eor_a_idpy(0x57, eor),
|
||||
or_a_idpy(0x17, or),
|
||||
sbc_a_idpy(0xb7, sbc) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:sp = op_readdp(dp);
|
||||
4:sp |= op_readdp(dp + 1) << 8;
|
||||
5:rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_ix_iy(0x99, adc, 1),
|
||||
and_ix_iy(0x39, and, 1),
|
||||
cmp_ix_iy(0x79, cmp, 0),
|
||||
eor_ix_iy(0x59, eor, 1),
|
||||
or_ix_iy(0x19, or, 1),
|
||||
sbc_ix_iy(0xb9, sbc, 1) {
|
||||
1:op_io();
|
||||
2:rd = op_readdp(regs.y);
|
||||
3:wr = op_readdp(regs.x);
|
||||
wr = op_$1(wr, rd);
|
||||
4:($2) ? op_writedp(regs.x, wr) : op_io();
|
||||
}
|
||||
|
||||
adc_dp_dp(0x89, adc, 1),
|
||||
and_dp_dp(0x29, and, 1),
|
||||
cmp_dp_dp(0x69, cmp, 0),
|
||||
eor_dp_dp(0x49, eor, 1),
|
||||
or_dp_dp(0x09, or, 1),
|
||||
sbc_dp_dp(0xa9, sbc, 1) {
|
||||
1:sp = op_readpc();
|
||||
2:rd = op_readdp(sp);
|
||||
3:dp = op_readpc();
|
||||
4:wr = op_readdp(dp);
|
||||
5:wr = op_$1(wr, rd);
|
||||
($2) ? op_writedp(dp, wr) : op_io();
|
||||
}
|
||||
|
||||
adc_dp_const(0x98, adc, 1),
|
||||
and_dp_const(0x38, and, 1),
|
||||
cmp_dp_const(0x78, cmp, 0),
|
||||
eor_dp_const(0x58, eor, 1),
|
||||
or_dp_const(0x18, or, 1),
|
||||
sbc_dp_const(0xb8, sbc, 1) {
|
||||
1:rd = op_readpc();
|
||||
2:dp = op_readpc();
|
||||
3:wr = op_readdp(dp);
|
||||
4:wr = op_$1(wr, rd);
|
||||
($2) ? op_writedp(dp, wr) : op_io();
|
||||
}
|
||||
|
||||
addw_ya_dp(0x7a, addw),
|
||||
subw_ya_dp(0x9a, subw) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
3:op_io();
|
||||
4:rd |= op_readdp(dp + 1) << 8;
|
||||
regs.ya = op_$1(regs.ya, rd);
|
||||
}
|
||||
|
||||
cmpw_ya_dp(0x5a) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
3:rd |= op_readdp(dp + 1) << 8;
|
||||
op_cmpw(regs.ya, rd);
|
||||
}
|
||||
|
||||
and1_bit(0x4a, !!),
|
||||
and1_notbit(0x6a, !) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.c = regs.p.c & $1(rd & (1 << bit));
|
||||
}
|
||||
|
||||
eor1_bit(0x8a) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
4:op_io();
|
||||
regs.p.c = regs.p.c ^ !!(rd & (1 << bit));
|
||||
}
|
||||
|
||||
not1_bit(0xea) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
rd ^= (1 << bit);
|
||||
4:op_writeaddr(dp, rd);
|
||||
}
|
||||
|
||||
or1_bit(0x0a, !!),
|
||||
or1_notbit(0x2a, !) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
4:op_io();
|
||||
regs.p.c = regs.p.c | $1(rd & (1 << bit));
|
||||
}
|
|
@ -1,744 +0,0 @@
|
|||
case 0x88: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x28: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_and(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x68: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc8: {
|
||||
rd = op_readpc();
|
||||
regs.x = op_cmp(regs.x, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xad: {
|
||||
rd = op_readpc();
|
||||
regs.y = op_cmp(regs.y, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x48: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x08: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_or(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa8: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x86: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x26: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x66: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x46: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x06: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa6: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x84: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x24: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x64: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3e: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.x = op_cmp(regs.x, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x7e: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.y = op_cmp(regs.y, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x44: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x04: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa4: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x94: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x34: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x74: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x54: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x14: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb4: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x85: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x25: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x65: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x1e: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.x = op_cmp(regs.x, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x5e: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.y = op_cmp(regs.y, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x45: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x05: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa5: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x95: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x96: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x35: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x36: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x75: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x76: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x55: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x56: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x15: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x16: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb5: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb6: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x87: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x27: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x67: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x47: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x07: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa7: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x97: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x37: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x77: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x57: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x17: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb7: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x99: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_adc(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x39: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_and(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x79: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_cmp(wr, rd);
|
||||
(0) ? op_writedp(regs.x, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x59: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_eor(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x19: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_or(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb9: {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_sbc(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x89: {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_adc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x29: {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_and(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x69: {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_cmp(wr, rd);
|
||||
(0) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x49: {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_eor(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x09: {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_or(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa9: {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_sbc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x98: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_adc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x38: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_and(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x78: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_cmp(wr, rd);
|
||||
(0) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x58: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_eor(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x18: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_or(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb8: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_sbc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x7a: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
op_io();
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
regs.ya = op_addw(regs.ya, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9a: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
op_io();
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
regs.ya = op_subw(regs.ya, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x5a: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
op_cmpw(regs.ya, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4a: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.c = regs.p.c & !!(rd & (1 << bit));
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x6a: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.c = regs.p.c & !(rd & (1 << bit));
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8a: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.c = regs.p.c ^ !!(rd & (1 << bit));
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xea: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
rd ^= (1 << bit);
|
||||
op_writeaddr(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0a: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.c = regs.p.c | !!(rd & (1 << bit));
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2a: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.c = regs.p.c | !(rd & (1 << bit));
|
||||
break;
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
inc_a(0xbc, inc, a),
|
||||
inc_x(0x3d, inc, x),
|
||||
inc_y(0xfc, inc, y),
|
||||
dec_a(0x9c, dec, a),
|
||||
dec_x(0x1d, dec, x),
|
||||
dec_y(0xdc, dec, y),
|
||||
asl_a(0x1c, asl, a),
|
||||
lsr_a(0x5c, lsr, a),
|
||||
rol_a(0x3c, rol, a),
|
||||
ror_a(0x7c, ror, a) {
|
||||
1:op_io();
|
||||
regs.$2 = op_$1(regs.$2);
|
||||
}
|
||||
|
||||
inc_dp(0xab, inc),
|
||||
dec_dp(0x8b, dec),
|
||||
asl_dp(0x0b, asl),
|
||||
lsr_dp(0x4b, lsr),
|
||||
rol_dp(0x2b, rol),
|
||||
ror_dp(0x6b, ror) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
3:rd = op_$1(rd);
|
||||
op_writedp(dp, rd);
|
||||
}
|
||||
|
||||
inc_dpx(0xbb, inc),
|
||||
dec_dpx(0x9b, dec),
|
||||
asl_dpx(0x1b, asl),
|
||||
lsr_dpx(0x5b, lsr),
|
||||
rol_dpx(0x3b, rol),
|
||||
ror_dpx(0x7b, ror) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:rd = op_readdp(dp + regs.x);
|
||||
4:rd = op_$1(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
}
|
||||
|
||||
inc_addr(0xac, inc),
|
||||
dec_addr(0x8c, dec),
|
||||
asl_addr(0x0c, asl),
|
||||
lsr_addr(0x4c, lsr),
|
||||
rol_addr(0x2c, rol),
|
||||
ror_addr(0x6c, ror) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:rd = op_readaddr(dp);
|
||||
4:rd = op_$1(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
}
|
||||
|
||||
tset_addr_a(0x0e, |),
|
||||
tclr_addr_a(0x4e, &~) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:rd = op_readaddr(dp);
|
||||
regs.p.n = !!((regs.a - rd) & 0x80);
|
||||
regs.p.z = ((regs.a - rd) == 0);
|
||||
4:op_readaddr(dp);
|
||||
5:op_writeaddr(dp, rd $1 regs.a);
|
||||
}
|
||||
|
||||
incw_dp(0x3a, ++),
|
||||
decw_dp(0x1a, --) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
rd$1;
|
||||
3:op_writedp(dp++, rd);
|
||||
4:rd += op_readdp(dp) << 8;
|
||||
5:op_writedp(dp, rd >> 8);
|
||||
regs.p.n = !!(rd & 0x8000);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
|
@ -1,262 +0,0 @@
|
|||
case 0xbc: {
|
||||
op_io();
|
||||
regs.a = op_inc(regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3d: {
|
||||
op_io();
|
||||
regs.x = op_inc(regs.x);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xfc: {
|
||||
op_io();
|
||||
regs.y = op_inc(regs.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9c: {
|
||||
op_io();
|
||||
regs.a = op_dec(regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x1d: {
|
||||
op_io();
|
||||
regs.x = op_dec(regs.x);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xdc: {
|
||||
op_io();
|
||||
regs.y = op_dec(regs.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x1c: {
|
||||
op_io();
|
||||
regs.a = op_asl(regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x5c: {
|
||||
op_io();
|
||||
regs.a = op_lsr(regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3c: {
|
||||
op_io();
|
||||
regs.a = op_rol(regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x7c: {
|
||||
op_io();
|
||||
regs.a = op_ror(regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xab: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_inc(rd);
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8b: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_dec(rd);
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0b: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_asl(rd);
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4b: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_lsr(rd);
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2b: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_rol(rd);
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x6b: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_ror(rd);
|
||||
op_writedp(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xbb: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_inc(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9b: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_dec(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x1b: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_asl(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x5b: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_lsr(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3b: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_rol(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x7b: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_ror(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xac: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_inc(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8c: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_dec(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0c: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_asl(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4c: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_lsr(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2c: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_rol(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x6c: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_ror(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0e: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.n = !!((regs.a - rd) & 0x80);
|
||||
regs.p.z = ((regs.a - rd) == 0);
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, rd | regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4e: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.n = !!((regs.a - rd) & 0x80);
|
||||
regs.p.z = ((regs.a - rd) == 0);
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, rd &~ regs.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3a: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd++;
|
||||
op_writedp(dp++, rd);
|
||||
rd += op_readdp(dp) << 8;
|
||||
op_writedp(dp, rd >> 8);
|
||||
regs.p.n = !!(rd & 0x8000);
|
||||
regs.p.z = (rd == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x1a: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd--;
|
||||
op_writedp(dp++, rd);
|
||||
rd += op_readdp(dp) << 8;
|
||||
op_writedp(dp, rd >> 8);
|
||||
regs.p.n = !!(rd & 0x8000);
|
||||
regs.p.z = (rd == 0);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1,696 +0,0 @@
|
|||
case 0x00: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xef: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
regs.pc--;
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xff: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
regs.pc--;
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9f: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
op_io();
|
||||
break;
|
||||
case 4:
|
||||
op_io();
|
||||
regs.a = (regs.a >> 4) | (regs.a << 4);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xdf: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
if(regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a += 0x60;
|
||||
regs.p.c = 1;
|
||||
}
|
||||
if(regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a += 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xbe: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
if(!regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a -= 0x60;
|
||||
regs.p.c = 0;
|
||||
}
|
||||
if(!regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a -= 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x60: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.p.c = 0;
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x20: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.p.p = 0;
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x80: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.p.c = 1;
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x40: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.p.p = 1;
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe0: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.p.v = 0;
|
||||
regs.p.h = 0;
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xed: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
regs.p.c = !regs.p.c;
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa0: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
regs.p.i = 1;
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc0: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
regs.p.i = 0;
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x02: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd |= 0x01;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x12: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd &= ~0x01;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x22: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd |= 0x02;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x32: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd &= ~0x02;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x42: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd |= 0x04;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x52: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd &= ~0x04;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x62: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd |= 0x08;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x72: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd &= ~0x08;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x82: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd |= 0x10;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x92: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd &= ~0x10;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa2: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd |= 0x20;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb2: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd &= ~0x20;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc2: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd |= 0x40;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd2: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd &= ~0x40;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe2: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd |= 0x80;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf2: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd &= ~0x80;
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2d: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
op_writestack(regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4d: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
op_writestack(regs.x);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x6d: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
op_writestack(regs.y);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0d: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
op_writestack(regs.p);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xae: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
regs.a = op_readstack();
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xce: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
regs.x = op_readstack();
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xee: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
regs.y = op_readstack();
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8e: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
regs.p = op_readstack();
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xcf: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
op_io();
|
||||
break;
|
||||
case 4:
|
||||
op_io();
|
||||
break;
|
||||
case 5:
|
||||
op_io();
|
||||
break;
|
||||
case 6:
|
||||
op_io();
|
||||
break;
|
||||
case 7:
|
||||
op_io();
|
||||
break;
|
||||
case 8:
|
||||
op_io();
|
||||
ya = regs.y * regs.a;
|
||||
regs.a = ya;
|
||||
regs.y = ya >> 8;
|
||||
//result is set based on y (high-byte) only
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9e: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
op_io();
|
||||
break;
|
||||
case 4:
|
||||
op_io();
|
||||
break;
|
||||
case 5:
|
||||
op_io();
|
||||
break;
|
||||
case 6:
|
||||
op_io();
|
||||
break;
|
||||
case 7:
|
||||
op_io();
|
||||
break;
|
||||
case 8:
|
||||
op_io();
|
||||
break;
|
||||
case 9:
|
||||
op_io();
|
||||
break;
|
||||
case 10:
|
||||
op_io();
|
||||
break;
|
||||
case 11:
|
||||
op_io();
|
||||
ya = regs.ya;
|
||||
//overflow set if quotient >= 256
|
||||
regs.p.v = !!(regs.y >= regs.x);
|
||||
regs.p.h = !!((regs.y & 15) >= (regs.x & 15));
|
||||
if(regs.y < (regs.x << 1)) {
|
||||
//if quotient is <= 511 (will fit into 9-bit result)
|
||||
regs.a = ya / regs.x;
|
||||
regs.y = ya % regs.x;
|
||||
} else {
|
||||
//otherwise, the quotient won't fit into regs.p.v + regs.a
|
||||
//this emulates the odd behavior of the S-SMP in this case
|
||||
regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x);
|
||||
regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x);
|
||||
}
|
||||
//result is set based on a (quotient) only
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1,806 +0,0 @@
|
|||
case 0x7d: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.a = regs.x;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xdd: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.a = regs.y;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x5d: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.x = regs.a;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xfd: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.y = regs.a;
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9d: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.x = regs.sp;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xbd: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.sp = regs.x;
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe8: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
regs.a = op_readpc();
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xcd: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
regs.x = op_readpc();
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8d: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
regs.y = op_readpc();
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe6: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
regs.a = op_readdp(regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xbf: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
regs.a = op_readdp(regs.x++);
|
||||
break;
|
||||
case 3:
|
||||
op_io();
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe4: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
regs.a = op_readdp(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf8: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
regs.x = op_readdp(sp);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xeb: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
regs.y = op_readdp(sp);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf4: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
regs.a = op_readdp(sp + regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf9: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
regs.x = op_readdp(sp + regs.y);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xfb: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
regs.y = op_readdp(sp + regs.x);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe5: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
sp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
regs.a = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe9: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
sp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
regs.x = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xec: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
sp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
regs.y = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf5: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
sp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
op_io();
|
||||
break;
|
||||
case 4:
|
||||
regs.a = op_readaddr(sp + regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf6: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
sp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
op_io();
|
||||
break;
|
||||
case 4:
|
||||
regs.a = op_readaddr(sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xe7: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc() + regs.x;
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
sp = op_readdp(dp);
|
||||
break;
|
||||
case 4:
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
break;
|
||||
case 5:
|
||||
regs.a = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xf7: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
sp = op_readdp(dp);
|
||||
break;
|
||||
case 4:
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
break;
|
||||
case 5:
|
||||
regs.a = op_readaddr(sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xfa: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(sp);
|
||||
break;
|
||||
case 3:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 4:
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8f: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
rd = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 3:
|
||||
op_readdp(dp);
|
||||
break;
|
||||
case 4:
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc6: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_readdp(regs.x);
|
||||
break;
|
||||
case 3:
|
||||
op_writedp(regs.x, regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xaf: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
op_writedp(regs.x++, regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc4: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
op_writedp(dp, regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd8: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
op_writedp(dp, regs.x);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xcb: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
op_writedp(dp, regs.y);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd4: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
dp += regs.x;
|
||||
break;
|
||||
case 3:
|
||||
op_readdp(dp);
|
||||
break;
|
||||
case 4:
|
||||
op_writedp(dp, regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd9: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
dp += regs.y;
|
||||
break;
|
||||
case 3:
|
||||
op_readdp(dp);
|
||||
break;
|
||||
case 4:
|
||||
op_writedp(dp, regs.x);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xdb: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
dp += regs.x;
|
||||
break;
|
||||
case 3:
|
||||
op_readdp(dp);
|
||||
break;
|
||||
case 4:
|
||||
op_writedp(dp, regs.y);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc5: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
op_readaddr(dp);
|
||||
break;
|
||||
case 4:
|
||||
op_writeaddr(dp, regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc9: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
op_readaddr(dp);
|
||||
break;
|
||||
case 4:
|
||||
op_writeaddr(dp, regs.x);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xcc: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
op_readaddr(dp);
|
||||
break;
|
||||
case 4:
|
||||
op_writeaddr(dp, regs.y);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd5: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
op_io();
|
||||
dp += regs.x;
|
||||
break;
|
||||
case 4:
|
||||
op_readaddr(dp);
|
||||
break;
|
||||
case 5:
|
||||
op_writeaddr(dp, regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd6: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
op_io();
|
||||
dp += regs.y;
|
||||
break;
|
||||
case 4:
|
||||
op_readaddr(dp);
|
||||
break;
|
||||
case 5:
|
||||
op_writeaddr(dp, regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc7: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
sp += regs.x;
|
||||
break;
|
||||
case 3:
|
||||
dp = op_readdp(sp);
|
||||
break;
|
||||
case 4:
|
||||
dp |= op_readdp(sp + 1) << 8;
|
||||
break;
|
||||
case 5:
|
||||
op_readaddr(dp);
|
||||
break;
|
||||
case 6:
|
||||
op_writeaddr(dp, regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd7: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp = op_readdp(sp);
|
||||
break;
|
||||
case 3:
|
||||
dp |= op_readdp(sp + 1) << 8;
|
||||
break;
|
||||
case 4:
|
||||
op_io();
|
||||
dp += regs.y;
|
||||
break;
|
||||
case 5:
|
||||
op_readaddr(dp);
|
||||
break;
|
||||
case 6:
|
||||
op_writeaddr(dp, regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xba: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
regs.a = op_readdp(sp);
|
||||
break;
|
||||
case 3:
|
||||
op_io();
|
||||
break;
|
||||
case 4:
|
||||
regs.y = op_readdp(sp + 1);
|
||||
regs.p.n = !!(regs.ya & 0x8000);
|
||||
regs.p.z = (regs.ya == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xda: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
op_writedp(dp, regs.a);
|
||||
break;
|
||||
case 4:
|
||||
op_writedp(dp + 1, regs.y);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xaa: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
sp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
sp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
bit = sp >> 13;
|
||||
sp &= 0x1fff;
|
||||
rd = op_readaddr(sp);
|
||||
regs.p.c = !!(rd & (1 << bit));
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xca: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
if(regs.p.c)rd |= (1 << bit);
|
||||
else rd &= ~(1 << bit);
|
||||
break;
|
||||
case 4:
|
||||
op_io();
|
||||
break;
|
||||
case 5:
|
||||
op_writeaddr(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,550 +0,0 @@
|
|||
case 0xbc: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.a = op_inc(regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3d: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.x = op_inc(regs.x);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xfc: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.y = op_inc(regs.y);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9c: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.a = op_dec(regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x1d: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.x = op_dec(regs.x);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xdc: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.y = op_dec(regs.y);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x1c: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.a = op_asl(regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x5c: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.a = op_lsr(regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3c: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.a = op_rol(regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x7c: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
op_io();
|
||||
regs.a = op_ror(regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xab: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd = op_inc(rd);
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8b: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd = op_dec(rd);
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0b: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd = op_asl(rd);
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4b: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd = op_lsr(rd);
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2b: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd = op_rol(rd);
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x6b: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
break;
|
||||
case 3:
|
||||
rd = op_ror(rd);
|
||||
op_writedp(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xbb: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readdp(dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_inc(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9b: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readdp(dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_dec(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x1b: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readdp(dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_asl(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x5b: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readdp(dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_lsr(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3b: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readdp(dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_rol(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x7b: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
op_io();
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readdp(dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_ror(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xac: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readaddr(dp);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_inc(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8c: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readaddr(dp);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_dec(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0c: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readaddr(dp);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_asl(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4c: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readaddr(dp);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_lsr(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2c: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readaddr(dp);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_rol(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x6c: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readaddr(dp);
|
||||
break;
|
||||
case 4:
|
||||
rd = op_ror(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0e: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.n = !!((regs.a - rd) & 0x80);
|
||||
regs.p.z = ((regs.a - rd) == 0);
|
||||
break;
|
||||
case 4:
|
||||
op_readaddr(dp);
|
||||
break;
|
||||
case 5:
|
||||
op_writeaddr(dp, rd | regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4e: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
dp |= op_readpc() << 8;
|
||||
break;
|
||||
case 3:
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.n = !!((regs.a - rd) & 0x80);
|
||||
regs.p.z = ((regs.a - rd) == 0);
|
||||
break;
|
||||
case 4:
|
||||
op_readaddr(dp);
|
||||
break;
|
||||
case 5:
|
||||
op_writeaddr(dp, rd &~ regs.a);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3a: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
rd++;
|
||||
break;
|
||||
case 3:
|
||||
op_writedp(dp++, rd);
|
||||
break;
|
||||
case 4:
|
||||
rd += op_readdp(dp) << 8;
|
||||
break;
|
||||
case 5:
|
||||
op_writedp(dp, rd >> 8);
|
||||
regs.p.n = !!(rd & 0x8000);
|
||||
regs.p.z = (rd == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x1a: {
|
||||
switch(opcode_cycle++) {
|
||||
case 1:
|
||||
dp = op_readpc();
|
||||
break;
|
||||
case 2:
|
||||
rd = op_readdp(dp);
|
||||
rd--;
|
||||
break;
|
||||
case 3:
|
||||
op_writedp(dp++, rd);
|
||||
break;
|
||||
case 4:
|
||||
rd += op_readdp(dp) << 8;
|
||||
break;
|
||||
case 5:
|
||||
op_writedp(dp, rd >> 8);
|
||||
regs.p.n = !!(rd & 0x8000);
|
||||
regs.p.z = (rd == 0);
|
||||
opcode_cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1,305 +0,0 @@
|
|||
auto SMP::disassemble_read(uint16 addr) -> uint8 {
|
||||
if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f];
|
||||
return smp.apuram[addr];
|
||||
}
|
||||
|
||||
auto SMP::relb(int8 offset, int op_len) -> uint16 {
|
||||
uint16 pc = regs.pc + op_len;
|
||||
return pc + offset;
|
||||
}
|
||||
|
||||
auto SMP::disassemble_opcode(char* output, uint16 addr) -> void {
|
||||
char* s;
|
||||
char t[512];
|
||||
uint8 op, op0, op1;
|
||||
uint16 opw, opdp0, opdp1;
|
||||
s = output;
|
||||
|
||||
sprintf(s, "..%.4x ", addr);
|
||||
|
||||
op = disassemble_read(addr + 0);
|
||||
op0 = disassemble_read(addr + 1);
|
||||
op1 = disassemble_read(addr + 2);
|
||||
opw = (op0) | (op1 << 8);
|
||||
opdp0 = ((unsigned)regs.p.p << 8) + op0;
|
||||
opdp1 = ((unsigned)regs.p.p << 8) + op1;
|
||||
|
||||
strcpy(t, " ");
|
||||
|
||||
switch(op) {
|
||||
case 0x00: sprintf(t, "nop"); break;
|
||||
case 0x01: sprintf(t, "tcall 0"); break;
|
||||
case 0x02: sprintf(t, "set0 $%.3x", opdp0); break;
|
||||
case 0x03: sprintf(t, "bbs0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x04: sprintf(t, "or a,$%.3x", opdp0); break;
|
||||
case 0x05: sprintf(t, "or a,$%.4x", opw); break;
|
||||
case 0x06: sprintf(t, "or a,(x)"); break;
|
||||
case 0x07: sprintf(t, "or a,($%.3x+x)", opdp0); break;
|
||||
case 0x08: sprintf(t, "or a,#$%.2x", op0); break;
|
||||
case 0x09: sprintf(t, "or $%.3x,$%.3x", opdp1, opdp0); break;
|
||||
case 0x0a: sprintf(t, "or1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0x0b: sprintf(t, "asl $%.3x", opdp0); break;
|
||||
case 0x0c: sprintf(t, "asl $%.4x", opw); break;
|
||||
case 0x0d: sprintf(t, "push p"); break;
|
||||
case 0x0e: sprintf(t, "tset $%.4x,a", opw); break;
|
||||
case 0x0f: sprintf(t, "brk"); break;
|
||||
case 0x10: sprintf(t, "bpl $%.4x", relb(op0, 2)); break;
|
||||
case 0x11: sprintf(t, "tcall 1"); break;
|
||||
case 0x12: sprintf(t, "clr0 $%.3x", opdp0); break;
|
||||
case 0x13: sprintf(t, "bbc0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x14: sprintf(t, "or a,$%.3x+x", opdp0); break;
|
||||
case 0x15: sprintf(t, "or a,$%.4x+x", opw); break;
|
||||
case 0x16: sprintf(t, "or a,$%.4x+y", opw); break;
|
||||
case 0x17: sprintf(t, "or a,($%.3x)+y", opdp0); break;
|
||||
case 0x18: sprintf(t, "or $%.3x,#$%.2x", opdp1, op0); break;
|
||||
case 0x19: sprintf(t, "or (x),(y)"); break;
|
||||
case 0x1a: sprintf(t, "decw $%.3x", opdp0); break;
|
||||
case 0x1b: sprintf(t, "asl $%.3x+x", opdp0); break;
|
||||
case 0x1c: sprintf(t, "asl a"); break;
|
||||
case 0x1d: sprintf(t, "dec x"); break;
|
||||
case 0x1e: sprintf(t, "cmp x,$%.4x", opw); break;
|
||||
case 0x1f: sprintf(t, "jmp ($%.4x+x)", opw); break;
|
||||
case 0x20: sprintf(t, "clrp"); break;
|
||||
case 0x21: sprintf(t, "tcall 2"); break;
|
||||
case 0x22: sprintf(t, "set1 $%.3x", opdp0); break;
|
||||
case 0x23: sprintf(t, "bbs1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x24: sprintf(t, "and a,$%.3x", opdp0); break;
|
||||
case 0x25: sprintf(t, "and a,$%.4x", opw); break;
|
||||
case 0x26: sprintf(t, "and a,(x)"); break;
|
||||
case 0x27: sprintf(t, "and a,($%.3x+x)", opdp0); break;
|
||||
case 0x28: sprintf(t, "and a,#$%.2x", op0); break;
|
||||
case 0x29: sprintf(t, "and $%.3x,$%.3x", opdp1, opdp0); break;
|
||||
case 0x2a: sprintf(t, "or1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0x2b: sprintf(t, "rol $%.3x", opdp0); break;
|
||||
case 0x2c: sprintf(t, "rol $%.4x", opw); break;
|
||||
case 0x2d: sprintf(t, "push a"); break;
|
||||
case 0x2e: sprintf(t, "cbne $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x2f: sprintf(t, "bra $%.4x", relb(op0, 2)); break;
|
||||
case 0x30: sprintf(t, "bmi $%.4x", relb(op0, 2)); break;
|
||||
case 0x31: sprintf(t, "tcall 3"); break;
|
||||
case 0x32: sprintf(t, "clr1 $%.3x", opdp0); break;
|
||||
case 0x33: sprintf(t, "bbc1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x34: sprintf(t, "and a,$%.3x+x", opdp0); break;
|
||||
case 0x35: sprintf(t, "and a,$%.4x+x", opw); break;
|
||||
case 0x36: sprintf(t, "and a,$%.4x+y", opw); break;
|
||||
case 0x37: sprintf(t, "and a,($%.3x)+y", opdp0); break;
|
||||
case 0x38: sprintf(t, "and $%.3x,#$%.2x", opdp1, op0); break;
|
||||
case 0x39: sprintf(t, "and (x),(y)"); break;
|
||||
case 0x3a: sprintf(t, "incw $%.3x", opdp0); break;
|
||||
case 0x3b: sprintf(t, "rol $%.3x+x", opdp0); break;
|
||||
case 0x3c: sprintf(t, "rol a"); break;
|
||||
case 0x3d: sprintf(t, "inc x"); break;
|
||||
case 0x3e: sprintf(t, "cmp x,$%.3x", opdp0); break;
|
||||
case 0x3f: sprintf(t, "call $%.4x", opw); break;
|
||||
case 0x40: sprintf(t, "setp"); break;
|
||||
case 0x41: sprintf(t, "tcall 4"); break;
|
||||
case 0x42: sprintf(t, "set2 $%.3x", opdp0); break;
|
||||
case 0x43: sprintf(t, "bbs2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x44: sprintf(t, "eor a,$%.3x", opdp0); break;
|
||||
case 0x45: sprintf(t, "eor a,$%.4x", opw); break;
|
||||
case 0x46: sprintf(t, "eor a,(x)"); break;
|
||||
case 0x47: sprintf(t, "eor a,($%.3x+x)", opdp0); break;
|
||||
case 0x48: sprintf(t, "eor a,#$%.2x", op0); break;
|
||||
case 0x49: sprintf(t, "eor $%.3x,$%.3x", opdp1, opdp0); break;
|
||||
case 0x4a: sprintf(t, "and1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0x4b: sprintf(t, "lsr $%.3x", opdp0); break;
|
||||
case 0x4c: sprintf(t, "lsr $%.4x", opw); break;
|
||||
case 0x4d: sprintf(t, "push x"); break;
|
||||
case 0x4e: sprintf(t, "tclr $%.4x,a", opw); break;
|
||||
case 0x4f: sprintf(t, "pcall $ff%.2x", op0); break;
|
||||
case 0x50: sprintf(t, "bvc $%.4x", relb(op0, 2)); break;
|
||||
case 0x51: sprintf(t, "tcall 5"); break;
|
||||
case 0x52: sprintf(t, "clr2 $%.3x", opdp0); break;
|
||||
case 0x53: sprintf(t, "bbc2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x54: sprintf(t, "eor a,$%.3x+x", opdp0); break;
|
||||
case 0x55: sprintf(t, "eor a,$%.4x+x", opw); break;
|
||||
case 0x56: sprintf(t, "eor a,$%.4x+y", opw); break;
|
||||
case 0x57: sprintf(t, "eor a,($%.3x)+y", opdp0); break;
|
||||
case 0x58: sprintf(t, "eor $%.3x,#$%.2x", opdp1, op0); break;
|
||||
case 0x59: sprintf(t, "eor (x),(y)"); break;
|
||||
case 0x5a: sprintf(t, "cmpw ya,$%.3x", opdp0); break;
|
||||
case 0x5b: sprintf(t, "lsr $%.3x+x", opdp0); break;
|
||||
case 0x5c: sprintf(t, "lsr a"); break;
|
||||
case 0x5d: sprintf(t, "mov x,a"); break;
|
||||
case 0x5e: sprintf(t, "cmp y,$%.4x", opw); break;
|
||||
case 0x5f: sprintf(t, "jmp $%.4x", opw); break;
|
||||
case 0x60: sprintf(t, "clrc"); break;
|
||||
case 0x61: sprintf(t, "tcall 6"); break;
|
||||
case 0x62: sprintf(t, "set3 $%.3x", opdp0); break;
|
||||
case 0x63: sprintf(t, "bbs3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x64: sprintf(t, "cmp a,$%.3x", opdp0); break;
|
||||
case 0x65: sprintf(t, "cmp a,$%.4x", opw); break;
|
||||
case 0x66: sprintf(t, "cmp a,(x)"); break;
|
||||
case 0x67: sprintf(t, "cmp a,($%.3x+x)", opdp0); break;
|
||||
case 0x68: sprintf(t, "cmp a,#$%.2x", op0); break;
|
||||
case 0x69: sprintf(t, "cmp $%.3x,$%.3x", opdp1, opdp0); break;
|
||||
case 0x6a: sprintf(t, "and1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0x6b: sprintf(t, "ror $%.3x", opdp0); break;
|
||||
case 0x6c: sprintf(t, "ror $%.4x", opw); break;
|
||||
case 0x6d: sprintf(t, "push y"); break;
|
||||
case 0x6e: sprintf(t, "dbnz $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x6f: sprintf(t, "ret"); break;
|
||||
case 0x70: sprintf(t, "bvs $%.4x", relb(op0, 2)); break;
|
||||
case 0x71: sprintf(t, "tcall 7"); break;
|
||||
case 0x72: sprintf(t, "clr3 $%.3x", opdp0); break;
|
||||
case 0x73: sprintf(t, "bbc3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x74: sprintf(t, "cmp a,$%.3x+x", opdp0); break;
|
||||
case 0x75: sprintf(t, "cmp a,$%.4x+x", opw); break;
|
||||
case 0x76: sprintf(t, "cmp a,$%.4x+y", opw); break;
|
||||
case 0x77: sprintf(t, "cmp a,($%.3x)+y", opdp0); break;
|
||||
case 0x78: sprintf(t, "cmp $%.3x,#$%.2x", opdp1, op0); break;
|
||||
case 0x79: sprintf(t, "cmp (x),(y)"); break;
|
||||
case 0x7a: sprintf(t, "addw ya,$%.3x", opdp0); break;
|
||||
case 0x7b: sprintf(t, "ror $%.3x+x", opdp0); break;
|
||||
case 0x7c: sprintf(t, "ror a"); break;
|
||||
case 0x7d: sprintf(t, "mov a,x"); break;
|
||||
case 0x7e: sprintf(t, "cmp y,$%.3x", opdp0); break;
|
||||
case 0x7f: sprintf(t, "reti"); break;
|
||||
case 0x80: sprintf(t, "setc"); break;
|
||||
case 0x81: sprintf(t, "tcall 8"); break;
|
||||
case 0x82: sprintf(t, "set4 $%.3x", opdp0); break;
|
||||
case 0x83: sprintf(t, "bbs4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x84: sprintf(t, "adc a,$%.3x", opdp0); break;
|
||||
case 0x85: sprintf(t, "adc a,$%.4x", opw); break;
|
||||
case 0x86: sprintf(t, "adc a,(x)"); break;
|
||||
case 0x87: sprintf(t, "adc a,($%.3x+x)", opdp0); break;
|
||||
case 0x88: sprintf(t, "adc a,#$%.2x", op0); break;
|
||||
case 0x89: sprintf(t, "adc $%.3x,$%.3x", opdp1, opdp0); break;
|
||||
case 0x8a: sprintf(t, "eor1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0x8b: sprintf(t, "dec $%.3x", opdp0); break;
|
||||
case 0x8c: sprintf(t, "dec $%.4x", opw); break;
|
||||
case 0x8d: sprintf(t, "mov y,#$%.2x", op0); break;
|
||||
case 0x8e: sprintf(t, "pop p"); break;
|
||||
case 0x8f: sprintf(t, "mov $%.3x,#$%.2x", opdp1, op0); break;
|
||||
case 0x90: sprintf(t, "bcc $%.4x", relb(op0, 2)); break;
|
||||
case 0x91: sprintf(t, "tcall 9"); break;
|
||||
case 0x92: sprintf(t, "clr4 $%.3x", opdp0); break;
|
||||
case 0x93: sprintf(t, "bbc4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0x94: sprintf(t, "adc a,$%.3x+x", opdp0); break;
|
||||
case 0x95: sprintf(t, "adc a,$%.4x+x", opw); break;
|
||||
case 0x96: sprintf(t, "adc a,$%.4x+y", opw); break;
|
||||
case 0x97: sprintf(t, "adc a,($%.3x)+y", opdp0); break;
|
||||
case 0x98: sprintf(t, "adc $%.3x,#$%.2x", opdp1, op0); break;
|
||||
case 0x99: sprintf(t, "adc (x),(y)"); break;
|
||||
case 0x9a: sprintf(t, "subw ya,$%.3x", opdp0); break;
|
||||
case 0x9b: sprintf(t, "dec $%.3x+x", opdp0); break;
|
||||
case 0x9c: sprintf(t, "dec a"); break;
|
||||
case 0x9d: sprintf(t, "mov x,sp"); break;
|
||||
case 0x9e: sprintf(t, "div ya,x"); break;
|
||||
case 0x9f: sprintf(t, "xcn a"); break;
|
||||
case 0xa0: sprintf(t, "ei"); break;
|
||||
case 0xa1: sprintf(t, "tcall 10"); break;
|
||||
case 0xa2: sprintf(t, "set5 $%.3x", opdp0); break;
|
||||
case 0xa3: sprintf(t, "bbs5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0xa4: sprintf(t, "sbc a,$%.3x", opdp0); break;
|
||||
case 0xa5: sprintf(t, "sbc a,$%.4x", opw); break;
|
||||
case 0xa6: sprintf(t, "sbc a,(x)"); break;
|
||||
case 0xa7: sprintf(t, "sbc a,($%.3x+x)", opdp0); break;
|
||||
case 0xa8: sprintf(t, "sbc a,#$%.2x", op0); break;
|
||||
case 0xa9: sprintf(t, "sbc $%.3x,$%.3x", opdp1, opdp0); break;
|
||||
case 0xaa: sprintf(t, "mov1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0xab: sprintf(t, "inc $%.3x", opdp0); break;
|
||||
case 0xac: sprintf(t, "inc $%.4x", opw); break;
|
||||
case 0xad: sprintf(t, "cmp y,#$%.2x", op0); break;
|
||||
case 0xae: sprintf(t, "pop a"); break;
|
||||
case 0xaf: sprintf(t, "mov (x)+,a"); break;
|
||||
case 0xb0: sprintf(t, "bcs $%.4x", relb(op0, 2)); break;
|
||||
case 0xb1: sprintf(t, "tcall 11"); break;
|
||||
case 0xb2: sprintf(t, "clr5 $%.3x", opdp0); break;
|
||||
case 0xb3: sprintf(t, "bbc5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0xb4: sprintf(t, "sbc a,$%.3x+x", opdp0); break;
|
||||
case 0xb5: sprintf(t, "sbc a,$%.4x+x", opw); break;
|
||||
case 0xb6: sprintf(t, "sbc a,$%.4x+y", opw); break;
|
||||
case 0xb7: sprintf(t, "sbc a,($%.3x)+y", opdp0); break;
|
||||
case 0xb8: sprintf(t, "sbc $%.3x,#$%.2x", opdp1, op0); break;
|
||||
case 0xb9: sprintf(t, "sbc (x),(y)"); break;
|
||||
case 0xba: sprintf(t, "movw ya,$%.3x", opdp0); break;
|
||||
case 0xbb: sprintf(t, "inc $%.3x+x", opdp0); break;
|
||||
case 0xbc: sprintf(t, "inc a"); break;
|
||||
case 0xbd: sprintf(t, "mov sp,x"); break;
|
||||
case 0xbe: sprintf(t, "das a"); break;
|
||||
case 0xbf: sprintf(t, "mov a,(x)+"); break;
|
||||
case 0xc0: sprintf(t, "di"); break;
|
||||
case 0xc1: sprintf(t, "tcall 12"); break;
|
||||
case 0xc2: sprintf(t, "set6 $%.3x", opdp0); break;
|
||||
case 0xc3: sprintf(t, "bbs6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0xc4: sprintf(t, "mov $%.3x,a", opdp0); break;
|
||||
case 0xc5: sprintf(t, "mov $%.4x,a", opw); break;
|
||||
case 0xc6: sprintf(t, "mov (x),a"); break;
|
||||
case 0xc7: sprintf(t, "mov ($%.3x+x),a", opdp0); break;
|
||||
case 0xc8: sprintf(t, "cmp x,#$%.2x", op0); break;
|
||||
case 0xc9: sprintf(t, "mov $%.4x,x", opw); break;
|
||||
case 0xca: sprintf(t, "mov1 $%.4x:%d,c", opw & 0x1fff, opw >> 13); break;
|
||||
case 0xcb: sprintf(t, "mov $%.3x,y", opdp0); break;
|
||||
case 0xcc: sprintf(t, "mov $%.4x,y", opw); break;
|
||||
case 0xcd: sprintf(t, "mov x,#$%.2x", op0); break;
|
||||
case 0xce: sprintf(t, "pop x"); break;
|
||||
case 0xcf: sprintf(t, "mul ya"); break;
|
||||
case 0xd0: sprintf(t, "bne $%.4x", relb(op0, 2)); break;
|
||||
case 0xd1: sprintf(t, "tcall 13"); break;
|
||||
case 0xd2: sprintf(t, "clr6 $%.3x", opdp0); break;
|
||||
case 0xd3: sprintf(t, "bbc6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0xd4: sprintf(t, "mov $%.3x+x,a", opdp0); break;
|
||||
case 0xd5: sprintf(t, "mov $%.4x+x,a", opw); break;
|
||||
case 0xd6: sprintf(t, "mov $%.4x+y,a", opw); break;
|
||||
case 0xd7: sprintf(t, "mov ($%.3x)+y,a", opdp0); break;
|
||||
case 0xd8: sprintf(t, "mov $%.3x,x", opdp0); break;
|
||||
case 0xd9: sprintf(t, "mov $%.3x+y,x", opdp0); break;
|
||||
case 0xda: sprintf(t, "movw $%.3x,ya", opdp0); break;
|
||||
case 0xdb: sprintf(t, "mov $%.3x+x,y", opdp0); break;
|
||||
case 0xdc: sprintf(t, "dec y"); break;
|
||||
case 0xdd: sprintf(t, "mov a,y"); break;
|
||||
case 0xde: sprintf(t, "cbne $%.3x+x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0xdf: sprintf(t, "daa a"); break;
|
||||
case 0xe0: sprintf(t, "clrv"); break;
|
||||
case 0xe1: sprintf(t, "tcall 14"); break;
|
||||
case 0xe2: sprintf(t, "set7 $%.3x", opdp0); break;
|
||||
case 0xe3: sprintf(t, "bbs7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0xe4: sprintf(t, "mov a,$%.3x", opdp0); break;
|
||||
case 0xe5: sprintf(t, "mov a,$%.4x", opw); break;
|
||||
case 0xe6: sprintf(t, "mov a,(x)"); break;
|
||||
case 0xe7: sprintf(t, "mov a,($%.3x+x)", opdp0); break;
|
||||
case 0xe8: sprintf(t, "mov a,#$%.2x", op0); break;
|
||||
case 0xe9: sprintf(t, "mov x,$%.4x", opw); break;
|
||||
case 0xea: sprintf(t, "not1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0xeb: sprintf(t, "mov y,$%.3x", opdp0); break;
|
||||
case 0xec: sprintf(t, "mov y,$%.4x", opw); break;
|
||||
case 0xed: sprintf(t, "notc"); break;
|
||||
case 0xee: sprintf(t, "pop y"); break;
|
||||
case 0xef: sprintf(t, "sleep"); break;
|
||||
case 0xf0: sprintf(t, "beq $%.4x", relb(op0, 2)); break;
|
||||
case 0xf1: sprintf(t, "tcall 15"); break;
|
||||
case 0xf2: sprintf(t, "clr7 $%.3x", opdp0); break;
|
||||
case 0xf3: sprintf(t, "bbc7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
|
||||
case 0xf4: sprintf(t, "mov a,$%.3x+x", opdp0); break;
|
||||
case 0xf5: sprintf(t, "mov a,$%.4x+x", opw); break;
|
||||
case 0xf6: sprintf(t, "mov a,$%.4x+y", opw); break;
|
||||
case 0xf7: sprintf(t, "mov a,($%.3x)+y", opdp0); break;
|
||||
case 0xf8: sprintf(t, "mov x,$%.3x", opdp0); break;
|
||||
case 0xf9: sprintf(t, "mov x,$%.3x+y", opdp0); break;
|
||||
case 0xfa: sprintf(t, "mov $%.3x,$%.3x", opdp1, opdp0); break;
|
||||
case 0xfb: sprintf(t, "mov y,$%.3x+x", opdp0); break;
|
||||
case 0xfc: sprintf(t, "inc y"); break;
|
||||
case 0xfd: sprintf(t, "mov y,a"); break;
|
||||
case 0xfe: sprintf(t, "dbnz y,$%.4x", relb(op0, 2)); break;
|
||||
case 0xff: sprintf(t, "stop"); break;
|
||||
}
|
||||
|
||||
t[strlen(t)] = ' ';
|
||||
strcat(s, t);
|
||||
|
||||
sprintf(t, "A:%.2x X:%.2x Y:%.2x SP:01%.2x YA:%.4x ",
|
||||
regs.a, regs.x, regs.y, regs.sp, (uint16)regs.ya);
|
||||
strcat(s, t);
|
||||
|
||||
sprintf(t, "%c%c%c%c%c%c%c%c",
|
||||
regs.p.n ? 'N' : 'n',
|
||||
regs.p.v ? 'V' : 'v',
|
||||
regs.p.p ? 'P' : 'p',
|
||||
regs.p.b ? 'B' : 'b',
|
||||
regs.p.h ? 'H' : 'h',
|
||||
regs.p.i ? 'I' : 'i',
|
||||
regs.p.z ? 'Z' : 'z',
|
||||
regs.p.c ? 'C' : 'c');
|
||||
strcat(s, t);
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
auto SMP::port_read(uint addr) -> uint {
|
||||
return apuram[0xf4 + (addr & 3)];
|
||||
}
|
||||
|
||||
auto SMP::port_write(uint addr, uint data) -> void {
|
||||
apuram[0xf4 + (addr & 3)] = data;
|
||||
}
|
||||
|
||||
auto SMP::mmio_read(uint addr) -> uint {
|
||||
switch(addr) {
|
||||
|
||||
case 0xf2:
|
||||
return status.dsp_addr;
|
||||
|
||||
case 0xf3:
|
||||
return dsp.read(status.dsp_addr & 0x7f);
|
||||
|
||||
case 0xf4:
|
||||
case 0xf5:
|
||||
case 0xf6:
|
||||
case 0xf7:
|
||||
synchronizeCPU();
|
||||
return cpu.port_read(addr);
|
||||
|
||||
case 0xf8:
|
||||
return status.ram00f8;
|
||||
|
||||
case 0xf9:
|
||||
return status.ram00f9;
|
||||
|
||||
case 0xfd: {
|
||||
unsigned result = timer0.stage3_ticks & 15;
|
||||
timer0.stage3_ticks = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
case 0xfe: {
|
||||
unsigned result = timer1.stage3_ticks & 15;
|
||||
timer1.stage3_ticks = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
case 0xff: {
|
||||
unsigned result = timer2.stage3_ticks & 15;
|
||||
timer2.stage3_ticks = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto SMP::mmio_write(uint addr, uint data) -> void {
|
||||
switch(addr) {
|
||||
|
||||
case 0xf1:
|
||||
status.iplrom_enable = data & 0x80;
|
||||
|
||||
if(data & 0x30) {
|
||||
synchronizeCPU();
|
||||
if(data & 0x20) {
|
||||
cpu.port_write(3, 0x00);
|
||||
cpu.port_write(2, 0x00);
|
||||
}
|
||||
if(data & 0x10) {
|
||||
cpu.port_write(1, 0x00);
|
||||
cpu.port_write(0, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
if(timer2.enable == false && (data & 0x04)) {
|
||||
timer2.stage2_ticks = 0;
|
||||
timer2.stage3_ticks = 0;
|
||||
}
|
||||
timer2.enable = data & 0x04;
|
||||
|
||||
if(timer1.enable == false && (data & 0x02)) {
|
||||
timer1.stage2_ticks = 0;
|
||||
timer1.stage3_ticks = 0;
|
||||
}
|
||||
timer1.enable = data & 0x02;
|
||||
|
||||
if(timer0.enable == false && (data & 0x01)) {
|
||||
timer0.stage2_ticks = 0;
|
||||
timer0.stage3_ticks = 0;
|
||||
}
|
||||
timer0.enable = data & 0x01;
|
||||
|
||||
break;
|
||||
|
||||
case 0xf2:
|
||||
status.dsp_addr = data;
|
||||
break;
|
||||
|
||||
case 0xf3:
|
||||
if(status.dsp_addr & 0x80) break;
|
||||
dsp.write(status.dsp_addr, data);
|
||||
break;
|
||||
|
||||
case 0xf4:
|
||||
case 0xf5:
|
||||
case 0xf6:
|
||||
case 0xf7:
|
||||
synchronizeCPU();
|
||||
port_write(addr, data);
|
||||
break;
|
||||
|
||||
case 0xf8:
|
||||
status.ram00f8 = data;
|
||||
break;
|
||||
|
||||
case 0xf9:
|
||||
status.ram00f9 = data;
|
||||
break;
|
||||
|
||||
case 0xfa:
|
||||
timer0.target = data;
|
||||
break;
|
||||
|
||||
case 0xfb:
|
||||
timer1.target = data;
|
||||
break;
|
||||
|
||||
case 0xfc:
|
||||
timer2.target = data;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
#define CYCLE_ACCURATE
|
||||
|
||||
#include <sfc/sfc.hpp>
|
||||
|
||||
#define SMP_CPP
|
||||
namespace SuperFamicom {
|
||||
|
||||
SMP smp;
|
||||
|
||||
#include "algorithms.cpp"
|
||||
#include "core.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "timing.cpp"
|
||||
|
||||
SMP::SMP() {
|
||||
apuram = new uint8[64 * 1024];
|
||||
for(auto& byte : iplrom) byte = 0;
|
||||
}
|
||||
|
||||
auto SMP::synchronizeCPU() -> void {
|
||||
if(CPU::Threaded == true) {
|
||||
//if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
} else {
|
||||
while(clock >= 0) cpu.main();
|
||||
}
|
||||
}
|
||||
|
||||
auto SMP::synchronizeDSP() -> void {
|
||||
if(DSP::Threaded == true) {
|
||||
//if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread);
|
||||
} else {
|
||||
while(dsp.clock < 0) dsp.main();
|
||||
}
|
||||
}
|
||||
|
||||
auto SMP::main() -> void {
|
||||
while(clock < 0) op_step();
|
||||
}
|
||||
|
||||
auto SMP::power() -> void {
|
||||
Thread::frequency = system.apuFrequency();
|
||||
Thread::clock = 0;
|
||||
|
||||
timer0.target = 0;
|
||||
timer1.target = 0;
|
||||
timer2.target = 0;
|
||||
|
||||
for(uint n = 0; n < 256; n++) {
|
||||
cycle_table_dsp[n] = (cycle_count_table[n] * 24);
|
||||
cycle_table_cpu[n] = (cycle_count_table[n] * 24) * cpu.frequency;
|
||||
}
|
||||
|
||||
cycle_step_cpu = 24 * cpu.frequency;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
auto SMP::reset() -> void {
|
||||
for(uint n = 0x0000; n <= 0xffff; n++) apuram[n] = 0x00;
|
||||
|
||||
opcode_number = 0;
|
||||
opcode_cycle = 0;
|
||||
|
||||
regs.pc = 0xffc0;
|
||||
regs.sp = 0xef;
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
regs.p = 0x02;
|
||||
|
||||
//$00f1
|
||||
status.iplrom_enable = true;
|
||||
|
||||
//$00f2
|
||||
status.dsp_addr = 0x00;
|
||||
|
||||
//$00f8,$00f9
|
||||
status.ram00f8 = 0x00;
|
||||
status.ram00f9 = 0x00;
|
||||
|
||||
//timers
|
||||
timer0.enable = timer1.enable = timer2.enable = false;
|
||||
timer0.stage1_ticks = timer1.stage1_ticks = timer2.stage1_ticks = 0;
|
||||
timer0.stage2_ticks = timer1.stage2_ticks = timer2.stage2_ticks = 0;
|
||||
timer0.stage3_ticks = timer1.stage3_ticks = timer2.stage3_ticks = 0;
|
||||
}
|
||||
|
||||
auto SMP::serialize(serializer& s) -> void {
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(apuram, 64 * 1024);
|
||||
|
||||
s.integer(opcode_number);
|
||||
s.integer(opcode_cycle);
|
||||
|
||||
s.integer(regs.pc);
|
||||
s.integer(regs.sp);
|
||||
s.integer(regs.a);
|
||||
s.integer(regs.x);
|
||||
s.integer(regs.y);
|
||||
|
||||
s.integer(regs.p.n);
|
||||
s.integer(regs.p.v);
|
||||
s.integer(regs.p.p);
|
||||
s.integer(regs.p.b);
|
||||
s.integer(regs.p.h);
|
||||
s.integer(regs.p.i);
|
||||
s.integer(regs.p.z);
|
||||
s.integer(regs.p.c);
|
||||
|
||||
s.integer(rd);
|
||||
s.integer(wr);
|
||||
s.integer(dp);
|
||||
s.integer(sp);
|
||||
s.integer(ya);
|
||||
s.integer(bit);
|
||||
|
||||
s.integer(status.iplrom_enable);
|
||||
|
||||
s.integer(status.dsp_addr);
|
||||
|
||||
s.integer(status.ram00f8);
|
||||
s.integer(status.ram00f9);
|
||||
|
||||
s.integer(timer0.enable);
|
||||
s.integer(timer0.target);
|
||||
s.integer(timer0.stage1_ticks);
|
||||
s.integer(timer0.stage2_ticks);
|
||||
s.integer(timer0.stage3_ticks);
|
||||
|
||||
s.integer(timer1.enable);
|
||||
s.integer(timer1.target);
|
||||
s.integer(timer1.stage1_ticks);
|
||||
s.integer(timer1.stage2_ticks);
|
||||
s.integer(timer1.stage3_ticks);
|
||||
|
||||
s.integer(timer2.enable);
|
||||
s.integer(timer2.target);
|
||||
|
||||
s.integer(timer2.stage1_ticks);
|
||||
s.integer(timer2.stage2_ticks);
|
||||
s.integer(timer2.stage3_ticks);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
struct SMP : Thread {
|
||||
enum : bool { Threaded = false };
|
||||
|
||||
SMP();
|
||||
|
||||
alwaysinline auto synchronizeCPU() -> void;
|
||||
alwaysinline auto synchronizeDSP() -> void;
|
||||
|
||||
auto port_read(uint port) -> uint;
|
||||
auto port_write(uint port, unsigned data) -> void;
|
||||
|
||||
auto mmio_read(uint addr) -> uint;
|
||||
auto mmio_write(uint addr, uint data) -> void;
|
||||
|
||||
auto main() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
auto disassemble_opcode(char* output, uint16 addr) -> void;
|
||||
|
||||
uint8 iplrom[64];
|
||||
uint8* apuram;
|
||||
|
||||
//private:
|
||||
auto tick() -> void;
|
||||
alwaysinline auto op_io() -> void;
|
||||
alwaysinline auto op_read(uint16 addr) -> uint8;
|
||||
alwaysinline auto op_write(uint16 addr, uint8 data) -> void;
|
||||
alwaysinline auto op_step() -> void;
|
||||
|
||||
auto op_adc (uint8 x, uint8 y) -> uint8;
|
||||
auto op_addw(uint16 x, uint16 y) -> uint16;
|
||||
auto op_and (uint8 x, uint8 y) -> uint8;
|
||||
auto op_cmp (uint8 x, uint8 y) -> uint8;
|
||||
auto op_cmpw(uint16 x, uint16 y) -> uint16;
|
||||
auto op_eor (uint8 x, uint8 y) -> uint8;
|
||||
auto op_inc (uint8 x) -> uint8;
|
||||
auto op_dec (uint8 x) -> uint8;
|
||||
auto op_or (uint8 x, uint8 y) -> uint8;
|
||||
auto op_sbc (uint8 x, uint8 y) -> uint8;
|
||||
auto op_subw(uint16 x, uint16 y) -> uint16;
|
||||
auto op_asl (uint8 x) -> uint8;
|
||||
auto op_lsr (uint8 x) -> uint8;
|
||||
auto op_rol (uint8 x) -> uint8;
|
||||
auto op_ror (uint8 x) -> uint8;
|
||||
|
||||
struct Flags {
|
||||
alwaysinline operator uint() const {
|
||||
return (n << 7) | (v << 6) | (p << 5) | (b << 4)
|
||||
| (h << 3) | (i << 2) | (z << 1) | (c << 0);
|
||||
};
|
||||
|
||||
alwaysinline auto operator=(uint data) -> uint {
|
||||
n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10;
|
||||
h = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
|
||||
return data;
|
||||
}
|
||||
|
||||
alwaysinline auto operator|=(uint data) -> uint { return operator=(operator uint() | data); }
|
||||
alwaysinline auto operator^=(uint data) -> uint { return operator=(operator uint() ^ data); }
|
||||
alwaysinline auto operator&=(uint data) -> uint { return operator=(operator uint() & data); }
|
||||
|
||||
bool n, v, p, b, h, i, z, c;
|
||||
};
|
||||
|
||||
struct Regs {
|
||||
uint16 pc;
|
||||
uint8 sp;
|
||||
union {
|
||||
uint16_t ya;
|
||||
struct { uint8_t order_lsb2(a, y); };
|
||||
};
|
||||
uint8 x;
|
||||
Flags p;
|
||||
} regs;
|
||||
|
||||
uint16 rd, wr, dp, sp, ya, bit;
|
||||
|
||||
struct Status {
|
||||
//$00f1
|
||||
bool iplrom_enable;
|
||||
|
||||
//$00f2
|
||||
uint dsp_addr;
|
||||
|
||||
//$00f8,$00f9
|
||||
uint ram00f8;
|
||||
uint ram00f9;
|
||||
} status;
|
||||
|
||||
uint opcode_number;
|
||||
uint opcode_cycle;
|
||||
|
||||
template<uint frequency>
|
||||
struct Timer {
|
||||
auto tick() -> void;
|
||||
auto tick(uint clocks) -> void;
|
||||
|
||||
bool enable;
|
||||
uint8 target;
|
||||
uint8 stage1_ticks;
|
||||
uint8 stage2_ticks;
|
||||
uint8 stage3_ticks;
|
||||
};
|
||||
|
||||
Timer<128> timer0;
|
||||
Timer<128> timer1;
|
||||
Timer< 16> timer2;
|
||||
|
||||
static const uint cycle_count_table[256];
|
||||
uint64 cycle_table_cpu[256];
|
||||
uint cycle_table_dsp[256];
|
||||
uint64 cycle_step_cpu;
|
||||
};
|
||||
|
||||
extern SMP smp;
|
|
@ -1,26 +0,0 @@
|
|||
template<uint cycle_frequency>
|
||||
auto SMP::Timer<cycle_frequency>::tick() -> void {
|
||||
if(++stage1_ticks < cycle_frequency) return;
|
||||
|
||||
stage1_ticks = 0;
|
||||
if(enable == false) return;
|
||||
|
||||
if(++stage2_ticks != target) return;
|
||||
|
||||
stage2_ticks = 0;
|
||||
stage3_ticks = (stage3_ticks + 1) & 15;
|
||||
}
|
||||
|
||||
template<uint cycle_frequency>
|
||||
auto SMP::Timer<cycle_frequency>::tick(uint clocks) -> void {
|
||||
stage1_ticks += clocks;
|
||||
if(stage1_ticks < cycle_frequency) return;
|
||||
|
||||
stage1_ticks -= cycle_frequency;
|
||||
if(enable == false) return;
|
||||
|
||||
if(++stage2_ticks != target) return;
|
||||
|
||||
stage2_ticks = 0;
|
||||
stage3_ticks = (stage3_ticks + 1) & 15;
|
||||
}
|
|
@ -24,19 +24,6 @@ auto Controller::main() -> void {
|
|||
step(1);
|
||||
}
|
||||
|
||||
auto Controller::step(uint clocks) -> void {
|
||||
clock += clocks * (uint64)cpu.frequency;
|
||||
synchronizeCPU();
|
||||
}
|
||||
|
||||
auto Controller::synchronizeCPU() -> void {
|
||||
if(CPU::Threaded) {
|
||||
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
||||
} else {
|
||||
while(clock >= 0) cpu.main();
|
||||
}
|
||||
}
|
||||
|
||||
auto Controller::iobit() -> bool {
|
||||
switch(port) {
|
||||
case Controller::Port1: return cpu.pio() & 0x40;
|
||||
|
|
|
@ -11,17 +11,13 @@
|
|||
// 6: iobit $4201.d6 write; $4213.d6 read $4201.d7 write; $4213.d7 read
|
||||
// 7: gnd
|
||||
|
||||
struct Controller : Thread {
|
||||
struct Controller : Cothread {
|
||||
enum : bool { Port1 = 0, Port2 = 1 };
|
||||
|
||||
Controller(bool port);
|
||||
|
||||
static auto Enter() -> void;
|
||||
|
||||
virtual auto main() -> void;
|
||||
|
||||
auto step(uint clocks) -> void;
|
||||
auto synchronizeCPU() -> void;
|
||||
|
||||
auto iobit() -> bool;
|
||||
auto iobit(bool data) -> void;
|
||||
virtual auto data() -> uint2 { return 0; }
|
||||
|
|
|
@ -50,7 +50,7 @@ auto ArmDSP::main() -> void {
|
|||
|
||||
auto ArmDSP::step(uint clocks) -> void {
|
||||
if(bridge.timer && --bridge.timer == 0);
|
||||
Coprocessor::step(clocks);
|
||||
Cothread::step(clocks);
|
||||
synchronizeCPU();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//ARMv3 (ARM60)
|
||||
|
||||
struct ArmDSP : Processor::ARM, Coprocessor {
|
||||
struct ArmDSP : Processor::ARM, Cothread {
|
||||
#include "registers.hpp"
|
||||
|
||||
ArmDSP();
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
struct Coprocessor : Thread {
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto synchronizeCPU() -> void;
|
||||
};
|
||||
|
||||
#include <sfc/coprocessor/icd2/icd2.hpp>
|
||||
#include <sfc/coprocessor/mcc/mcc.hpp>
|
||||
#include <sfc/coprocessor/nss/nss.hpp>
|
||||
|
@ -23,11 +18,3 @@ struct Coprocessor : Thread {
|
|||
#include <sfc/coprocessor/obc1/obc1.hpp>
|
||||
|
||||
#include <sfc/coprocessor/msu1/msu1.hpp>
|
||||
|
||||
auto Coprocessor::step(uint clocks) -> void {
|
||||
clock += clocks * (uint64)cpu.frequency;
|
||||
}
|
||||
|
||||
auto Coprocessor::synchronizeCPU() -> void {
|
||||
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//Epson RTC-4513 Real-Time Clock
|
||||
|
||||
struct EpsonRTC : Coprocessor {
|
||||
struct EpsonRTC : Cothread {
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//* Campus Challenge '92
|
||||
//* Powerfest '94
|
||||
|
||||
struct Event : Coprocessor {
|
||||
struct Event : Cothread {
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto init() -> void;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct HitachiDSP : Processor::HG51B, Coprocessor {
|
||||
struct HitachiDSP : Processor::HG51B, Cothread {
|
||||
MappedRAM rom;
|
||||
MappedRAM ram;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#if defined(SFC_SUPERGAMEBOY)
|
||||
|
||||
struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Coprocessor {
|
||||
struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Cothread {
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct MSU1 : Coprocessor {
|
||||
struct MSU1 : Cothread {
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto init() -> void;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct NECDSP : Processor::uPD96050, Coprocessor {
|
||||
struct NECDSP : Processor::uPD96050, Cothread {
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue