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:
Tim Allen 2016-04-09 13:40:12 +10:00
parent aff00506c5
commit 19e1d89f00
146 changed files with 151 additions and 18013 deletions

View File

@ -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

5
higan/audio/audio.cpp Normal file
View File

@ -0,0 +1,5 @@
#include <emulator/emulator.hpp>
namespace {
}

7
higan/audio/audio.hpp Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include "core.hpp"
namespace {
}

View File

@ -1,3 +0,0 @@
objects += emulator
obj/emulator.o: emulator/emulator.cpp $(call rwildcard,emulator/)

View File

@ -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"

View File

@ -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/)

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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];
}

View File

@ -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));
}

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}
}
}
}

View File

@ -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;
};

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
};

View File

@ -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();
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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));
}
}

View File

@ -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;
};

View File

@ -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;
}
}
}

View File

@ -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];
};

View File

@ -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;
}

View File

@ -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
};

View File

@ -1 +0,0 @@
g++-4.5 -std=gnu++0x -I../../../.. -o generate generate.cpp

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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; }

View File

@ -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();
}

View File

@ -1,6 +1,6 @@
//ARMv3 (ARM60)
struct ArmDSP : Processor::ARM, Coprocessor {
struct ArmDSP : Processor::ARM, Cothread {
#include "registers.hpp"
ArmDSP();

View File

@ -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);
}

View File

@ -1,6 +1,6 @@
//Epson RTC-4513 Real-Time Clock
struct EpsonRTC : Coprocessor {
struct EpsonRTC : Cothread {
static auto Enter() -> void;
auto main() -> void;

View File

@ -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;

View File

@ -1,4 +1,4 @@
struct HitachiDSP : Processor::HG51B, Coprocessor {
struct HitachiDSP : Processor::HG51B, Cothread {
MappedRAM rom;
MappedRAM ram;

View File

@ -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;

View File

@ -1,4 +1,4 @@
struct MSU1 : Coprocessor {
struct MSU1 : Cothread {
static auto Enter() -> void;
auto main() -> void;
auto init() -> void;

View File

@ -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