Remove (old) BSNES' unmanaged source and the binary

This commit is contained in:
YoshiRulz 2025-01-11 01:14:27 +10:00
parent 3cc3440f22
commit 86ea977dd7
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
442 changed files with 0 additions and 62765 deletions

View File

@ -88,7 +88,6 @@ jobs:
Assets/dll/faust.wbx.zst
Assets/dll/gpgx.wbx.zst
Assets/dll/hyper.wbx.zst
Assets/dll/libsnes.wbx.zst
Assets/dll/melonDS.wbx.zst
Assets/dll/ngp.wbx.zst
Assets/dll/pcfx.wbx.zst

Binary file not shown.

View File

View File

@ -1,63 +0,0 @@
NEED_LIBCO := 1
#-DPROFILE_PERFORMANCE
CXXFLAGS := -DHOOKS -DBIZHAWK -DPROFILE_COMPATIBILITY -DGAMEBOY \
-D_GNU_SOURCE \
-Werror=int-to-pointer-cast \
-I../libco -I./bsnes \
-Wno-parentheses -Wno-sign-compare -Wno-unused-variable -Wno-unused-function \
-Wno-switch -Wno-switch-bool -Wno-reorder -Wno-return-type -Wno-bool-operation \
-Wno-mismatched-tags -Wno-delete-non-virtual-dtor \
-fno-threadsafe-statics \
-std=gnu++17
TARGET = libsnes.wbx
SRCS_PERF = \
$(ROOT_DIR)/bsnes/snes/alt/cpu/cpu.cpp \
$(ROOT_DIR)/bsnes/snes/alt/ppu-performance/ppu.cpp \
$(ROOT_DIR)/bsnes/snes/alt/smp/smp.cpp
SRCS_COMPAT = \
$(ROOT_DIR)/bsnes/snes/alt/ppu-compatibility/ppu.cpp \
$(ROOT_DIR)/bsnes/snes/cpu/cpu.cpp \
$(ROOT_DIR)/bsnes/snes/smp/smp.cpp
SRCS_ALL = \
$(ROOT_DIR)/bsnes/base/base.cpp \
$(ROOT_DIR)/bsnes/gameboy/apu/apu.cpp \
$(ROOT_DIR)/bsnes/gameboy/cartridge/cartridge.cpp \
$(ROOT_DIR)/bsnes/gameboy/cpu/cpu.cpp \
$(ROOT_DIR)/bsnes/snes/alt/dsp/dsp.cpp \
$(ROOT_DIR)/bsnes/gameboy/interface/interface.cpp \
$(ROOT_DIR)/bsnes/gameboy/lcd/lcd.cpp \
$(ROOT_DIR)/bsnes/gameboy/memory/memory.cpp \
$(ROOT_DIR)/bsnes/gameboy/scheduler/scheduler.cpp \
$(ROOT_DIR)/bsnes/gameboy/system/system.cpp \
$(ROOT_DIR)/bsnes/gameboy/video/video.cpp \
$(ROOT_DIR)/bsnes/snes/cartridge/cartridge.cpp \
$(ROOT_DIR)/bsnes/snes/chip/armdsp/armdsp.cpp \
$(ROOT_DIR)/bsnes/snes/chip/bsx/bsx.cpp \
$(ROOT_DIR)/bsnes/snes/chip/hitachidsp/hitachidsp.cpp \
$(ROOT_DIR)/bsnes/snes/chip/icd2/icd2.cpp \
$(ROOT_DIR)/bsnes/snes/chip/link/link.cpp \
$(ROOT_DIR)/bsnes/snes/chip/msu1/msu1.cpp \
$(ROOT_DIR)/bsnes/snes/chip/necdsp/necdsp.cpp \
$(ROOT_DIR)/bsnes/snes/chip/nss/nss.cpp \
$(ROOT_DIR)/bsnes/snes/chip/obc1/obc1.cpp \
$(ROOT_DIR)/bsnes/snes/chip/sa1/sa1.cpp \
$(ROOT_DIR)/bsnes/snes/chip/sdd1/sdd1.cpp \
$(ROOT_DIR)/bsnes/snes/chip/spc7110/spc7110.cpp \
$(ROOT_DIR)/bsnes/snes/chip/srtc/srtc.cpp \
$(ROOT_DIR)/bsnes/snes/chip/sufamiturbo/sufamiturbo.cpp \
$(ROOT_DIR)/bsnes/snes/chip/superfx/superfx.cpp \
$(ROOT_DIR)/bsnes/snes/config/config.cpp \
$(ROOT_DIR)/bsnes/snes/controller/controller.cpp \
$(ROOT_DIR)/bsnes/snes/cpu/core/core.cpp \
$(ROOT_DIR)/bsnes/snes/interface/interface.cpp \
$(ROOT_DIR)/bsnes/snes/memory/memory.cpp \
$(ROOT_DIR)/bsnes/snes/smp/core/core.cpp \
$(ROOT_DIR)/bsnes/snes/system/system.cpp \
$(ROOT_DIR)/bsnes/target-libsnes/libsnes.cpp \
$(ROOT_DIR)/bsnes/target-libsnes/libsnes_pwrap.cpp
SRCS = $(SRCS_ALL) $(SRCS_COMPAT)
include ../common.mak

View File

@ -1,12 +0,0 @@
#include "base.hpp"
#include "snes/snes.hpp"
CDLInfo cdlInfo;
void CDLInfo::dorom(uint32_t addr)
{
blocks[eCDLog_AddrType_CARTROM_DB][addr] = SNES::cpu.regs.db;
blocks[eCDLog_AddrType_CARTROM_D][addr*2+0] = SNES::cpu.regs.d;
blocks[eCDLog_AddrType_CARTROM_D][addr*2+1] = SNES::cpu.regs.d>>8;
}

View File

@ -1,169 +0,0 @@
#ifndef BASE_HPP
#define BASE_HPP
const char Version[] = "087";
#include <nall/platform.hpp>
#include <nall/algorithm.hpp>
#include <nall/any.hpp>
#include <nall/array.hpp>
#include <nall/dl.hpp>
#include <nall/dsp.hpp>
#include <nall/endian.hpp>
#include <nall/file.hpp>
#include <nall/function.hpp>
#include <nall/moduloarray.hpp>
#include <nall/priorityqueue.hpp>
#include <nall/property.hpp>
#include <nall/random.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#include <nall/varint.hpp>
#include <nall/vector.hpp>
using namespace nall;
//debugging function hook:
//no overhead (and no debugger invocation) if not compiled with -DDEBUGGER
//wraps testing of function to allow invocation without a defined callback
template<typename T> struct hook;
template<typename R, typename... P> struct hook<R (P...)> {
function<R (P...)> callback;
R operator()(P... p) const {
#if defined(DEBUGGER) || defined(HOOKS)
if(callback) return callback(std::forward<P>(p)...);
#endif
return R();
}
hook() {}
hook(const hook &hook) { callback = hook.callback; }
hook(void *function) { callback = function; }
hook(R (*function)(P...)) { callback = function; }
template<typename C> hook(R (C::*function)(P...), C *object) { callback = { function, object }; }
template<typename C> hook(R (C::*function)(P...) const, C *object) { callback = { function, object }; }
template<typename L> hook(const L& function) { callback = function; }
hook& operator=(const hook& hook) { callback = hook.callback; return *this; }
};
#if defined(DEBUGGER)
#define privileged public
#else
#define privileged private
#endif
enum eCDLog_AddrType
{
eCDLog_AddrType_CARTROM, eCDLog_AddrType_CARTROM_DB, eCDLog_AddrType_CARTROM_D, eCDLog_AddrType_CARTRAM, eCDLog_AddrType_WRAM, eCDLog_AddrType_APURAM,
eCDLog_AddrType_SGB_CARTROM, eCDLog_AddrType_SGB_CARTRAM, eCDLog_AddrType_SGB_WRAM, eCDLog_AddrType_SGB_HRAM,
eCDLog_AddrType_NUM
};
enum eCDLog_Flags
{
eCDLog_Flags_None = 0x00,
eCDLog_Flags_ExecFirst = 0x01,
eCDLog_Flags_ExecOperand = 0x02,
eCDLog_Flags_CPUData = 0x04,
eCDLog_Flags_DMAData = 0x08,
eCDLog_Flags_CPUXFlag = 0x10, //these values are picky, don't change them
eCDLog_Flags_CPUMFlag = 0x20, //these values are picky, don't change them
eCDLog_Flags_BRR = 0x80
};
struct CDLInfo
{
eCDLog_Flags currFlags;
uint8_t* blocks[16]; //[0]==nullptr -> disabled
uint32_t blockSizes[16];
void set(eCDLog_AddrType addrType, uint32_t addr)
{
if(!blocks[0]) return;
if(addr >= blockSizes[addrType])
return;
blocks[addrType][addr] |= currFlags;
if(addrType == eCDLog_AddrType_CARTROM)
{
dorom(addr);
}
}
void dorom(uint32_t addr);
};
extern CDLInfo cdlInfo;
inline bool wantCDL() { return cdlInfo.blocks[0] != nullptr; }
typedef int1_t int1;
typedef int2_t int2;
typedef int3_t int3;
typedef int4_t int4;
typedef int5_t int5;
typedef int6_t int6;
typedef int7_t int7;
typedef int8_t int8;
typedef int9_t int9;
typedef int10_t int10;
typedef int11_t int11;
typedef int12_t int12;
typedef int13_t int13;
typedef int14_t int14;
typedef int15_t int15;
typedef int16_t int16;
typedef int17_t int17;
typedef int18_t int18;
typedef int19_t int19;
typedef int20_t int20;
typedef int21_t int21;
typedef int22_t int22;
typedef int23_t int23;
typedef int24_t int24;
typedef int25_t int25;
typedef int26_t int26;
typedef int27_t int27;
typedef int28_t int28;
typedef int29_t int29;
typedef int30_t int30;
typedef int31_t int31;
typedef int32_t int32;
typedef int64_t int64;
typedef uint1_t uint1;
typedef uint2_t uint2;
typedef uint3_t uint3;
typedef uint4_t uint4;
typedef uint5_t uint5;
typedef uint6_t uint6;
typedef uint7_t uint7;
typedef uint8_t uint8;
typedef uint9_t uint9;
typedef uint10_t uint10;
typedef uint11_t uint11;
typedef uint12_t uint12;
typedef uint13_t uint13;
typedef uint14_t uint14;
typedef uint15_t uint15;
typedef uint16_t uint16;
typedef uint17_t uint17;
typedef uint18_t uint18;
typedef uint19_t uint19;
typedef uint20_t uint20;
typedef uint21_t uint21;
typedef uint22_t uint22;
typedef uint23_t uint23;
typedef uint24_t uint24;
typedef uint25_t uint25;
typedef uint26_t uint26;
typedef uint27_t uint27;
typedef uint28_t uint28;
typedef uint29_t uint29;
typedef uint30_t uint30;
typedef uint31_t uint31;
typedef uint32_t uint32;
typedef uint_t<33> uint33;
typedef uint64_t uint64;
typedef varuint_t varuint;
#endif

View File

@ -1,106 +0,0 @@
#include <gameboy/gameboy.hpp>
#define APU_CPP
namespace GameBoy {
#include "square1/square1.cpp"
#include "square2/square2.cpp"
#include "wave/wave.cpp"
#include "noise/noise.cpp"
#include "master/master.cpp"
APU apu;
void APU::Main() {
apu.main();
}
void APU::main() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
if(sequencer_base == 0) { //512hz
if(sequencer_step == 0 || sequencer_step == 2 || sequencer_step == 4 || sequencer_step == 6) { //256hz
square1.clock_length();
square2.clock_length();
wave.clock_length();
noise.clock_length();
}
if(sequencer_step == 2 || sequencer_step == 6) { //128hz
square1.clock_sweep();
}
if(sequencer_step == 7) { //64hz
square1.clock_envelope();
square2.clock_envelope();
noise.clock_envelope();
}
sequencer_step++;
}
sequencer_base++;
square1.run();
square2.run();
wave.run();
noise.run();
master.run();
interface->audioSample(master.center, master.left, master.right);
clock += 1 * cpu.frequency;
if(clock >= 0) co_switch(scheduler.active_thread = cpu.thread);
}
}
void APU::power() {
create(Main, 4 * 1024 * 1024);
for(unsigned n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
for(auto &n : mmio_data) n = 0x00;
sequencer_base = 0;
sequencer_step = 0;
square1.power();
square2.power();
wave.power();
noise.power();
master.power();
}
uint8 APU::mmio_read(uint16 addr) {
static const uint8 table[48] = {
0x80, 0x3f, 0x00, 0xff, 0xbf, //square1
0xff, 0x3f, 0x00, 0xff, 0xbf, //square2
0x7f, 0xff, 0x9f, 0xff, 0xbf, //wave
0xff, 0xff, 0x00, 0x00, 0xbf, //noise
0x00, 0x00, 0x70, //master
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //unmapped
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
};
if(addr == 0xff26) {
uint8 data = master.enable << 7;
if(square1.enable) data |= 0x01;
if(square2.enable) data |= 0x02;
if( wave.enable) data |= 0x04;
if( noise.enable) data |= 0x08;
return data | table[addr - 0xff10];
}
if(addr >= 0xff10 && addr <= 0xff3f) return mmio_data[addr - 0xff10] | table[addr - 0xff10];
return 0xff;
}
void APU::mmio_write(uint16 addr, uint8 data) {
if(addr >= 0xff10 && addr <= 0xff3f) mmio_data[addr - 0xff10] = data;
if(addr >= 0xff10 && addr <= 0xff14) return square1.write (addr - 0xff10, data);
if(addr >= 0xff15 && addr <= 0xff19) return square2.write (addr - 0xff15, data);
if(addr >= 0xff1a && addr <= 0xff1e) return wave.write (addr - 0xff1a, data);
if(addr >= 0xff1f && addr <= 0xff23) return noise.write (addr - 0xff1f, data);
if(addr >= 0xff24 && addr <= 0xff26) return master.write (addr - 0xff24, data);
if(addr >= 0xff30 && addr <= 0xff3f) return wave.write_pattern(addr - 0xff30, data);
}
}

View File

@ -1,26 +0,0 @@
struct APU : Processor, MMIO {
#include "square1/square1.hpp"
#include "square2/square2.hpp"
#include "wave/wave.hpp"
#include "noise/noise.hpp"
#include "master/master.hpp"
uint8 mmio_data[48];
uint13 sequencer_base;
uint3 sequencer_step;
Square1 square1;
Square2 square2;
Wave wave;
Noise noise;
Master master;
static void Main();
void main();
void power();
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
};
extern APU apu;

View File

@ -1,99 +0,0 @@
#ifdef APU_CPP
void APU::Master::run() {
if(enable == false) {
center = 0;
left = 0;
right = 0;
return;
}
signed sample = 0;
sample += apu.square1.output;
sample += apu.square2.output;
sample += apu.wave.output;
sample += apu.noise.output;
center = (sample * 512) - 16384;
sample = 0;
if(channel1_left_enable) sample += apu.square1.output;
if(channel2_left_enable) sample += apu.square2.output;
if(channel3_left_enable) sample += apu.wave.output;
if(channel4_left_enable) sample += apu.noise.output;
left = (sample * 512) - 16384;
switch(left_volume) {
case 0: left >>= 3; break; // 12.5%
case 1: left >>= 2; break; // 25.0%
case 2: left = (left >> 2) + (left >> 3); break; // 37.5%
case 3: left >>= 1; break; // 50.0%
case 4: left = (left >> 1) + (left >> 3); break; // 62.5%
case 5: left -= (left >> 2); break; // 75.0%
case 6: left -= (left >> 3); break; // 87.5%
//case 7: break; //100.0%
}
sample = 0;
if(channel1_right_enable) sample += apu.square1.output;
if(channel2_right_enable) sample += apu.square2.output;
if(channel3_right_enable) sample += apu.wave.output;
if(channel4_right_enable) sample += apu.noise.output;
right = (sample * 512) - 16384;
switch(right_volume) {
case 0: right >>= 3; break; // 12.5%
case 1: right >>= 2; break; // 25.0%
case 2: right = (right >> 2) + (right >> 3); break; // 37.5%
case 3: right >>= 1; break; // 50.0%
case 4: right = (right >> 1) + (right >> 3); break; // 62.5%
case 5: right -= (right >> 2); break; // 75.0%
case 6: right -= (right >> 3); break; // 87.5%
//case 7: break; //100.0%
}
}
void APU::Master::write(unsigned r, uint8 data) {
if(r == 0) { //$ff24 NR50
left_in_enable = data & 0x80;
left_volume = (data >> 4) & 7;
right_in_enable = data & 0x08;
right_volume = (data >> 0) & 7;
}
if(r == 1) { //$ff25 NR51
channel4_left_enable = data & 0x80;
channel3_left_enable = data & 0x40;
channel2_left_enable = data & 0x20;
channel1_left_enable = data & 0x10;
channel4_right_enable = data & 0x08;
channel3_right_enable = data & 0x04;
channel2_right_enable = data & 0x02;
channel1_right_enable = data & 0x01;
}
if(r == 2) { //$ff26 NR52
enable = data & 0x80;
}
}
void APU::Master::power() {
left_in_enable = 0;
left_volume = 0;
right_in_enable = 0;
right_volume = 0;
channel4_left_enable = 0;
channel3_left_enable = 0;
channel2_left_enable = 0;
channel1_left_enable = 0;
channel4_right_enable = 0;
channel3_right_enable = 0;
channel2_right_enable = 0;
channel1_right_enable = 0;
enable = 0;
center = 0;
left = 0;
right = 0;
}
#endif

View File

@ -1,23 +0,0 @@
struct Master {
bool left_in_enable;
uint3 left_volume;
bool right_in_enable;
uint3 right_volume;
bool channel4_left_enable;
bool channel3_left_enable;
bool channel2_left_enable;
bool channel1_left_enable;
bool channel4_right_enable;
bool channel3_right_enable;
bool channel2_right_enable;
bool channel1_right_enable;
bool enable;
int16 center;
int16 left;
int16 right;
void run();
void write(unsigned r, uint8 data);
void power();
};

View File

@ -1,89 +0,0 @@
#ifdef APU_CPP
bool APU::Noise::dac_enable() {
return (envelope_volume || envelope_direction);
}
void APU::Noise::run() {
if(period && --period == 0) {
period = divisor << frequency;
if(frequency < 14) {
bool bit = (lfsr ^ (lfsr >> 1)) & 1;
lfsr = (lfsr >> 1) ^ (bit << (narrow_lfsr ? 6 : 14));
}
}
uint4 sample = (lfsr & 1) ? (uint4)0 : volume;
if(enable == false) sample = 0;
output = sample;
}
void APU::Noise::clock_length() {
if(counter && length) {
if(--length == 0) enable = false;
}
}
void APU::Noise::clock_envelope() {
if(enable && envelope_frequency && --envelope_period == 0) {
envelope_period = envelope_frequency;
if(envelope_direction == 0 && volume > 0) volume--;
if(envelope_direction == 1 && volume < 15) volume++;
}
}
void APU::Noise::write(unsigned r, uint8 data) {
if(r == 1) { //$ff20 NR41
length = 64 - (data & 0x3f);
}
if(r == 2) { //$ff21 NR42
envelope_volume = data >> 4;
envelope_direction = data & 0x08;
envelope_frequency = data & 0x07;
if(dac_enable() == false) enable = false;
}
if(r == 3) { //$ff22 NR43
frequency = data >> 4;
narrow_lfsr = data & 0x08;
divisor = (data & 0x07) << 4;
if(divisor == 0) divisor = 8;
period = divisor << frequency;
}
if(r == 4) { //$ff34 NR44
bool initialize = data & 0x80;
counter = data & 0x40;
if(initialize) {
enable = dac_enable();
lfsr = ~0U;
envelope_period = envelope_frequency;
volume = envelope_volume;
if(length == 0) length = 64;
}
}
}
void APU::Noise::power() {
enable = 0;
envelope_volume = 0;
envelope_direction = 0;
envelope_frequency = 0;
frequency = 0;
narrow_lfsr = 0;
divisor = 0;
counter = 0;
output = 0;
length = 0;
envelope_period = 0;
volume = 0;
period = 0;
lfsr = 0;
}
#endif

View File

@ -1,26 +0,0 @@
struct Noise {
bool enable;
uint4 envelope_volume;
bool envelope_direction;
uint3 envelope_frequency;
uint4 frequency;
bool narrow_lfsr;
unsigned divisor;
bool counter;
int16 output;
unsigned length;
uint3 envelope_period;
uint4 volume;
unsigned period;
uint15 lfsr;
bool dac_enable();
void run();
void clock_length();
void clock_envelope();
void write(unsigned r, uint8 data);
void power();
};

View File

@ -1,134 +0,0 @@
#ifdef APU_CPP
bool APU::Square1::dac_enable() {
return (envelope_volume || envelope_direction);
}
void APU::Square1::run() {
if(period && --period == 0) {
period = 4 * (2048 - frequency);
phase++;
switch(duty) {
case 0: duty_output = (phase == 6); break; //______-_
case 1: duty_output = (phase >= 6); break; //______--
case 2: duty_output = (phase >= 4); break; //____----
case 3: duty_output = (phase <= 5); break; //------__
}
}
uint4 sample = (duty_output ? volume : (uint4)0);
if(enable == false) sample = 0;
output = sample;
}
void APU::Square1::sweep(bool update) {
if(sweep_enable == false) return;
sweep_negate = sweep_direction;
unsigned delta = frequency_shadow >> sweep_shift;
signed freq = frequency_shadow + (sweep_negate ? -delta : delta);
if(freq > 2047) {
enable = false;
} else if(sweep_shift && update) {
frequency_shadow = freq;
frequency = freq & 2047;
period = 4 * (2048 - frequency);
}
}
void APU::Square1::clock_length() {
if(counter && length) {
if(--length == 0) enable = false;
}
}
void APU::Square1::clock_sweep() {
if(enable && sweep_frequency && --sweep_period == 0) {
sweep_period = sweep_frequency;
sweep(1);
sweep(0);
}
}
void APU::Square1::clock_envelope() {
if(enable && envelope_frequency && --envelope_period == 0) {
envelope_period = envelope_frequency;
if(envelope_direction == 0 && volume > 0) volume--;
if(envelope_direction == 1 && volume < 15) volume++;
}
}
void APU::Square1::write(unsigned r, uint8 data) {
if(r == 0) { //$ff10 NR10
if(sweep_negate && sweep_direction && !(data & 0x08)) enable = false;
sweep_frequency = (data >> 4) & 7;
sweep_direction = data & 0x08;
sweep_shift = data & 0x07;
}
if(r == 1) { //$ff11 NR11
duty = data >> 6;
length = 64 - (data & 0x3f);
}
if(r == 2) { //$ff12 NR12
envelope_volume = data >> 4;
envelope_direction = data & 0x08;
envelope_frequency = data & 0x07;
if(dac_enable() == false) enable = false;
}
if(r == 3) { //$ff13 NR13
frequency = (frequency & 0x0700) | data;
}
if(r == 4) { //$ff14 NR14
bool initialize = data & 0x80;
counter = data & 0x40;
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
if(initialize) {
enable = dac_enable();
envelope_period = envelope_frequency;
volume = envelope_volume;
frequency_shadow = frequency;
sweep_period = sweep_frequency;
sweep_enable = sweep_period || sweep_shift;
sweep_negate = false;
if(sweep_shift) sweep(0);
if(length == 0) length = 64;
}
}
period = 4 * (2048 - frequency);
}
void APU::Square1::power() {
enable = 0;
sweep_frequency = 0;
sweep_direction = 0;
sweep_shift = 0;
sweep_negate = 0;
duty = 0;
length = 0;
envelope_volume = 0;
envelope_direction = 0;
envelope_frequency = 0;
frequency = 0;
counter = 0;
output = 0;
duty_output = 0;
phase = 0;
period = 0;
envelope_period = 0;
sweep_period = 0;
frequency_shadow = 0;
sweep_enable = 0;
volume = 0;
}
#endif

View File

@ -1,35 +0,0 @@
struct Square1 {
bool enable;
uint3 sweep_frequency;
bool sweep_direction;
uint3 sweep_shift;
bool sweep_negate;
uint2 duty;
unsigned length;
uint4 envelope_volume;
bool envelope_direction;
uint3 envelope_frequency;
uint11 frequency;
bool counter;
int16 output;
bool duty_output;
uint3 phase;
unsigned period;
uint3 envelope_period;
uint3 sweep_period;
signed frequency_shadow;
bool sweep_enable;
uint4 volume;
bool dac_enable();
void run();
void sweep(bool update);
void clock_length();
void clock_sweep();
void clock_envelope();
void write(unsigned r, uint8 data);
void power();
};

View File

@ -1,91 +0,0 @@
#ifdef APU_CPP
bool APU::Square2::dac_enable() {
return (envelope_volume || envelope_direction);
}
void APU::Square2::run() {
if(period && --period == 0) {
period = 4 * (2048 - frequency);
phase++;
switch(duty) {
case 0: duty_output = (phase == 6); break; //______-_
case 1: duty_output = (phase >= 6); break; //______--
case 2: duty_output = (phase >= 4); break; //____----
case 3: duty_output = (phase <= 5); break; //------__
}
}
uint4 sample = (duty_output ? volume : (uint4)0);
if(enable == false) sample = 0;
output = sample;
}
void APU::Square2::clock_length() {
if(counter && length) {
if(--length == 0) enable = false;
}
}
void APU::Square2::clock_envelope() {
if(enable && envelope_frequency && --envelope_period == 0) {
envelope_period = envelope_frequency;
if(envelope_direction == 0 && volume > 0) volume--;
if(envelope_direction == 1 && volume < 15) volume++;
}
}
void APU::Square2::write(unsigned r, uint8 data) {
if(r == 1) { //$ff16 NR21
duty = data >> 6;
length = 64 - (data & 0x3f);
}
if(r == 2) { //$ff17 NR22
envelope_volume = data >> 4;
envelope_direction = data & 0x08;
envelope_frequency = data & 0x07;
if(dac_enable() == false) enable = false;
}
if(r == 3) { //$ff18 NR23
frequency = (frequency & 0x0700) | data;
}
if(r == 4) { //$ff19 NR24
bool initialize = data & 0x80;
counter = data & 0x40;
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
if(initialize) {
enable = dac_enable();
envelope_period = envelope_frequency;
volume = envelope_volume;
if(length == 0) length = 64;
}
}
period = 4 * (2048 - frequency);
}
void APU::Square2::power() {
enable = 0;
duty = 0;
length = 0;
envelope_volume = 0;
envelope_direction = 0;
envelope_frequency = 0;
frequency = 0;
counter = 0;
output = 0;
duty_output = 0;
phase = 0;
period = 0;
envelope_period = 0;
volume = 0;
}
#endif

View File

@ -1,26 +0,0 @@
struct Square2 {
bool enable;
uint2 duty;
unsigned length;
uint4 envelope_volume;
bool envelope_direction;
uint3 envelope_frequency;
uint11 frequency;
bool counter;
int16 output;
bool duty_output;
uint3 phase;
unsigned period;
uint3 envelope_period;
uint4 volume;
bool dac_enable();
void run();
void clock_length();
void clock_envelope();
void write(unsigned r, uint8 data);
void power();
};

View File

@ -1,83 +0,0 @@
#ifdef APU_CPP
void APU::Wave::run() {
if(period && --period == 0) {
period = 2 * (2048 - frequency);
pattern_sample = pattern[++pattern_offset];
}
uint4 sample = pattern_sample >> volume_shift;
if(enable == false) sample = 0;
output = sample;
}
void APU::Wave::clock_length() {
if(counter && length) {
if(--length == 0) enable = false;
}
}
void APU::Wave::write(unsigned r, uint8 data) {
if(r == 0) { //$ff1a NR30
dac_enable = data & 0x80;
if(dac_enable == false) enable = false;
}
if(r == 1) { //$ff1b NR31
length = 256 - data;
}
if(r == 2) { //$ff1c NR32
switch((data >> 5) & 3) {
case 0: volume_shift = 4; break; // 0%
case 1: volume_shift = 0; break; //100%
case 2: volume_shift = 1; break; // 50%
case 3: volume_shift = 2; break; // 25%
}
}
if(r == 3) { //$ff1d NR33
frequency = (frequency & 0x0700) | data;
}
if(r == 4) { //$ff1e NR34
bool initialize = data & 0x80;
counter = data & 0x40;
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
if(initialize) {
enable = dac_enable;
pattern_offset = 0;
if(length == 0) length = 256;
}
}
period = 2 * (2048 - frequency);
}
void APU::Wave::write_pattern(unsigned p, uint8 data) {
p <<= 1;
pattern[p + 0] = (data >> 4) & 15;
pattern[p + 1] = (data >> 0) & 15;
}
void APU::Wave::power() {
enable = 0;
dac_enable = 0;
volume_shift = 0;
frequency = 0;
counter = 0;
random_lfsr r;
for(auto &n : pattern) n = r() & 15;
output = 0;
length = 0;
period = 0;
pattern_offset = 0;
pattern_sample = 0;
}
#endif

View File

@ -1,21 +0,0 @@
struct Wave {
bool enable;
bool dac_enable;
unsigned volume_shift;
uint11 frequency;
bool counter;
uint8 pattern[32];
int16 output;
unsigned length;
unsigned period;
uint5 pattern_offset;
uint4 pattern_sample;
void run();
void clock_length();
void write(unsigned r, uint8 data);
void write_pattern(unsigned p, uint8 data);
void power();
};

View File

@ -1,154 +0,0 @@
#include <gameboy/gameboy.hpp>
#include <nall/crc32.hpp>
#define CARTRIDGE_CPP
namespace GameBoy {
#include "mbc0/mbc0.cpp"
#include "mbc1/mbc1.cpp"
#include "mbc2/mbc2.cpp"
#include "mbc3/mbc3.cpp"
#include "mbc5/mbc5.cpp"
#include "mmm01/mmm01.cpp"
#include "huc1/huc1.cpp"
#include "huc3/huc3.cpp"
Cartridge cartridge;
void Cartridge::load(System::Revision revision, const string &markup, const uint8_t *data, unsigned size) {
if(size == 0) size = 32768;
romdata = allocate<uint8>(romsize = size, 0xff);
if(data) memcpy(romdata, data, size);
info.mapper = Mapper::Unknown;
info.ram = false;
info.battery = false;
info.rtc = false;
info.rumble = false;
info.romsize = 0;
info.ramsize = 0;
XML::Document document(markup);
auto &mapperid = document["cartridge"]["mapper"].data;
if(mapperid == "none" ) info.mapper = Mapper::MBC0;
if(mapperid == "MBC1" ) info.mapper = Mapper::MBC1;
if(mapperid == "MBC2" ) info.mapper = Mapper::MBC2;
if(mapperid == "MBC3" ) info.mapper = Mapper::MBC3;
if(mapperid == "MBC5" ) info.mapper = Mapper::MBC5;
if(mapperid == "MMM01") info.mapper = Mapper::MMM01;
if(mapperid == "HuC1" ) info.mapper = Mapper::HuC1;
if(mapperid == "HuC3" ) info.mapper = Mapper::HuC3;
info.rtc = document["cartridge"]["rtc"].data == "true";
info.rumble = document["cartridge"]["rumble"].data == "true";
info.romsize = numeral(document["cartridge"]["rom"]["size"].data);
info.ramsize = numeral(document["cartridge"]["ram"]["size"].data);
info.battery = document["cartridge"]["ram"]["battery"].data == "true";
switch(info.mapper) { default:
case Mapper::MBC0: mapper = &mbc0; break;
case Mapper::MBC1: mapper = &mbc1; break;
case Mapper::MBC2: mapper = &mbc2; break;
case Mapper::MBC3: mapper = &mbc3; break;
case Mapper::MBC5: mapper = &mbc5; break;
case Mapper::MMM01: mapper = &mmm01; break;
case Mapper::HuC1: mapper = &huc1; break;
case Mapper::HuC3: mapper = &huc3; break;
}
ramdata = (uint8_t*)interface->allocSharedMemory("SGB_CARTRAM",ramsize = info.ramsize, 0xff);
system.load(revision);
loaded = true;
sha256 = nall::sha256(romdata, romsize);
}
void Cartridge::unload() {
if(loaded == false) return;
if(romdata) { delete[] romdata; romdata = 0; }
if(ramdata) { interface->freeSharedMemory(ramdata); }
loaded = false;
}
uint8 Cartridge::rom_read(unsigned addr) {
if(addr >= romsize) addr %= romsize;
cdlInfo.set(eCDLog_AddrType_SGB_CARTROM, addr);
return romdata[addr];
}
void Cartridge::rom_write(unsigned addr, uint8 data) {
if(addr >= romsize) addr %= romsize;
romdata[addr] = data;
}
uint8 Cartridge::ram_read(unsigned addr) {
if(ramsize == 0) return 0x00;
if(addr >= ramsize) addr %= ramsize;
cdlInfo.set(eCDLog_AddrType_SGB_CARTRAM, addr);
return ramdata[addr];
}
void Cartridge::ram_write(unsigned addr, uint8 data) {
if(ramsize == 0) return;
if(addr >= ramsize) addr %= ramsize;
ramdata[addr] = data;
}
uint8 Cartridge::mmio_read(uint16 addr) {
if(addr == 0xff50) return 0x00;
if(bootrom_enable) {
const uint8 *data = nullptr;
switch(system.revision()) { default:
case System::Revision::GameBoy: data = System::BootROM::dmg; break;
case System::Revision::SuperGameBoy: data = System::BootROM::sgb; break;
case System::Revision::GameBoyColor: data = System::BootROM::cgb; break;
}
if(addr >= 0x0000 && addr <= 0x00ff) return data[addr];
if(addr >= 0x0200 && addr <= 0x08ff && system.cgb()) return data[addr - 256];
}
return mapper->mmio_read(addr);
}
void Cartridge::mmio_write(uint16 addr, uint8 data) {
if(bootrom_enable && addr == 0xff50) {
bootrom_enable = false;
return;
}
mapper->mmio_write(addr, data);
}
void Cartridge::power() {
bootrom_enable = true;
mbc0.power();
mbc1.power();
mbc2.power();
mbc3.power();
mbc5.power();
mmm01.power();
huc1.power();
huc3.power();
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this;
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this;
bus.mmio[0xff50] = this;
}
Cartridge::Cartridge() {
loaded = false;
romdata = 0;
ramdata = 0;
}
Cartridge::~Cartridge() {
unload();
}
}

View File

@ -1,65 +0,0 @@
struct Cartridge : MMIO, property<Cartridge> {
#include "mbc0/mbc0.hpp"
#include "mbc1/mbc1.hpp"
#include "mbc2/mbc2.hpp"
#include "mbc3/mbc3.hpp"
#include "mbc5/mbc5.hpp"
#include "mmm01/mmm01.hpp"
#include "huc1/huc1.hpp"
#include "huc3/huc3.hpp"
enum Mapper : unsigned {
MBC0,
MBC1,
MBC2,
MBC3,
MBC5,
MMM01,
HuC1,
HuC3,
Unknown,
};
struct Information {
string xml;
Mapper mapper;
bool ram;
bool battery;
bool rtc;
bool rumble;
unsigned romsize;
unsigned ramsize;
} info;
readonly<bool> loaded;
readonly<string> sha256;
uint8_t *romdata;
unsigned romsize;
uint8_t *ramdata;
unsigned ramsize;
MMIO *mapper;
bool bootrom_enable;
void load(System::Revision revision, const string &markup, const uint8_t *data, unsigned size);
void unload();
uint8 rom_read(unsigned addr);
void rom_write(unsigned addr, uint8 data);
uint8 ram_read(unsigned addr);
void ram_write(unsigned addr, uint8 data);
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
Cartridge();
~Cartridge();
};
extern Cartridge cartridge;

View File

@ -1,54 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
}
return 0x00;
}
void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_writable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = data;
if(rom_select == 0) rom_select = 1;
return;
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data;
return;
}
if((addr & 0xe000) == 0x6000) { //$6000-7fff
model = data & 0x01;
return;
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_writable == false) return;
return cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
}
}
void Cartridge::HuC1::power() {
ram_writable = false;
rom_select = 0x01;
ram_select = 0x00;
model = 0;
}
#endif

View File

@ -1,10 +0,0 @@
struct HuC1 : MMIO {
bool ram_writable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
bool model; //$6000-7fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} huc1;

View File

@ -1,53 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
return 0x00;
}
void Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = data;
return;
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data;
return;
}
if((addr & 0xe000) == 0x6000) { //$6000-7fff
//unknown purpose
return;
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}
}
void Cartridge::HuC3::power() {
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
}
#endif

View File

@ -1,9 +0,0 @@
struct HuC3 : MMIO {
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} huc3;

View File

@ -1,25 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
if((addr & 0x8000) == 0x0000) { //$0000-7fff
return cartridge.rom_read(addr);
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
return cartridge.ram_read(addr & 0x1fff);
}
return 0x00;
}
void Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
cartridge.ram_write(addr & 0x1fff, data);
return;
}
}
void Cartridge::MBC0::power() {
}
#endif

View File

@ -1,5 +0,0 @@
struct MBC0 : MMIO {
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mbc0;

View File

@ -1,70 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
if(mode_select == 0) {
return cartridge.rom_read((ram_select << 19) | (rom_select << 14) | (addr & 0x3fff));
} else {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(mode_select == 0) {
return cartridge.ram_read(addr & 0x1fff);
} else {
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
}
}
return 0x00;
}
return 0x00;
}
void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = (data & 0x1f) + ((data & 0x1f) == 0);
return;
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data & 0x03;
return;
}
if((addr & 0xe000) == 0x6000) { //$6000-7fff
mode_select = data & 0x01;
return;
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(mode_select == 0) {
cartridge.ram_write(addr & 0x1fff, data);
} else {
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
}
}
return;
}
}
void Cartridge::MBC1::power() {
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
mode_select = 0;
}
#endif

View File

@ -1,10 +0,0 @@
struct MBC1 : MMIO {
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
bool mode_select; //$6000-7fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mbc1;

View File

@ -1,42 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xee00) == 0xa000) { //$a000-a1ff
if(ram_enable) return cartridge.ram_read(addr & 0x1ff);
return 0x00;
}
return 0x00;
}
void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
if(!(addr & 0x0100)) ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
if( (addr & 0x0100)) rom_select = (data & 0x0f) + ((data & 0x0f) == 0);
return;
}
if((addr & 0xee00) == 0xa000) { //$a000-a1ff
if(ram_enable) cartridge.ram_write(addr & 0x1ff, data & 0x0f);
return;
}
}
void Cartridge::MBC2::power() {
ram_enable = false;
rom_select = 0x01;
}
#endif

View File

@ -1,8 +0,0 @@
struct MBC2 : MMIO {
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mbc2;

View File

@ -1,120 +0,0 @@
#ifdef CARTRIDGE_CPP
void Cartridge::MBC3::second() {
if(rtc_halt == false) {
if(++rtc_second >= 60) {
rtc_second = 0;
if(++rtc_minute >= 60) {
rtc_minute = 0;
if(++rtc_hour >= 24) {
rtc_hour = 0;
if(++rtc_day >= 512) {
rtc_day = 0;
rtc_day_carry = true;
}
}
}
}
}
}
uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
}
if(ram_select == 0x08) return rtc_latch_second;
if(ram_select == 0x09) return rtc_latch_minute;
if(ram_select == 0x0a) return rtc_latch_hour;
if(ram_select == 0x0b) return rtc_latch_day;
if(ram_select == 0x0c) return (rtc_latch_day_carry << 7) | (rtc_latch_day >> 8);
}
return 0x00;
}
return 0x00;
}
void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = (data & 0x7f) + ((data & 0x7f) == 0);
return;
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data;
return;
}
if((addr & 0xe000) == 0x6000) { //$6000-7fff
if(rtc_latch == 0 && data == 1) {
rtc_latch_second = rtc_second;
rtc_latch_minute = rtc_minute;
rtc_latch_hour = rtc_hour;
rtc_latch_day = rtc_day;
rtc_latch_day_carry = rtc_day_carry;
}
rtc_latch = data;
return;
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
} else if(ram_select == 0x08) {
if(data >= 60) data = 0;
rtc_second = data;
} else if(ram_select == 0x09) {
if(data >= 60) data = 0;
rtc_minute = data;
} else if(ram_select == 0x0a) {
if(data >= 24) data = 0;
rtc_hour = data;
} else if(ram_select == 0x0b) {
rtc_day = (rtc_day & 0x0100) | data;
} else if(ram_select == 0x0c) {
rtc_day = ((data & 1) << 8) | (rtc_day & 0xff);
rtc_halt = data & 0x40;
rtc_day_carry = data & 0x80;
}
}
return;
}
}
void Cartridge::MBC3::power() {
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
rtc_latch = 0;
rtc_halt = true;
rtc_second = 0;
rtc_minute = 0;
rtc_hour = 0;
rtc_day = 0;
rtc_day_carry = false;
rtc_latch_second = 0;
rtc_latch_minute = 0;
rtc_latch_hour = 0;
rtc_latch_day = 0;
rtc_latch_day_carry = false;
}
#endif

View File

@ -1,24 +0,0 @@
struct MBC3 : MMIO {
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
bool rtc_latch; //$6000-7fff
bool rtc_halt;
unsigned rtc_second;
unsigned rtc_minute;
unsigned rtc_hour;
unsigned rtc_day;
bool rtc_day_carry;
unsigned rtc_latch_second;
unsigned rtc_latch_minute;
unsigned rtc_latch_hour;
unsigned rtc_latch_day;
unsigned rtc_latch_day_carry;
void second();
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mbc3;

View File

@ -1,53 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
return 0x00;
}
void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xf000) == 0x2000) { //$2000-2fff
rom_select = (rom_select & 0x0100) | data;
return;
}
if((addr & 0xf000) == 0x3000) { //$3000-3fff
rom_select = ((data & 1) << 8) | (rom_select & 0x00ff);
return;
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data & 0x0f;
return;
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}
}
void Cartridge::MBC5::power() {
ram_enable = false;
rom_select = 0x001;
ram_select = 0x00;
}
#endif

View File

@ -1,9 +0,0 @@
struct MBC5 : MMIO {
bool ram_enable; //$0000-1fff
uint16 rom_select; //$2000-2fff + $3000-3fff
uint8 ram_select; //$4000-5fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mbc5;

View File

@ -1,65 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
if((addr & 0x8000) == 0x0000) { //$0000-7fff
if(rom_mode == 0) return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(0x8000 + (rom_base << 14) + (addr & 0x3fff));
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read(0x8000 + (rom_base << 14) + (rom_select << 14) + (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) return cartridge.ram_read((ram_select << 13) + (addr & 0x1fff));
return 0x00;
}
return 0x00;
}
void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
if(rom_mode == 0) {
rom_mode = 1;
} else {
ram_enable = (data & 0x0f) == 0x0a;
}
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
if(rom_mode == 0) {
rom_base = data & 0x3f;
} else {
rom_select = data;
}
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
if(rom_mode == 1) {
ram_select = data;
}
}
if((addr & 0xe000) == 0x6000) { //$6000-7fff
//unknown purpose
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) cartridge.ram_write((ram_select << 13) + (addr & 0x1fff), data);
}
}
void Cartridge::MMM01::power() {
rom_mode = 0;
rom_base = 0;
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
}
#endif

View File

@ -1,12 +0,0 @@
struct MMM01 : MMIO {
bool rom_mode;
uint8 rom_base;
bool ram_enable;
uint8 rom_select;
uint8 ram_select;
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mmm01;

View File

@ -1,689 +0,0 @@
#ifdef CPU_CPP
#include "table.cpp"
#include "disassembler.cpp"
uint8 CPU::op_fetch() {
cdlInfo.currFlags = eCDLog_Flags_ExecOperand;
uint8 opcode = op_read(r[PC]++);
cdlInfo.currFlags = eCDLog_Flags_CPUData;
return opcode;
}
void CPU::op_xx() {
}
void CPU::op_cb() {
uint8 opcode = op_fetch();
(this->*opcode_table_cb[opcode])();
}
//8-bit load commands
template<unsigned x, unsigned y> void CPU::op_ld_r_r() {
r[x] = r[y];
}
template<unsigned x> void CPU::op_ld_r_n() {
r[x] = op_fetch();
}
template<unsigned x> void CPU::op_ld_r_hl() {
r[x] = op_read(r[HL]);
}
template<unsigned x> void CPU::op_ld_hl_r() {
op_write(r[HL], r[x]);
}
void CPU::op_ld_hl_n() {
op_write(r[HL], op_fetch());
}
template<unsigned x> void CPU::op_ld_a_rr() {
r[A] = op_read(r[x]);
}
void CPU::op_ld_a_nn() {
uint8 lo = op_fetch();
uint8 hi = op_fetch();
r[A] = op_read((hi << 8) | (lo << 0));
}
template<unsigned x> void CPU::op_ld_rr_a() {
op_write(r[x], r[A]);
}
void CPU::op_ld_nn_a() {
uint8 lo = op_fetch();
uint8 hi = op_fetch();
op_write((hi << 8) | (lo << 0), r[A]);
}
void CPU::op_ld_a_ffn() {
r[A] = op_read(0xff00 + op_fetch());
}
void CPU::op_ld_ffn_a() {
op_write(0xff00 + op_fetch(), r[A]);
}
void CPU::op_ld_a_ffc() {
r[A] = op_read(0xff00 + r[C]);
}
void CPU::op_ld_ffc_a() {
op_write(0xff00 + r[C], r[A]);
}
void CPU::op_ldi_hl_a() {
op_write(r[HL], r[A]);
r[HL]++;
}
void CPU::op_ldi_a_hl() {
r[A] = op_read(r[HL]);
r[HL]++;
}
void CPU::op_ldd_hl_a() {
op_write(r[HL], r[A]);
r[HL]--;
}
void CPU::op_ldd_a_hl() {
r[A] = op_read(r[HL]);
r[HL]--;
}
//16-bit load commands
template<unsigned x> void CPU::op_ld_rr_nn() {
r[x] = op_fetch() << 0;
r[x] |= op_fetch() << 8;
}
void CPU::op_ld_nn_sp() {
uint16 addr = op_fetch() << 0;
addr |= op_fetch() << 8;
op_write(addr + 0, r[SP] >> 0);
op_write(addr + 1, r[SP] >> 8);
}
void CPU::op_ld_sp_hl() {
r[SP] = r[HL];
op_io();
}
template<unsigned x> void CPU::op_push_rr() {
op_write(--r[SP], r[x] >> 8);
op_write(--r[SP], r[x] >> 0);
op_io();
}
template<unsigned x> void CPU::op_pop_rr() {
r[x] = op_read(r[SP]++) << 0;
r[x] |= op_read(r[SP]++) << 8;
}
//8-bit arithmetic commands
void CPU::opi_add_a(uint8 x) {
uint16 rh = r[A] + x;
uint16 rl = (r[A] & 0x0f) + (x & 0x0f);
r[A] = rh;
r.f.z = (uint8)rh == 0;
r.f.n = 0;
r.f.h = rl > 0x0f;
r.f.c = rh > 0xff;
}
template<unsigned x> void CPU::op_add_a_r() { opi_add_a(r[x]); }
void CPU::op_add_a_n() { opi_add_a(op_fetch()); }
void CPU::op_add_a_hl() { opi_add_a(op_read(r[HL])); }
void CPU::opi_adc_a(uint8 x) {
uint16 rh = r[A] + x + r.f.c;
uint16 rl = (r[A] & 0x0f) + (x & 0x0f) + r.f.c;
r[A] = rh;
r.f.z = (uint8)rh == 0;
r.f.n = 0;
r.f.h = rl > 0x0f;
r.f.c = rh > 0xff;
}
template<unsigned x> void CPU::op_adc_a_r() { opi_adc_a(r[x]); }
void CPU::op_adc_a_n() { opi_adc_a(op_fetch()); }
void CPU::op_adc_a_hl() { opi_adc_a(op_read(r[HL])); }
void CPU::opi_sub_a(uint8 x) {
uint16 rh = r[A] - x;
uint16 rl = (r[A] & 0x0f) - (x & 0x0f);
r[A] = rh;
r.f.z = (uint8)rh == 0;
r.f.n = 1;
r.f.h = rl > 0x0f;
r.f.c = rh > 0xff;
}
template<unsigned x> void CPU::op_sub_a_r() { opi_sub_a(r[x]); }
void CPU::op_sub_a_n() { opi_sub_a(op_fetch()); }
void CPU::op_sub_a_hl() { opi_sub_a(op_read(r[HL])); }
void CPU::opi_sbc_a(uint8 x) {
uint16 rh = r[A] - x - r.f.c;
uint16 rl = (r[A] & 0x0f) - (x & 0x0f) - r.f.c;
r[A] = rh;
r.f.z = (uint8)rh == 0;
r.f.n = 1;
r.f.h = rl > 0x0f;
r.f.c = rh > 0xff;
}
template<unsigned x> void CPU::op_sbc_a_r() { opi_sbc_a(r[x]); }
void CPU::op_sbc_a_n() { opi_sbc_a(op_fetch()); }
void CPU::op_sbc_a_hl() { opi_sbc_a(op_read(r[HL])); }
void CPU::opi_and_a(uint8 x) {
r[A] &= x;
r.f.z = r[A] == 0;
r.f.n = 0;
r.f.h = 1;
r.f.c = 0;
}
template<unsigned x> void CPU::op_and_a_r() { opi_and_a(r[x]); }
void CPU::op_and_a_n() { opi_and_a(op_fetch()); }
void CPU::op_and_a_hl() { opi_and_a(op_read(r[HL])); }
void CPU::opi_xor_a(uint8 x) {
r[A] ^= x;
r.f.z = r[A] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = 0;
}
template<unsigned x> void CPU::op_xor_a_r() { opi_xor_a(r[x]); }
void CPU::op_xor_a_n() { opi_xor_a(op_fetch()); }
void CPU::op_xor_a_hl() { opi_xor_a(op_read(r[HL])); }
void CPU::opi_or_a(uint8 x) {
r[A] |= x;
r.f.z = r[A] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = 0;
}
template<unsigned x> void CPU::op_or_a_r() { opi_or_a(r[x]); }
void CPU::op_or_a_n() { opi_or_a(op_fetch()); }
void CPU::op_or_a_hl() { opi_or_a(op_read(r[HL])); }
void CPU::opi_cp_a(uint8 x) {
uint16 rh = r[A] - x;
uint16 rl = (r[A] & 0x0f) - (x & 0x0f);
r.f.z = (uint8)rh == 0;
r.f.n = 1;
r.f.h = rl > 0x0f;
r.f.c = rh > 0xff;
}
template<unsigned x> void CPU::op_cp_a_r() { opi_cp_a(r[x]); }
void CPU::op_cp_a_n() { opi_cp_a(op_fetch()); }
void CPU::op_cp_a_hl() { opi_cp_a(op_read(r[HL])); }
template<unsigned x> void CPU::op_inc_r() {
r[x]++;
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = (r[x] & 0x0f) == 0x00;
}
void CPU::op_inc_hl() {
uint8 n = op_read(r[HL]);
op_write(r[HL], ++n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = (n & 0x0f) == 0x00;
}
template<unsigned x> void CPU::op_dec_r() {
r[x]--;
r.f.z = r[x] == 0;
r.f.n = 1;
r.f.h = (r[x] & 0x0f) == 0x0f;
}
void CPU::op_dec_hl() {
uint8 n = op_read(r[HL]);
op_write(r[HL], --n);
r.f.z = n == 0;
r.f.n = 1;
r.f.h = (n & 0x0f) == 0x0f;
}
void CPU::op_daa() {
uint16 a = r[A];
if(r.f.n == 0) {
if(r.f.h || (a & 0x0f) > 0x09) a += 0x06;
if(r.f.c || (a ) > 0x9f) a += 0x60;
} else {
if(r.f.h) {
a -= 0x06;
if(r.f.c == 0) a &= 0xff;
}
if(r.f.c) a -= 0x60;
}
r[A] = a;
r.f.z = r[A] == 0;
r.f.h = 0;
r.f.c |= a & 0x100;
}
void CPU::op_cpl() {
r[A] ^= 0xff;
r.f.n = 1;
r.f.h = 1;
}
//16-bit arithmetic commands
template<unsigned x> void CPU::op_add_hl_rr() {
op_io();
uint32 rb = (r[HL] + r[x]);
uint32 rn = (r[HL] & 0xfff) + (r[x] & 0xfff);
r[HL] = rb;
r.f.n = 0;
r.f.h = rn > 0x0fff;
r.f.c = rb > 0xffff;
}
template<unsigned x> void CPU::op_inc_rr() {
op_io();
r[x]++;
}
template<unsigned x> void CPU::op_dec_rr() {
op_io();
r[x]--;
}
void CPU::op_add_sp_n() {
op_io();
op_io();
signed n = (int8)op_fetch();
r.f.z = 0;
r.f.n = 0;
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff;
r[SP] += n;
}
void CPU::op_ld_hl_sp_n() {
op_io();
signed n = (int8)op_fetch();
r.f.z = 0;
r.f.n = 0;
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff;
r[HL] = r[SP] + n;
}
//rotate/shift commands
void CPU::op_rlca() {
r[A] = (r[A] << 1) | (r[A] >> 7);
r.f.z = 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = r[A] & 0x01;
}
void CPU::op_rla() {
bool c = r[A] & 0x80;
r[A] = (r[A] << 1) | (r.f.c << 0);
r.f.z = 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_rrca() {
r[A] = (r[A] >> 1) | (r[A] << 7);
r.f.z = 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = r[A] & 0x80;
}
void CPU::op_rra() {
bool c = r[A] & 0x01;
r[A] = (r[A] >> 1) | (r.f.c << 7);
r.f.z = 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
template<unsigned x> void CPU::op_rlc_r() {
r[x] = (r[x] << 1) | (r[x] >> 7);
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = r[x] & 0x01;
}
void CPU::op_rlc_hl() {
uint8 n = op_read(r[HL]);
n = (n << 1) | (n >> 7);
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = n & 0x01;
}
template<unsigned x> void CPU::op_rl_r() {
bool c = r[x] & 0x80;
r[x] = (r[x] << 1) | (r.f.c << 0);
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_rl_hl() {
uint8 n = op_read(r[HL]);
bool c = n & 0x80;
n = (n << 1) | (r.f.c << 0);
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
template<unsigned x> void CPU::op_rrc_r() {
r[x] = (r[x] >> 1) | (r[x] << 7);
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = r[x] & 0x80;
}
void CPU::op_rrc_hl() {
uint8 n = op_read(r[HL]);
n = (n >> 1) | (n << 7);
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = n & 0x80;
}
template<unsigned x> void CPU::op_rr_r() {
bool c = r[x] & 0x01;
r[x] = (r[x] >> 1) | (r.f.c << 7);
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_rr_hl() {
uint8 n = op_read(r[HL]);
bool c = n & 0x01;
n = (n >> 1) | (r.f.c << 7);
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
template<unsigned x> void CPU::op_sla_r() {
bool c = r[x] & 0x80;
r[x] <<= 1;
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_sla_hl() {
uint8 n = op_read(r[HL]);
bool c = n & 0x80;
n <<= 1;
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
template<unsigned x> void CPU::op_swap_r() {
r[x] = (r[x] << 4) | (r[x] >> 4);
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = 0;
}
void CPU::op_swap_hl() {
uint8 n = op_read(r[HL]);
n = (n << 4) | (n >> 4);
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = 0;
}
template<unsigned x> void CPU::op_sra_r() {
bool c = r[x] & 0x01;
r[x] = (int8)r[x] >> 1;
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_sra_hl() {
uint8 n = op_read(r[HL]);
bool c = n & 0x01;
n = (int8)n >> 1;
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
template<unsigned x> void CPU::op_srl_r() {
bool c = r[x] & 0x01;
r[x] >>= 1;
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_srl_hl() {
uint8 n = op_read(r[HL]);
bool c = n & 0x01;
n >>= 1;
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
//single-bit commands
template<unsigned b, unsigned x> void CPU::op_bit_n_r() {
r.f.z = (r[x] & (1 << b)) == 0;
r.f.n = 0;
r.f.h = 1;
}
template<unsigned b> void CPU::op_bit_n_hl() {
uint8 n = op_read(r[HL]);
r.f.z = (n & (1 << b)) == 0;
r.f.n = 0;
r.f.h = 1;
}
template<unsigned b, unsigned x> void CPU::op_set_n_r() {
r[x] |= 1 << b;
}
template<unsigned b> void CPU::op_set_n_hl() {
uint8 n = op_read(r[HL]);
n |= 1 << b;
op_write(r[HL], n);
}
template<unsigned b, unsigned x> void CPU::op_res_n_r() {
r[x] &= ~(1 << b);
}
template<unsigned b> void CPU::op_res_n_hl() {
uint8 n = op_read(r[HL]);
n &= ~(1 << b);
op_write(r[HL], n);
}
//control commands
void CPU::op_ccf() {
r.f.n = 0;
r.f.h = 0;
r.f.c = !r.f.c;
}
void CPU::op_scf() {
r.f.n = 0;
r.f.h = 0;
r.f.c = 1;
}
void CPU::op_nop() {
}
void CPU::op_halt() {
status.halt = true;
while(status.halt == true) op_io();
}
void CPU::op_stop() {
if(status.speed_switch) {
status.speed_switch = 0;
status.speed_double ^= 1;
frequency = 4 * 1024 * 1024;
if(status.speed_double) frequency *= 2;
return;
}
status.stop = true;
while(status.stop == true) op_io();
}
void CPU::op_di() {
status.ime = 0;
}
void CPU::op_ei() {
status.ei = true;
//status.ime = 1;
}
//jump commands
void CPU::op_jp_nn() {
uint8 lo = op_fetch();
uint8 hi = op_fetch();
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
void CPU::op_jp_hl() {
r[PC] = r[HL];
}
template<unsigned x, bool y> void CPU::op_jp_f_nn() {
uint8 lo = op_fetch();
uint8 hi = op_fetch();
if(r.f[x] == y) {
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
}
void CPU::op_jr_n() {
int8 n = op_fetch();
r[PC] += n;
op_io();
}
template<unsigned x, bool y> void CPU::op_jr_f_n() {
int8 n = op_fetch();
if(r.f[x] == y) {
r[PC] += n;
op_io();
}
}
void CPU::op_call_nn() {
uint8 lo = op_fetch();
uint8 hi = op_fetch();
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
template<unsigned x, bool y> void CPU::op_call_f_nn() {
uint8 lo = op_fetch();
uint8 hi = op_fetch();
if(r.f[x] == y) {
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
}
void CPU::op_ret() {
uint8 lo = op_read(r[SP]++);
uint8 hi = op_read(r[SP]++);
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
template<unsigned x, bool y> void CPU::op_ret_f() {
op_io();
if(r.f[x] == y) {
uint8 lo = op_read(r[SP]++);
uint8 hi = op_read(r[SP]++);
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
}
void CPU::op_reti() {
uint8 lo = op_read(r[SP]++);
uint8 hi = op_read(r[SP]++);
r[PC] = (hi << 8) | (lo << 0);
op_io();
status.ime = 1;
}
template<unsigned n> void CPU::op_rst_n() {
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
r[PC] = n;
op_io();
}
#endif

View File

@ -1,146 +0,0 @@
#include "registers.hpp"
void (CPU::*opcode_table[256])();
void (CPU::*opcode_table_cb[256])();
void initialize_opcode_table();
void op_xx();
void op_cb();
uint8 op_fetch();
//8-bit load commands
template<unsigned x, unsigned y> void op_ld_r_r();
template<unsigned x> void op_ld_r_n();
template<unsigned x> void op_ld_r_hl();
template<unsigned x> void op_ld_hl_r();
void op_ld_hl_n();
template<unsigned x> void op_ld_a_rr();
void op_ld_a_nn();
template<unsigned x> void op_ld_rr_a();
void op_ld_nn_a();
void op_ld_a_ffn();
void op_ld_ffn_a();
void op_ld_a_ffc();
void op_ld_ffc_a();
void op_ldi_hl_a();
void op_ldi_a_hl();
void op_ldd_hl_a();
void op_ldd_a_hl();
//16-bit load commands
template<unsigned x> void op_ld_rr_nn();
void op_ld_nn_sp();
void op_ld_sp_hl();
template<unsigned x> void op_push_rr();
template<unsigned x> void op_pop_rr();
//8-bit arithmetic commands
void opi_add_a(uint8 x);
template<unsigned x> void op_add_a_r();
void op_add_a_n();
void op_add_a_hl();
void opi_adc_a(uint8 x);
template<unsigned x> void op_adc_a_r();
void op_adc_a_n();
void op_adc_a_hl();
void opi_sub_a(uint8 x);
template<unsigned x> void op_sub_a_r();
void op_sub_a_n();
void op_sub_a_hl();
void opi_sbc_a(uint8 x);
template<unsigned x> void op_sbc_a_r();
void op_sbc_a_n();
void op_sbc_a_hl();
void opi_and_a(uint8 x);
template<unsigned x> void op_and_a_r();
void op_and_a_n();
void op_and_a_hl();
void opi_xor_a(uint8 x);
template<unsigned x> void op_xor_a_r();
void op_xor_a_n();
void op_xor_a_hl();
void opi_or_a(uint8 x);
template<unsigned x> void op_or_a_r();
void op_or_a_n();
void op_or_a_hl();
void opi_cp_a(uint8 x);
template<unsigned x> void op_cp_a_r();
void op_cp_a_n();
void op_cp_a_hl();
template<unsigned x> void op_inc_r();
void op_inc_hl();
template<unsigned x> void op_dec_r();
void op_dec_hl();
void op_daa();
void op_cpl();
//16-bit arithmetic commands
template<unsigned x> void op_add_hl_rr();
template<unsigned x> void op_inc_rr();
template<unsigned x> void op_dec_rr();
void op_add_sp_n();
void op_ld_hl_sp_n();
//rotate/shift commands
void op_rlca();
void op_rla();
void op_rrca();
void op_rra();
template<unsigned x> void op_rlc_r();
void op_rlc_hl();
template<unsigned x> void op_rl_r();
void op_rl_hl();
template<unsigned x> void op_rrc_r();
void op_rrc_hl();
template<unsigned x> void op_rr_r();
void op_rr_hl();
template<unsigned x> void op_sla_r();
void op_sla_hl();
template<unsigned x> void op_swap_r();
void op_swap_hl();
template<unsigned x> void op_sra_r();
void op_sra_hl();
template<unsigned x> void op_srl_r();
void op_srl_hl();
//single-bit commands
template<unsigned b, unsigned x> void op_bit_n_r();
template<unsigned b> void op_bit_n_hl();
template<unsigned b, unsigned x> void op_set_n_r();
template<unsigned b> void op_set_n_hl();
template<unsigned b, unsigned x> void op_res_n_r();
template<unsigned b> void op_res_n_hl();
//control commands
void op_ccf();
void op_scf();
void op_nop();
void op_halt();
void op_stop();
void op_di();
void op_ei();
//jump commands
void op_jp_nn();
void op_jp_hl();
template<unsigned x, bool y> void op_jp_f_nn();
void op_jr_n();
template<unsigned x, bool y> void op_jr_f_n();
void op_call_nn();
template<unsigned x, bool y> void op_call_f_nn();
void op_ret();
template<unsigned x, bool y> void op_ret_f();
void op_reti();
template<unsigned n> void op_rst_n();
//disassembler.cpp
string disassemble(uint16 pc);
string disassemble_opcode(uint16 pc);
string disassemble_opcode_cb(uint16 pc);

View File

@ -1,560 +0,0 @@
#ifdef CPU_CPP
string CPU::disassemble(uint16 pc) {
char output[80];
memset(output, ' ', sizeof output);
output[79] = 0;
string opcode = disassemble_opcode(pc);
string registers = {
" AF:", hex<4>(r[AF]),
" BC:", hex<4>(r[BC]),
" DE:", hex<4>(r[DE]),
" HL:", hex<4>(r[HL]),
" SP:", hex<4>(r[SP])
};
memcpy(output + 0, hex<4>(pc), 4);
memcpy(output + 6, opcode, opcode.length());
memcpy(output + 23, registers, registers.length());
output[63] = 0;
return output;
}
string CPU::disassemble_opcode(uint16 pc) {
uint8 opcode = bus.read(pc);
uint8 p0 = bus.read(pc + 1);
uint8 p1 = bus.read(pc + 2);
uint8 p2 = bus.read(pc + 3);
switch(opcode) {
case 0x00: return { "nop" };
case 0x01: return { "ld bc,$", hex<2>(p1), hex<2>(p0) };
case 0x02: return { "ld (bc),a" };
case 0x03: return { "inc bc" };
case 0x04: return { "inc b" };
case 0x05: return { "dec b" };
case 0x06: return { "ld b,$", hex<2>(p0) };
case 0x07: return { "rlc a" };
case 0x08: return { "ld ($", hex<2>(p1), hex<2>(p0), "),sp" };
case 0x09: return { "add hl,bc" };
case 0x0a: return { "ld a,(bc)" };
case 0x0b: return { "dec bc" };
case 0x0c: return { "inc c" };
case 0x0d: return { "dec c" };
case 0x0e: return { "ld c,$", hex<2>(p0) };
case 0x0f: return { "rrc a" };
case 0x10: return { "stop" };
case 0x11: return { "ld de,$", hex<2>(p1), hex<2>(p0) };
case 0x12: return { "ld (de),a" };
case 0x13: return { "inc de" };
case 0x14: return { "inc d" };
case 0x15: return { "dec d" };
case 0x16: return { "ld d,$", hex<2>(p0) };
case 0x17: return { "rl a" };
case 0x18: return { "jr $", hex<4>(r[PC] + 2 + (int8)p0) };
case 0x19: return { "add hl,de" };
case 0x1a: return { "ld a,(de)" };
case 0x1b: return { "dec de" };
case 0x1c: return { "inc e" };
case 0x1d: return { "dec e" };
case 0x1e: return { "ld e,$", hex<2>(p0) };
case 0x1f: return { "rr a" };
case 0x20: return { "jr nz,$", hex<4>(r[PC] + 2 + (int8)p0) };
case 0x21: return { "ld hl,$", hex<2>(p1), hex<2>(p0) };
case 0x22: return { "ldi (hl),a" };
case 0x23: return { "inc hl" };
case 0x24: return { "inc h" };
case 0x25: return { "dec h" };
case 0x26: return { "ld h,$", hex<2>(p0) };
case 0x27: return { "daa" };
case 0x28: return { "jr z,$", hex<4>(r[PC] + 2 + (int8)p0) };
case 0x29: return { "add hl,hl" };
case 0x2a: return { "ldi a,(hl)" };
case 0x2b: return { "dec hl" };
case 0x2c: return { "inc l" };
case 0x2d: return { "dec l" };
case 0x2e: return { "ld l,$", hex<2>(p0) };
case 0x2f: return { "cpl" };
case 0x30: return { "jr nc,$", hex<4>(r[PC] + 2 + (int8)p0) };
case 0x31: return { "ld sp,$", hex<2>(p1), hex<2>(p0) };
case 0x32: return { "ldd (hl),a" };
case 0x33: return { "inc sp" };
case 0x34: return { "inc (hl)" };
case 0x35: return { "dec (hl)" };
case 0x36: return { "ld (hl),$", hex<2>(p0) };
case 0x37: return { "scf" };
case 0x38: return { "jr c,$", hex<4>(r[PC] + 2 + (int8)p0) };
case 0x39: return { "add hl,sp" };
case 0x3a: return { "ldd a,(hl)" };
case 0x3b: return { "dec sp" };
case 0x3c: return { "inc a" };
case 0x3d: return { "dec a" };
case 0x3e: return { "ld a,$", hex<2>(p0) };
case 0x3f: return { "ccf" };
case 0x40: return { "ld b,b" };
case 0x41: return { "ld b,c" };
case 0x42: return { "ld b,d" };
case 0x43: return { "ld b,e" };
case 0x44: return { "ld b,h" };
case 0x45: return { "ld b,l" };
case 0x46: return { "ld b,(hl)" };
case 0x47: return { "ld b,a" };
case 0x48: return { "ld c,b" };
case 0x49: return { "ld c,c" };
case 0x4a: return { "ld c,d" };
case 0x4b: return { "ld c,e" };
case 0x4c: return { "ld c,h" };
case 0x4d: return { "ld c,l" };
case 0x4e: return { "ld c,(hl)" };
case 0x4f: return { "ld c,a" };
case 0x50: return { "ld d,b" };
case 0x51: return { "ld d,c" };
case 0x52: return { "ld d,d" };
case 0x53: return { "ld d,e" };
case 0x54: return { "ld d,h" };
case 0x55: return { "ld d,l" };
case 0x56: return { "ld d,(hl)" };
case 0x57: return { "ld d,a" };
case 0x58: return { "ld e,b" };
case 0x59: return { "ld e,c" };
case 0x5a: return { "ld e,d" };
case 0x5b: return { "ld e,e" };
case 0x5c: return { "ld e,h" };
case 0x5d: return { "ld e,l" };
case 0x5e: return { "ld e,(hl)" };
case 0x5f: return { "ld e,a" };
case 0x60: return { "ld h,b" };
case 0x61: return { "ld h,c" };
case 0x62: return { "ld h,d" };
case 0x63: return { "ld h,e" };
case 0x64: return { "ld h,h" };
case 0x65: return { "ld h,l" };
case 0x66: return { "ld h,(hl)" };
case 0x67: return { "ld h,a" };
case 0x68: return { "ld l,b" };
case 0x69: return { "ld l,c" };
case 0x6a: return { "ld l,d" };
case 0x6b: return { "ld l,e" };
case 0x6c: return { "ld l,h" };
case 0x6d: return { "ld l,l" };
case 0x6e: return { "ld l,(hl)" };
case 0x6f: return { "ld l,a" };
case 0x70: return { "ld (hl),b" };
case 0x71: return { "ld (hl),c" };
case 0x72: return { "ld (hl),d" };
case 0x73: return { "ld (hl),e" };
case 0x74: return { "ld (hl),h" };
case 0x75: return { "ld (hl),l" };
case 0x76: return { "halt" };
case 0x77: return { "ld (hl),a" };
case 0x78: return { "ld a,b" };
case 0x79: return { "ld a,c" };
case 0x7a: return { "ld a,d" };
case 0x7b: return { "ld a,e" };
case 0x7c: return { "ld a,h" };
case 0x7d: return { "ld a,l" };
case 0x7e: return { "ld a,(hl)" };
case 0x7f: return { "ld a,a" };
case 0x80: return { "add a,b" };
case 0x81: return { "add a,c" };
case 0x82: return { "add a,d" };
case 0x83: return { "add a,e" };
case 0x84: return { "add a,h" };
case 0x85: return { "add a,l" };
case 0x86: return { "add a,(hl)" };
case 0x87: return { "add a,a" };
case 0x88: return { "adc a,b" };
case 0x89: return { "adc a,c" };
case 0x8a: return { "adc a,d" };
case 0x8b: return { "adc a,e" };
case 0x8c: return { "adc a,h" };
case 0x8d: return { "adc a,l" };
case 0x8e: return { "adc a,(hl)" };
case 0x8f: return { "adc a,a" };
case 0x90: return { "sub a,b" };
case 0x91: return { "sub a,c" };
case 0x92: return { "sub a,d" };
case 0x93: return { "sub a,e" };
case 0x94: return { "sub a,h" };
case 0x95: return { "sub a,l" };
case 0x96: return { "sub a,(hl)" };
case 0x97: return { "sub a,a" };
case 0x98: return { "sbc a,b" };
case 0x99: return { "sbc a,c" };
case 0x9a: return { "sbc a,d" };
case 0x9b: return { "sbc a,e" };
case 0x9c: return { "sbc a,h" };
case 0x9d: return { "sbc a,l" };
case 0x9e: return { "sbc a,(hl)" };
case 0x9f: return { "sbc a,a" };
case 0xa0: return { "and a,b" };
case 0xa1: return { "and a,c" };
case 0xa2: return { "and a,d" };
case 0xa3: return { "and a,e" };
case 0xa4: return { "and a,h" };
case 0xa5: return { "and a,l" };
case 0xa6: return { "and a,(hl)" };
case 0xa7: return { "and a,a" };
case 0xa8: return { "xor a,b" };
case 0xa9: return { "xor a,c" };
case 0xaa: return { "xor a,d" };
case 0xab: return { "xor a,e" };
case 0xac: return { "xor a,h" };
case 0xad: return { "xor a,l" };
case 0xae: return { "xor a,(hl)" };
case 0xaf: return { "xor a,a" };
case 0xb0: return { "or a,b" };
case 0xb1: return { "or a,c" };
case 0xb2: return { "or a,d" };
case 0xb3: return { "or a,e" };
case 0xb4: return { "or a,h" };
case 0xb5: return { "or a,l" };
case 0xb6: return { "or a,(hl)" };
case 0xb7: return { "or a,a" };
case 0xb8: return { "cp a,b" };
case 0xb9: return { "cp a,c" };
case 0xba: return { "cp a,d" };
case 0xbb: return { "cp a,e" };
case 0xbc: return { "cp a,h" };
case 0xbd: return { "cp a,l" };
case 0xbe: return { "cp a,(hl)" };
case 0xbf: return { "cp a,a" };
case 0xc0: return { "ret nz" };
case 0xc1: return { "pop bc" };
case 0xc2: return { "jp nz,$", hex<2>(p1), hex<2>(p0) };
case 0xc3: return { "jp $", hex<2>(p1), hex<2>(p0) };
case 0xc4: return { "call nz,$", hex<2>(p1), hex<2>(p0) };
case 0xc5: return { "push bc" };
case 0xc6: return { "add a,$", hex<2>(p0) };
case 0xc7: return { "rst $0000" };
case 0xc8: return { "ret z" };
case 0xc9: return { "ret" };
case 0xca: return { "jp z,$", hex<2>(p1), hex<2>(p0) };
case 0xcb: return disassemble_opcode_cb(pc + 1);
case 0xcc: return { "call z,$", hex<2>(p1), hex<2>(p0) };
case 0xcd: return { "call $", hex<2>(p1), hex<2>(p0) };
case 0xce: return { "adc a,$", hex<2>(p0) };
case 0xcf: return { "rst $0008" };
case 0xd0: return { "ret nc" };
case 0xd1: return { "pop de" };
case 0xd2: return { "jp nc,$", hex<2>(p1), hex<2>(p0) };
case 0xd3: return { "xx" };
case 0xd4: return { "call nc,$", hex<2>(p1), hex<2>(p0) };
case 0xd5: return { "push de" };
case 0xd6: return { "sub a,$", hex<2>(p0) };
case 0xd7: return { "rst $0010" };
case 0xd8: return { "ret c" };
case 0xd9: return { "reti" };
case 0xda: return { "jp c,$", hex<2>(p1), hex<2>(p0) };
case 0xdb: return { "xx" };
case 0xdc: return { "call c,$", hex<2>(p1), hex<2>(p0) };
case 0xdd: return { "xx" };
case 0xde: return { "sbc a,$", hex<2>(p0) };
case 0xdf: return { "rst $0018" };
case 0xe0: return { "ld ($ff", hex<2>(p0), "),a" };
case 0xe1: return { "pop hl" };
case 0xe2: return { "ld ($ff00+c),a" };
case 0xe3: return { "xx" };
case 0xe4: return { "xx" };
case 0xe5: return { "push hl" };
case 0xe6: return { "and a,$", hex<2>(p0) };
case 0xe7: return { "rst $0020" };
case 0xe8: return { "add sp,$", hex<4>((int8)p0) };
case 0xe9: return { "jp hl" };
case 0xea: return { "ld ($", hex<2>(p1), hex<2>(p0), "),a" };
case 0xeb: return { "xx" };
case 0xec: return { "xx" };
case 0xed: return { "xx" };
case 0xee: return { "xor a,$", hex<2>(p0) };
case 0xef: return { "rst $0028" };
case 0xf0: return { "ld a,($ff", hex<2>(p0), ")" };
case 0xf1: return { "pop af" };
case 0xf2: return { "ld a,($ff00+c)" };
case 0xf3: return { "di" };
case 0xf4: return { "xx" };
case 0xf5: return { "push af" };
case 0xf6: return { "or a,$", hex<2>(p0) };
case 0xf7: return { "rst $0030" };
case 0xf8: return { "ld hl,sp+$", hex<4>((int8)p0) };
case 0xf9: return { "ld sp,hl" };
case 0xfa: return { "ld a,($", hex<2>(p1), hex<2>(p0), ")" };
case 0xfb: return { "ei" };
case 0xfc: return { "xx" };
case 0xfd: return { "xx" };
case 0xfe: return { "cp a,$", hex<2>(p0) };
case 0xff: return { "rst $0038" };
}
return "";
}
string CPU::disassemble_opcode_cb(uint16 pc) {
uint8 opcode = bus.read(pc);
uint8 p0 = bus.read(pc + 1);
uint8 p1 = bus.read(pc + 2);
uint8 p2 = bus.read(pc + 3);
switch(opcode) {
case 0x00: return { "rlc b" };
case 0x01: return { "rlc c" };
case 0x02: return { "rlc d" };
case 0x03: return { "rlc e" };
case 0x04: return { "rlc h" };
case 0x05: return { "rlc l" };
case 0x06: return { "rlc (hl)" };
case 0x07: return { "rlc a" };
case 0x08: return { "rrc b" };
case 0x09: return { "rrc c" };
case 0x0a: return { "rrc d" };
case 0x0b: return { "rrc e" };
case 0x0c: return { "rrc h" };
case 0x0d: return { "rrc l" };
case 0x0e: return { "rrc (hl)" };
case 0x0f: return { "rrc a" };
case 0x10: return { "rl b" };
case 0x11: return { "rl c" };
case 0x12: return { "rl d" };
case 0x13: return { "rl e" };
case 0x14: return { "rl h" };
case 0x15: return { "rl l" };
case 0x16: return { "rl (hl)" };
case 0x17: return { "rl a" };
case 0x18: return { "rr b" };
case 0x19: return { "rr c" };
case 0x1a: return { "rr d" };
case 0x1b: return { "rr e" };
case 0x1c: return { "rr h" };
case 0x1d: return { "rr l" };
case 0x1e: return { "rr (hl)" };
case 0x1f: return { "rr a" };
case 0x20: return { "sla b" };
case 0x21: return { "sla c" };
case 0x22: return { "sla d" };
case 0x23: return { "sla e" };
case 0x24: return { "sla h" };
case 0x25: return { "sla l" };
case 0x26: return { "sla (hl)" };
case 0x27: return { "sla a" };
case 0x28: return { "sra b" };
case 0x29: return { "sra c" };
case 0x2a: return { "sra d" };
case 0x2b: return { "sra e" };
case 0x2c: return { "sra h" };
case 0x2d: return { "sra l" };
case 0x2e: return { "sra (hl)" };
case 0x2f: return { "sra a" };
case 0x30: return { "swap b" };
case 0x31: return { "swap c" };
case 0x32: return { "swap d" };
case 0x33: return { "swap e" };
case 0x34: return { "swap h" };
case 0x35: return { "swap l" };
case 0x36: return { "swap (hl)" };
case 0x37: return { "swap a" };
case 0x38: return { "srl b" };
case 0x39: return { "srl c" };
case 0x3a: return { "srl d" };
case 0x3b: return { "srl e" };
case 0x3c: return { "srl h" };
case 0x3d: return { "srl l" };
case 0x3e: return { "srl (hl)" };
case 0x3f: return { "srl a" };
case 0x40: return { "bit 0,b" };
case 0x41: return { "bit 0,c" };
case 0x42: return { "bit 0,d" };
case 0x43: return { "bit 0,e" };
case 0x44: return { "bit 0,h" };
case 0x45: return { "bit 0,l" };
case 0x46: return { "bit 0,(hl)" };
case 0x47: return { "bit 0,a" };
case 0x48: return { "bit 1,b" };
case 0x49: return { "bit 1,c" };
case 0x4a: return { "bit 1,d" };
case 0x4b: return { "bit 1,e" };
case 0x4c: return { "bit 1,h" };
case 0x4d: return { "bit 1,l" };
case 0x4e: return { "bit 1,(hl)" };
case 0x4f: return { "bit 1,a" };
case 0x50: return { "bit 2,b" };
case 0x51: return { "bit 2,c" };
case 0x52: return { "bit 2,d" };
case 0x53: return { "bit 2,e" };
case 0x54: return { "bit 2,h" };
case 0x55: return { "bit 2,l" };
case 0x56: return { "bit 2,(hl)" };
case 0x57: return { "bit 2,a" };
case 0x58: return { "bit 3,b" };
case 0x59: return { "bit 3,c" };
case 0x5a: return { "bit 3,d" };
case 0x5b: return { "bit 3,e" };
case 0x5c: return { "bit 3,h" };
case 0x5d: return { "bit 3,l" };
case 0x5e: return { "bit 3,(hl)" };
case 0x5f: return { "bit 3,a" };
case 0x60: return { "bit 4,b" };
case 0x61: return { "bit 4,c" };
case 0x62: return { "bit 4,d" };
case 0x63: return { "bit 4,e" };
case 0x64: return { "bit 4,h" };
case 0x65: return { "bit 4,l" };
case 0x66: return { "bit 4,(hl)" };
case 0x67: return { "bit 4,a" };
case 0x68: return { "bit 5,b" };
case 0x69: return { "bit 5,c" };
case 0x6a: return { "bit 5,d" };
case 0x6b: return { "bit 5,e" };
case 0x6c: return { "bit 5,h" };
case 0x6d: return { "bit 5,l" };
case 0x6e: return { "bit 5,(hl)" };
case 0x6f: return { "bit 5,a" };
case 0x70: return { "bit 6,b" };
case 0x71: return { "bit 6,c" };
case 0x72: return { "bit 6,d" };
case 0x73: return { "bit 6,e" };
case 0x74: return { "bit 6,h" };
case 0x75: return { "bit 6,l" };
case 0x76: return { "bit 6,(hl)" };
case 0x77: return { "bit 6,a" };
case 0x78: return { "bit 7,b" };
case 0x79: return { "bit 7,c" };
case 0x7a: return { "bit 7,d" };
case 0x7b: return { "bit 7,e" };
case 0x7c: return { "bit 7,h" };
case 0x7d: return { "bit 7,l" };
case 0x7e: return { "bit 7,(hl)" };
case 0x7f: return { "bit 7,a" };
case 0x80: return { "res 0,b" };
case 0x81: return { "res 0,c" };
case 0x82: return { "res 0,d" };
case 0x83: return { "res 0,e" };
case 0x84: return { "res 0,h" };
case 0x85: return { "res 0,l" };
case 0x86: return { "res 0,(hl)" };
case 0x87: return { "res 0,a" };
case 0x88: return { "res 1,b" };
case 0x89: return { "res 1,c" };
case 0x8a: return { "res 1,d" };
case 0x8b: return { "res 1,e" };
case 0x8c: return { "res 1,h" };
case 0x8d: return { "res 1,l" };
case 0x8e: return { "res 1,(hl)" };
case 0x8f: return { "res 1,a" };
case 0x90: return { "res 2,b" };
case 0x91: return { "res 2,c" };
case 0x92: return { "res 2,d" };
case 0x93: return { "res 2,e" };
case 0x94: return { "res 2,h" };
case 0x95: return { "res 2,l" };
case 0x96: return { "res 2,(hl)" };
case 0x97: return { "res 2,a" };
case 0x98: return { "res 3,b" };
case 0x99: return { "res 3,c" };
case 0x9a: return { "res 3,d" };
case 0x9b: return { "res 3,e" };
case 0x9c: return { "res 3,h" };
case 0x9d: return { "res 3,l" };
case 0x9e: return { "res 3,(hl)" };
case 0x9f: return { "res 3,a" };
case 0xa0: return { "res 4,b" };
case 0xa1: return { "res 4,c" };
case 0xa2: return { "res 4,d" };
case 0xa3: return { "res 4,e" };
case 0xa4: return { "res 4,h" };
case 0xa5: return { "res 4,l" };
case 0xa6: return { "res 4,(hl)" };
case 0xa7: return { "res 4,a" };
case 0xa8: return { "res 5,b" };
case 0xa9: return { "res 5,c" };
case 0xaa: return { "res 5,d" };
case 0xab: return { "res 5,e" };
case 0xac: return { "res 5,h" };
case 0xad: return { "res 5,l" };
case 0xae: return { "res 5,(hl)" };
case 0xaf: return { "res 5,a" };
case 0xb0: return { "res 6,b" };
case 0xb1: return { "res 6,c" };
case 0xb2: return { "res 6,d" };
case 0xb3: return { "res 6,e" };
case 0xb4: return { "res 6,h" };
case 0xb5: return { "res 6,l" };
case 0xb6: return { "res 6,(hl)" };
case 0xb7: return { "res 6,a" };
case 0xb8: return { "res 7,b" };
case 0xb9: return { "res 7,c" };
case 0xba: return { "res 7,d" };
case 0xbb: return { "res 7,e" };
case 0xbc: return { "res 7,h" };
case 0xbd: return { "res 7,l" };
case 0xbe: return { "res 7,(hl)" };
case 0xbf: return { "res 7,a" };
case 0xc0: return { "set 0,b" };
case 0xc1: return { "set 0,c" };
case 0xc2: return { "set 0,d" };
case 0xc3: return { "set 0,e" };
case 0xc4: return { "set 0,h" };
case 0xc5: return { "set 0,l" };
case 0xc6: return { "set 0,(hl)" };
case 0xc7: return { "set 0,a" };
case 0xc8: return { "set 1,b" };
case 0xc9: return { "set 1,c" };
case 0xca: return { "set 1,d" };
case 0xcb: return { "set 1,e" };
case 0xcc: return { "set 1,h" };
case 0xcd: return { "set 1,l" };
case 0xce: return { "set 1,(hl)" };
case 0xcf: return { "set 1,a" };
case 0xd0: return { "set 2,b" };
case 0xd1: return { "set 2,c" };
case 0xd2: return { "set 2,d" };
case 0xd3: return { "set 2,e" };
case 0xd4: return { "set 2,h" };
case 0xd5: return { "set 2,l" };
case 0xd6: return { "set 2,(hl)" };
case 0xd7: return { "set 2,a" };
case 0xd8: return { "set 3,b" };
case 0xd9: return { "set 3,c" };
case 0xda: return { "set 3,d" };
case 0xdb: return { "set 3,e" };
case 0xdc: return { "set 3,h" };
case 0xdd: return { "set 3,l" };
case 0xde: return { "set 3,(hl)" };
case 0xdf: return { "set 3,a" };
case 0xe0: return { "set 4,b" };
case 0xe1: return { "set 4,c" };
case 0xe2: return { "set 4,d" };
case 0xe3: return { "set 4,e" };
case 0xe4: return { "set 4,h" };
case 0xe5: return { "set 4,l" };
case 0xe6: return { "set 4,(hl)" };
case 0xe7: return { "set 4,a" };
case 0xe8: return { "set 5,b" };
case 0xe9: return { "set 5,c" };
case 0xea: return { "set 5,d" };
case 0xeb: return { "set 5,e" };
case 0xec: return { "set 5,h" };
case 0xed: return { "set 5,l" };
case 0xee: return { "set 5,(hl)" };
case 0xef: return { "set 5,a" };
case 0xf0: return { "set 6,b" };
case 0xf1: return { "set 6,c" };
case 0xf2: return { "set 6,d" };
case 0xf3: return { "set 6,e" };
case 0xf4: return { "set 6,h" };
case 0xf5: return { "set 6,l" };
case 0xf6: return { "set 6,(hl)" };
case 0xf7: return { "set 6,a" };
case 0xf8: return { "set 7,b" };
case 0xf9: return { "set 7,c" };
case 0xfa: return { "set 7,d" };
case 0xfb: return { "set 7,e" };
case 0xfc: return { "set 7,h" };
case 0xfd: return { "set 7,l" };
case 0xfe: return { "set 7,(hl)" };
case 0xff: return { "set 7,a" };
}
return "";
}
#endif

View File

@ -1,101 +0,0 @@
enum {
A, F, AF,
B, C, BC,
D, E, DE,
H, L, HL,
SP, PC,
};
enum {
ZF, NF, HF, CF,
};
//register base class
//the idea here is to have all registers derive from a single base class.
//this allows construction of opcodes that can take any register as input or output,
//despite the fact that behind-the-scenes, special handling is done for eg: F, AF, HL, etc.
//registers can also be chained together: eg af = 0x0000 writes both a and f.
struct Register {
virtual operator unsigned() const = 0;
virtual unsigned operator=(unsigned x) = 0;
Register& operator=(const Register &x) { operator=((unsigned)x); return *this; }
unsigned operator++(int) { unsigned r = *this; operator=(*this + 1); return r; }
unsigned operator--(int) { unsigned r = *this; operator=(*this - 1); return r; }
unsigned operator++() { return operator=(*this + 1); }
unsigned operator--() { return operator=(*this - 1); }
unsigned operator |=(unsigned x) { return operator=(*this | x); }
unsigned operator ^=(unsigned x) { return operator=(*this ^ x); }
unsigned operator &=(unsigned x) { return operator=(*this & x); }
unsigned operator<<=(unsigned x) { return operator=(*this << x); }
unsigned operator>>=(unsigned x) { return operator=(*this >> x); }
unsigned operator +=(unsigned x) { return operator=(*this + x); }
unsigned operator -=(unsigned x) { return operator=(*this - x); }
unsigned operator *=(unsigned x) { return operator=(*this * x); }
unsigned operator /=(unsigned x) { return operator=(*this / x); }
unsigned operator %=(unsigned x) { return operator=(*this % x); }
};
struct Register8 : Register {
uint8 data;
operator unsigned() const { return data; }
unsigned operator=(unsigned x) { return data = x; }
};
struct RegisterF : Register {
bool z, n, h, c;
operator unsigned() const { return (z << 7) | (n << 6) | (h << 5) | (c << 4); }
unsigned operator=(unsigned x) { z = x & 0x80; n = x & 0x40; h = x & 0x20; c = x & 0x10; return *this; }
bool& operator[](unsigned r) {
static bool* table[] = { &z, &n, &h, &c };
return *table[r];
}
};
struct Register16 : Register {
uint16 data;
operator unsigned() const { return data; }
unsigned operator=(unsigned x) { return data = x; }
};
struct RegisterAF : Register {
Register8 &hi;
RegisterF &lo;
operator unsigned() const { return (hi << 8) | (lo << 0); }
unsigned operator=(unsigned x) { hi = x >> 8; lo = x >> 0; return *this; }
RegisterAF(Register8 &hi, RegisterF &lo) : hi(hi), lo(lo) {}
};
struct RegisterW : Register {
Register8 &hi, &lo;
operator unsigned() const { return (hi << 8) | (lo << 0); }
unsigned operator=(unsigned x) { hi = x >> 8; lo = x >> 0; return *this; }
RegisterW(Register8 &hi, Register8 &lo) : hi(hi), lo(lo) {}
};
struct Registers {
Register8 a;
RegisterF f;
RegisterAF af;
Register8 b;
Register8 c;
RegisterW bc;
Register8 d;
Register8 e;
RegisterW de;
Register8 h;
Register8 l;
RegisterW hl;
Register16 sp;
Register16 pc;
Register& operator[](unsigned r) {
static Register* table[] = { &a, &f, &af, &b, &c, &bc, &d, &e, &de, &h, &l, &hl, &sp, &pc };
return *table[r];
}
Registers() : af(a, f), bc(b, c), de(d, e), hl(h, l) {}
} r;

View File

@ -1,519 +0,0 @@
#ifdef CPU_CPP
void CPU::initialize_opcode_table() {
opcode_table[0x00] = &CPU::op_nop;
opcode_table[0x01] = &CPU::op_ld_rr_nn<BC>;
opcode_table[0x02] = &CPU::op_ld_rr_a<BC>;
opcode_table[0x03] = &CPU::op_inc_rr<BC>;
opcode_table[0x04] = &CPU::op_inc_r<B>;
opcode_table[0x05] = &CPU::op_dec_r<B>;
opcode_table[0x06] = &CPU::op_ld_r_n<B>;
opcode_table[0x07] = &CPU::op_rlca;
opcode_table[0x08] = &CPU::op_ld_nn_sp;
opcode_table[0x09] = &CPU::op_add_hl_rr<BC>;
opcode_table[0x0a] = &CPU::op_ld_a_rr<BC>;
opcode_table[0x0b] = &CPU::op_dec_rr<BC>;
opcode_table[0x0c] = &CPU::op_inc_r<C>;
opcode_table[0x0d] = &CPU::op_dec_r<C>;
opcode_table[0x0e] = &CPU::op_ld_r_n<C>;
opcode_table[0x0f] = &CPU::op_rrca;
opcode_table[0x10] = &CPU::op_stop;
opcode_table[0x11] = &CPU::op_ld_rr_nn<DE>;
opcode_table[0x12] = &CPU::op_ld_rr_a<DE>;
opcode_table[0x13] = &CPU::op_inc_rr<DE>;
opcode_table[0x14] = &CPU::op_inc_r<D>;
opcode_table[0x15] = &CPU::op_dec_r<D>;
opcode_table[0x16] = &CPU::op_ld_r_n<D>;
opcode_table[0x17] = &CPU::op_rla;
opcode_table[0x18] = &CPU::op_jr_n;
opcode_table[0x19] = &CPU::op_add_hl_rr<DE>;
opcode_table[0x1a] = &CPU::op_ld_a_rr<DE>;
opcode_table[0x1b] = &CPU::op_dec_rr<DE>;
opcode_table[0x1c] = &CPU::op_inc_r<E>;
opcode_table[0x1d] = &CPU::op_dec_r<E>;
opcode_table[0x1e] = &CPU::op_ld_r_n<E>;
opcode_table[0x1f] = &CPU::op_rra;
opcode_table[0x20] = &CPU::op_jr_f_n<ZF, 0>;
opcode_table[0x21] = &CPU::op_ld_rr_nn<HL>;
opcode_table[0x22] = &CPU::op_ldi_hl_a;
opcode_table[0x23] = &CPU::op_inc_rr<HL>;
opcode_table[0x24] = &CPU::op_inc_r<H>;
opcode_table[0x25] = &CPU::op_dec_r<H>;
opcode_table[0x26] = &CPU::op_ld_r_n<H>;
opcode_table[0x27] = &CPU::op_daa;
opcode_table[0x28] = &CPU::op_jr_f_n<ZF, 1>;
opcode_table[0x29] = &CPU::op_add_hl_rr<HL>;
opcode_table[0x2a] = &CPU::op_ldi_a_hl;
opcode_table[0x2b] = &CPU::op_dec_rr<HL>;
opcode_table[0x2c] = &CPU::op_inc_r<L>;
opcode_table[0x2d] = &CPU::op_dec_r<L>;
opcode_table[0x2e] = &CPU::op_ld_r_n<L>;
opcode_table[0x2f] = &CPU::op_cpl;
opcode_table[0x30] = &CPU::op_jr_f_n<CF, 0>;
opcode_table[0x31] = &CPU::op_ld_rr_nn<SP>;
opcode_table[0x32] = &CPU::op_ldd_hl_a;
opcode_table[0x33] = &CPU::op_inc_rr<SP>;
opcode_table[0x34] = &CPU::op_inc_hl;
opcode_table[0x35] = &CPU::op_dec_hl;
opcode_table[0x36] = &CPU::op_ld_hl_n;
opcode_table[0x37] = &CPU::op_scf;
opcode_table[0x38] = &CPU::op_jr_f_n<CF, 1>;
opcode_table[0x39] = &CPU::op_add_hl_rr<SP>;
opcode_table[0x3a] = &CPU::op_ldd_a_hl;
opcode_table[0x3b] = &CPU::op_dec_rr<SP>;
opcode_table[0x3c] = &CPU::op_inc_r<A>;
opcode_table[0x3d] = &CPU::op_dec_r<A>;
opcode_table[0x3e] = &CPU::op_ld_r_n<A>;
opcode_table[0x3f] = &CPU::op_ccf;
opcode_table[0x40] = &CPU::op_ld_r_r<B, B>;
opcode_table[0x41] = &CPU::op_ld_r_r<B, C>;
opcode_table[0x42] = &CPU::op_ld_r_r<B, D>;
opcode_table[0x43] = &CPU::op_ld_r_r<B, E>;
opcode_table[0x44] = &CPU::op_ld_r_r<B, H>;
opcode_table[0x45] = &CPU::op_ld_r_r<B, L>;
opcode_table[0x46] = &CPU::op_ld_r_hl<B>;
opcode_table[0x47] = &CPU::op_ld_r_r<B, A>;
opcode_table[0x48] = &CPU::op_ld_r_r<C, B>;
opcode_table[0x49] = &CPU::op_ld_r_r<C, C>;
opcode_table[0x4a] = &CPU::op_ld_r_r<C, D>;
opcode_table[0x4b] = &CPU::op_ld_r_r<C, E>;
opcode_table[0x4c] = &CPU::op_ld_r_r<C, H>;
opcode_table[0x4d] = &CPU::op_ld_r_r<C, L>;
opcode_table[0x4e] = &CPU::op_ld_r_hl<C>;
opcode_table[0x4f] = &CPU::op_ld_r_r<C, A>;
opcode_table[0x50] = &CPU::op_ld_r_r<D, B>;
opcode_table[0x51] = &CPU::op_ld_r_r<D, C>;
opcode_table[0x52] = &CPU::op_ld_r_r<D, D>;
opcode_table[0x53] = &CPU::op_ld_r_r<D, E>;
opcode_table[0x54] = &CPU::op_ld_r_r<D, H>;
opcode_table[0x55] = &CPU::op_ld_r_r<D, L>;
opcode_table[0x56] = &CPU::op_ld_r_hl<D>;
opcode_table[0x57] = &CPU::op_ld_r_r<D, A>;
opcode_table[0x58] = &CPU::op_ld_r_r<E, B>;
opcode_table[0x59] = &CPU::op_ld_r_r<E, C>;
opcode_table[0x5a] = &CPU::op_ld_r_r<E, D>;
opcode_table[0x5b] = &CPU::op_ld_r_r<E, E>;
opcode_table[0x5c] = &CPU::op_ld_r_r<E, H>;
opcode_table[0x5d] = &CPU::op_ld_r_r<E, L>;
opcode_table[0x5e] = &CPU::op_ld_r_hl<E>;
opcode_table[0x5f] = &CPU::op_ld_r_r<E, A>;
opcode_table[0x60] = &CPU::op_ld_r_r<H, B>;
opcode_table[0x61] = &CPU::op_ld_r_r<H, C>;
opcode_table[0x62] = &CPU::op_ld_r_r<H, D>;
opcode_table[0x63] = &CPU::op_ld_r_r<H, E>;
opcode_table[0x64] = &CPU::op_ld_r_r<H, H>;
opcode_table[0x65] = &CPU::op_ld_r_r<H, L>;
opcode_table[0x66] = &CPU::op_ld_r_hl<H>;
opcode_table[0x67] = &CPU::op_ld_r_r<H, A>;
opcode_table[0x68] = &CPU::op_ld_r_r<L, B>;
opcode_table[0x69] = &CPU::op_ld_r_r<L, C>;
opcode_table[0x6a] = &CPU::op_ld_r_r<L, D>;
opcode_table[0x6b] = &CPU::op_ld_r_r<L, E>;
opcode_table[0x6c] = &CPU::op_ld_r_r<L, H>;
opcode_table[0x6d] = &CPU::op_ld_r_r<L, L>;
opcode_table[0x6e] = &CPU::op_ld_r_hl<L>;
opcode_table[0x6f] = &CPU::op_ld_r_r<L, A>;
opcode_table[0x70] = &CPU::op_ld_hl_r<B>;
opcode_table[0x71] = &CPU::op_ld_hl_r<C>;
opcode_table[0x72] = &CPU::op_ld_hl_r<D>;
opcode_table[0x73] = &CPU::op_ld_hl_r<E>;
opcode_table[0x74] = &CPU::op_ld_hl_r<H>;
opcode_table[0x75] = &CPU::op_ld_hl_r<L>;
opcode_table[0x76] = &CPU::op_halt;
opcode_table[0x77] = &CPU::op_ld_hl_r<A>;
opcode_table[0x78] = &CPU::op_ld_r_r<A, B>;
opcode_table[0x79] = &CPU::op_ld_r_r<A, C>;
opcode_table[0x7a] = &CPU::op_ld_r_r<A, D>;
opcode_table[0x7b] = &CPU::op_ld_r_r<A, E>;
opcode_table[0x7c] = &CPU::op_ld_r_r<A, H>;
opcode_table[0x7d] = &CPU::op_ld_r_r<A, L>;
opcode_table[0x7e] = &CPU::op_ld_r_hl<A>;
opcode_table[0x7f] = &CPU::op_ld_r_r<A, A>;
opcode_table[0x80] = &CPU::op_add_a_r<B>;
opcode_table[0x81] = &CPU::op_add_a_r<C>;
opcode_table[0x82] = &CPU::op_add_a_r<D>;
opcode_table[0x83] = &CPU::op_add_a_r<E>;
opcode_table[0x84] = &CPU::op_add_a_r<H>;
opcode_table[0x85] = &CPU::op_add_a_r<L>;
opcode_table[0x86] = &CPU::op_add_a_hl;
opcode_table[0x87] = &CPU::op_add_a_r<A>;
opcode_table[0x88] = &CPU::op_adc_a_r<B>;
opcode_table[0x89] = &CPU::op_adc_a_r<C>;
opcode_table[0x8a] = &CPU::op_adc_a_r<D>;
opcode_table[0x8b] = &CPU::op_adc_a_r<E>;
opcode_table[0x8c] = &CPU::op_adc_a_r<H>;
opcode_table[0x8d] = &CPU::op_adc_a_r<L>;
opcode_table[0x8e] = &CPU::op_adc_a_hl;
opcode_table[0x8f] = &CPU::op_adc_a_r<A>;
opcode_table[0x90] = &CPU::op_sub_a_r<B>;
opcode_table[0x91] = &CPU::op_sub_a_r<C>;
opcode_table[0x92] = &CPU::op_sub_a_r<D>;
opcode_table[0x93] = &CPU::op_sub_a_r<E>;
opcode_table[0x94] = &CPU::op_sub_a_r<H>;
opcode_table[0x95] = &CPU::op_sub_a_r<L>;
opcode_table[0x96] = &CPU::op_sub_a_hl;
opcode_table[0x97] = &CPU::op_sub_a_r<A>;
opcode_table[0x98] = &CPU::op_sbc_a_r<B>;
opcode_table[0x99] = &CPU::op_sbc_a_r<C>;
opcode_table[0x9a] = &CPU::op_sbc_a_r<D>;
opcode_table[0x9b] = &CPU::op_sbc_a_r<E>;
opcode_table[0x9c] = &CPU::op_sbc_a_r<H>;
opcode_table[0x9d] = &CPU::op_sbc_a_r<L>;
opcode_table[0x9e] = &CPU::op_sbc_a_hl;
opcode_table[0x9f] = &CPU::op_sbc_a_r<A>;
opcode_table[0xa0] = &CPU::op_and_a_r<B>;
opcode_table[0xa1] = &CPU::op_and_a_r<C>;
opcode_table[0xa2] = &CPU::op_and_a_r<D>;
opcode_table[0xa3] = &CPU::op_and_a_r<E>;
opcode_table[0xa4] = &CPU::op_and_a_r<H>;
opcode_table[0xa5] = &CPU::op_and_a_r<L>;
opcode_table[0xa6] = &CPU::op_and_a_hl;
opcode_table[0xa7] = &CPU::op_and_a_r<A>;
opcode_table[0xa8] = &CPU::op_xor_a_r<B>;
opcode_table[0xa9] = &CPU::op_xor_a_r<C>;
opcode_table[0xaa] = &CPU::op_xor_a_r<D>;
opcode_table[0xab] = &CPU::op_xor_a_r<E>;
opcode_table[0xac] = &CPU::op_xor_a_r<H>;
opcode_table[0xad] = &CPU::op_xor_a_r<L>;
opcode_table[0xae] = &CPU::op_xor_a_hl;
opcode_table[0xaf] = &CPU::op_xor_a_r<A>;
opcode_table[0xb0] = &CPU::op_or_a_r<B>;
opcode_table[0xb1] = &CPU::op_or_a_r<C>;
opcode_table[0xb2] = &CPU::op_or_a_r<D>;
opcode_table[0xb3] = &CPU::op_or_a_r<E>;
opcode_table[0xb4] = &CPU::op_or_a_r<H>;
opcode_table[0xb5] = &CPU::op_or_a_r<L>;
opcode_table[0xb6] = &CPU::op_or_a_hl;
opcode_table[0xb7] = &CPU::op_or_a_r<A>;
opcode_table[0xb8] = &CPU::op_cp_a_r<B>;
opcode_table[0xb9] = &CPU::op_cp_a_r<C>;
opcode_table[0xba] = &CPU::op_cp_a_r<D>;
opcode_table[0xbb] = &CPU::op_cp_a_r<E>;
opcode_table[0xbc] = &CPU::op_cp_a_r<H>;
opcode_table[0xbd] = &CPU::op_cp_a_r<L>;
opcode_table[0xbe] = &CPU::op_cp_a_hl;
opcode_table[0xbf] = &CPU::op_cp_a_r<A>;
opcode_table[0xc0] = &CPU::op_ret_f<ZF, 0>;
opcode_table[0xc1] = &CPU::op_pop_rr<BC>;
opcode_table[0xc2] = &CPU::op_jp_f_nn<ZF, 0>;
opcode_table[0xc3] = &CPU::op_jp_nn;
opcode_table[0xc4] = &CPU::op_call_f_nn<ZF, 0>;
opcode_table[0xc5] = &CPU::op_push_rr<BC>;
opcode_table[0xc6] = &CPU::op_add_a_n;
opcode_table[0xc7] = &CPU::op_rst_n<0x00>;
opcode_table[0xc8] = &CPU::op_ret_f<ZF, 1>;
opcode_table[0xc9] = &CPU::op_ret;
opcode_table[0xca] = &CPU::op_jp_f_nn<ZF, 1>;
opcode_table[0xcb] = &CPU::op_cb;
opcode_table[0xcc] = &CPU::op_call_f_nn<ZF, 1>;
opcode_table[0xcd] = &CPU::op_call_nn;
opcode_table[0xce] = &CPU::op_adc_a_n;
opcode_table[0xcf] = &CPU::op_rst_n<0x08>;
opcode_table[0xd0] = &CPU::op_ret_f<CF, 0>;
opcode_table[0xd1] = &CPU::op_pop_rr<DE>;
opcode_table[0xd2] = &CPU::op_jp_f_nn<CF, 0>;
opcode_table[0xd3] = &CPU::op_xx;
opcode_table[0xd4] = &CPU::op_call_f_nn<CF, 0>;
opcode_table[0xd5] = &CPU::op_push_rr<DE>;
opcode_table[0xd6] = &CPU::op_sub_a_n;
opcode_table[0xd7] = &CPU::op_rst_n<0x10>;
opcode_table[0xd8] = &CPU::op_ret_f<CF, 1>;
opcode_table[0xd9] = &CPU::op_reti;
opcode_table[0xda] = &CPU::op_jp_f_nn<CF, 1>;
opcode_table[0xdb] = &CPU::op_xx;
opcode_table[0xdc] = &CPU::op_call_f_nn<CF, 1>;
opcode_table[0xdd] = &CPU::op_xx;
opcode_table[0xde] = &CPU::op_sbc_a_n;
opcode_table[0xdf] = &CPU::op_rst_n<0x18>;
opcode_table[0xe0] = &CPU::op_ld_ffn_a;
opcode_table[0xe1] = &CPU::op_pop_rr<HL>;
opcode_table[0xe2] = &CPU::op_ld_ffc_a;
opcode_table[0xe3] = &CPU::op_xx;
opcode_table[0xe4] = &CPU::op_xx;
opcode_table[0xe5] = &CPU::op_push_rr<HL>;
opcode_table[0xe6] = &CPU::op_and_a_n;
opcode_table[0xe7] = &CPU::op_rst_n<0x20>;
opcode_table[0xe8] = &CPU::op_add_sp_n;
opcode_table[0xe9] = &CPU::op_jp_hl;
opcode_table[0xea] = &CPU::op_ld_nn_a;
opcode_table[0xeb] = &CPU::op_xx;
opcode_table[0xec] = &CPU::op_xx;
opcode_table[0xed] = &CPU::op_xx;
opcode_table[0xee] = &CPU::op_xor_a_n;
opcode_table[0xef] = &CPU::op_rst_n<0x28>;
opcode_table[0xf0] = &CPU::op_ld_a_ffn;
opcode_table[0xf1] = &CPU::op_pop_rr<AF>;
opcode_table[0xf2] = &CPU::op_ld_a_ffc;
opcode_table[0xf3] = &CPU::op_di;
opcode_table[0xf4] = &CPU::op_xx;
opcode_table[0xf5] = &CPU::op_push_rr<AF>;
opcode_table[0xf6] = &CPU::op_or_a_n;
opcode_table[0xf7] = &CPU::op_rst_n<0x30>;
opcode_table[0xf8] = &CPU::op_ld_hl_sp_n;
opcode_table[0xf9] = &CPU::op_ld_sp_hl;
opcode_table[0xfa] = &CPU::op_ld_a_nn;
opcode_table[0xfb] = &CPU::op_ei;
opcode_table[0xfc] = &CPU::op_xx;
opcode_table[0xfd] = &CPU::op_xx;
opcode_table[0xfe] = &CPU::op_cp_a_n;
opcode_table[0xff] = &CPU::op_rst_n<0x38>;
opcode_table_cb[0x00] = &CPU::op_rlc_r<B>;
opcode_table_cb[0x01] = &CPU::op_rlc_r<C>;
opcode_table_cb[0x02] = &CPU::op_rlc_r<D>;
opcode_table_cb[0x03] = &CPU::op_rlc_r<E>;
opcode_table_cb[0x04] = &CPU::op_rlc_r<H>;
opcode_table_cb[0x05] = &CPU::op_rlc_r<L>;
opcode_table_cb[0x06] = &CPU::op_rlc_hl;
opcode_table_cb[0x07] = &CPU::op_rlc_r<A>;
opcode_table_cb[0x08] = &CPU::op_rrc_r<B>;
opcode_table_cb[0x09] = &CPU::op_rrc_r<C>;
opcode_table_cb[0x0a] = &CPU::op_rrc_r<D>;
opcode_table_cb[0x0b] = &CPU::op_rrc_r<E>;
opcode_table_cb[0x0c] = &CPU::op_rrc_r<H>;
opcode_table_cb[0x0d] = &CPU::op_rrc_r<L>;
opcode_table_cb[0x0e] = &CPU::op_rrc_hl;
opcode_table_cb[0x0f] = &CPU::op_rrc_r<A>;
opcode_table_cb[0x10] = &CPU::op_rl_r<B>;
opcode_table_cb[0x11] = &CPU::op_rl_r<C>;
opcode_table_cb[0x12] = &CPU::op_rl_r<D>;
opcode_table_cb[0x13] = &CPU::op_rl_r<E>;
opcode_table_cb[0x14] = &CPU::op_rl_r<H>;
opcode_table_cb[0x15] = &CPU::op_rl_r<L>;
opcode_table_cb[0x16] = &CPU::op_rl_hl;
opcode_table_cb[0x17] = &CPU::op_rl_r<A>;
opcode_table_cb[0x18] = &CPU::op_rr_r<B>;
opcode_table_cb[0x19] = &CPU::op_rr_r<C>;
opcode_table_cb[0x1a] = &CPU::op_rr_r<D>;
opcode_table_cb[0x1b] = &CPU::op_rr_r<E>;
opcode_table_cb[0x1c] = &CPU::op_rr_r<H>;
opcode_table_cb[0x1d] = &CPU::op_rr_r<L>;
opcode_table_cb[0x1e] = &CPU::op_rr_hl;
opcode_table_cb[0x1f] = &CPU::op_rr_r<A>;
opcode_table_cb[0x20] = &CPU::op_sla_r<B>;
opcode_table_cb[0x21] = &CPU::op_sla_r<C>;
opcode_table_cb[0x22] = &CPU::op_sla_r<D>;
opcode_table_cb[0x23] = &CPU::op_sla_r<E>;
opcode_table_cb[0x24] = &CPU::op_sla_r<H>;
opcode_table_cb[0x25] = &CPU::op_sla_r<L>;
opcode_table_cb[0x26] = &CPU::op_sla_hl;
opcode_table_cb[0x27] = &CPU::op_sla_r<A>;
opcode_table_cb[0x28] = &CPU::op_sra_r<B>;
opcode_table_cb[0x29] = &CPU::op_sra_r<C>;
opcode_table_cb[0x2a] = &CPU::op_sra_r<D>;
opcode_table_cb[0x2b] = &CPU::op_sra_r<E>;
opcode_table_cb[0x2c] = &CPU::op_sra_r<H>;
opcode_table_cb[0x2d] = &CPU::op_sra_r<L>;
opcode_table_cb[0x2e] = &CPU::op_sra_hl;
opcode_table_cb[0x2f] = &CPU::op_sra_r<A>;
opcode_table_cb[0x30] = &CPU::op_swap_r<B>;
opcode_table_cb[0x31] = &CPU::op_swap_r<C>;
opcode_table_cb[0x32] = &CPU::op_swap_r<D>;
opcode_table_cb[0x33] = &CPU::op_swap_r<E>;
opcode_table_cb[0x34] = &CPU::op_swap_r<H>;
opcode_table_cb[0x35] = &CPU::op_swap_r<L>;
opcode_table_cb[0x36] = &CPU::op_swap_hl;
opcode_table_cb[0x37] = &CPU::op_swap_r<A>;
opcode_table_cb[0x38] = &CPU::op_srl_r<B>;
opcode_table_cb[0x39] = &CPU::op_srl_r<C>;
opcode_table_cb[0x3a] = &CPU::op_srl_r<D>;
opcode_table_cb[0x3b] = &CPU::op_srl_r<E>;
opcode_table_cb[0x3c] = &CPU::op_srl_r<H>;
opcode_table_cb[0x3d] = &CPU::op_srl_r<L>;
opcode_table_cb[0x3e] = &CPU::op_srl_hl;
opcode_table_cb[0x3f] = &CPU::op_srl_r<A>;
opcode_table_cb[0x40] = &CPU::op_bit_n_r<0, B>;
opcode_table_cb[0x41] = &CPU::op_bit_n_r<0, C>;
opcode_table_cb[0x42] = &CPU::op_bit_n_r<0, D>;
opcode_table_cb[0x43] = &CPU::op_bit_n_r<0, E>;
opcode_table_cb[0x44] = &CPU::op_bit_n_r<0, H>;
opcode_table_cb[0x45] = &CPU::op_bit_n_r<0, L>;
opcode_table_cb[0x46] = &CPU::op_bit_n_hl<0>;
opcode_table_cb[0x47] = &CPU::op_bit_n_r<0, A>;
opcode_table_cb[0x48] = &CPU::op_bit_n_r<1, B>;
opcode_table_cb[0x49] = &CPU::op_bit_n_r<1, C>;
opcode_table_cb[0x4a] = &CPU::op_bit_n_r<1, D>;
opcode_table_cb[0x4b] = &CPU::op_bit_n_r<1, E>;
opcode_table_cb[0x4c] = &CPU::op_bit_n_r<1, H>;
opcode_table_cb[0x4d] = &CPU::op_bit_n_r<1, L>;
opcode_table_cb[0x4e] = &CPU::op_bit_n_hl<1>;
opcode_table_cb[0x4f] = &CPU::op_bit_n_r<1, A>;
opcode_table_cb[0x50] = &CPU::op_bit_n_r<2, B>;
opcode_table_cb[0x51] = &CPU::op_bit_n_r<2, C>;
opcode_table_cb[0x52] = &CPU::op_bit_n_r<2, D>;
opcode_table_cb[0x53] = &CPU::op_bit_n_r<2, E>;
opcode_table_cb[0x54] = &CPU::op_bit_n_r<2, H>;
opcode_table_cb[0x55] = &CPU::op_bit_n_r<2, L>;
opcode_table_cb[0x56] = &CPU::op_bit_n_hl<2>;
opcode_table_cb[0x57] = &CPU::op_bit_n_r<2, A>;
opcode_table_cb[0x58] = &CPU::op_bit_n_r<3, B>;
opcode_table_cb[0x59] = &CPU::op_bit_n_r<3, C>;
opcode_table_cb[0x5a] = &CPU::op_bit_n_r<3, D>;
opcode_table_cb[0x5b] = &CPU::op_bit_n_r<3, E>;
opcode_table_cb[0x5c] = &CPU::op_bit_n_r<3, H>;
opcode_table_cb[0x5d] = &CPU::op_bit_n_r<3, L>;
opcode_table_cb[0x5e] = &CPU::op_bit_n_hl<3>;
opcode_table_cb[0x5f] = &CPU::op_bit_n_r<3, A>;
opcode_table_cb[0x60] = &CPU::op_bit_n_r<4, B>;
opcode_table_cb[0x61] = &CPU::op_bit_n_r<4, C>;
opcode_table_cb[0x62] = &CPU::op_bit_n_r<4, D>;
opcode_table_cb[0x63] = &CPU::op_bit_n_r<4, E>;
opcode_table_cb[0x64] = &CPU::op_bit_n_r<4, H>;
opcode_table_cb[0x65] = &CPU::op_bit_n_r<4, L>;
opcode_table_cb[0x66] = &CPU::op_bit_n_hl<4>;
opcode_table_cb[0x67] = &CPU::op_bit_n_r<4, A>;
opcode_table_cb[0x68] = &CPU::op_bit_n_r<5, B>;
opcode_table_cb[0x69] = &CPU::op_bit_n_r<5, C>;
opcode_table_cb[0x6a] = &CPU::op_bit_n_r<5, D>;
opcode_table_cb[0x6b] = &CPU::op_bit_n_r<5, E>;
opcode_table_cb[0x6c] = &CPU::op_bit_n_r<5, H>;
opcode_table_cb[0x6d] = &CPU::op_bit_n_r<5, L>;
opcode_table_cb[0x6e] = &CPU::op_bit_n_hl<5>;
opcode_table_cb[0x6f] = &CPU::op_bit_n_r<5, A>;
opcode_table_cb[0x70] = &CPU::op_bit_n_r<6, B>;
opcode_table_cb[0x71] = &CPU::op_bit_n_r<6, C>;
opcode_table_cb[0x72] = &CPU::op_bit_n_r<6, D>;
opcode_table_cb[0x73] = &CPU::op_bit_n_r<6, E>;
opcode_table_cb[0x74] = &CPU::op_bit_n_r<6, H>;
opcode_table_cb[0x75] = &CPU::op_bit_n_r<6, L>;
opcode_table_cb[0x76] = &CPU::op_bit_n_hl<6>;
opcode_table_cb[0x77] = &CPU::op_bit_n_r<6, A>;
opcode_table_cb[0x78] = &CPU::op_bit_n_r<7, B>;
opcode_table_cb[0x79] = &CPU::op_bit_n_r<7, C>;
opcode_table_cb[0x7a] = &CPU::op_bit_n_r<7, D>;
opcode_table_cb[0x7b] = &CPU::op_bit_n_r<7, E>;
opcode_table_cb[0x7c] = &CPU::op_bit_n_r<7, H>;
opcode_table_cb[0x7d] = &CPU::op_bit_n_r<7, L>;
opcode_table_cb[0x7e] = &CPU::op_bit_n_hl<7>;
opcode_table_cb[0x7f] = &CPU::op_bit_n_r<7, A>;
opcode_table_cb[0x80] = &CPU::op_res_n_r<0, B>;
opcode_table_cb[0x81] = &CPU::op_res_n_r<0, C>;
opcode_table_cb[0x82] = &CPU::op_res_n_r<0, D>;
opcode_table_cb[0x83] = &CPU::op_res_n_r<0, E>;
opcode_table_cb[0x84] = &CPU::op_res_n_r<0, H>;
opcode_table_cb[0x85] = &CPU::op_res_n_r<0, L>;
opcode_table_cb[0x86] = &CPU::op_res_n_hl<0>;
opcode_table_cb[0x87] = &CPU::op_res_n_r<0, A>;
opcode_table_cb[0x88] = &CPU::op_res_n_r<1, B>;
opcode_table_cb[0x89] = &CPU::op_res_n_r<1, C>;
opcode_table_cb[0x8a] = &CPU::op_res_n_r<1, D>;
opcode_table_cb[0x8b] = &CPU::op_res_n_r<1, E>;
opcode_table_cb[0x8c] = &CPU::op_res_n_r<1, H>;
opcode_table_cb[0x8d] = &CPU::op_res_n_r<1, L>;
opcode_table_cb[0x8e] = &CPU::op_res_n_hl<1>;
opcode_table_cb[0x8f] = &CPU::op_res_n_r<1, A>;
opcode_table_cb[0x90] = &CPU::op_res_n_r<2, B>;
opcode_table_cb[0x91] = &CPU::op_res_n_r<2, C>;
opcode_table_cb[0x92] = &CPU::op_res_n_r<2, D>;
opcode_table_cb[0x93] = &CPU::op_res_n_r<2, E>;
opcode_table_cb[0x94] = &CPU::op_res_n_r<2, H>;
opcode_table_cb[0x95] = &CPU::op_res_n_r<2, L>;
opcode_table_cb[0x96] = &CPU::op_res_n_hl<2>;
opcode_table_cb[0x97] = &CPU::op_res_n_r<2, A>;
opcode_table_cb[0x98] = &CPU::op_res_n_r<3, B>;
opcode_table_cb[0x99] = &CPU::op_res_n_r<3, C>;
opcode_table_cb[0x9a] = &CPU::op_res_n_r<3, D>;
opcode_table_cb[0x9b] = &CPU::op_res_n_r<3, E>;
opcode_table_cb[0x9c] = &CPU::op_res_n_r<3, H>;
opcode_table_cb[0x9d] = &CPU::op_res_n_r<3, L>;
opcode_table_cb[0x9e] = &CPU::op_res_n_hl<3>;
opcode_table_cb[0x9f] = &CPU::op_res_n_r<3, A>;
opcode_table_cb[0xa0] = &CPU::op_res_n_r<4, B>;
opcode_table_cb[0xa1] = &CPU::op_res_n_r<4, C>;
opcode_table_cb[0xa2] = &CPU::op_res_n_r<4, D>;
opcode_table_cb[0xa3] = &CPU::op_res_n_r<4, E>;
opcode_table_cb[0xa4] = &CPU::op_res_n_r<4, H>;
opcode_table_cb[0xa5] = &CPU::op_res_n_r<4, L>;
opcode_table_cb[0xa6] = &CPU::op_res_n_hl<4>;
opcode_table_cb[0xa7] = &CPU::op_res_n_r<4, A>;
opcode_table_cb[0xa8] = &CPU::op_res_n_r<5, B>;
opcode_table_cb[0xa9] = &CPU::op_res_n_r<5, C>;
opcode_table_cb[0xaa] = &CPU::op_res_n_r<5, D>;
opcode_table_cb[0xab] = &CPU::op_res_n_r<5, E>;
opcode_table_cb[0xac] = &CPU::op_res_n_r<5, H>;
opcode_table_cb[0xad] = &CPU::op_res_n_r<5, L>;
opcode_table_cb[0xae] = &CPU::op_res_n_hl<5>;
opcode_table_cb[0xaf] = &CPU::op_res_n_r<5, A>;
opcode_table_cb[0xb0] = &CPU::op_res_n_r<6, B>;
opcode_table_cb[0xb1] = &CPU::op_res_n_r<6, C>;
opcode_table_cb[0xb2] = &CPU::op_res_n_r<6, D>;
opcode_table_cb[0xb3] = &CPU::op_res_n_r<6, E>;
opcode_table_cb[0xb4] = &CPU::op_res_n_r<6, H>;
opcode_table_cb[0xb5] = &CPU::op_res_n_r<6, L>;
opcode_table_cb[0xb6] = &CPU::op_res_n_hl<6>;
opcode_table_cb[0xb7] = &CPU::op_res_n_r<6, A>;
opcode_table_cb[0xb8] = &CPU::op_res_n_r<7, B>;
opcode_table_cb[0xb9] = &CPU::op_res_n_r<7, C>;
opcode_table_cb[0xba] = &CPU::op_res_n_r<7, D>;
opcode_table_cb[0xbb] = &CPU::op_res_n_r<7, E>;
opcode_table_cb[0xbc] = &CPU::op_res_n_r<7, H>;
opcode_table_cb[0xbd] = &CPU::op_res_n_r<7, L>;
opcode_table_cb[0xbe] = &CPU::op_res_n_hl<7>;
opcode_table_cb[0xbf] = &CPU::op_res_n_r<7, A>;
opcode_table_cb[0xc0] = &CPU::op_set_n_r<0, B>;
opcode_table_cb[0xc1] = &CPU::op_set_n_r<0, C>;
opcode_table_cb[0xc2] = &CPU::op_set_n_r<0, D>;
opcode_table_cb[0xc3] = &CPU::op_set_n_r<0, E>;
opcode_table_cb[0xc4] = &CPU::op_set_n_r<0, H>;
opcode_table_cb[0xc5] = &CPU::op_set_n_r<0, L>;
opcode_table_cb[0xc6] = &CPU::op_set_n_hl<0>;
opcode_table_cb[0xc7] = &CPU::op_set_n_r<0, A>;
opcode_table_cb[0xc8] = &CPU::op_set_n_r<1, B>;
opcode_table_cb[0xc9] = &CPU::op_set_n_r<1, C>;
opcode_table_cb[0xca] = &CPU::op_set_n_r<1, D>;
opcode_table_cb[0xcb] = &CPU::op_set_n_r<1, E>;
opcode_table_cb[0xcc] = &CPU::op_set_n_r<1, H>;
opcode_table_cb[0xcd] = &CPU::op_set_n_r<1, L>;
opcode_table_cb[0xce] = &CPU::op_set_n_hl<1>;
opcode_table_cb[0xcf] = &CPU::op_set_n_r<1, A>;
opcode_table_cb[0xd0] = &CPU::op_set_n_r<2, B>;
opcode_table_cb[0xd1] = &CPU::op_set_n_r<2, C>;
opcode_table_cb[0xd2] = &CPU::op_set_n_r<2, D>;
opcode_table_cb[0xd3] = &CPU::op_set_n_r<2, E>;
opcode_table_cb[0xd4] = &CPU::op_set_n_r<2, H>;
opcode_table_cb[0xd5] = &CPU::op_set_n_r<2, L>;
opcode_table_cb[0xd6] = &CPU::op_set_n_hl<2>;
opcode_table_cb[0xd7] = &CPU::op_set_n_r<2, A>;
opcode_table_cb[0xd8] = &CPU::op_set_n_r<3, B>;
opcode_table_cb[0xd9] = &CPU::op_set_n_r<3, C>;
opcode_table_cb[0xda] = &CPU::op_set_n_r<3, D>;
opcode_table_cb[0xdb] = &CPU::op_set_n_r<3, E>;
opcode_table_cb[0xdc] = &CPU::op_set_n_r<3, H>;
opcode_table_cb[0xdd] = &CPU::op_set_n_r<3, L>;
opcode_table_cb[0xde] = &CPU::op_set_n_hl<3>;
opcode_table_cb[0xdf] = &CPU::op_set_n_r<3, A>;
opcode_table_cb[0xe0] = &CPU::op_set_n_r<4, B>;
opcode_table_cb[0xe1] = &CPU::op_set_n_r<4, C>;
opcode_table_cb[0xe2] = &CPU::op_set_n_r<4, D>;
opcode_table_cb[0xe3] = &CPU::op_set_n_r<4, E>;
opcode_table_cb[0xe4] = &CPU::op_set_n_r<4, H>;
opcode_table_cb[0xe5] = &CPU::op_set_n_r<4, L>;
opcode_table_cb[0xe6] = &CPU::op_set_n_hl<4>;
opcode_table_cb[0xe7] = &CPU::op_set_n_r<4, A>;
opcode_table_cb[0xe8] = &CPU::op_set_n_r<5, B>;
opcode_table_cb[0xe9] = &CPU::op_set_n_r<5, C>;
opcode_table_cb[0xea] = &CPU::op_set_n_r<5, D>;
opcode_table_cb[0xeb] = &CPU::op_set_n_r<5, E>;
opcode_table_cb[0xec] = &CPU::op_set_n_r<5, H>;
opcode_table_cb[0xed] = &CPU::op_set_n_r<5, L>;
opcode_table_cb[0xee] = &CPU::op_set_n_hl<5>;
opcode_table_cb[0xef] = &CPU::op_set_n_r<5, A>;
opcode_table_cb[0xf0] = &CPU::op_set_n_r<6, B>;
opcode_table_cb[0xf1] = &CPU::op_set_n_r<6, C>;
opcode_table_cb[0xf2] = &CPU::op_set_n_r<6, D>;
opcode_table_cb[0xf3] = &CPU::op_set_n_r<6, E>;
opcode_table_cb[0xf4] = &CPU::op_set_n_r<6, H>;
opcode_table_cb[0xf5] = &CPU::op_set_n_r<6, L>;
opcode_table_cb[0xf6] = &CPU::op_set_n_hl<6>;
opcode_table_cb[0xf7] = &CPU::op_set_n_r<6, A>;
opcode_table_cb[0xf8] = &CPU::op_set_n_r<7, B>;
opcode_table_cb[0xf9] = &CPU::op_set_n_r<7, C>;
opcode_table_cb[0xfa] = &CPU::op_set_n_r<7, D>;
opcode_table_cb[0xfb] = &CPU::op_set_n_r<7, E>;
opcode_table_cb[0xfc] = &CPU::op_set_n_r<7, H>;
opcode_table_cb[0xfd] = &CPU::op_set_n_r<7, L>;
opcode_table_cb[0xfe] = &CPU::op_set_n_hl<7>;
opcode_table_cb[0xff] = &CPU::op_set_n_r<7, A>;
}
#endif

View File

@ -1,226 +0,0 @@
#include <gameboy/gameboy.hpp>
#include <snes/snes.hpp>
#define CPU_CPP
namespace GameBoy {
#include "core/core.cpp"
#include "mmio/mmio.cpp"
#include "timing/timing.cpp"
CPU cpu;
void CPU::Main() {
cpu.main();
}
void CPU::main() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
scheduler.sync = Scheduler::SynchronizeMode::All;
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
if(SNES::interface()->wanttrace & TRACE_GB_MASK)
{
auto disasm = disassemble(r[PC]);
SNES::interface()->cpuTrace(TRACE_GB, (const char*)disasm);
}
//if(trace) print(disassemble(r[PC]), "\n");
interrupt_test();
cdlInfo.currFlags = eCDLog_Flags_ExecFirst;
uint8 opcode = op_read(r[PC]++);
cdlInfo.currFlags = eCDLog_Flags_CPUData;
(this->*opcode_table[opcode])();
}
}
void CPU::interrupt_raise(CPU::Interrupt id) {
if(id == Interrupt::Vblank) {
status.interrupt_request_vblank = 1;
if(status.interrupt_enable_vblank) status.halt = false;
}
if(id == Interrupt::Stat) {
status.interrupt_request_stat = 1;
if(status.interrupt_enable_stat) status.halt = false;
}
if(id == Interrupt::Timer) {
status.interrupt_request_timer = 1;
if(status.interrupt_enable_timer) status.halt = false;
}
if(id == Interrupt::Serial) {
status.interrupt_request_serial = 1;
if(status.interrupt_enable_serial) status.halt = false;
}
if(id == Interrupt::Joypad) {
status.interrupt_request_joypad = 1;
if(status.interrupt_enable_joypad) status.halt = status.stop = false;
}
}
void CPU::interrupt_test() {
if(status.ime) {
if(status.interrupt_request_vblank && status.interrupt_enable_vblank) {
status.interrupt_request_vblank = 0;
return interrupt_exec(0x0040);
}
if(status.interrupt_request_stat && status.interrupt_enable_stat) {
status.interrupt_request_stat = 0;
return interrupt_exec(0x0048);
}
if(status.interrupt_request_timer && status.interrupt_enable_timer) {
status.interrupt_request_timer = 0;
return interrupt_exec(0x0050);
}
if(status.interrupt_request_serial && status.interrupt_enable_serial) {
status.interrupt_request_serial = 0;
return interrupt_exec(0x0058);
}
if(status.interrupt_request_joypad && status.interrupt_enable_joypad) {
status.interrupt_request_joypad = 0;
return interrupt_exec(0x0060);
}
}
}
void CPU::interrupt_exec(uint16 pc) {
status.ime = 0;
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
r[PC] = pc;
op_io();
op_io();
op_io();
}
void CPU::power() {
create(Main, 4 * 1024 * 1024);
for(unsigned n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM
for(unsigned n = 0xe000; n <= 0xfdff; n++) bus.mmio[n] = this; //WRAM (mirror)
for(unsigned n = 0xff80; n <= 0xfffe; n++) bus.mmio[n] = this; //HRAM
bus.mmio[0xff00] = this; //JOYP
bus.mmio[0xff01] = this; //SB
bus.mmio[0xff02] = this; //SC
bus.mmio[0xff04] = this; //DIV
bus.mmio[0xff05] = this; //TIMA
bus.mmio[0xff06] = this; //TMA
bus.mmio[0xff07] = this; //TAC
bus.mmio[0xff0f] = this; //IF
bus.mmio[0xff46] = this; //DMA
bus.mmio[0xffff] = this; //IE
if(system.cgb()) {
bus.mmio[0xff4d] = this; //KEY1
bus.mmio[0xff51] = this; //HDMA1
bus.mmio[0xff52] = this; //HDMA2
bus.mmio[0xff53] = this; //HDMA3
bus.mmio[0xff54] = this; //HDMA4
bus.mmio[0xff55] = this; //HDMA5
bus.mmio[0xff56] = this; //RP
bus.mmio[0xff6c] = this; //???
bus.mmio[0xff70] = this; //SVBK
bus.mmio[0xff72] = this; //???
bus.mmio[0xff73] = this; //???
bus.mmio[0xff74] = this; //???
bus.mmio[0xff75] = this; //???
bus.mmio[0xff76] = this; //???
bus.mmio[0xff77] = this; //???
}
for(unsigned n = 0; n < 32768; n++) wram[n] = 0x00;
for(unsigned n = 0; n < 8192; n++) hram[n] = 0x00;
r[PC] = 0x0000;
r[SP] = 0x0000;
r[AF] = 0x0000;
r[BC] = 0x0000;
r[DE] = 0x0000;
r[HL] = 0x0000;
status.clock = 0;
status.halt = false;
status.stop = false;
status.ei = false;
status.ime = 0;
status.p15 = 0;
status.p14 = 0;
status.joyp = 0;
status.mlt_req = 0;
status.serial_data = 0;
status.serial_bits = 0;
status.serial_transfer = 0;
status.serial_clock = 0;
status.div = 0;
status.tima = 0;
status.tma = 0;
status.timer_enable = 0;
status.timer_clock = 0;
status.interrupt_request_joypad = 0;
status.interrupt_request_serial = 0;
status.interrupt_request_timer = 0;
status.interrupt_request_stat = 0;
status.interrupt_request_vblank = 0;
status.speed_double = 0;
status.speed_switch = 0;
status.dma_source = 0;
status.dma_target = 0;
status.dma_mode = 0;
status.dma_length = 0;
status.ff6c = 0;
status.ff72 = 0;
status.ff73 = 0;
status.ff74 = 0;
status.ff75 = 0;
status.wram_bank = 1;
status.interrupt_enable_joypad = 0;
status.interrupt_enable_serial = 0;
status.interrupt_enable_timer = 0;
status.interrupt_enable_stat = 0;
status.interrupt_enable_vblank = 0;
}
CPU::CPU()
: trace(false)
, wram(nullptr)
, hram(nullptr)
{
initialize_opcode_table();
}
CPU::~CPU()
{
SNES::interface()->freeSharedMemory(wram);
SNES::interface()->freeSharedMemory(hram);
}
void CPU::initialize()
{
wram = (uint8*)SNES::interface()->allocSharedMemory("SGB_WRAM", 32768);
hram = (uint8*)SNES::interface()->allocSharedMemory("SGB_HRAM", 8192);
}
} //namespace GameBoy

View File

@ -1,106 +0,0 @@
struct CPU : Processor, MMIO {
#include "core/core.hpp"
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"
bool trace;
enum class Interrupt : unsigned {
Vblank,
Stat,
Timer,
Serial,
Joypad,
};
struct Status {
unsigned clock;
bool halt;
bool stop;
bool ei;
bool ime;
//$ff00 JOYP
bool p15;
bool p14;
uint8 joyp;
uint8 mlt_req;
//$ff01 SB
uint8 serial_data;
unsigned serial_bits;
//$ff02 SC
bool serial_transfer;
bool serial_clock;
//$ff04 DIV
uint8 div;
//$ff05 TIMA
uint8 tima;
//$ff06 TMA
uint8 tma;
//$ff07 TAC
bool timer_enable;
unsigned timer_clock;
//$ff0f IF
bool interrupt_request_joypad;
bool interrupt_request_serial;
bool interrupt_request_timer;
bool interrupt_request_stat;
bool interrupt_request_vblank;
//$ff4d KEY1
bool speed_double;
bool speed_switch;
//$ff51,$ff52 HDMA1,HDMA2
uint16 dma_source;
//$ff53,$ff54 HDMA3,HDMA4
uint16 dma_target;
//$ff55 HDMA5
bool dma_mode;
uint16 dma_length;
//$ff6c ???
uint8 ff6c;
//$ff70 SVBK
uint3 wram_bank;
//$ff72-$ff75 ???
uint8 ff72;
uint8 ff73;
uint8 ff74;
uint8 ff75;
//$ffff IE
bool interrupt_enable_joypad;
bool interrupt_enable_serial;
bool interrupt_enable_timer;
bool interrupt_enable_stat;
bool interrupt_enable_vblank;
} status;
uint8* wram; //[32768]; //GB=8192, GBC=32768
uint8* hram; //[128];
static void Main();
void main();
void interrupt_raise(Interrupt id);
void interrupt_test();
void interrupt_exec(uint16 pc);
void power();
void initialize();
CPU();
~CPU();
};
extern CPU cpu;

View File

@ -1,278 +0,0 @@
#ifdef CPU_CPP
unsigned CPU::wram_addr(uint16 addr) const {
addr &= 0x1fff;
if(addr < 0x1000) return addr;
auto bank = status.wram_bank + (status.wram_bank == 0);
return (bank * 0x1000) + (addr & 0x0fff);
}
void CPU::mmio_joyp_poll() {
unsigned button = 0, dpad = 0;
button |= interface->inputPoll((unsigned)Input::Start) << 3;
button |= interface->inputPoll((unsigned)Input::Select) << 2;
button |= interface->inputPoll((unsigned)Input::B) << 1;
button |= interface->inputPoll((unsigned)Input::A) << 0;
dpad |= interface->inputPoll((unsigned)Input::Down) << 3;
dpad |= interface->inputPoll((unsigned)Input::Up) << 2;
dpad |= interface->inputPoll((unsigned)Input::Left) << 1;
dpad |= interface->inputPoll((unsigned)Input::Right) << 0;
status.joyp = 0x0f;
if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mlt_req;
if(status.p15 == 0) status.joyp &= button ^ 0x0f;
if(status.p14 == 0) status.joyp &= dpad ^ 0x0f;
if(status.joyp != 0x0f) interrupt_raise(Interrupt::Joypad);
}
uint8 CPU::mmio_read(uint16 addr) {
if(addr >= 0xc000 && addr <= 0xfdff) {
unsigned mapped_addr = wram_addr(addr);
cdlInfo.set(eCDLog_AddrType_SGB_WRAM, mapped_addr);
return wram[mapped_addr];
}
if(addr >= 0xff80 && addr <= 0xfffe) {
cdlInfo.set(eCDLog_AddrType_SGB_HRAM, addr & 0x7f);
return hram[addr & 0x7f];
}
if(addr == 0xff00) { //JOYP
return (status.p15 << 5)
| (status.p14 << 4)
| (status.joyp << 0);
}
if(addr == 0xff01) { //SB
return 0xff;
}
if(addr == 0xff02) { //SC
return (status.serial_transfer << 7)
| (status.serial_clock << 0);
}
if(addr == 0xff04) { //DIV
return status.div;
}
if(addr == 0xff05) { //TIMA
return status.tima;
}
if(addr == 0xff06) { //TMA
return status.tma;
}
if(addr == 0xff07) { //TAC
return (status.timer_enable << 2)
| (status.timer_clock << 0);
}
if(addr == 0xff0f) { //IF
return (status.interrupt_request_joypad << 4)
| (status.interrupt_request_serial << 3)
| (status.interrupt_request_timer << 2)
| (status.interrupt_request_stat << 1)
| (status.interrupt_request_vblank << 0);
}
if(addr == 0xff4d) { //KEY1
return (status.speed_double << 7);
}
if(addr == 0xff55) { //HDMA5
return (status.dma_length / 16) - 1;
}
if(addr == 0xff56) { //RP
return 0x02;
}
if(addr == 0xff6c) { //???
return 0xfe | status.ff6c;
}
if(addr == 0xff70) { //SVBK
return status.wram_bank;
}
if(addr == 0xff72) { //???
return status.ff72;
}
if(addr == 0xff73) { //???
return status.ff73;
}
if(addr == 0xff74) { //???
return status.ff74;
}
if(addr == 0xff75) { //???
return 0x8f | status.ff75;
}
if(addr == 0xff76) { //???
return 0x00;
}
if(addr == 0xff77) { //???
return 0x00;
}
if(addr == 0xffff) { //IE
return (status.interrupt_enable_joypad << 4)
| (status.interrupt_enable_serial << 3)
| (status.interrupt_enable_timer << 2)
| (status.interrupt_enable_stat << 1)
| (status.interrupt_enable_vblank << 0);
}
return 0x00;
}
void CPU::mmio_write(uint16 addr, uint8 data) {
if(addr >= 0xc000 && addr <= 0xfdff) { wram[wram_addr(addr)] = data; return; }
if(addr >= 0xff80 && addr <= 0xfffe) { hram[addr & 0x7f] = data; return; }
if(addr == 0xff00) { //JOYP
status.p15 = data & 0x20;
status.p14 = data & 0x10;
interface->joypWrite(status.p15, status.p14);
mmio_joyp_poll();
return;
}
if(addr == 0xff01) { //SB
status.serial_data = data;
return;
}
if(addr == 0xff02) { //SC
status.serial_transfer = data & 0x80;
status.serial_clock = data & 0x01;
if(status.serial_transfer) status.serial_bits = 8;
return;
}
if(addr == 0xff04) { //DIV
status.div = 0;
return;
}
if(addr == 0xff05) { //TIMA
status.tima = data;
return;
}
if(addr == 0xff06) { //TMA
status.tma = data;
return;
}
if(addr == 0xff07) { //TAC
status.timer_enable = data & 0x04;
status.timer_clock = data & 0x03;
return;
}
if(addr == 0xff0f) { //IF
status.interrupt_request_joypad = data & 0x10;
status.interrupt_request_serial = data & 0x08;
status.interrupt_request_timer = data & 0x04;
status.interrupt_request_stat = data & 0x02;
status.interrupt_request_vblank = data & 0x01;
return;
}
if(addr == 0xff46) { //DMA
for(unsigned n = 0x00; n <= 0x9f; n++) {
bus.write(0xfe00 + n, bus.read((data << 8) + n));
add_clocks(4);
}
return;
}
if(addr == 0xff4d) { //KEY1
status.speed_switch = data & 0x01;
return;
}
if(addr == 0xff51) { //HDMA1
status.dma_source = (status.dma_source & 0x00ff) | (data << 8);
return;
}
if(addr == 0xff52) { //HDMA2
status.dma_source = (status.dma_source & 0xff00) | (data << 0);
return;
}
if(addr == 0xff53) { //HDMA3
status.dma_target = (status.dma_target & 0x00ff) | (data << 8);
return;
}
if(addr == 0xff54) { //HDMA4
status.dma_target = (status.dma_target & 0xff00) | (data << 0);
return;
}
if(addr == 0xff55) { //HDMA5
status.dma_mode = data & 0x80;
status.dma_length = ((data & 0x7f) + 1) * 16;
if(status.dma_mode == 0) do {
bus.write(status.dma_target++, bus.read(status.dma_source++));
add_clocks(4 << status.speed_double);
} while(--status.dma_length);
return;
}
if(addr == 0xff56) { //RP
return;
}
if(addr == 0xff6c) { //???
status.ff6c = data & 0x01;
return;
}
if(addr == 0xff72) { //???
status.ff72 = data;
return;
}
if(addr == 0xff73) { //???
status.ff73 = data;
return;
}
if(addr == 0xff74) { //???
status.ff74 = data;
return;
}
if(addr == 0xff75) { //???
status.ff75 = data & 0x70;
return;
}
if(addr == 0xff70) { //SVBK
status.wram_bank = data & 0x07;
return;
}
if(addr == 0xffff) { //IE
status.interrupt_enable_joypad = data & 0x10;
status.interrupt_enable_serial = data & 0x08;
status.interrupt_enable_timer = data & 0x04;
status.interrupt_enable_stat = data & 0x02;
status.interrupt_enable_vblank = data & 0x01;
return;
}
}
#endif

View File

@ -1,4 +0,0 @@
unsigned wram_addr(uint16 addr) const;
void mmio_joyp_poll();
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);

View File

@ -1,28 +0,0 @@
#ifdef CPU_CPP
void CPU::op_io() {
cycle_edge();
add_clocks(4);
}
uint8 CPU::op_read(uint16 addr) {
cycle_edge();
uint8 r = bus.read(addr);
add_clocks(4);
return r;
}
void CPU::op_write(uint16 addr, uint8 data) {
cycle_edge();
bus.write(addr, data);
add_clocks(4);
}
void CPU::cycle_edge() {
if(status.ei) {
status.ei = false;
status.ime = 1;
}
}
#endif

View File

@ -1,96 +0,0 @@
//70224 clocks/frame
// 456 clocks/scanline
// 154 scanlines/frame
#ifdef CPU_CPP
#include "opcode.cpp"
void CPU::add_clocks(unsigned clocks) {
system.clocks_executed += clocks;
auto flags = cdlInfo.currFlags;
if(system.sgb()) scheduler.exit(Scheduler::ExitReason::StepEvent);
cdlInfo.currFlags = flags;
status.clock += clocks;
if(status.clock >= 4 * 1024 * 1024) {
status.clock -= 4 * 1024 * 1024;
cartridge.mbc3.second();
}
//4MHz / N(hz) - 1 = mask
if((status.clock & 15) == 0) timer_262144hz();
if((status.clock & 63) == 0) timer_65536hz();
if((status.clock & 255) == 0) timer_16384hz();
if((status.clock & 511) == 0) timer_8192hz();
if((status.clock & 1023) == 0) timer_4096hz();
lcd.clock -= clocks * lcd.frequency;
if(lcd.clock <= 0) co_switch(scheduler.active_thread = lcd.thread);
cdlInfo.currFlags = flags;
apu.clock -= clocks * apu.frequency;
if(apu.clock <= 0) co_switch(scheduler.active_thread = apu.thread);
cdlInfo.currFlags = flags;
}
void CPU::timer_262144hz() {
if(status.timer_enable && status.timer_clock == 1) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
}
}
}
void CPU::timer_65536hz() {
if(status.timer_enable && status.timer_clock == 2) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
}
}
}
void CPU::timer_16384hz() {
if(status.timer_enable && status.timer_clock == 3) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
}
}
status.div++;
}
void CPU::timer_8192hz() {
if(status.serial_transfer && status.serial_clock) {
if(--status.serial_bits == 0) {
status.serial_transfer = 0;
interrupt_raise(Interrupt::Serial);
}
}
}
void CPU::timer_4096hz() {
if(status.timer_enable && status.timer_clock == 0) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
}
}
}
void CPU::hblank() {
if(status.dma_mode == 1 && status.dma_length) {
for(unsigned n = 0; n < 16; n++) {
bus.write(status.dma_target++, bus.read(status.dma_source++));
add_clocks(4);
}
status.dma_length -= 16;
}
}
#endif

View File

@ -1,13 +0,0 @@
void add_clocks(unsigned clocks);
void timer_262144hz();
void timer_65536hz();
void timer_16384hz();
void timer_8192hz();
void timer_4096hz();
void hblank();
//opcode.cpp
void op_io();
uint8 op_read(uint16 addr);
void op_write(uint16 addr, uint8 data);
void cycle_edge();

View File

@ -1,47 +0,0 @@
#ifndef GAMEBOY_HPP
#define GAMEBOY_HPP
#include <base/base.hpp>
/*
bgameboy - Game Boy, Super Game Boy, and Game Boy Color emulator
author: byuu
license: GPLv3
project started: 2010-12-27
*/
#include <libco.h>
#include <nall/gameboy/cartridge.hpp>
namespace GameBoy {
struct Processor {
cothread_t thread;
unsigned frequency;
int64 clock;
inline void create(void (*entrypoint)(), unsigned frequency) {
if(thread) co_delete(thread);
thread = co_create(65536 * sizeof(void*), entrypoint);
this->frequency = frequency;
clock = 0;
}
inline Processor() : thread(nullptr) {
}
inline ~Processor() {
if(thread) co_delete(thread);
}
};
#include <gameboy/memory/memory.hpp>
#include <gameboy/system/system.hpp>
#include <gameboy/scheduler/scheduler.hpp>
#include <gameboy/cartridge/cartridge.hpp>
#include <gameboy/cpu/cpu.hpp>
#include <gameboy/apu/apu.hpp>
#include <gameboy/lcd/lcd.hpp>
#include <gameboy/video/video.hpp>
};
#endif

View File

@ -1,27 +0,0 @@
#include <gameboy/gameboy.hpp>
namespace GameBoy {
Interface *interface = nullptr;
void Interface::lcdScanline() {
}
void Interface::joypWrite(bool p15, bool p14) {
}
void Interface::videoRefresh(const uint16_t *data) {
}
void Interface::audioSample(int16_t center, int16_t left, int16_t right) {
}
bool Interface::inputPoll(unsigned id) {
return false;
}
void Interface::message(const string &text) {
print(text, "\n");
}
}

View File

@ -1,15 +0,0 @@
struct Interface {
virtual void lcdScanline();
virtual void joypWrite(bool p15, bool p14);
virtual void videoRefresh(const uint16_t *data);
virtual void audioSample(int16_t center, int16_t left, int16_t right);
virtual bool inputPoll(unsigned id);
virtual void message(const string &text);
virtual void* allocSharedMemory(const char* memtype, size_t amt, int initialByte = -1) = 0;
virtual void freeSharedMemory(void* ptr) = 0;
};
extern Interface *interface;

View File

@ -1,185 +0,0 @@
#ifdef LCD_CPP
void LCD::cgb_render() {
for(unsigned n = 0; n < 160; n++) {
line[n] = 0x7fff;
origin[n] = Origin::None;
}
if(status.display_enable) {
cgb_render_bg();
if(status.window_display_enable) cgb_render_window();
if(status.ob_enable) cgb_render_ob();
}
uint16 *output = screen + status.ly * 160;
for(unsigned n = 0; n < 160; n++) output[n] = line[n];
interface->lcdScanline();
}
//Attributes:
//0x80: 0 = OAM priority, 1 = BG priority
//0x40: vertical flip
//0x20: horizontal flip
//0x08: VRAM bank#
//0x07: palette#
void LCD::cgb_read_tile(bool select, unsigned x, unsigned y, unsigned &tile, unsigned &attr, unsigned &data) {
unsigned tmaddr = 0x1800 + (select << 10);
tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff;
tile = vram[0x0000 + tmaddr];
attr = vram[0x2000 + tmaddr];
unsigned tdaddr = attr & 0x08 ? 0x2000 : 0x0000;
if(status.bg_tiledata_select == 0) {
tdaddr += 0x1000 + ((int8)tile << 4);
} else {
tdaddr += 0x0000 + (tile << 4);
}
y &= 7;
if(attr & 0x40) y ^= 7;
tdaddr += y << 1;
data = vram[tdaddr++] << 0;
data |= vram[tdaddr++] << 8;
if(attr & 0x20) data = hflip(data);
}
void LCD::cgb_render_bg() {
unsigned iy = (status.ly + status.scy) & 255;
unsigned ix = status.scx, tx = ix & 7;
unsigned tile, attr, data;
cgb_read_tile(status.bg_tilemap_select, ix, iy, tile, attr, data);
for(unsigned ox = 0; ox < 160; ox++) {
unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0)
| ((data & (0x8000 >> tx)) ? 2 : 0);
unsigned palette_index = ((attr & 0x07) << 3) + (index << 1);
unsigned palette = 0;
palette |= bgpd[palette_index++] << 0;
palette |= bgpd[palette_index++] << 8;
palette &= 0x7fff;
line[ox] = palette;
origin[ox] = (attr & 0x80 ? Origin::BGP : Origin::BG);
ix = (ix + 1) & 255;
tx = (tx + 1) & 7;
if(tx == 0) cgb_read_tile(status.bg_tilemap_select, ix, iy, tile, attr, data);
}
}
void LCD::cgb_render_window() {
if(status.ly - status.wy >= 144u) return;
if(status.wx >= 167u) return;
unsigned iy = status.wyc++;
unsigned ix = (7 - status.wx) & 255, tx = ix & 7;
unsigned tile, attr, data;
cgb_read_tile(status.window_tilemap_select, ix, iy, tile, attr, data);
for(unsigned ox = 0; ox < 160; ox++) {
unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0)
| ((data & (0x8000 >> tx)) ? 2 : 0);
unsigned palette_index = ((attr & 0x07) << 3) + (index << 1);
unsigned palette = 0;
palette |= bgpd[palette_index++] << 0;
palette |= bgpd[palette_index++] << 8;
palette &= 0x7fff;
if(ox - (status.wx - 7) < 160u) {
line[ox] = palette;
origin[ox] = (attr & 0x80 ? Origin::BGP : Origin::BG);
}
ix = (ix + 1) & 255;
tx = (tx + 1) & 7;
if(tx == 0) cgb_read_tile(status.window_tilemap_select, ix, iy, tile, attr, data);
}
}
//Attributes:
//0x80: 0 = OBJ above BG, 1 = BG above OBJ
//0x40: vertical flip
//0x20: horizontal flip
//0x08: VRAM bank#
//0x07: palette#
void LCD::cgb_render_ob() {
const unsigned Height = (status.ob_size == 0 ? 8 : 16);
unsigned sprite[10], sprites = 0;
//find first ten sprites on this scanline
for(unsigned s = 0; s < 40; s++) {
unsigned sy = oam[(s << 2) + 0] - 16;
unsigned sx = oam[(s << 2) + 1] - 8;
sy = status.ly - sy;
if(sy >= Height) continue;
sprite[sprites++] = s;
if(sprites == 10) break;
}
//sort by X-coordinate, when equal, lower address comes first
for(unsigned x = 0; x < sprites; x++) {
for(unsigned y = x + 1; y < sprites; y++) {
signed sx = oam[(sprite[x] << 2) + 1] - 8;
signed sy = oam[(sprite[y] << 2) + 1] - 8;
if(sy < sx) {
sprite[x] ^= sprite[y];
sprite[y] ^= sprite[x];
sprite[x] ^= sprite[y];
}
}
}
//render backwards, so that first sprite has highest priority
for(signed s = sprites - 1; s >= 0; s--) {
unsigned n = sprite[s] << 2;
unsigned sy = oam[n + 0] - 16;
unsigned sx = oam[n + 1] - 8;
unsigned tile = oam[n + 2] & ~status.ob_size;
unsigned attr = oam[n + 3];
sy = status.ly - sy;
if(sy >= Height) continue;
if(attr & 0x40) sy ^= (Height - 1);
unsigned tdaddr = (attr & 0x08 ? 0x2000 : 0x0000) + (tile << 4) + (sy << 1), data = 0;
data |= vram[tdaddr++] << 0;
data |= vram[tdaddr++] << 8;
if(attr & 0x20) data = hflip(data);
for(unsigned tx = 0; tx < 8; tx++) {
unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0)
| ((data & (0x8000 >> tx)) ? 2 : 0);
if(index == 0) continue;
unsigned palette_index = ((attr & 0x07) << 3) + (index << 1);
unsigned palette = 0;
palette |= obpd[palette_index++] << 0;
palette |= obpd[palette_index++] << 8;
palette &= 0x7fff;
unsigned ox = sx + tx;
if(ox < 160) {
//When LCDC.D0 (BG enable) is off, OB is always rendered above BG+Window
if(status.bg_enable) {
if(origin[ox] == Origin::BGP) continue;
if(attr & 0x80) {
if(origin[ox] == Origin::BG || origin[ox] == Origin::BGP) {
if(line[ox] > 0) continue;
}
}
}
line[ox] = palette;
origin[ox] = Origin::OB;
}
}
}
}
#endif

View File

@ -1,145 +0,0 @@
#ifdef LCD_CPP
void LCD::dmg_render() {
for(unsigned n = 0; n < 160; n++) {
line[n] = 0x00;
origin[n] = Origin::None;
}
if(status.display_enable) {
if(status.bg_enable) dmg_render_bg();
if(status.window_display_enable) dmg_render_window();
if(status.ob_enable) dmg_render_ob();
}
uint16 *output = screen + status.ly * 160;
for(unsigned n = 0; n < 160; n++) output[n] = line[n];
interface->lcdScanline();
}
uint16 LCD::dmg_read_tile(bool select, unsigned x, unsigned y) {
unsigned tmaddr = 0x1800 + (select << 10), tdaddr;
tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff;
if(status.bg_tiledata_select == 0) {
tdaddr = 0x1000 + ((int8)vram[tmaddr] << 4);
} else {
tdaddr = 0x0000 + (vram[tmaddr] << 4);
}
tdaddr += (y & 7) << 1;
return (vram[tdaddr + 0] << 0) | (vram[tdaddr + 1] << 8);
}
void LCD::dmg_render_bg() {
unsigned iy = (status.ly + status.scy) & 255;
unsigned ix = status.scx, tx = ix & 7;
unsigned data = dmg_read_tile(status.bg_tilemap_select, ix, iy);
for(unsigned ox = 0; ox < 160; ox++) {
uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0)
| ((data & (0x8000 >> tx)) ? 2 : 0);
line[ox] = bgp[palette];
origin[ox] = Origin::BG;
ix = (ix + 1) & 255;
tx = (tx + 1) & 7;
if(tx == 0) data = dmg_read_tile(status.bg_tilemap_select, ix, iy);
}
}
void LCD::dmg_render_window() {
if(status.ly - status.wy >= 144u) return;
if(status.wx >= 167u) return;
unsigned iy = status.wyc++;
unsigned ix = (7 - status.wx) & 255, tx = ix & 7;
unsigned data = dmg_read_tile(status.window_tilemap_select, ix, iy);
for(unsigned ox = 0; ox < 160; ox++) {
uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0)
| ((data & (0x8000 >> tx)) ? 2 : 0);
if(ox - (status.wx - 7) < 160u) {
line[ox] = bgp[palette];
origin[ox] = Origin::BG;
}
ix = (ix + 1) & 255;
tx = (tx + 1) & 7;
if(tx == 0) data = dmg_read_tile(status.window_tilemap_select, ix, iy);
}
}
//Attributes:
//0x80: 0 = OBJ above BG, 1 = BG above OBJ
//0x40: vertical flip
//0x20: horizontal flip
//0x10: palette#
void LCD::dmg_render_ob() {
const unsigned Height = (status.ob_size == 0 ? 8 : 16);
unsigned sprite[10], sprites = 0;
//find first ten sprites on this scanline
for(unsigned s = 0; s < 40; s++) {
unsigned sy = oam[(s << 2) + 0] - 16;
unsigned sx = oam[(s << 2) + 1] - 8;
sy = status.ly - sy;
if(sy >= Height) continue;
sprite[sprites++] = s;
if(sprites == 10) break;
}
//sort by X-coordinate, when equal, lower address comes first
for(unsigned x = 0; x < sprites; x++) {
for(unsigned y = x + 1; y < sprites; y++) {
signed sx = oam[(sprite[x] << 2) + 1] - 8;
signed sy = oam[(sprite[y] << 2) + 1] - 8;
if(sy < sx) {
sprite[x] ^= sprite[y];
sprite[y] ^= sprite[x];
sprite[x] ^= sprite[y];
}
}
}
//render backwards, so that first sprite has highest priority
for(signed s = sprites - 1; s >= 0; s--) {
unsigned n = sprite[s] << 2;
unsigned sy = oam[n + 0] - 16;
unsigned sx = oam[n + 1] - 8;
unsigned tile = oam[n + 2] & ~status.ob_size;
unsigned attr = oam[n + 3];
sy = status.ly - sy;
if(sy >= Height) continue;
if(attr & 0x40) sy ^= (Height - 1);
unsigned tdaddr = (tile << 4) + (sy << 1), data = 0;
data |= vram[tdaddr++] << 0;
data |= vram[tdaddr++] << 8;
if(attr & 0x20) data = hflip(data);
for(unsigned tx = 0; tx < 8; tx++) {
uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0)
| ((data & (0x8000 >> tx)) ? 2 : 0);
if(palette == 0) continue;
palette = obp[(bool)(attr & 0x10)][palette];
unsigned ox = sx + tx;
if(ox < 160) {
if(attr & 0x80) {
if(origin[ox] == Origin::BG) {
if(line[ox] > 0) continue;
}
}
line[ox] = palette;
origin[ox] = Origin::OB;
}
}
}
}
#endif

View File

@ -1,157 +0,0 @@
#include <gameboy/gameboy.hpp>
//LY = 0-153
//Raster = 0-143
//Vblank = 144-153
//LX = 0-455
#define LCD_CPP
namespace GameBoy {
#include "dmg.cpp"
#include "cgb.cpp"
#include "mmio/mmio.cpp"
LCD lcd;
void LCD::Main() {
lcd.main();
}
void LCD::main() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
add_clocks(4);
status.lx += 4;
if(status.lx >= 456) scanline();
if(status.display_enable && status.lx == 0) {
if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat);
}
if(status.display_enable && status.lx == 252) {
if(status.interrupt_hblank) cpu.interrupt_raise(CPU::Interrupt::Stat);
cpu.hblank();
}
}
}
void LCD::add_clocks(unsigned clocks) {
clock += clocks * cpu.frequency;
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) {
co_switch(scheduler.active_thread = cpu.thread);
}
}
void LCD::scanline() {
status.lx -= 456;
if(++status.ly == 154) frame();
if(status.display_enable && status.interrupt_lyc == true) {
if(status.ly == status.lyc) cpu.interrupt_raise(CPU::Interrupt::Stat);
}
if(status.ly < 144) {
system.cgb() == false ? dmg_render() : cgb_render();
}
if(status.display_enable && status.ly == 144) {
cpu.interrupt_raise(CPU::Interrupt::Vblank);
if(status.interrupt_vblank) cpu.interrupt_raise(CPU::Interrupt::Stat);
}
}
void LCD::frame() {
interface->videoRefresh(screen);
cpu.mmio_joyp_poll();
status.ly = 0;
status.wyc = 0;
scheduler.exit(Scheduler::ExitReason::FrameEvent);
}
unsigned LCD::hflip(unsigned data) const {
return ((data & 0x8080) >> 7) | ((data & 0x4040) >> 5)
| ((data & 0x2020) >> 3) | ((data & 0x1010) >> 1)
| ((data & 0x0808) << 1) | ((data & 0x0404) << 3)
| ((data & 0x0202) << 5) | ((data & 0x0101) << 7);
}
void LCD::power() {
create(Main, 4 * 1024 * 1024);
for(unsigned n = 0x8000; n <= 0x9fff; n++) bus.mmio[n] = this; //VRAM
for(unsigned n = 0xfe00; n <= 0xfe9f; n++) bus.mmio[n] = this; //OAM
bus.mmio[0xff40] = this; //LCDC
bus.mmio[0xff41] = this; //STAT
bus.mmio[0xff42] = this; //SCY
bus.mmio[0xff43] = this; //SCX
bus.mmio[0xff44] = this; //LY
bus.mmio[0xff45] = this; //LYC
bus.mmio[0xff47] = this; //BGP
bus.mmio[0xff48] = this; //OBP0
bus.mmio[0xff49] = this; //OBP1
bus.mmio[0xff4a] = this; //WY
bus.mmio[0xff4b] = this; //WX
if(system.cgb()) {
bus.mmio[0xff4f] = this; //VBK
bus.mmio[0xff68] = this; //BGPI
bus.mmio[0xff69] = this; //BGPD
bus.mmio[0xff6a] = this; //OBPI
bus.mmio[0xff6b] = this; //OBPD
}
for(auto &n : screen) n = 0x0000;
for(auto &n : line) n = 0x0000;
for(auto &n : origin) n = Origin::None;
for(auto &n : vram) n = 0x00;
for(auto &n : oam) n = 0x00;
for(auto &n : bgp) n = 0x00;
for(auto &n : obp[0]) n = 0x00;
for(auto &n : obp[1]) n = 0x00;
for(auto &n : bgpd) n = 0x0000;
for(auto &n : obpd) n = 0x0000;
status.lx = 0;
status.wyc = 0;
status.display_enable = 0;
status.window_tilemap_select = 0;
status.window_display_enable = 0;
status.bg_tiledata_select = 0;
status.bg_tilemap_select = 0;
status.ob_size = 0;
status.ob_enable = 0;
status.bg_enable = 0;
status.interrupt_lyc = 0;
status.interrupt_oam = 0;
status.interrupt_vblank = 0;
status.interrupt_hblank = 0;
status.scy = 0;
status.scx = 0;
status.ly = 0;
status.lyc = 0;
status.wy = 0;
status.wx = 0;
status.vram_bank = 0;
status.bgpi_increment = 0;
status.bgpi = 0;
status.obpi_increment = 0;
status.obpi = 0;
}
LCD::LCD() {
}
}

View File

@ -1,93 +0,0 @@
struct LCD : Processor, MMIO {
#include "mmio/mmio.hpp"
struct Status {
unsigned lx;
unsigned wyc;
//$ff40 LCDC
bool display_enable;
bool window_tilemap_select;
bool window_display_enable;
bool bg_tiledata_select;
bool bg_tilemap_select;
bool ob_size;
bool ob_enable;
bool bg_enable;
//$ff41 STAT
bool interrupt_lyc;
bool interrupt_oam;
bool interrupt_vblank;
bool interrupt_hblank;
//$ff42 SCY
uint8 scy;
//$ff43 SCX
uint8 scx;
//$ff44 LY
uint8 ly;
//$ff45 LYC
uint8 lyc;
//$ff4a WY
uint8 wy;
//$ff4b WX
uint8 wx;
//$ff4f VBK
bool vram_bank;
//$ff68 BGPI
bool bgpi_increment;
uint6 bgpi;
//$ff6a OBPI
bool obpi_increment;
uint8 obpi;
} status;
uint16 screen[160 * 144];
uint16 line[160];
struct Origin { enum : unsigned { None, BG, BGP, OB }; };
uint8 origin[160];
uint8 vram[16384]; //GB = 8192, GBC = 16384
uint8 oam[160];
uint8 bgp[4];
uint8 obp[2][4];
uint8 bgpd[64];
uint8 obpd[64];
static void Main();
void main();
void add_clocks(unsigned clocks);
void scanline();
void frame();
unsigned hflip(unsigned data) const;
//dmg.cpp
void dmg_render();
uint16 dmg_read_tile(bool select, unsigned x, unsigned y);
void dmg_render_bg();
void dmg_render_window();
void dmg_render_ob();
//cgb.cpp
void cgb_render();
void cgb_read_tile(bool select, unsigned x, unsigned y, unsigned &tile, unsigned &attr, unsigned &data);
void cgb_render_bg();
void cgb_render_window();
void cgb_render_ob();
void power();
LCD();
};
extern LCD lcd;

View File

@ -1,203 +0,0 @@
#ifdef LCD_CPP
unsigned LCD::vram_addr(uint16 addr) const {
return (status.vram_bank * 0x2000) + (addr & 0x1fff);
}
uint8 LCD::mmio_read(uint16 addr) {
if(addr >= 0x8000 && addr <= 0x9fff) return vram[vram_addr(addr)];
if(addr >= 0xfe00 && addr <= 0xfe9f) return oam[addr & 0xff];
if(addr == 0xff40) { //LCDC
return (status.display_enable << 7)
| (status.window_tilemap_select << 6)
| (status.window_display_enable << 5)
| (status.bg_tiledata_select << 4)
| (status.bg_tilemap_select << 3)
| (status.ob_size << 2)
| (status.ob_enable << 1)
| (status.bg_enable << 0);
}
if(addr == 0xff41) { //STAT
unsigned mode;
if(status.ly >= 144) mode = 1; //Vblank
else if(status.lx < 80) mode = 2; //OAM
else if(status.lx < 252) mode = 3; //LCD
else mode = 0; //Hblank
return (status.interrupt_lyc << 6)
| (status.interrupt_oam << 5)
| (status.interrupt_vblank << 4)
| (status.interrupt_hblank << 3)
| ((status.ly == status.lyc) << 2)
| (mode << 0);
}
if(addr == 0xff42) { //SCY
return status.scy;
}
if(addr == 0xff43) { //SCX
return status.scx;
}
if(addr == 0xff44) { //LY
return status.ly;
}
if(addr == 0xff45) { //LYC
return status.lyc;
}
if(addr == 0xff47) { //BGP
return (bgp[3] << 6)
| (bgp[2] << 4)
| (bgp[1] << 2)
| (bgp[0] << 0);
}
if(addr == 0xff48) { //OBP0
return (obp[0][3] << 6)
| (obp[0][2] << 4)
| (obp[0][1] << 2)
| (obp[0][0] << 0);
}
if(addr == 0xff49) { //OBP1
return (obp[1][3] << 6)
| (obp[1][2] << 4)
| (obp[1][1] << 2)
| (obp[1][0] << 0);
}
if(addr == 0xff4a) { //WY
return status.wy;
}
if(addr == 0xff4b) { //WX
return status.wx;
}
if(addr == 0xff69) { //BGPD
return bgpd[status.bgpi];
}
if(addr == 0xff6b) { //OBPD
return obpd[status.obpi];
}
return 0x00;
}
void LCD::mmio_write(uint16 addr, uint8 data) {
if(addr >= 0x8000 && addr <= 0x9fff) { vram[vram_addr(addr)] = data; return; }
if(addr >= 0xfe00 && addr <= 0xfe9f) { oam[addr & 0xff] = data; return; }
if(addr == 0xff40) { //LCDC
if(status.display_enable == false && (data & 0x80)) {
status.lx = 0; //unverified behavior; fixes Super Mario Land 2 - Tree Zone
}
status.display_enable = data & 0x80;
status.window_tilemap_select = data & 0x40;
status.window_display_enable = data & 0x20;
status.bg_tiledata_select = data & 0x10;
status.bg_tilemap_select = data & 0x08;
status.ob_size = data & 0x04;
status.ob_enable = data & 0x02;
status.bg_enable = data & 0x01;
return;
}
if(addr == 0xff41) { //STAT
status.interrupt_lyc = data & 0x40;
status.interrupt_oam = data & 0x20;
status.interrupt_vblank = data & 0x10;
status.interrupt_hblank = data & 0x08;
return;
}
if(addr == 0xff42) { //SCY
status.scy = data;
return;
}
if(addr == 0xff43) { //SCX
status.scx = data;
return;
}
if(addr == 0xff44) { //LY
status.ly = 0;
return;
}
if(addr == 0xff45) { //LYC
status.lyc = data;
return;
}
if(addr == 0xff47) { //BGP
bgp[3] = (data >> 6) & 3;
bgp[2] = (data >> 4) & 3;
bgp[1] = (data >> 2) & 3;
bgp[0] = (data >> 0) & 3;
return;
}
if(addr == 0xff48) { //OBP0
obp[0][3] = (data >> 6) & 3;
obp[0][2] = (data >> 4) & 3;
obp[0][1] = (data >> 2) & 3;
obp[0][0] = (data >> 0) & 3;
return;
}
if(addr == 0xff49) { //OBP1
obp[1][3] = (data >> 6) & 3;
obp[1][2] = (data >> 4) & 3;
obp[1][1] = (data >> 2) & 3;
obp[1][0] = (data >> 0) & 3;
return;
}
if(addr == 0xff4a) { //WY
status.wy = data;
return;
}
if(addr == 0xff4b) { //WX
status.wx = data;
return;
}
if(addr == 0xff4f) { //VBK
status.vram_bank = data & 1;
return;
}
if(addr == 0xff68) { //BGPI
status.bgpi_increment = data & 0x80;
status.bgpi = data & 0x3f;
return;
}
if(addr == 0xff69) { //BGPD
bgpd[status.bgpi] = data;
if(status.bgpi_increment) status.bgpi++;
return;
}
if(addr == 0xff6a) { //OBPI
status.obpi_increment = data & 0x80;
status.obpi = data & 0x3f;
}
if(addr == 0xff6b) { //OBPD
obpd[status.obpi] = data;
if(status.obpi_increment) status.obpi++;
}
}
#endif

View File

@ -1,3 +0,0 @@
unsigned vram_addr(uint16 addr) const;
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);

View File

@ -1,57 +0,0 @@
#include <gameboy/gameboy.hpp>
#define MEMORY_CPP
namespace GameBoy {
Unmapped unmapped;
Bus bus;
uint8_t& Memory::operator[](unsigned addr) {
return data[addr];
}
void Memory::allocate(unsigned size_) {
free();
size = size_;
data = new uint8_t[size]();
}
void Memory::copy(const uint8_t *data_, unsigned size_) {
free();
size = size_;
data = new uint8_t[size];
memcpy(data, data_, size);
}
void Memory::free() {
if(data) {
delete[] data;
data = 0;
}
}
Memory::Memory() {
data = 0;
size = 0;
}
Memory::~Memory() {
free();
}
//
uint8 Bus::read(uint16 addr) {
uint8 data = mmio[addr]->mmio_read(addr);
return data;
}
void Bus::write(uint16 addr, uint8 data) {
mmio[addr]->mmio_write(addr, data);
}
void Bus::power() {
for(unsigned n = 0x0000; n <= 0xffff; n++) mmio[n] = &unmapped;
}
}

View File

@ -1,32 +0,0 @@
struct Memory {
uint8_t *data;
unsigned size;
uint8_t& operator[](unsigned addr);
void allocate(unsigned size);
void copy(const uint8_t *data, unsigned size);
void free();
Memory();
~Memory();
};
struct MMIO {
virtual uint8 mmio_read(uint16 addr) = 0;
virtual void mmio_write(uint16 addr, uint8 data) = 0;
};
struct Unmapped : MMIO {
uint8 mmio_read(uint16) { return 0x00; }
void mmio_write(uint16, uint8) {}
};
struct Bus {
MMIO *mmio[65536];
uint8 read(uint16 addr);
void write(uint16 addr, uint8 data);
void power();
};
extern Unmapped unmapped;
extern Bus bus;

View File

@ -1,35 +0,0 @@
#include <gameboy/gameboy.hpp>
#define SCHEDULER_CPP
namespace GameBoy {
Scheduler scheduler;
void Scheduler::enter() {
host_thread = co_active();
co_switch(active_thread);
}
void Scheduler::exit(ExitReason reason) {
exit_reason = reason;
active_thread = co_active();
co_switch(host_thread);
}
void Scheduler::swapto(Processor &p) {
active_thread = p.thread;
co_switch(active_thread);
}
void Scheduler::init() {
host_thread = co_active();
active_thread = cpu.thread;
}
Scheduler::Scheduler() {
exit_reason = ExitReason::UnknownEvent;
host_thread = 0;
active_thread = 0;
}
}

View File

@ -1,17 +0,0 @@
struct Scheduler : property<Scheduler> {
enum class SynchronizeMode : unsigned { None, CPU, All } sync;
enum class ExitReason : unsigned { UnknownEvent, StepEvent, FrameEvent, SynchronizeEvent };
readonly<ExitReason> exit_reason;
cothread_t host_thread;
cothread_t active_thread;
void enter();
void exit(ExitReason);
void swapto(Processor&);
void init();
Scheduler();
};
extern Scheduler scheduler;

View File

@ -1,135 +0,0 @@
#ifdef SYSTEM_CPP
//from FastCgbBoot (cgb_boot.rom.gz)
const uint8_t System::BootROM::cgb[2048] = {
0x01,0x00,0x00,0x11,0x08,0x00,0x21,0x7C,0x00,0x31,0xFE,0xFF,0x3E,0x39,0xE0,0xFA,
0x3E,0x01,0xE0,0xFB,0x3E,0x2E,0xE0,0xFC,0x3E,0x00,0xE0,0xFD,0x3E,0x00,0xE0,0x42,
0xE0,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x80,0xE0,0x26,0x3E,
0x00,0xE0,0x25,0x3E,0x77,0xE0,0x24,0x3E,0x80,0xE0,0x11,0x3E,0x13,0xE0,0x12,0x3E,
0x80,0xE0,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x3E,0x91,0xE0,0x40,0xF0,0x44,0xFE,0x90,0x20,0xFA,0xCD,0x00,0x02,0xF0,0x44,0xFE,
0x00,0x20,0xFA,0x3C,0xFE,0x10,0x20,0xFB,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x3E,0xF3,0xE0,0x25,0x3E,0xF3,0xE0,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x3E,0x00,0xE0,0x70,0xAF,0x3E,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x50,
0xFA,0x43,0x01,0xEE,0x3F,0xE6,0xC4,0xCB,0x7F,0x28,0x05,0xD6,0x04,0xE0,0x4C,0xC9,
0x3E,0x80,0xE0,0x6A,0x3E,0xFF,0xE0,0x6B,0x3E,0x7F,0xE0,0x6B,0x3E,0x1F,0xE0,0x6B,
0x3E,0x42,0xE0,0x6B,0x3E,0xF2,0xE0,0x6B,0x3E,0x1C,0xE0,0x6B,0x3E,0x00,0xE0,0x6B,
0x3E,0x00,0xE0,0x6B,0x3E,0xFF,0xE0,0x6B,0x3E,0x7F,0xE0,0x6B,0x3E,0x1F,0xE0,0x6B,
0x3E,0x42,0xE0,0x6B,0x3E,0xF2,0xE0,0x6B,0x3E,0x1C,0xE0,0x6B,0x3E,0x00,0xE0,0x6B,
0x3E,0x00,0xE0,0x6B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x80,0xE0,0x68,
0x3E,0xFF,0xE0,0x69,0x3E,0x7F,0xE0,0x69,0x3E,0xEF,0xE0,0x69,0x3E,0x1B,0xE0,0x69,
0x3E,0x80,0xE0,0x69,0x3E,0x61,0xE0,0x69,0x3E,0x00,0xE0,0x69,0x3E,0x00,0xE0,0x69,
0xC6,0x04,0xE0,0x4C,0xC9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
#endif

View File

@ -1,23 +0,0 @@
#ifdef SYSTEM_CPP
//from FastDmgBoot (dmg_boot.rom.gz)
const uint8_t System::BootROM::dmg[256] = {
0x01,0x13,0x00,0x11,0xD8,0x00,0x21,0x4D,0x01,0x31,0xFE,0xFF,0x3E,0x39,0xE0,0xFA,
0x3E,0x01,0xE0,0xFB,0x3E,0x2E,0xE0,0xFC,0x3E,0x00,0xE0,0xFD,0x3E,0x00,0xE0,0x42,
0xE0,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x80,0xE0,0x26,0x3E,
0x00,0xE0,0x25,0x3E,0x77,0xE0,0x24,0x3E,0x80,0xE0,0x11,0x3E,0x13,0xE0,0x12,0x3E,
0x80,0xE0,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x3E,0x91,0xE0,0x40,0xF0,0x44,0xFE,0x98,0x20,0xFA,0xF0,0x44,0xFE,0x00,0x20,0xFA,
0x3C,0xFE,0x10,0x20,0xFB,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x3E,0xF3,0xE0,0x25,0x3E,0xF3,0xE0,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x28,0x83,0x7C,0xE0,0x50,
};
#endif

View File

@ -1,23 +0,0 @@
#ifdef SYSTEM_CPP
//from https://github.com/LIJI32/SameBoy/tree/v0.14.3/BootROMs
const uint8_t System::BootROM::sgb[256] = {
0x31,0xFE,0xFF,0x21,0x00,0x80,0x22,0xCB,0x6C,0x28,0xFB,0x3E,0x80,0xE0,0x26,0xE0,
0x11,0x3E,0xF3,0xE0,0x12,0xE0,0x25,0x3E,0x77,0xE0,0x24,0x3E,0x00,0xE0,0x47,0x11,
0x04,0x01,0x21,0x10,0x80,0x1A,0x47,0xCD,0xC9,0x00,0xCD,0xC9,0x00,0x13,0x7B,0xEE,
0x34,0x20,0xF2,0x11,0xEA,0x00,0x0E,0x08,0x1A,0x13,0x22,0x23,0x0D,0x20,0xF9,0x3E,
0x19,0xEA,0x10,0x99,0x21,0x2F,0x99,0x0E,0x0C,0x3D,0x28,0x08,0x32,0x0D,0x20,0xF9,
0x2E,0x0F,0x18,0xF5,0x3E,0x91,0xE0,0x40,0x3E,0xF1,0xE0,0x80,0x21,0x04,0x01,0xAF,
0x4F,0xAF,0xE2,0x3E,0x30,0xE2,0xF0,0x80,0xCD,0xB7,0x00,0xE5,0x06,0x0E,0x16,0x00,
0xCD,0xAD,0x00,0x82,0x57,0x05,0x20,0xF8,0xCD,0xB7,0x00,0xE1,0x06,0x0E,0xCD,0xAD,
0x00,0xCD,0xB7,0x00,0x05,0x20,0xF7,0x3E,0x20,0xE2,0x3E,0x30,0xE2,0xF0,0x80,0xC6,
0x02,0xE0,0x80,0x3E,0x58,0xBD,0x20,0xC9,0x0E,0x13,0x3E,0xC1,0xE2,0x0C,0x3E,0x07,
0xE2,0x3E,0xFC,0xE0,0x47,0x3E,0x01,0x21,0x60,0xC0,0xC3,0xFE,0x00,0x3E,0x4F,0xBD,
0x38,0x02,0x2A,0xC9,0x23,0xAF,0xC9,0x5F,0x16,0x08,0x3E,0x10,0xCB,0x1B,0x38,0x01,
0x87,0xE2,0x3E,0x30,0xE2,0x15,0xC8,0x18,0xF1,0x3E,0x04,0x0E,0x00,0xCB,0x20,0xF5,
0xCB,0x11,0xF1,0xCB,0x11,0x3D,0x20,0xF5,0x79,0x22,0x23,0x22,0x23,0xC9,0xE5,0x21,
0x0F,0xFF,0xCB,0x86,0xCB,0x46,0x28,0xFC,0xE1,0xC9,0x3C,0x42,0xB9,0xA5,0xB9,0xA5,
0x42,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x50,
};
#endif

View File

@ -1,55 +0,0 @@
#include <gameboy/gameboy.hpp>
#define SYSTEM_CPP
namespace GameBoy {
#include "bootrom-dmg.cpp"
#include "bootrom-sgb.cpp"
#include "bootrom-cgb.cpp"
System system;
void System::run() {
scheduler.sync = Scheduler::SynchronizeMode::None;
scheduler.enter();
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
}
}
void System::runtosave() {
scheduler.sync = Scheduler::SynchronizeMode::CPU;
runthreadtosave();
scheduler.active_thread = lcd.thread;
runthreadtosave();
}
void System::runthreadtosave() {
while(true) {
scheduler.enter();
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
}
}
}
void System::init() {
assert(interface != 0);
}
void System::load(Revision revision) {
this->revision = revision;
}
void System::power() {
bus.power();
cartridge.power();
cpu.power();
apu.power();
lcd.power();
scheduler.init();
clocks_executed = 0;
}
}

View File

@ -1,38 +0,0 @@
class Interface;
enum class Input : unsigned {
Up, Down, Left, Right, B, A, Select, Start,
};
struct System : property<System> {
enum class Revision : unsigned {
GameBoy,
SuperGameBoy,
GameBoyColor,
};
readonly<Revision> revision;
inline bool dmg() const { return (Revision)revision == Revision::GameBoy; }
inline bool sgb() const { return (Revision)revision == Revision::SuperGameBoy; }
inline bool cgb() const { return (Revision)revision == Revision::GameBoyColor; }
struct BootROM {
static const uint8 dmg[ 256];
static const uint8 sgb[ 256];
static const uint8 cgb[2048];
} bootROM;
void run();
void runtosave();
void runthreadtosave();
void init();
void load(Revision);
void power();
unsigned clocks_executed;
};
#include <gameboy/interface/interface.hpp>
extern System system;

View File

@ -1,82 +0,0 @@
#include <gameboy/gameboy.hpp>
#define VIDEO_CPP
namespace GameBoy {
Video video;
unsigned Video::palette_dmg(unsigned color) const {
unsigned R = monochrome[color][0] * 1023.0;
unsigned G = monochrome[color][1] * 1023.0;
unsigned B = monochrome[color][2] * 1023.0;
return (R << 20) + (G << 10) + (B << 0);
}
unsigned Video::palette_sgb(unsigned color) const {
unsigned R = (3 - color) * 341;
unsigned G = (3 - color) * 341;
unsigned B = (3 - color) * 341;
return (R << 20) + (G << 10) + (B << 0);
}
unsigned Video::palette_cgb(unsigned color) const {
unsigned r = (color >> 0) & 31;
unsigned g = (color >> 5) & 31;
unsigned b = (color >> 10) & 31;
unsigned R = (r * 26 + g * 4 + b * 2);
unsigned G = ( g * 24 + b * 8);
unsigned B = (r * 6 + g * 4 + b * 22);
R = min(960, R);
G = min(960, G);
B = min(960, B);
return (R << 20) + (G << 10) + (B << 0);
}
void Video::generate(Format format) {
if(system.dmg()) for(unsigned n = 0; n < 4; n++) palette[n] = palette_dmg(n);
if(system.sgb()) for(unsigned n = 0; n < 4; n++) palette[n] = palette_sgb(n);
if(system.cgb()) for(unsigned n = 0; n < (1 << 15); n++) palette[n] = palette_cgb(n);
if(format == Format::RGB24) {
for(unsigned n = 0; n < (1 << 15); n++) {
unsigned color = palette[n];
palette[n] = ((color >> 6) & 0xff0000) + ((color >> 4) & 0x00ff00) + ((color >> 2) & 0x0000ff);
}
}
if(format == Format::RGB16) {
for(unsigned n = 0; n < (1 << 15); n++) {
unsigned color = palette[n];
palette[n] = ((color >> 14) & 0xf800) + ((color >> 9) & 0x07e0) + ((color >> 5) & 0x001f);
}
}
if(format == Format::RGB15) {
for(unsigned n = 0; n < (1 << 15); n++) {
unsigned color = palette[n];
palette[n] = ((color >> 15) & 0x7c00) + ((color >> 10) & 0x03e0) + ((color >> 5) & 0x001f);
}
}
}
Video::Video() {
palette = new unsigned[1 << 15];
}
Video::~Video() {
delete[] palette;
}
const double Video::monochrome[4][3] = {
{ 0.605, 0.734, 0.059 },
{ 0.543, 0.672, 0.059 },
{ 0.188, 0.383, 0.188 },
{ 0.059, 0.219, 0.059 },
};
}

View File

@ -1,17 +0,0 @@
struct Video {
enum class Format : unsigned { RGB30, RGB24, RGB16, RGB15 };
unsigned *palette;
unsigned palette_dmg(unsigned color) const;
unsigned palette_sgb(unsigned color) const;
unsigned palette_cgb(unsigned color) const;
void generate(Format format);
Video();
~Video();
private:
static const double monochrome[4][3];
};
extern Video video;

View File

@ -1,17 +0,0 @@
#ifndef NALL_ALGORITHM_HPP
#define NALL_ALGORITHM_HPP
#undef min
#undef max
namespace nall {
template<typename T, typename U> T min(const T &t, const U &u) {
return t < u ? t : u;
}
template<typename T, typename U> T max(const T &t, const U &u) {
return t > u ? t : u;
}
}
#endif

View File

@ -1,72 +0,0 @@
#ifndef NALL_ANY_HPP
#define NALL_ANY_HPP
#include <typeinfo>
#include <nall/type_traits.hpp>
namespace nall {
struct any {
bool empty() const { return container; }
const std::type_info& type() const { return container ? container->type() : typeid(void); }
template<typename T> any& operator=(const T& value_) {
typedef typename type_if<
std::is_array<T>::value,
typename std::remove_extent<typename std::add_const<T>::type>::type*,
T
>::type auto_t;
if(type() == typeid(auto_t)) {
static_cast<holder<auto_t>*>(container)->value = (auto_t)value_;
} else {
if(container) delete container;
container = new holder<auto_t>((auto_t)value_);
}
return *this;
}
any() : container(0) {}
template<typename T> any(const T& value_) : container(0) { operator=(value_); }
private:
struct placeholder {
virtual const std::type_info& type() const = 0;
} *container;
template<typename T> struct holder : placeholder {
T value;
const std::type_info& type() const { return typeid(T); }
holder(const T& value_) : value(value_) {}
};
template<typename T> friend T any_cast(any&);
template<typename T> friend T any_cast(const any&);
template<typename T> friend T* any_cast(any*);
template<typename T> friend const T* any_cast(const any*);
};
template<typename T> T any_cast(any &value) {
typedef typename std::remove_reference<T>::type nonref;
if(value.type() != typeid(nonref)) throw;
return static_cast<any::holder<nonref>*>(value.container)->value;
}
template<typename T> T any_cast(const any &value) {
typedef const typename std::remove_reference<T>::type nonref;
if(value.type() != typeid(nonref)) throw;
return static_cast<any::holder<nonref>*>(value.container)->value;
}
template<typename T> T* any_cast(any *value) {
if(!value || value->type() != typeid(T)) return 0;
return &static_cast<any::holder<T>*>(value->container)->value;
}
template<typename T> const T* any_cast(const any *value) {
if(!value || value->type() != typeid(T)) return 0;
return &static_cast<any::holder<T>*>(value->container)->value;
}
}
#endif

View File

@ -1,289 +0,0 @@
#ifndef NALL_ARRAY_HPP
#define NALL_ARRAY_HPP
#include <stdlib.h>
#include <algorithm>
#include <initializer_list>
#include <utility>
#include <nall/algorithm.hpp>
#include <nall/bit.hpp>
#include <nall/sort.hpp>
#include <nall/type_traits.hpp>
#include <nall/utility.hpp>
namespace nall {
template<typename T, typename Enable = void> struct array;
//non-reference array
//===================
template<typename T> struct array<T, typename std::enable_if<!std::is_reference<T>::value>::type> {
struct exception_out_of_bounds{};
protected:
T *pool;
unsigned poolsize, objectsize;
public:
unsigned size() const { return objectsize; }
unsigned capacity() const { return poolsize; }
void reset() {
if(pool) free(pool);
pool = nullptr;
poolsize = 0;
objectsize = 0;
}
void reserve(unsigned newsize) {
if(newsize == poolsize) return;
pool = (T*)realloc(pool, newsize * sizeof(T));
poolsize = newsize;
objectsize = min(objectsize, newsize);
}
void resize(unsigned newsize) {
if(newsize > poolsize) reserve(bit::round(newsize)); //round reserve size up to power of 2
objectsize = newsize;
}
T* get(unsigned minsize = 0) {
if(minsize > objectsize) resize(minsize);
return pool;
}
void append(const T data) {
operator()(objectsize) = data;
}
void append(const T data[], unsigned length) {
for(unsigned n = 0; n < length; n++) operator()(objectsize) = data[n];
}
void remove() {
if(size() > 0) resize(size() - 1); //remove last element only
}
void remove(unsigned index, unsigned count = 1) {
for(unsigned i = index; count + i < objectsize; i++) {
pool[i] = pool[count + i];
}
if(count + index >= objectsize) resize(index); //every element >= index was removed
else resize(objectsize - count);
}
void sort() {
nall::sort(pool, objectsize);
}
template<typename Comparator> void sort(const Comparator &lessthan) {
nall::sort(pool, objectsize, lessthan);
}
optional<unsigned> find(const T data) {
for(unsigned n = 0; n < size(); n++) if(pool[n] == data) return { true, n };
return { false, 0u };
}
void clear() {
memset(pool, 0, objectsize * sizeof(T));
}
array() : pool(nullptr), poolsize(0), objectsize(0) {
}
array(std::initializer_list<T> list) : pool(nullptr), poolsize(0), objectsize(0) {
for(auto &data : list) append(data);
}
~array() {
reset();
}
//copy
array& operator=(const array &source) {
if(pool) free(pool);
objectsize = source.objectsize;
poolsize = source.poolsize;
pool = (T*)malloc(sizeof(T) * poolsize); //allocate entire pool size,
memcpy(pool, source.pool, sizeof(T) * objectsize); //... but only copy used pool objects
return *this;
}
array(const array &source) : pool(nullptr), poolsize(0), objectsize(0) {
operator=(source);
}
//move
array& operator=(array &&source) {
if(pool) free(pool);
pool = source.pool;
poolsize = source.poolsize;
objectsize = source.objectsize;
source.pool = nullptr;
source.reset();
return *this;
}
array(array &&source) : pool(nullptr), poolsize(0), objectsize(0) {
operator=(std::move(source));
}
//access
inline T& operator[](unsigned position) {
if(position >= objectsize) throw exception_out_of_bounds();
return pool[position];
}
inline const T& operator[](unsigned position) const {
if(position >= objectsize) throw exception_out_of_bounds();
return pool[position];
}
inline T& operator()(unsigned position) {
if(position >= objectsize) resize(position + 1);
return pool[position];
}
inline const T& operator()(unsigned position, const T& data) {
if(position >= objectsize) return data;
return pool[position];
}
//iteration
T* begin() { return &pool[0]; }
T* end() { return &pool[objectsize]; }
const T* begin() const { return &pool[0]; }
const T* end() const { return &pool[objectsize]; }
};
//reference array
//===============
template<typename TR> struct array<TR, typename std::enable_if<std::is_reference<TR>::value>::type> {
struct exception_out_of_bounds{};
protected:
typedef typename std::remove_reference<TR>::type T;
T **pool;
unsigned poolsize, objectsize;
public:
unsigned size() const { return objectsize; }
unsigned capacity() const { return poolsize; }
void reset() {
if(pool) free(pool);
pool = nullptr;
poolsize = 0;
objectsize = 0;
}
void reserve(unsigned newsize) {
if(newsize == poolsize) return;
pool = (T**)realloc(pool, sizeof(T*) * newsize);
poolsize = newsize;
objectsize = min(objectsize, newsize);
}
void resize(unsigned newsize) {
if(newsize > poolsize) reserve(bit::round(newsize));
objectsize = newsize;
}
template<typename... Args>
bool append(T& data, Args&&... args) {
bool result = append(data);
append(std::forward<Args>(args)...);
return result;
}
bool append(T& data) {
if(find(data)) return false;
unsigned offset = objectsize++;
if(offset >= poolsize) resize(offset + 1);
pool[offset] = &data;
return true;
}
bool remove(T& data) {
if(auto position = find(data)) {
for(signed i = position(); i < objectsize - 1; i++) pool[i] = pool[i + 1];
resize(objectsize - 1);
return true;
}
return false;
}
optional<unsigned> find(const T& data) {
for(unsigned n = 0; n < objectsize; n++) if(pool[n] == &data) return { true, n };
return { false, 0u };
}
template<typename... Args> array(Args&&... args) : pool(nullptr), poolsize(0), objectsize(0) {
construct(std::forward<Args>(args)...);
}
~array() {
reset();
}
array& operator=(const array &source) {
if(pool) free(pool);
objectsize = source.objectsize;
poolsize = source.poolsize;
pool = (T**)malloc(sizeof(T*) * poolsize);
memcpy(pool, source.pool, sizeof(T*) * objectsize);
return *this;
}
array& operator=(const array &&source) {
if(pool) free(pool);
pool = source.pool;
poolsize = source.poolsize;
objectsize = source.objectsize;
source.pool = nullptr;
source.reset();
return *this;
}
T& operator[](unsigned position) const {
if(position >= objectsize) throw exception_out_of_bounds();
return *pool[position];
}
//iteration
struct iterator {
bool operator!=(const iterator &source) const { return position != source.position; }
T& operator*() { return source.operator[](position); }
iterator& operator++() { position++; return *this; }
iterator(const array &source, unsigned position) : source(source), position(position) {}
private:
const array &source;
unsigned position;
};
iterator begin() { return iterator(*this, 0); }
iterator end() { return iterator(*this, objectsize); }
const iterator begin() const { return iterator(*this, 0); }
const iterator end() const { return iterator(*this, objectsize); }
private:
void construct() {
}
void construct(const array& source) { operator=(source); }
void construct(const array&& source) { operator=(std::move(source)); }
template<typename... Args> void construct(T& data, Args&&... args) {
append(data);
construct(std::forward<Args>(args)...);
}
};
}
#endif

View File

@ -1,101 +0,0 @@
#ifndef NALL_ATOI_HPP
#define NALL_ATOI_HPP
namespace nall {
//note: this header is intended to form the base for user-defined literals;
//once they are supported by GCC. eg:
//unsigned operator "" b(const char *s) { return binary(s); }
//-> signed data = 1001b;
//(0b1001 is nicer, but is not part of the C++ standard)
constexpr inline uintmax_t binary_(const char *s, uintmax_t sum = 0) {
return (
*s == '0' || *s == '1' ? binary_(s + 1, (sum << 1) | *s - '0') :
sum
);
}
constexpr inline uintmax_t octal_(const char *s, uintmax_t sum = 0) {
return (
*s >= '0' && *s <= '7' ? octal_(s + 1, (sum << 3) | *s - '0') :
sum
);
}
constexpr inline uintmax_t decimal_(const char *s, uintmax_t sum = 0) {
return (
*s >= '0' && *s <= '9' ? decimal_(s + 1, (sum * 10) + *s - '0') :
sum
);
}
constexpr inline uintmax_t hex_(const char *s, uintmax_t sum = 0) {
return (
*s >= 'A' && *s <= 'F' ? hex_(s + 1, (sum << 4) | *s - 'A' + 10) :
*s >= 'a' && *s <= 'f' ? hex_(s + 1, (sum << 4) | *s - 'a' + 10) :
*s >= '0' && *s <= '9' ? hex_(s + 1, (sum << 4) | *s - '0') :
sum
);
}
//
constexpr inline uintmax_t binary(const char *s) {
return (
*s == '0' && *(s + 1) == 'B' ? binary_(s + 2) :
*s == '0' && *(s + 1) == 'b' ? binary_(s + 2) :
*s == '%' ? binary_(s + 1) :
binary_(s)
);
}
constexpr inline uintmax_t octal(const char *s) {
return (
octal_(s)
);
}
constexpr inline intmax_t integer(const char *s) {
return (
*s == '+' ? +decimal_(s + 1) :
*s == '-' ? -decimal_(s + 1) :
decimal_(s)
);
}
constexpr inline uintmax_t decimal(const char *s) {
return (
decimal_(s)
);
}
constexpr inline uintmax_t hex(const char *s) {
return (
*s == '0' && *(s + 1) == 'X' ? hex_(s + 2) :
*s == '0' && *(s + 1) == 'x' ? hex_(s + 2) :
*s == '$' ? hex_(s + 1) :
hex_(s)
);
}
constexpr inline intmax_t numeral(const char *s) {
return (
*s == '0' && *(s + 1) == 'X' ? hex_(s + 2) :
*s == '0' && *(s + 1) == 'x' ? hex_(s + 2) :
*s == '0' && *(s + 1) == 'B' ? binary_(s + 2) :
*s == '0' && *(s + 1) == 'b' ? binary_(s + 2) :
*s == '0' ? octal_(s + 1) :
*s == '+' ? +decimal_(s + 1) :
*s == '-' ? -decimal_(s + 1) :
decimal_(s)
);
}
inline double fp(const char *s) {
return atof(s);
}
}
#endif

View File

@ -1,90 +0,0 @@
#ifndef NALL_BASE64_HPP
#define NALL_BASE64_HPP
#include <string.h>
#include <nall/stdint.hpp>
namespace nall {
struct base64 {
static bool encode(char *&output, const uint8_t* input, unsigned inlength) {
output = new char[inlength * 8 / 6 + 6]();
unsigned i = 0, o = 0;
while(i < inlength) {
switch(i % 3) {
case 0: {
output[o++] = enc(input[i] >> 2);
output[o] = enc((input[i] & 3) << 4);
} break;
case 1: {
uint8_t prev = dec(output[o]);
output[o++] = enc(prev + (input[i] >> 4));
output[o] = enc((input[i] & 15) << 2);
} break;
case 2: {
uint8_t prev = dec(output[o]);
output[o++] = enc(prev + (input[i] >> 6));
output[o++] = enc(input[i] & 63);
} break;
}
i++;
}
return true;
}
static bool decode(uint8_t *&output, unsigned &outlength, const char *input) {
unsigned inlength = strlen(input), infix = 0;
output = new uint8_t[inlength]();
unsigned i = 0, o = 0;
while(i < inlength) {
uint8_t x = dec(input[i]);
switch(i++ & 3) {
case 0: {
output[o] = x << 2;
} break;
case 1: {
output[o++] |= x >> 4;
output[o] = (x & 15) << 4;
} break;
case 2: {
output[o++] |= x >> 2;
output[o] = (x & 3) << 6;
} break;
case 3: {
output[o++] |= x;
} break;
}
}
outlength = o;
return true;
}
private:
static char enc(uint8_t n) {
//base64 for URL encodings
static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
return lookup_table[n & 63];
}
static uint8_t dec(char n) {
if(n >= 'A' && n <= 'Z') return n - 'A';
if(n >= 'a' && n <= 'z') return n - 'a' + 26;
if(n >= '0' && n <= '9') return n - '0' + 52;
if(n == '-') return 62;
if(n == '_') return 63;
return 0;
}
};
}
#endif

View File

@ -1,69 +0,0 @@
#ifndef NALL_BIT_HPP
#define NALL_BIT_HPP
namespace nall {
template<unsigned bits>
constexpr inline uintmax_t uclamp(const uintmax_t x) {
enum : uintmax_t { b = 1ull << (bits - 1), y = b * 2 - 1 };
return y + ((x - y) & -(x < y)); //min(x, y);
}
template<unsigned bits>
constexpr inline uintmax_t uclip(const uintmax_t x) {
//zero 17-jun-2015 - revised to use more standard constexpr behaviour
//enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
//return (x & m); //test
return (x & ((uintmax_t)(((uintmax_t)(1ull << (bits - 1))) * 2 - 1)));
}
template<unsigned bits>
constexpr inline intmax_t sclamp(const intmax_t x) {
//zero 17-jun-2015 - revised to use more standard constexpr behaviour
//enum : intmax_t { b = 1ull << (bits - 1), m = b - 1 };
//(intmax_t)(1ull << (bits - 1)) //b
//(((intmax_t)(1ull << (bits - 1))) - 1) //m
//return (x > m) ? m : (x < -b) ? -b : x;
return (x > (((intmax_t)(1ull << (bits - 1))) - 1)) ? (((intmax_t)(1ull << (bits - 1))) - 1) : (x < -((intmax_t)(1ull << (bits - 1)))) ? -((intmax_t)(1ull << (bits - 1))) : x; //test
}
template<unsigned bits>
constexpr inline intmax_t sclip(const intmax_t x) {
//zero 17-jun-2015 - revised to use more standard constexpr behaviour
//enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; //test
return ((x & ((uintmax_t)(((uintmax_t)(1ull << (bits - 1))) * 2 - 1))) ^ ((uintmax_t)(1ull << (bits - 1)))) - ((uintmax_t)(1ull << (bits - 1)));
}
namespace bit {
//lowest(0b1110) == 0b0010
constexpr inline uintmax_t lowest(const uintmax_t x) {
return x & -x;
}
//clear_lowest(0b1110) == 0b1100
constexpr inline uintmax_t clear_lowest(const uintmax_t x) {
return x & (x - 1);
}
//set_lowest(0b0101) == 0b0111
constexpr inline uintmax_t set_lowest(const uintmax_t x) {
return x | (x + 1);
}
//count number of bits set in a byte
inline unsigned count(uintmax_t x) {
unsigned count = 0;
do count += x & 1; while(x >>= 1);
return count;
}
//round up to next highest single bit:
//round(15) == 16, round(16) == 16, round(17) == 32
inline uintmax_t round(uintmax_t x) {
if((x & (x - 1)) == 0) return x;
while(x & (x - 1)) x &= x - 1;
return x << 1;
}
}
}
#endif

View File

@ -1,101 +0,0 @@
#ifndef NALL_BMP_HPP
#define NALL_BMP_HPP
#include <nall/file.hpp>
//BMP reader / writer
//author: byuu
//note: only 24-bit RGB and 32-bit ARGB uncompressed images supported
namespace nall {
struct bmp {
inline static bool read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height);
inline static bool write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha = false);
};
bool bmp::read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height) {
file fp;
if(fp.open(filename, file::mode::read) == false) return false;
if(fp.size() < 0x36) return false;
if(fp.readm(2) != 0x424d) return false;
fp.seek(0x000a);
unsigned offset = fp.readl(4);
unsigned dibsize = fp.readl(4);
if(dibsize != 40) return false;
signed headerWidth = fp.readl(4);
if(headerWidth < 0) return false;
signed headerHeight = fp.readl(4);
fp.readl(2);
unsigned bitsPerPixel = fp.readl(2);
if(bitsPerPixel != 24 && bitsPerPixel != 32) return false;
unsigned compression = fp.readl(4);
if(compression != 0) return false;
fp.seek(offset);
bool noFlip = headerHeight < 0;
width = headerWidth, height = abs(headerHeight);
data = new uint32_t[width * height];
unsigned bytesPerPixel = bitsPerPixel / 8;
unsigned alignedWidth = width * bytesPerPixel;
unsigned paddingLength = 0;
while(alignedWidth % 4) alignedWidth++, paddingLength++;
for(unsigned y = 0; y < height; y++) {
uint32_t *p = noFlip ? data + y * width : data + (height - 1 - y) * width;
for(unsigned x = 0; x < width; x++, p++) {
*p = fp.readl(bytesPerPixel);
if(bytesPerPixel == 3) *p |= 255 << 24;
}
if(paddingLength) fp.readl(paddingLength);
}
fp.close();
return true;
}
bool bmp::write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha) {
file fp;
if(fp.open(filename, file::mode::write) == false) return false;
unsigned bitsPerPixel = alpha ? 32 : 24;
unsigned bytesPerPixel = bitsPerPixel / 8;
unsigned alignedWidth = width * bytesPerPixel;
unsigned paddingLength = 0;
unsigned imageSize = alignedWidth * height;
unsigned fileSize = 0x36 + imageSize;
while(alignedWidth % 4) alignedWidth++, paddingLength++;
fp.writem(0x424d, 2); //signature
fp.writel(fileSize, 4); //file size
fp.writel(0, 2); //reserved
fp.writel(0, 2); //reserved
fp.writel(0x36, 4); //offset
fp.writel(40, 4); //DIB size
fp.writel(width, 4); //width
fp.writel(-height, 4); //height
fp.writel(1, 2); //color planes
fp.writel(bitsPerPixel, 2); //bits per pixel
fp.writel(0, 4); //compression method (BI_RGB)
fp.writel(imageSize, 4); //image data size
fp.writel(3780, 4); //horizontal resolution
fp.writel(3780, 4); //vertical resolution
fp.writel(0, 4); //palette size
fp.writel(0, 4); //important color count
for(unsigned y = 0; y < height; y++) {
const uint32_t *p = (const uint32_t*)((const uint8_t*)data + y * pitch);
for(unsigned x = 0; x < width; x++) fp.writel(*p++, bytesPerPixel);
if(paddingLength) fp.writel(0, paddingLength);
}
fp.close();
return true;
}
}
#endif

View File

@ -1,214 +0,0 @@
#ifndef NALL_BPS_DELTA_HPP
#define NALL_BPS_DELTA_HPP
#include <nall/crc32.hpp>
#include <nall/file.hpp>
#include <nall/filemap.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
struct bpsdelta {
inline void source(const uint8_t *data, unsigned size);
inline void target(const uint8_t *data, unsigned size);
inline bool source(const string &filename);
inline bool target(const string &filename);
inline bool create(const string &filename, const string &metadata = "");
protected:
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
enum : unsigned { Granularity = 1 };
struct Node {
unsigned offset;
Node *next;
inline Node() : offset(0), next(nullptr) {}
inline ~Node() { if(next) delete next; }
};
filemap sourceFile;
const uint8_t *sourceData;
unsigned sourceSize;
filemap targetFile;
const uint8_t *targetData;
unsigned targetSize;
};
void bpsdelta::source(const uint8_t *data, unsigned size) {
sourceData = data;
sourceSize = size;
}
void bpsdelta::target(const uint8_t *data, unsigned size) {
targetData = data;
targetSize = size;
}
bool bpsdelta::source(const string &filename) {
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
source(sourceFile.data(), sourceFile.size());
return true;
}
bool bpsdelta::target(const string &filename) {
if(targetFile.open(filename, filemap::mode::read) == false) return false;
target(targetFile.data(), targetFile.size());
return true;
}
bool bpsdelta::create(const string &filename, const string &metadata) {
file modifyFile;
if(modifyFile.open(filename, file::mode::write) == false) return false;
uint32_t sourceChecksum = ~0, modifyChecksum = ~0;
unsigned sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
auto write = [&](uint8_t data) {
modifyFile.write(data);
modifyChecksum = crc32_adjust(modifyChecksum, data);
};
auto encode = [&](uint64_t data) {
while(true) {
uint64_t x = data & 0x7f;
data >>= 7;
if(data == 0) {
write(0x80 | x);
break;
}
write(x);
data--;
}
};
write('B');
write('P');
write('S');
write('1');
encode(sourceSize);
encode(targetSize);
unsigned markupSize = metadata.length();
encode(markupSize);
for(unsigned n = 0; n < markupSize; n++) write(metadata[n]);
Node *sourceTree[65536], *targetTree[65536];
for(unsigned n = 0; n < 65536; n++) sourceTree[n] = 0, targetTree[n] = 0;
//source tree creation
for(unsigned offset = 0; offset < sourceSize; offset++) {
uint16_t symbol = sourceData[offset + 0];
sourceChecksum = crc32_adjust(sourceChecksum, symbol);
if(offset < sourceSize - 1) symbol |= sourceData[offset + 1] << 8;
Node *node = new Node;
node->offset = offset;
node->next = sourceTree[symbol];
sourceTree[symbol] = node;
}
unsigned targetReadLength = 0;
auto targetReadFlush = [&]() {
if(targetReadLength) {
encode(TargetRead | ((targetReadLength - 1) << 2));
unsigned offset = outputOffset - targetReadLength;
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
}
};
while(outputOffset < targetSize) {
unsigned maxLength = 0, maxOffset = 0, mode = TargetRead;
uint16_t symbol = targetData[outputOffset + 0];
if(outputOffset < targetSize - 1) symbol |= targetData[outputOffset + 1] << 8;
{ //source read
unsigned length = 0, offset = outputOffset;
while(offset < sourceSize && offset < targetSize && sourceData[offset] == targetData[offset]) {
length++;
offset++;
}
if(length > maxLength) maxLength = length, mode = SourceRead;
}
{ //source copy
Node *node = sourceTree[symbol];
while(node) {
unsigned length = 0, x = node->offset, y = outputOffset;
while(x < sourceSize && y < targetSize && sourceData[x++] == targetData[y++]) length++;
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = SourceCopy;
node = node->next;
}
}
{ //target copy
Node *node = targetTree[symbol];
while(node) {
unsigned length = 0, x = node->offset, y = outputOffset;
while(y < targetSize && targetData[x++] == targetData[y++]) length++;
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = TargetCopy;
node = node->next;
}
//target tree append
node = new Node;
node->offset = outputOffset;
node->next = targetTree[symbol];
targetTree[symbol] = node;
}
{ //target read
if(maxLength < 4) {
maxLength = min((unsigned)Granularity, targetSize - outputOffset);
mode = TargetRead;
}
}
if(mode != TargetRead) targetReadFlush();
switch(mode) {
case SourceRead:
encode(SourceRead | ((maxLength - 1) << 2));
break;
case TargetRead:
//delay write to group sequential TargetRead commands into one
targetReadLength += maxLength;
break;
case SourceCopy:
case TargetCopy:
encode(mode | ((maxLength - 1) << 2));
signed relativeOffset;
if(mode == SourceCopy) {
relativeOffset = maxOffset - sourceRelativeOffset;
sourceRelativeOffset = maxOffset + maxLength;
} else {
relativeOffset = maxOffset - targetRelativeOffset;
targetRelativeOffset = maxOffset + maxLength;
}
encode((relativeOffset < 0) | (abs(relativeOffset) << 1));
break;
}
outputOffset += maxLength;
}
targetReadFlush();
sourceChecksum = ~sourceChecksum;
for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n);
uint32_t targetChecksum = crc32_calculate(targetData, targetSize);
for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n);
uint32_t outputChecksum = ~modifyChecksum;
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
modifyFile.close();
return true;
}
}
#endif

View File

@ -1,152 +0,0 @@
#ifndef NALL_BPS_LINEAR_HPP
#define NALL_BPS_LINEAR_HPP
#include <nall/crc32.hpp>
#include <nall/file.hpp>
#include <nall/filemap.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
struct bpslinear {
inline void source(const uint8_t *data, unsigned size);
inline void target(const uint8_t *data, unsigned size);
inline bool source(const string &filename);
inline bool target(const string &filename);
inline bool create(const string &filename, const string &metadata = "");
protected:
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
enum : unsigned { Granularity = 1 };
filemap sourceFile;
const uint8_t *sourceData;
unsigned sourceSize;
filemap targetFile;
const uint8_t *targetData;
unsigned targetSize;
};
void bpslinear::source(const uint8_t *data, unsigned size) {
sourceData = data;
sourceSize = size;
}
void bpslinear::target(const uint8_t *data, unsigned size) {
targetData = data;
targetSize = size;
}
bool bpslinear::source(const string &filename) {
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
source(sourceFile.data(), sourceFile.size());
return true;
}
bool bpslinear::target(const string &filename) {
if(targetFile.open(filename, filemap::mode::read) == false) return false;
target(targetFile.data(), targetFile.size());
return true;
}
bool bpslinear::create(const string &filename, const string &metadata) {
file modifyFile;
if(modifyFile.open(filename, file::mode::write) == false) return false;
uint32_t modifyChecksum = ~0;
unsigned targetRelativeOffset = 0, outputOffset = 0;
auto write = [&](uint8_t data) {
modifyFile.write(data);
modifyChecksum = crc32_adjust(modifyChecksum, data);
};
auto encode = [&](uint64_t data) {
while(true) {
uint64_t x = data & 0x7f;
data >>= 7;
if(data == 0) {
write(0x80 | x);
break;
}
write(x);
data--;
}
};
unsigned targetReadLength = 0;
auto targetReadFlush = [&]() {
if(targetReadLength) {
encode(TargetRead | ((targetReadLength - 1) << 2));
unsigned offset = outputOffset - targetReadLength;
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
}
};
write('B');
write('P');
write('S');
write('1');
encode(sourceSize);
encode(targetSize);
unsigned markupSize = metadata.length();
encode(markupSize);
for(unsigned n = 0; n < markupSize; n++) write(metadata[n]);
while(outputOffset < targetSize) {
unsigned sourceLength = 0;
for(unsigned n = 0; outputOffset + n < min(sourceSize, targetSize); n++) {
if(sourceData[outputOffset + n] != targetData[outputOffset + n]) break;
sourceLength++;
}
unsigned rleLength = 0;
for(unsigned n = 1; outputOffset + n < targetSize; n++) {
if(targetData[outputOffset] != targetData[outputOffset + n]) break;
rleLength++;
}
if(rleLength >= 4) {
//write byte to repeat
targetReadLength++;
outputOffset++;
targetReadFlush();
//copy starting from repetition byte
encode(TargetCopy | ((rleLength - 1) << 2));
unsigned relativeOffset = (outputOffset - 1) - targetRelativeOffset;
encode(relativeOffset << 1);
outputOffset += rleLength;
targetRelativeOffset = outputOffset - 1;
} else if(sourceLength >= 4) {
targetReadFlush();
encode(SourceRead | ((sourceLength - 1) << 2));
outputOffset += sourceLength;
} else {
targetReadLength += Granularity;
outputOffset += Granularity;
}
}
targetReadFlush();
uint32_t sourceChecksum = crc32_calculate(sourceData, sourceSize);
for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n);
uint32_t targetChecksum = crc32_calculate(targetData, targetSize);
for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n);
uint32_t outputChecksum = ~modifyChecksum;
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
modifyFile.close();
return true;
}
}
#endif

View File

@ -1,121 +0,0 @@
#ifndef NALL_BPS_METADATA_HPP
#define NALL_BPS_METADATA_HPP
#include <nall/crc32.hpp>
#include <nall/file.hpp>
#include <nall/filemap.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
struct bpsmetadata {
inline bool load(const string &filename);
inline bool save(const string &filename, const string &metadata);
inline string metadata() const;
protected:
file sourceFile;
string metadataString;
};
bool bpsmetadata::load(const string &filename) {
if(sourceFile.open(filename, file::mode::read) == false) return false;
auto read = [&]() -> uint8_t {
return sourceFile.read();
};
auto decode = [&]() -> uint64_t {
uint64_t data = 0, shift = 1;
while(true) {
uint8_t x = read();
data += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
data += shift;
}
return data;
};
if(read() != 'B') return false;
if(read() != 'P') return false;
if(read() != 'S') return false;
if(read() != '1') return false;
decode();
decode();
unsigned metadataSize = decode();
char data[metadataSize + 1];
for(unsigned n = 0; n < metadataSize; n++) data[n] = read();
data[metadataSize] = 0;
metadataString = (const char*)data;
return true;
}
bool bpsmetadata::save(const string &filename, const string &metadata) {
file targetFile;
if(targetFile.open(filename, file::mode::write) == false) return false;
if(sourceFile.open() == false) return false;
sourceFile.seek(0);
auto read = [&]() -> uint8_t {
return sourceFile.read();
};
auto decode = [&]() -> uint64_t {
uint64_t data = 0, shift = 1;
while(true) {
uint8_t x = read();
data += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
data += shift;
}
return data;
};
uint32_t checksum = ~0;
auto write = [&](uint8_t data) {
targetFile.write(data);
checksum = crc32_adjust(checksum, data);
};
auto encode = [&](uint64_t data) {
while(true) {
uint64_t x = data & 0x7f;
data >>= 7;
if(data == 0) {
write(0x80 | x);
break;
}
write(x);
data--;
}
};
for(unsigned n = 0; n < 4; n++) write(read());
encode(decode());
encode(decode());
unsigned sourceLength = decode();
unsigned targetLength = metadata.length();
encode(targetLength);
sourceFile.seek(sourceLength, file::index::relative);
for(unsigned n = 0; n < targetLength; n++) write(metadata[n]);
unsigned length = sourceFile.size() - sourceFile.offset() - 4;
for(unsigned n = 0; n < length; n++) write(read());
uint32_t outputChecksum = ~checksum;
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
targetFile.close();
return true;
}
string bpsmetadata::metadata() const {
return metadataString;
}
}
#endif

View File

@ -1,219 +0,0 @@
#ifndef NALL_BPS_PATCH_HPP
#define NALL_BPS_PATCH_HPP
#include <nall/crc32.hpp>
#include <nall/file.hpp>
#include <nall/filemap.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
struct bpspatch {
inline bool modify(const uint8_t *data, unsigned size);
inline void source(const uint8_t *data, unsigned size);
inline void target(uint8_t *data, unsigned size);
inline bool modify(const string &filename);
inline bool source(const string &filename);
inline bool target(const string &filename);
inline string metadata() const;
inline unsigned size() const;
enum result : unsigned {
unknown,
success,
patch_too_small,
patch_invalid_header,
source_too_small,
target_too_small,
source_checksum_invalid,
target_checksum_invalid,
patch_checksum_invalid,
};
inline result apply();
protected:
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
filemap modifyFile;
const uint8_t *modifyData;
unsigned modifySize;
filemap sourceFile;
const uint8_t *sourceData;
unsigned sourceSize;
filemap targetFile;
uint8_t *targetData;
unsigned targetSize;
unsigned modifySourceSize;
unsigned modifyTargetSize;
unsigned modifyMarkupSize;
string metadataString;
};
bool bpspatch::modify(const uint8_t *data, unsigned size) {
if(size < 19) return false;
modifyData = data;
modifySize = size;
unsigned offset = 4;
auto decode = [&]() -> uint64_t {
uint64_t data = 0, shift = 1;
while(true) {
uint8_t x = modifyData[offset++];
data += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
data += shift;
}
return data;
};
modifySourceSize = decode();
modifyTargetSize = decode();
modifyMarkupSize = decode();
char buffer[modifyMarkupSize + 1];
for(unsigned n = 0; n < modifyMarkupSize; n++) buffer[n] = modifyData[offset++];
buffer[modifyMarkupSize] = 0;
metadataString = (const char*)buffer;
return true;
}
void bpspatch::source(const uint8_t *data, unsigned size) {
sourceData = data;
sourceSize = size;
}
void bpspatch::target(uint8_t *data, unsigned size) {
targetData = data;
targetSize = size;
}
bool bpspatch::modify(const string &filename) {
if(modifyFile.open(filename, filemap::mode::read) == false) return false;
return modify(modifyFile.data(), modifyFile.size());
}
bool bpspatch::source(const string &filename) {
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
source(sourceFile.data(), sourceFile.size());
return true;
}
bool bpspatch::target(const string &filename) {
file fp;
if(fp.open(filename, file::mode::write) == false) return false;
fp.truncate(modifyTargetSize);
fp.close();
if(targetFile.open(filename, filemap::mode::readwrite) == false) return false;
target(targetFile.data(), targetFile.size());
return true;
}
string bpspatch::metadata() const {
return metadataString;
}
unsigned bpspatch::size() const {
return modifyTargetSize;
}
bpspatch::result bpspatch::apply() {
if(modifySize < 19) return result::patch_too_small;
uint32_t modifyChecksum = ~0, targetChecksum = ~0;
unsigned modifyOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
auto read = [&]() -> uint8_t {
uint8_t data = modifyData[modifyOffset++];
modifyChecksum = crc32_adjust(modifyChecksum, data);
return data;
};
auto decode = [&]() -> uint64_t {
uint64_t data = 0, shift = 1;
while(true) {
uint8_t x = read();
data += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
data += shift;
}
return data;
};
auto write = [&](uint8_t data) {
targetData[outputOffset++] = data;
targetChecksum = crc32_adjust(targetChecksum, data);
};
if(read() != 'B') return result::patch_invalid_header;
if(read() != 'P') return result::patch_invalid_header;
if(read() != 'S') return result::patch_invalid_header;
if(read() != '1') return result::patch_invalid_header;
modifySourceSize = decode();
modifyTargetSize = decode();
modifyMarkupSize = decode();
for(unsigned n = 0; n < modifyMarkupSize; n++) read();
if(modifySourceSize > sourceSize) return result::source_too_small;
if(modifyTargetSize > targetSize) return result::target_too_small;
while(modifyOffset < modifySize - 12) {
unsigned length = decode();
unsigned mode = length & 3;
length = (length >> 2) + 1;
switch(mode) {
case SourceRead:
while(length--) write(sourceData[outputOffset]);
break;
case TargetRead:
while(length--) write(read());
break;
case SourceCopy:
case TargetCopy:
signed offset = decode();
bool negative = offset & 1;
offset >>= 1;
if(negative) offset = -offset;
if(mode == SourceCopy) {
sourceRelativeOffset += offset;
while(length--) write(sourceData[sourceRelativeOffset++]);
} else {
targetRelativeOffset += offset;
while(length--) write(targetData[targetRelativeOffset++]);
}
break;
}
}
uint32_t modifySourceChecksum = 0, modifyTargetChecksum = 0, modifyModifyChecksum = 0;
for(unsigned n = 0; n < 32; n += 8) modifySourceChecksum |= read() << n;
for(unsigned n = 0; n < 32; n += 8) modifyTargetChecksum |= read() << n;
uint32_t checksum = ~modifyChecksum;
for(unsigned n = 0; n < 32; n += 8) modifyModifyChecksum |= read() << n;
uint32_t sourceChecksum = crc32_calculate(sourceData, modifySourceSize);
targetChecksum = ~targetChecksum;
if(sourceChecksum != modifySourceChecksum) return result::source_checksum_invalid;
if(targetChecksum != modifyTargetChecksum) return result::target_checksum_invalid;
if(checksum != modifyModifyChecksum) return result::patch_checksum_invalid;
return result::success;
}
}
#endif

View File

@ -1,152 +0,0 @@
#ifndef NALL_COMPOSITOR_HPP
#define NALL_COMPOSITOR_HPP
#include <nall/intrinsics.hpp>
namespace nall {
struct compositor {
inline static bool enabled();
inline static bool enable(bool status);
#if defined(PLATFORM_X)
enum class Compositor : unsigned { Unknown, Metacity, Xfwm4 };
inline static Compositor detect();
inline static bool enabled_metacity();
inline static bool enable_metacity(bool status);
inline static bool enabled_xfwm4();
inline static bool enable_xfwm4(bool status);
#endif
};
#if defined(PLATFORM_X)
//Metacity
bool compositor::enabled_metacity() {
FILE *fp = popen("gconftool-2 --get /apps/metacity/general/compositing_manager", "r");
if(fp == 0) return false;
char buffer[512];
if(fgets(buffer, sizeof buffer, fp) == 0) return false;
if(!memcmp(buffer, "true", 4)) return true;
return false;
}
bool compositor::enable_metacity(bool status) {
FILE *fp;
if(status) {
fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager true", "r");
} else {
fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager false", "r");
}
if(fp == 0) return false;
pclose(fp);
return true;
}
//Xfwm4
bool compositor::enabled_xfwm4() {
FILE *fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing'", "r");
if(fp == 0) return false;
char buffer[512];
if(fgets(buffer, sizeof buffer, fp) == 0) return false;
if(!memcmp(buffer, "true", 4)) return true;
return false;
}
bool compositor::enable_xfwm4(bool status) {
FILE *fp;
if(status) {
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'", "r");
} else {
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'false'", "r");
}
if(fp == 0) return false;
pclose(fp);
return true;
}
//General
compositor::Compositor compositor::detect() {
Compositor result = Compositor::Unknown;
FILE *fp;
char buffer[512];
fp = popen("pidof metacity", "r");
if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Metacity;
pclose(fp);
fp = popen("pidof xfwm4", "r");
if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Xfwm4;
pclose(fp);
return result;
}
bool compositor::enabled() {
switch(detect()) {
case Compositor::Metacity: return enabled_metacity();
case Compositor::Xfwm4: return enabled_xfwm4();
default: return false;
}
}
bool compositor::enable(bool status) {
switch(detect()) {
case Compositor::Metacity: return enable_metacity(status);
case Compositor::Xfwm4: return enable_xfwm4(status);
default: return false;
}
}
#elif defined(PLATFORM_WINDOWS)
bool compositor::enabled() {
HMODULE module = GetModuleHandleW(L"dwmapi");
if(module == 0) module = LoadLibraryW(L"dwmapi");
if(module == 0) return false;
auto pDwmIsCompositionEnabled = (HRESULT (WINAPI*)(BOOL*))GetProcAddress(module, "DwmIsCompositionEnabled");
if(pDwmIsCompositionEnabled == 0) return false;
BOOL result;
if(pDwmIsCompositionEnabled(&result) != S_OK) return false;
return result;
}
bool compositor::enable(bool status) {
HMODULE module = GetModuleHandleW(L"dwmapi");
if(module == 0) module = LoadLibraryW(L"dwmapi");
if(module == 0) return false;
auto pDwmEnableComposition = (HRESULT (WINAPI*)(UINT))GetProcAddress(module, "DwmEnableComposition");
if(pDwmEnableComposition == 0) return false;
if(pDwmEnableComposition(status) != S_OK) return false;
return true;
}
#else
bool compositor::enabled() {
return false;
}
bool compositor::enable(bool) {
return false;
}
#endif
}
#endif

View File

@ -1,126 +0,0 @@
#ifndef NALL_CONFIG_HPP
#define NALL_CONFIG_HPP
#include <nall/file.hpp>
#include <nall/string.hpp>
#include <nall/vector.hpp>
namespace nall {
namespace configuration_traits {
template<typename T> struct is_boolean { enum { value = false }; };
template<> struct is_boolean<bool> { enum { value = true }; };
template<typename T> struct is_signed { enum { value = false }; };
template<> struct is_signed<signed> { enum { value = true }; };
template<typename T> struct is_unsigned { enum { value = false }; };
template<> struct is_unsigned<unsigned> { enum { value = true }; };
template<typename T> struct is_double { enum { value = false }; };
template<> struct is_double<double> { enum { value = true }; };
template<typename T> struct is_string { enum { value = false }; };
template<> struct is_string<string> { enum { value = true }; };
}
class configuration {
public:
enum type_t { boolean_t, signed_t, unsigned_t, double_t, string_t, unknown_t };
struct item_t {
uintptr_t data;
string name;
string desc;
type_t type;
inline string get() const {
switch(type) {
case boolean_t: return { *(bool*)data };
case signed_t: return { *(signed*)data };
case unsigned_t: return { *(unsigned*)data };
case double_t: return { *(double*)data };
case string_t: return { "\"", *(string*)data, "\"" };
}
return "???";
}
inline void set(string s) {
switch(type) {
case boolean_t: *(bool*)data = (s == "true"); break;
case signed_t: *(signed*)data = integer(s); break;
case unsigned_t: *(unsigned*)data = decimal(s); break;
case double_t: *(double*)data = fp(s); break;
case string_t: s.trim("\""); *(string*)data = s; break;
}
}
};
vector<item_t> list;
template<typename T>
inline void append(T &data, const char *name, const char *desc = "") {
item_t item = { (uintptr_t)&data, name, desc };
if(configuration_traits::is_boolean<T>::value) item.type = boolean_t;
else if(configuration_traits::is_signed<T>::value) item.type = signed_t;
else if(configuration_traits::is_unsigned<T>::value) item.type = unsigned_t;
else if(configuration_traits::is_double<T>::value) item.type = double_t;
else if(configuration_traits::is_string<T>::value) item.type = string_t;
else item.type = unknown_t;
list.append(item);
}
//deprecated
template<typename T>
inline void attach(T &data, const char *name, const char *desc = "") {
append(data, name, desc);
}
inline virtual bool load(const string &filename) {
string data;
if(data.readfile(filename) == true) {
data.replace("\r", "");
lstring line;
line.split("\n", data);
for(unsigned i = 0; i < line.size(); i++) {
if(auto position = qstrpos(line[i], "#")) line[i][position()] = 0;
if(!qstrpos(line[i], " = ")) continue;
lstring part;
part.qsplit(" = ", line[i]);
part[0].trim();
part[1].trim();
for(unsigned n = 0; n < list.size(); n++) {
if(part[0] == list[n].name) {
list[n].set(part[1]);
break;
}
}
}
return true;
} else {
return false;
}
}
inline virtual bool save(const string &filename) const {
file fp;
if(fp.open(filename, file::mode::write)) {
for(unsigned i = 0; i < list.size(); i++) {
string output;
output.append(list[i].name, " = ", list[i].get());
if(list[i].desc != "") output.append(" # ", list[i].desc);
output.append("\r\n");
fp.print(output);
}
fp.close();
return true;
} else {
return false;
}
}
};
}
#endif

View File

@ -1,66 +0,0 @@
#ifndef NALL_CRC32_HPP
#define NALL_CRC32_HPP
#include <nall/stdint.hpp>
namespace nall {
const uint32_t crc32_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
inline uint32_t crc32_adjust(uint32_t crc32, uint8_t input) {
return ((crc32 >> 8) & 0x00ffffff) ^ crc32_table[(crc32 ^ input) & 0xff];
}
inline uint32_t crc32_calculate(const uint8_t *data, unsigned length) {
uint32_t crc32 = ~0;
for(unsigned i = 0; i < length; i++) {
crc32 = crc32_adjust(crc32, data[i]);
}
return ~crc32;
}
}
#endif

View File

@ -1,153 +0,0 @@
#ifndef NALL_DIRECTORY_HPP
#define NALL_DIRECTORY_HPP
#include <nall/intrinsics.hpp>
#include <nall/sort.hpp>
#include <nall/string.hpp>
#include <nall/vector.hpp>
#if defined(PLATFORM_WINDOWS)
#include <nall/windows/utf8.hpp>
#else
#include <dirent.h>
#include <stdio.h>
#include <sys/types.h>
#endif
namespace nall {
struct directory {
static bool exists(const string &pathname);
static lstring folders(const string &pathname, const string &pattern = "*");
static lstring files(const string &pathname, const string &pattern = "*");
static lstring contents(const string &pathname, const string &pattern = "*");
};
#if defined(PLATFORM_WINDOWS)
inline bool directory::exists(const string &pathname) {
DWORD result = GetFileAttributes(utf16_t(pathname));
if(result == INVALID_FILE_ATTRIBUTES) return false;
return (result & FILE_ATTRIBUTE_DIRECTORY);
}
inline lstring directory::folders(const string &pathname, const string &pattern) {
lstring list;
string path = pathname;
path.transform("/", "\\");
if(!strend(path, "\\")) path.append("\\");
path.append("*");
HANDLE handle;
WIN32_FIND_DATA data;
handle = FindFirstFile(utf16_t(path), &data);
if(handle != INVALID_HANDLE_VALUE) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
}
while(FindNextFile(handle, &data) != false) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
}
}
FindClose(handle);
}
if(list.size() > 0) list.sort();
for(auto &name : list) name.append("/"); //must append after sorting
return list;
}
inline lstring directory::files(const string &pathname, const string &pattern) {
lstring list;
string path = pathname;
path.transform("/", "\\");
if(!strend(path, "\\")) path.append("\\");
path.append("*");
HANDLE handle;
WIN32_FIND_DATA data;
handle = FindFirstFile(utf16_t(path), &data);
if(handle != INVALID_HANDLE_VALUE) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
while(FindNextFile(handle, &data) != false) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
}
FindClose(handle);
}
if(list.size() > 0) list.sort();
return list;
}
inline lstring directory::contents(const string &pathname, const string &pattern) {
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
lstring files = directory::files(pathname, pattern);
for(auto &file : files) folders.append(file);
return folders;
}
#else
inline bool directory::exists(const string &pathname) {
DIR *dp = opendir(pathname);
if(!dp) return false;
closedir(dp);
return true;
}
inline lstring directory::folders(const string &pathname, const string &pattern) {
lstring list;
DIR *dp;
struct dirent *ep;
dp = opendir(pathname);
if(dp) {
while(ep = readdir(dp)) {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if(ep->d_type & DT_DIR) {
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
}
}
closedir(dp);
}
if(list.size() > 0) list.sort();
for(auto &name : list) name.append("/"); //must append after sorting
return list;
}
inline lstring directory::files(const string &pathname, const string &pattern) {
lstring list;
DIR *dp;
struct dirent *ep;
dp = opendir(pathname);
if(dp) {
while(ep = readdir(dp)) {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if((ep->d_type & DT_DIR) == 0) {
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
}
}
closedir(dp);
}
if(list.size() > 0) list.sort();
return list;
}
inline lstring directory::contents(const string &pathname, const string &pattern) {
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
lstring files = directory::files(pathname, pattern);
for(auto &file : files) folders.append(file);
return folders;
}
#endif
}
#endif

View File

@ -1,115 +0,0 @@
#ifndef NALL_DL_HPP
#define NALL_DL_HPP
//dynamic linking support
#include <nall/intrinsics.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
#include <dlfcn.h>
#elif defined(PLATFORM_WINDOWS)
#include <windows.h>
#include <nall/windows/utf8.hpp>
#endif
namespace nall {
struct library {
bool opened() const { return handle; }
bool open(const char*, const char* = "");
bool open_absolute(const char*);
void* sym(const char*);
void close();
library() : handle(0) {}
~library() { close(); }
library& operator=(const library&) = delete;
library(const library&) = delete;
private:
uintptr_t handle;
};
#if defined(PLATFORM_X)
inline bool library::open(const char *name, const char *path) {
if(handle) close();
handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".so"), RTLD_LAZY);
if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY);
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return dlsym((void*)handle, name);
}
inline void library::close() {
if(!handle) return;
dlclose((void*)handle);
handle = 0;
}
#elif defined(PLATFORM_OSX)
inline bool library::open(const char *name, const char *path) {
if(handle) close();
handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".dylib"), RTLD_LAZY);
if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY);
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return dlsym((void*)handle, name);
}
inline void library::close() {
if(!handle) return;
dlclose((void*)handle);
handle = 0;
}
#elif defined(PLATFORM_WINDOWS)
inline bool library::open(const char *name, const char *path) {
if(handle) close();
string filepath(path, *path && !strend(path, "/") && !strend(path, "\\") ? "\\" : "", name, ".dll");
handle = (uintptr_t)LoadLibraryW(utf16_t(filepath));
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)LoadLibraryW(utf16_t(name));
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return (void*)GetProcAddress((HMODULE)handle, name);
}
inline void library::close() {
if(!handle) return;
FreeLibrary((HMODULE)handle);
handle = 0;
}
#else
inline bool library::open(const char*, const char*) { return false; }
inline void* library::sym(const char*) { return 0; }
inline void library::close() {}
#endif
};
#endif

View File

@ -1,13 +0,0 @@
#ifndef NALL_DSP_HPP
#define NALL_DSP_HPP
#include <algorithm>
#ifdef __SSE__
#include <xmmintrin.h>
#endif
#define NALL_DSP_INTERNAL_HPP
#include <nall/dsp/core.hpp>
#undef NALL_DSP_INTERNAL_HPP
#endif

View File

@ -1,51 +0,0 @@
#ifdef NALL_DSP_INTERNAL_HPP
struct Buffer {
double **sample;
uint16_t rdoffset;
uint16_t wroffset;
unsigned channels;
void setChannels(unsigned channels) {
for(unsigned c = 0; c < this->channels; c++) {
if(sample[c]) abort();
}
if(sample) abort();
this->channels = channels;
if(channels == 0) return;
sample = (double**)alloc_invisible(channels * sizeof(*sample));
for(unsigned c = 0; c < channels; c++) {
sample[c] = (double*)alloc_invisible(65536 * sizeof(**sample));
}
}
inline double& read(unsigned channel, signed offset = 0) {
return sample[channel][(uint16_t)(rdoffset + offset)];
}
inline double& write(unsigned channel, signed offset = 0) {
return sample[channel][(uint16_t)(wroffset + offset)];
}
inline void clear() {
for(unsigned c = 0; c < channels; c++) {
for(unsigned n = 0; n < 65536; n++) {
sample[c][n] = 0;
}
}
rdoffset = 0;
wroffset = 0;
}
Buffer() {
channels = 0;
}
~Buffer() {
setChannels(0);
}
};
#endif

View File

@ -1,168 +0,0 @@
#ifdef NALL_DSP_INTERNAL_HPP
#include <math.h>
#include <nall/stdint.hpp>
#include <emulibc.h>
namespace nall {
//precision: can be float, double or long double
#define real float
struct DSP;
struct Resampler {
DSP &dsp;
real frequency;
virtual void setFrequency() = 0;
virtual void clear() = 0;
virtual void sample() = 0;
Resampler(DSP &dsp) : dsp(dsp) {}
};
struct DSP {
enum class ResampleEngine : unsigned {
Nearest,
Linear,
Cosine,
Cubic,
Hermite,
Average,
Sinc,
};
inline void setChannels(unsigned channels);
inline void setPrecision(unsigned precision);
inline void setFrequency(real frequency); //inputFrequency
inline void setVolume(real volume);
inline void setBalance(real balance);
inline void setResampler(ResampleEngine resamplingEngine);
inline void setResamplerFrequency(real frequency); //outputFrequency
inline void sample(signed channel[]);
inline bool pending();
inline void read(signed channel[]);
inline void clear();
inline DSP();
inline ~DSP();
protected:
friend class ResampleNearest;
friend class ResampleLinear;
friend class ResampleCosine;
friend class ResampleCubic;
friend class ResampleAverage;
friend class ResampleHermite;
friend class ResampleSinc;
struct Settings {
unsigned channels;
unsigned precision;
real frequency;
real volume;
real balance;
//internal
real intensity;
real intensityInverse;
} settings;
Resampler *resampler;
inline void write(real channel[]);
#include "buffer.hpp"
Buffer buffer;
Buffer output;
inline void adjustVolume();
inline void adjustBalance();
inline signed clamp(const unsigned bits, const signed x);
};
#include "resample/nearest.hpp"
#include "resample/linear.hpp"
#include "resample/cosine.hpp"
#include "resample/cubic.hpp"
#include "resample/hermite.hpp"
#include "resample/average.hpp"
#include "resample/sinc.hpp"
#include "settings.hpp"
void DSP::sample(signed channel[]) {
for(unsigned c = 0; c < settings.channels; c++) {
buffer.write(c) = (real)channel[c] * settings.intensityInverse;
}
buffer.wroffset++;
resampler->sample();
}
bool DSP::pending() {
return output.rdoffset != output.wroffset;
}
void DSP::read(signed channel[]) {
adjustVolume();
adjustBalance();
for(unsigned c = 0; c < settings.channels; c++) {
channel[c] = clamp(settings.precision, output.read(c) * settings.intensity);
}
output.rdoffset++;
}
void DSP::write(real channel[]) {
for(unsigned c = 0; c < settings.channels; c++) {
output.write(c) = channel[c];
}
output.wroffset++;
}
void DSP::adjustVolume() {
for(unsigned c = 0; c < settings.channels; c++) {
output.read(c) *= settings.volume;
}
}
void DSP::adjustBalance() {
if(settings.channels != 2) return; //TODO: support > 2 channels
if(settings.balance < 0.0) output.read(1) *= 1.0 + settings.balance;
if(settings.balance > 0.0) output.read(0) *= 1.0 - settings.balance;
}
signed DSP::clamp(const unsigned bits, const signed x) {
const signed b = 1U << (bits - 1);
const signed m = (1U << (bits - 1)) - 1;
return (x > m) ? m : (x < -b) ? -b : x;
}
void DSP::clear() {
buffer.clear();
output.clear();
resampler->clear();
}
DSP::DSP() {
setResampler(ResampleEngine::Hermite);
setResamplerFrequency(44100.0);
setChannels(2);
setPrecision(16);
setFrequency(44100.0);
setVolume(1.0);
setBalance(0.0);
clear();
}
DSP::~DSP() {
if(resampler) delete resampler;
}
#undef real
}
#endif

View File

@ -1,72 +0,0 @@
#ifdef NALL_DSP_INTERNAL_HPP
struct ResampleAverage : Resampler {
inline void setFrequency();
inline void clear();
inline void sample();
inline void sampleLinear();
ResampleAverage(DSP &dsp) : Resampler(dsp) {}
real fraction;
real step;
};
void ResampleAverage::setFrequency() {
fraction = 0.0;
step = dsp.settings.frequency / frequency;
}
void ResampleAverage::clear() {
fraction = 0.0;
}
void ResampleAverage::sample() {
//can only average if input frequency >= output frequency
if(step < 1.0) return sampleLinear();
fraction += 1.0;
real scalar = 1.0;
if(fraction > step) scalar = 1.0 - (fraction - step);
for(unsigned c = 0; c < dsp.settings.channels; c++) {
dsp.output.write(c) += dsp.buffer.read(c) * scalar;
}
if(fraction >= step) {
for(unsigned c = 0; c < dsp.settings.channels; c++) {
dsp.output.write(c) /= step;
}
dsp.output.wroffset++;
fraction -= step;
for(unsigned c = 0; c < dsp.settings.channels; c++) {
dsp.output.write(c) = dsp.buffer.read(c) * fraction;
}
}
dsp.buffer.rdoffset++;
}
void ResampleAverage::sampleLinear() {
while(fraction <= 1.0) {
std::vector<real> channel(dsp.settings.channels);
for(unsigned n = 0; n < dsp.settings.channels; n++) {
real a = dsp.buffer.read(n, -1);
real b = dsp.buffer.read(n, -0);
real mu = fraction;
channel[n] = a * (1.0 - mu) + b * mu;
}
dsp.write(channel.data());
fraction += step;
}
dsp.buffer.rdoffset++;
fraction -= 1.0;
}
#endif

View File

@ -1,45 +0,0 @@
#ifdef NALL_DSP_INTERNAL_HPP
struct ResampleCosine : Resampler {
inline void setFrequency();
inline void clear();
inline void sample();
ResampleCosine(DSP &dsp) : Resampler(dsp) {}
real fraction;
real step;
};
void ResampleCosine::setFrequency() {
fraction = 0.0;
step = dsp.settings.frequency / frequency;
}
void ResampleCosine::clear() {
fraction = 0.0;
}
void ResampleCosine::sample() {
while(fraction <= 1.0) {
std::vector<real> channel(dsp.settings.channels);
for(unsigned n = 0; n < dsp.settings.channels; n++) {
real a = dsp.buffer.read(n, -1);
real b = dsp.buffer.read(n, -0);
real mu = fraction;
mu = (1.0 - cos(mu * 3.14159265)) / 2.0;
channel[n] = a * (1.0 - mu) + b * mu;
}
dsp.write(channel.data());
fraction += step;
}
dsp.buffer.rdoffset++;
fraction -= 1.0;
}
#endif

View File

@ -1,50 +0,0 @@
#ifdef NALL_DSP_INTERNAL_HPP
struct ResampleCubic : Resampler {
inline void setFrequency();
inline void clear();
inline void sample();
ResampleCubic(DSP &dsp) : Resampler(dsp) {}
real fraction;
real step;
};
void ResampleCubic::setFrequency() {
fraction = 0.0;
step = dsp.settings.frequency / frequency;
}
void ResampleCubic::clear() {
fraction = 0.0;
}
void ResampleCubic::sample() {
while(fraction <= 1.0) {
std::vector<real> channel(dsp.settings.channels);
for(unsigned n = 0; n < dsp.settings.channels; n++) {
real a = dsp.buffer.read(n, -3);
real b = dsp.buffer.read(n, -2);
real c = dsp.buffer.read(n, -1);
real d = dsp.buffer.read(n, -0);
real mu = fraction;
real A = d - c - a + b;
real B = a - b - A;
real C = c - a;
real D = b;
channel[n] = A * (mu * 3) + B * (mu * 2) + C * mu + D;
}
dsp.write(channel.data());
fraction += step;
}
dsp.buffer.rdoffset++;
fraction -= 1.0;
}
#endif

View File

@ -1,62 +0,0 @@
#ifdef NALL_DSP_INTERNAL_HPP
struct ResampleHermite : Resampler {
inline void setFrequency();
inline void clear();
inline void sample();
ResampleHermite(DSP &dsp) : Resampler(dsp) {}
real fraction;
real step;
};
void ResampleHermite::setFrequency() {
fraction = 0.0;
step = dsp.settings.frequency / frequency;
}
void ResampleHermite::clear() {
fraction = 0.0;
}
void ResampleHermite::sample() {
while(fraction <= 1.0) {
std::vector<real> channel(dsp.settings.channels);
for(unsigned n = 0; n < dsp.settings.channels; n++) {
real a = dsp.buffer.read(n, -3);
real b = dsp.buffer.read(n, -2);
real c = dsp.buffer.read(n, -1);
real d = dsp.buffer.read(n, -0);
const real tension = 0.0; //-1 = low, 0 = normal, +1 = high
const real bias = 0.0; //-1 = left, 0 = even, +1 = right
real mu1, mu2, mu3, m0, m1, a0, a1, a2, a3;
mu1 = fraction;
mu2 = mu1 * mu1;
mu3 = mu2 * mu1;
m0 = (b - a) * (1.0 + bias) * (1.0 - tension) / 2.0;
m0 += (c - b) * (1.0 - bias) * (1.0 - tension) / 2.0;
m1 = (c - b) * (1.0 + bias) * (1.0 - tension) / 2.0;
m1 += (d - c) * (1.0 - bias) * (1.0 - tension) / 2.0;
a0 = +2 * mu3 - 3 * mu2 + 1;
a1 = mu3 - 2 * mu2 + mu1;
a2 = mu3 - mu2;
a3 = -2 * mu3 + 3 * mu2;
channel[n] = (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c);
}
dsp.write(channel.data());
fraction += step;
}
dsp.buffer.rdoffset++;
fraction -= 1.0;
}
#endif

View File

@ -1,602 +0,0 @@
// If these types are changed to anything other than "float", you should comment out the SSE detection directives below
// so that the SSE code is not used.
typedef float resample_coeff_t; // note: sizeof(resample_coeff_t) must be == to a power of 2, and not larger than 16
typedef float resample_samp_t;
#include <string>
#include <vector>
// ...but don't comment this single RESAMPLE_SSEREGPARM define out when disabling SSE.
#define RESAMPLE_SSEREGPARM
#if defined(__SSE__)
#define SINCRESAMPLE_USE_SSE 1
#ifndef __x86_64__
#undef RESAMPLE_SSEREGPARM
#define RESAMPLE_SSEREGPARM __attribute__((sseregparm))
#endif
#else
// TODO: altivec here
#endif
namespace ResampleUtility
{
inline void kaiser_window(double* io, int count, double beta);
inline void gen_sinc(double* out, int size, double cutoff, double kaiser);
inline void gen_sinc_os(double* out, int size, double cutoff, double kaiser);
inline void normalize(double* io, int size, double gain = 1.0);
inline void* make_aligned(void* ptr, unsigned boundary); // boundary must be a power of 2
}
class SincResampleHR
{
private:
inline void Init(unsigned ratio_arg, double desired_bandwidth, double beta, double d);
inline void write(resample_samp_t sample) RESAMPLE_SSEREGPARM;
inline resample_samp_t read(void) RESAMPLE_SSEREGPARM;
inline bool output_avail(void);
private:
inline resample_samp_t mac(const resample_samp_t *wave, const resample_coeff_t *coeff, unsigned count);
unsigned ratio;
unsigned num_convolutions;
resample_coeff_t *coeffs;
std::vector<unsigned char> coeffs_mem;
// second half of ringbuffer should be copy of first half.
resample_samp_t *rb;
std::vector<unsigned char> rb_mem;
signed rb_readpos;
signed rb_writepos;
signed rb_in;
signed rb_eff_size;
friend class SincResample;
};
class SincResample
{
public:
enum
{
QUALITY_LOW = 0,
QUALITY_MEDIUM = 2,
QUALITY_HIGH = 4
};
inline SincResample(double input_rate, double output_rate, double desired_bandwidth, unsigned quality = QUALITY_HIGH);
inline void write(resample_samp_t sample) RESAMPLE_SSEREGPARM;
inline resample_samp_t read(void) RESAMPLE_SSEREGPARM;
inline bool output_avail(void);
private:
inline void Init(double input_rate, double output_rate, double desired_bandwidth, double beta, double d, unsigned pn_nume, unsigned phases_min);
inline resample_samp_t mac(const resample_samp_t *wave, const resample_coeff_t *coeffs_a, const resample_coeff_t *coeffs_b, const double ffract, unsigned count) RESAMPLE_SSEREGPARM;
unsigned num_convolutions;
unsigned num_phases;
unsigned step_int;
double step_fract;
double input_pos_fract;
std::vector<resample_coeff_t *> coeffs; // Pointers into coeff_mem.
std::vector<unsigned char> coeff_mem;
std::vector<resample_samp_t> rb; // second half should be copy of first half.
signed rb_readpos;
signed rb_writepos;
signed rb_in;
bool hr_used;
SincResampleHR hr;
};
//
// Code:
//
//#include "resample.hpp"
#if 0
namespace bit
{
inline unsigned round(unsigned x) {
if((x & (x - 1)) == 0) return x;
while(x & (x - 1)) x &= x - 1;
return x << 1;
}
}
#endif
void SincResampleHR::Init(unsigned ratio_arg, double desired_bandwidth, double beta, double d)
{
const unsigned align_boundary = 16;
std::vector<double> coeffs_tmp;
double cutoff; // 1.0 = f/2
ratio = ratio_arg;
//num_convolutions = ((unsigned)ceil(d / ((1.0 - desired_bandwidth) / ratio)) + 1) &~ 1; // round up to be even
num_convolutions = ((unsigned)ceil(d / ((1.0 - desired_bandwidth) / ratio)) | 1);
cutoff = (1.0 / ratio) - (d / num_convolutions);
//printf("%d %d %.20f\n", ratio, num_convolutions, cutoff);
assert(num_convolutions > ratio);
// Generate windowed sinc of POWER
coeffs_tmp.resize(num_convolutions);
//ResampleUtility::gen_sinc(&coeffs_tmp[0], num_convolutions, cutoff, beta);
ResampleUtility::gen_sinc_os(&coeffs_tmp[0], num_convolutions, cutoff, beta);
ResampleUtility::normalize(&coeffs_tmp[0], num_convolutions);
// Copy from coeffs_tmp to coeffs~
// We multiply many coefficients at a time in the mac loop, so make sure the last few that don't really
// exist are allocated, zero'd mem.
coeffs_mem.resize(((num_convolutions + 7) &~ 7) * sizeof(resample_coeff_t) + (align_boundary - 1));
coeffs = (resample_coeff_t *)ResampleUtility::make_aligned(&coeffs_mem[0], align_boundary);
for(unsigned i = 0; i < num_convolutions; i++)
coeffs[i] = coeffs_tmp[i];
rb_eff_size = nall::bit::round(num_convolutions * 2) >> 1;
rb_readpos = 0;
rb_writepos = 0;
rb_in = 0;
rb_mem.resize(rb_eff_size * 2 * sizeof(resample_samp_t) + (align_boundary - 1));
rb = (resample_samp_t *)ResampleUtility::make_aligned(&rb_mem[0], align_boundary);
}
inline bool SincResampleHR::output_avail(void)
{
return(rb_in >= (signed)num_convolutions);
}
inline void SincResampleHR::write(resample_samp_t sample)
{
assert(!output_avail());
rb[rb_writepos] = sample;
rb[rb_writepos + rb_eff_size] = sample;
rb_writepos = (rb_writepos + 1) & (rb_eff_size - 1);
rb_in++;
}
resample_samp_t SincResampleHR::mac(const resample_samp_t *wave, const resample_coeff_t *coeff, unsigned count)
{
#if SINCRESAMPLE_USE_SSE
__m128 accum_veca[2] = { _mm_set1_ps(0), _mm_set1_ps(0) };
resample_samp_t accum;
for(unsigned c = 0; c < count; c += 8)
{
for(unsigned i = 0; i < 2; i++)
{
__m128 co[2];
__m128 w[2];
co[i] = _mm_load_ps(&coeff[c + i * 4]);
w[i] = _mm_load_ps(&wave[c + i * 4]);
w[i] = _mm_mul_ps(w[i], co[i]);
accum_veca[i] = _mm_add_ps(w[i], accum_veca[i]);
}
}
__m128 accum_vec = _mm_add_ps(accum_veca[0], accum_veca[1]); //_mm_add_ps(_mm_add_ps(accum_veca[0], accum_veca[1]), _mm_add_ps(accum_veca[2], accum_veca[3]));
accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6)));
accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (1 << 0) | (0 << 2) | (1 << 4) | (0 << 6)));
_mm_store_ss(&accum, accum_vec);
return accum;
#else
resample_samp_t accum[4] = { 0, 0, 0, 0 };
for(unsigned c = 0; c < count; c+= 4)
{
accum[0] += wave[c + 0] * coeff[c + 0];
accum[1] += wave[c + 1] * coeff[c + 1];
accum[2] += wave[c + 2] * coeff[c + 2];
accum[3] += wave[c + 3] * coeff[c + 3];
}
return (accum[0] + accum[1]) + (accum[2] + accum[3]); // don't mess with parentheses(assuming compiler doesn't already, which it may...
#endif
}
resample_samp_t SincResampleHR::read(void)
{
assert(output_avail());
resample_samp_t ret;
ret = mac(&rb[rb_readpos], &coeffs[0], num_convolutions);
rb_readpos = (rb_readpos + ratio) & (rb_eff_size - 1);
rb_in -= ratio;
return ret;
}
SincResample::SincResample(double input_rate, double output_rate, double desired_bandwidth, unsigned quality)
{
const struct
{
double beta;
double d;
unsigned pn_nume;
unsigned phases_min;
} qtab[5] =
{
{ 5.658, 3.62, 4096, 4 },
{ 6.764, 4.32, 8192, 4 },
{ 7.865, 5.0, 16384, 8 },
{ 8.960, 5.7, 32768, 16 },
{ 10.056, 6.4, 65536, 32 }
};
// Sanity checks
assert(ceil(input_rate) > 0);
assert(ceil(output_rate) > 0);
assert(ceil(input_rate / output_rate) <= 1024);
assert(ceil(output_rate / input_rate) <= 1024);
// The simplistic number-of-phases calculation code doesn't work well enough for when desired_bandwidth is close to 1.0 and when
// upsampling.
assert(desired_bandwidth >= 0.25 && desired_bandwidth < 0.96);
assert(quality >= 0 && quality <= 4);
hr_used = false;
#if 1
// Round down to the nearest multiple of 4(so wave buffer remains aligned)
// It also adjusts the effective intermediate sampling rate up slightly, so that the upper frequencies below f/2
// aren't overly attenuated so much. In the future, we might want to do an FFT or something to choose the intermediate rate more accurately
// to virtually eliminate over-attenuation.
unsigned ioratio_rd = (unsigned)floor(input_rate / (output_rate * (1.0 + (1.0 - desired_bandwidth) / 2) )) & ~3;
if(ioratio_rd >= 8)
{
hr.Init(ioratio_rd, desired_bandwidth, qtab[quality].beta, qtab[quality].d); //10.056, 6.4);
hr_used = true;
input_rate /= ioratio_rd;
}
#endif
Init(input_rate, output_rate, desired_bandwidth, qtab[quality].beta, qtab[quality].d, qtab[quality].pn_nume, qtab[quality].phases_min);
}
void SincResample::Init(double input_rate, double output_rate, double desired_bandwidth, double beta, double d, unsigned pn_nume, unsigned phases_min)
{
const unsigned max_mult_atatime = 8; // multiply "granularity". must be power of 2.
const unsigned max_mult_minus1 = (max_mult_atatime - 1);
const unsigned conv_alignment_bytes = 16; // must be power of 2
const double input_to_output_ratio = input_rate / output_rate;
const double output_to_input_ratio = output_rate / input_rate;
double cutoff; // 1.0 = input_rate / 2
std::vector<double> coeff_init_buffer;
// Round up num_convolutions to be even.
if(output_rate > input_rate)
num_convolutions = ((unsigned)ceil(d / (1.0 - desired_bandwidth)) + 1) & ~1;
else
num_convolutions = ((unsigned)ceil(d / (output_to_input_ratio * (1.0 - desired_bandwidth))) + 1) & ~1;
if(output_rate > input_rate) // Upsampling
cutoff = desired_bandwidth;
else // Downsampling
cutoff = output_to_input_ratio * desired_bandwidth;
// Round up to be even.
num_phases = (std::max<unsigned>(pn_nume / num_convolutions, phases_min) + 1) &~1;
// Adjust cutoff to account for the multiple phases.
cutoff = cutoff / num_phases;
assert((num_convolutions & 1) == 0);
assert((num_phases & 1) == 0);
// fprintf(stderr, "num_convolutions=%u, num_phases=%u, total expected coeff byte size=%lu\n", num_convolutions, num_phases,
// (long)((num_phases + 2) * ((num_convolutions + max_mult_minus1) & ~max_mult_minus1) * sizeof(float) + conv_alignment_bytes));
coeff_init_buffer.resize(num_phases * num_convolutions);
coeffs.resize(num_phases + 1 + 1);
coeff_mem.resize((num_phases + 1 + 1) * ((num_convolutions + max_mult_minus1) &~ max_mult_minus1) * sizeof(resample_coeff_t) + conv_alignment_bytes);
// Assign aligned pointers into coeff_mem
{
resample_coeff_t *base_ptr = (resample_coeff_t *)ResampleUtility::make_aligned(&coeff_mem[0], conv_alignment_bytes);
for(unsigned phase = 0; phase < (num_phases + 1 + 1); phase++)
{
coeffs[phase] = base_ptr + (((num_convolutions + max_mult_minus1) & ~max_mult_minus1) * phase);
}
}
ResampleUtility::gen_sinc(&coeff_init_buffer[0], num_phases * num_convolutions, cutoff, beta);
ResampleUtility::normalize(&coeff_init_buffer[0], num_phases * num_convolutions, num_phases);
// Reorder coefficients to allow for more efficient convolution.
for(int phase = -1; phase < ((int)num_phases + 1); phase++)
{
for(int conv = 0; conv < (int)num_convolutions; conv++)
{
double coeff;
if(phase == -1 && conv == 0)
coeff = 0;
else if(phase == (int)num_phases && conv == ((int)num_convolutions - 1))
coeff = 0;
else
coeff = coeff_init_buffer[conv * num_phases + phase];
coeffs[phase + 1][conv] = coeff;
}
}
// Free a bit of mem
coeff_init_buffer.resize(0);
step_int = floor(input_to_output_ratio);
step_fract = input_to_output_ratio - step_int;
input_pos_fract = 0;
// Do NOT use rb.size() later in the code, since it'll include the padding.
// We should only need one "max_mult_minus1" here, not two, since it won't matter if it over-reads(due to doing "max_mult_atatime" multiplications at a time
// rather than just 1, in which case this over-read wouldn't happen), from the first half into the duplicated half,
// since those corresponding coefficients will be zero anyway; this is just to handle the case of reading off the end of the duplicated half to
// prevent illegal memory accesses.
rb.resize(num_convolutions * 2 + max_mult_minus1);
rb_readpos = 0;
rb_writepos = 0;
rb_in = 0;
}
resample_samp_t SincResample::mac(const resample_samp_t *wave, const resample_coeff_t *coeffs_a, const resample_coeff_t *coeffs_b, const double ffract, unsigned count)
{
resample_samp_t accum = 0;
#if SINCRESAMPLE_USE_SSE
__m128 accum_vec_a[2] = { _mm_set1_ps(0), _mm_set1_ps(0) };
__m128 accum_vec_b[2] = { _mm_set1_ps(0), _mm_set1_ps(0) };
for(unsigned c = 0; c < count; c += 8) //8) //4)
{
__m128 coeff_a[2];
__m128 coeff_b[2];
__m128 w[2];
__m128 result_a[2], result_b[2];
for(unsigned i = 0; i < 2; i++)
{
coeff_a[i] = _mm_load_ps(&coeffs_a[c + (i * 4)]);
coeff_b[i] = _mm_load_ps(&coeffs_b[c + (i * 4)]);
w[i] = _mm_loadu_ps(&wave[c + (i * 4)]);
result_a[i] = _mm_mul_ps(coeff_a[i], w[i]);
result_b[i] = _mm_mul_ps(coeff_b[i], w[i]);
accum_vec_a[i] = _mm_add_ps(result_a[i], accum_vec_a[i]);
accum_vec_b[i] = _mm_add_ps(result_b[i], accum_vec_b[i]);
}
}
__m128 accum_vec, av_a, av_b;
__m128 mult_a_vec = _mm_set1_ps(1.0 - ffract);
__m128 mult_b_vec = _mm_set1_ps(ffract);
av_a = _mm_mul_ps(mult_a_vec, /*accum_vec_a[0]);*/ _mm_add_ps(accum_vec_a[0], accum_vec_a[1]));
av_b = _mm_mul_ps(mult_b_vec, /*accum_vec_b[0]);*/ _mm_add_ps(accum_vec_b[0], accum_vec_b[1]));
accum_vec = _mm_add_ps(av_a, av_b);
accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6)));
accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (1 << 0) | (0 << 2) | (1 << 4) | (0 << 6)));
_mm_store_ss(&accum, accum_vec);
#else
resample_coeff_t mult_a = 1.0 - ffract;
resample_coeff_t mult_b = ffract;
for(unsigned c = 0; c < count; c += 4)
{
accum += wave[c + 0] * (coeffs_a[c + 0] * mult_a + coeffs_b[c + 0] * mult_b);
accum += wave[c + 1] * (coeffs_a[c + 1] * mult_a + coeffs_b[c + 1] * mult_b);
accum += wave[c + 2] * (coeffs_a[c + 2] * mult_a + coeffs_b[c + 2] * mult_b);
accum += wave[c + 3] * (coeffs_a[c + 3] * mult_a + coeffs_b[c + 3] * mult_b);
}
#endif
return accum;
}
inline bool SincResample::output_avail(void)
{
return(rb_in >= (int)num_convolutions);
}
resample_samp_t SincResample::read(void)
{
assert(output_avail());
double phase = input_pos_fract * num_phases - 0.5;
signed phase_int = (signed)floor(phase);
double phase_fract = phase - phase_int;
unsigned phase_a = num_phases - 1 - phase_int;
unsigned phase_b = phase_a - 1;
resample_samp_t ret;
ret = mac(&rb[rb_readpos], &coeffs[phase_a + 1][0], &coeffs[phase_b + 1][0], phase_fract, num_convolutions);
unsigned int_increment = step_int;
input_pos_fract += step_fract;
int_increment += floor(input_pos_fract);
input_pos_fract -= floor(input_pos_fract);
rb_readpos = (rb_readpos + int_increment) % num_convolutions;
rb_in -= int_increment;
return ret;
}
inline void SincResample::write(resample_samp_t sample)
{
assert(!output_avail());
if(hr_used)
{
hr.write(sample);
if(hr.output_avail())
{
sample = hr.read();
}
else
{
return;
}
}
rb[rb_writepos + 0 * num_convolutions] = sample;
rb[rb_writepos + 1 * num_convolutions] = sample;
rb_writepos = (rb_writepos + 1) % num_convolutions;
rb_in++;
}
void ResampleUtility::kaiser_window( double* io, int count, double beta)
{
int const accuracy = 24; //16; //12;
double* end = io + count;
double beta2 = beta * beta * (double) -0.25;
double to_fract = beta2 / ((double) count * count);
double i = 0;
double rescale = 0; // Doesn't need an initializer, to shut up gcc
for ( ; io < end; ++io, i += 1 )
{
double x = i * i * to_fract - beta2;
double u = x;
double k = x + 1;
double n = 2;
do
{
u *= x / (n * n);
n += 1;
k += u;
}
while ( k <= u * (1 << accuracy) );
if ( !i )
rescale = 1 / k; // otherwise values get large
*io *= k * rescale;
}
}
void ResampleUtility::gen_sinc(double* out, int size, double cutoff, double kaiser)
{
assert( size % 2 == 0 ); // size must be even
int const half_size = size / 2;
double* const mid = &out [half_size];
// Generate right half of sinc
for ( int i = 0; i < half_size; i++ )
{
double angle = (i * 2 + 1) * (M_PI / 2);
mid [i] = sin( angle * cutoff ) / angle;
}
kaiser_window( mid, half_size, kaiser );
// Mirror for left half
for ( int i = 0; i < half_size; i++ )
out [i] = mid [half_size - 1 - i];
}
void ResampleUtility::gen_sinc_os(double* out, int size, double cutoff, double kaiser)
{
assert( size % 2 == 1); // size must be odd
for(int i = 0; i < size; i++)
{
if(i == (size / 2))
out[i] = 2 * M_PI * (cutoff / 2); //0.078478; //1.0; //sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2));
else
out[i] = sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2));
// out[i] *= 0.3635819 - 0.4891775 * cos(2 * M_PI * i / (size - 1)) + 0.1365995 * cos(4 * M_PI * i / (size - 1)) - 0.0106411 * cos(6 * M_PI * i / (size - 1));
//0.42 - 0.5 * cos(2 * M_PI * i / (size - 1)) + 0.08 * cos(4 * M_PI * i / (size - 1));
// printf("%d %f\n", i, out[i]);
}
kaiser_window(&out[size / 2], size / 2 + 1, kaiser);
// Mirror for left half
for ( int i = 0; i < size / 2; i++ )
out [i] = out [size - 1 - i];
}
void ResampleUtility::normalize(double* io, int size, double gain)
{
double sum = 0;
for ( int i = 0; i < size; i++ )
sum += io [i];
double scale = gain / sum;
for ( int i = 0; i < size; i++ )
io [i] *= scale;
}
void* ResampleUtility::make_aligned(void* ptr, unsigned boundary)
{
unsigned char* null_ptr = (unsigned char *)NULL;
unsigned char* uc_ptr = (unsigned char *)ptr;
uc_ptr += (boundary - ((uc_ptr - null_ptr) & (boundary - 1))) & (boundary - 1);
//while((uc_ptr - null_ptr) & (boundary - 1))
// uc_ptr++;
//printf("%16llx %16llx\n", (unsigned long long)ptr, (unsigned long long)uc_ptr);
assert((uc_ptr - (unsigned char *)ptr) < boundary && (uc_ptr >= (unsigned char *)ptr));
return uc_ptr;
}

View File

@ -1,43 +0,0 @@
#ifdef NALL_DSP_INTERNAL_HPP
struct ResampleLinear : Resampler {
inline void setFrequency();
inline void clear();
inline void sample();
ResampleLinear(DSP &dsp) : Resampler(dsp) {}
real fraction;
real step;
};
void ResampleLinear::setFrequency() {
fraction = 0.0;
step = dsp.settings.frequency / frequency;
}
void ResampleLinear::clear() {
fraction = 0.0;
}
void ResampleLinear::sample() {
while(fraction <= 1.0) {
std::vector<real> channel(dsp.settings.channels);
for(unsigned n = 0; n < dsp.settings.channels; n++) {
real a = dsp.buffer.read(n, -1);
real b = dsp.buffer.read(n, -0);
real mu = fraction;
channel[n] = a * (1.0 - mu) + b * mu;
}
dsp.write(channel.data());
fraction += step;
}
dsp.buffer.rdoffset++;
fraction -= 1.0;
}
#endif

View File

@ -1,43 +0,0 @@
#ifdef NALL_DSP_INTERNAL_HPP
struct ResampleNearest : Resampler {
inline void setFrequency();
inline void clear();
inline void sample();
ResampleNearest(DSP &dsp) : Resampler(dsp) {}
real fraction;
real step;
};
void ResampleNearest::setFrequency() {
fraction = 0.0;
step = dsp.settings.frequency / frequency;
}
void ResampleNearest::clear() {
fraction = 0.0;
}
void ResampleNearest::sample() {
while(fraction <= 1.0) {
std::vector<real> channel(dsp.settings.channels);
for(unsigned n = 0; n < dsp.settings.channels; n++) {
real a = dsp.buffer.read(n, -1);
real b = dsp.buffer.read(n, -0);
real mu = fraction;
channel[n] = mu < 0.5 ? a : b;
}
dsp.write(channel.data());
fraction += step;
}
dsp.buffer.rdoffset++;
fraction -= 1.0;
}
#endif

View File

@ -1,54 +0,0 @@
#ifdef NALL_DSP_INTERNAL_HPP
#include "lib/sinc.hpp"
struct ResampleSinc : Resampler {
inline void setFrequency();
inline void clear();
inline void sample();
inline ResampleSinc(DSP &dsp);
private:
inline void remakeSinc();
SincResample *sinc_resampler[8];
};
void ResampleSinc::setFrequency() {
remakeSinc();
}
void ResampleSinc::clear() {
remakeSinc();
}
void ResampleSinc::sample() {
for(unsigned c = 0; c < dsp.settings.channels; c++) {
sinc_resampler[c]->write(dsp.buffer.read(c));
}
if(sinc_resampler[0]->output_avail()) {
do {
for(unsigned c = 0; c < dsp.settings.channels; c++) {
dsp.output.write(c) = sinc_resampler[c]->read();
}
dsp.output.wroffset++;
} while(sinc_resampler[0]->output_avail());
}
dsp.buffer.rdoffset++;
}
ResampleSinc::ResampleSinc(DSP &dsp) : Resampler(dsp) {
for(unsigned n = 0; n < 8; n++) sinc_resampler[n] = 0;
}
void ResampleSinc::remakeSinc() {
assert(dsp.settings.channels < 8);
for(unsigned c = 0; c < dsp.settings.channels; c++) {
if(sinc_resampler[c]) delete sinc_resampler[c];
sinc_resampler[c] = new SincResample(dsp.settings.frequency, frequency, 0.85, SincResample::QUALITY_HIGH);
}
}
#endif

View File

@ -1,50 +0,0 @@
#ifdef NALL_DSP_INTERNAL_HPP
void DSP::setChannels(unsigned channels) {
assert(channels > 0);
buffer.setChannels(channels);
output.setChannels(channels);
settings.channels = channels;
}
void DSP::setPrecision(unsigned precision) {
settings.precision = precision;
settings.intensity = 1 << (settings.precision - 1);
settings.intensityInverse = 1.0 / settings.intensity;
}
void DSP::setFrequency(real frequency) {
settings.frequency = frequency;
resampler->setFrequency();
}
void DSP::setVolume(real volume) {
settings.volume = volume;
}
void DSP::setBalance(real balance) {
settings.balance = balance;
}
void DSP::setResampler(ResampleEngine engine) {
if(resampler) delete resampler;
switch(engine) {
case ResampleEngine::Nearest: resampler = new ResampleNearest(*this); return;
case ResampleEngine::Linear: resampler = new ResampleLinear (*this); return;
case ResampleEngine::Cosine: resampler = new ResampleCosine (*this); return;
case ResampleEngine::Cubic: resampler = new ResampleCubic (*this); return;
case ResampleEngine::Hermite: resampler = new ResampleHermite(*this); return;
case ResampleEngine::Average: resampler = new ResampleAverage(*this); return;
case ResampleEngine::Sinc: resampler = new ResampleSinc (*this); return;
}
throw;
}
void DSP::setResamplerFrequency(real frequency) {
resampler->frequency = frequency;
resampler->setFrequency();
}
#endif

View File

@ -1,42 +0,0 @@
#ifndef NALL_ENDIAN_HPP
#define NALL_ENDIAN_HPP
#include <nall/intrinsics.hpp>
#if defined(ENDIAN_LSB)
//little-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x04030201
#define order_lsb2(a,b) a,b
#define order_lsb3(a,b,c) a,b,c
#define order_lsb4(a,b,c,d) a,b,c,d
#define order_lsb5(a,b,c,d,e) a,b,c,d,e
#define order_lsb6(a,b,c,d,e,f) a,b,c,d,e,f
#define order_lsb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g
#define order_lsb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h
#define order_msb2(a,b) b,a
#define order_msb3(a,b,c) c,b,a
#define order_msb4(a,b,c,d) d,c,b,a
#define order_msb5(a,b,c,d,e) e,d,c,b,a
#define order_msb6(a,b,c,d,e,f) f,e,d,c,b,a
#define order_msb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a
#define order_msb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a
#elif defined(ENDIAN_MSB)
//big-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x01020304
#define order_lsb2(a,b) b,a
#define order_lsb3(a,b,c) c,b,a
#define order_lsb4(a,b,c,d) d,c,b,a
#define order_lsb5(a,b,c,d,e) e,d,c,b,a
#define order_lsb6(a,b,c,d,e,f) f,e,d,c,b,a
#define order_lsb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a
#define order_lsb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a
#define order_msb2(a,b) a,b
#define order_msb3(a,b,c) a,b,c
#define order_msb4(a,b,c,d) a,b,c,d
#define order_msb5(a,b,c,d,e) a,b,c,d,e
#define order_msb6(a,b,c,d,e,f) a,b,c,d,e,f
#define order_msb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g
#define order_msb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h
#else
#error "Unknown endian. Please specify in nall/intrinsics.hpp"
#endif
#endif

View File

@ -1,291 +0,0 @@
#ifndef NALL_FILE_HPP
#define NALL_FILE_HPP
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#include <nall/windows/utf8.hpp>
namespace nall {
inline FILE* fopen_utf8(const string &utf8_filename, const char *mode) {
#if !defined(_WIN32)
return fopen(utf8_filename, mode);
#else
return _wfopen(utf16_t(utf8_filename), utf16_t(mode));
#endif
}
class file {
public:
enum class mode : unsigned { read, write, readwrite, writeread };
enum class index : unsigned { absolute, relative };
enum class time : unsigned { create, modify, access };
static bool read(const string &filename, uint8_t *&data, unsigned &size) {
data = 0;
file fp;
if(fp.open(filename, mode::read) == false) return false;
size = fp.size();
data = new uint8_t[size];
fp.read(data, size);
fp.close();
return true;
}
static bool read(const string &filename, const uint8_t *&data, unsigned &size) {
return file::read(filename, (uint8_t*&)data, size);
}
static bool write(const string &filename, const uint8_t *data, unsigned size) {
file fp;
if(fp.open(filename, mode::write) == false) return false;
fp.write(data, size);
fp.close();
return true;
}
uint8_t read() {
if(!fp) return 0xff; //file not open
if(file_mode == mode::write) return 0xff; //reads not permitted
if(file_offset >= file_size) return 0xff; //cannot read past end of file
buffer_sync();
return buffer[(file_offset++) & buffer_mask];
}
uintmax_t readl(unsigned length = 1) {
uintmax_t data = 0;
for(int i = 0; i < length; i++) {
data |= (uintmax_t)read() << (i << 3);
}
return data;
}
uintmax_t readm(unsigned length = 1) {
uintmax_t data = 0;
while(length--) {
data <<= 8;
data |= read();
}
return data;
}
void read(uint8_t *buffer, unsigned length) {
while(length--) *buffer++ = read();
}
void write(uint8_t data) {
if(!fp) return; //file not open
if(file_mode == mode::read) return; //writes not permitted
buffer_sync();
buffer[(file_offset++) & buffer_mask] = data;
buffer_dirty = true;
if(file_offset > file_size) file_size = file_offset;
}
void writel(uintmax_t data, unsigned length = 1) {
while(length--) {
write(data);
data >>= 8;
}
}
void writem(uintmax_t data, unsigned length = 1) {
for(int i = length - 1; i >= 0; i--) {
write(data >> (i << 3));
}
}
void write(const uint8_t *buffer, unsigned length) {
while(length--) write(*buffer++);
}
template<typename... Args> void print(Args... args) {
string data(args...);
const char *p = data;
while(*p) write(*p++);
}
void flush() {
buffer_flush();
fflush(fp);
}
void seek(int offset, index index_ = index::absolute) {
if(!fp) return; //file not open
buffer_flush();
uintmax_t req_offset = file_offset;
switch(index_) {
case index::absolute: req_offset = offset; break;
case index::relative: req_offset += offset; break;
}
if(req_offset < 0) req_offset = 0; //cannot seek before start of file
if(req_offset > file_size) {
if(file_mode == mode::read) { //cannot seek past end of file
req_offset = file_size;
} else { //pad file to requested location
file_offset = file_size;
while(file_size < req_offset) write(0x00);
}
}
file_offset = req_offset;
}
int offset() const {
if(!fp) return -1; //file not open
return file_offset;
}
int size() const {
if(!fp) return -1; //file not open
return file_size;
}
bool truncate(unsigned size) {
if(!fp) return false; //file not open
#if !defined(_WIN32)
return ftruncate(fileno(fp), size) == 0;
#else
return _chsize(fileno(fp), size) == 0;
#endif
}
bool end() {
if(!fp) return true; //file not open
return file_offset >= file_size;
}
static bool exists(const string &filename) {
#if !defined(_WIN32)
struct stat64 data;
return stat64(filename, &data) == 0;
#else
struct __stat64 data;
return _wstat64(utf16_t(filename), &data) == 0;
#endif
}
static uintmax_t size(const string &filename) {
#if !defined(_WIN32)
struct stat64 data;
stat64(filename, &data);
#else
struct __stat64 data;
_wstat64(utf16_t(filename), &data);
#endif
//not readily possible in msvc; not needed in bizhawk
#ifdef BIZHAWK
return data.st_size;
#else
return S_ISREG(data.st_mode) ? data.st_size : 0u; //TEST
#endif
}
static time_t timestamp(const string &filename, file::time mode = file::time::create) {
#if !defined(_WIN32)
struct stat64 data;
stat64(filename, &data);
#else
struct __stat64 data;
_wstat64(utf16_t(filename), &data);
#endif
switch(mode) { default:
case file::time::create: return data.st_ctime;
case file::time::modify: return data.st_mtime;
case file::time::access: return data.st_atime;
}
}
bool open() const {
return fp;
}
bool open(const string &filename, mode mode_) {
if(fp) return false;
switch(file_mode = mode_) {
#if !defined(_WIN32)
case mode::read: fp = fopen(filename, "rb" ); break;
case mode::write: fp = fopen(filename, "wb+"); break; //need read permission for buffering
case mode::readwrite: fp = fopen(filename, "rb+"); break;
case mode::writeread: fp = fopen(filename, "wb+"); break;
#else
case mode::read: fp = _wfopen(utf16_t(filename), L"rb" ); break;
case mode::write: fp = _wfopen(utf16_t(filename), L"wb+"); break;
case mode::readwrite: fp = _wfopen(utf16_t(filename), L"rb+"); break;
case mode::writeread: fp = _wfopen(utf16_t(filename), L"wb+"); break;
#endif
}
if(!fp) return false;
buffer_offset = -1; //invalidate buffer
file_offset = 0;
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
return true;
}
void close() {
if(!fp) return;
buffer_flush();
fclose(fp);
fp = 0;
}
file() {
memset(buffer, 0, sizeof buffer);
buffer_offset = -1;
buffer_dirty = false;
fp = 0;
file_offset = 0;
file_size = 0;
file_mode = mode::read;
}
~file() {
close();
}
file& operator=(const file&) = delete;
file(const file&) = delete;
private:
enum { buffer_size = 1 << 12, buffer_mask = buffer_size - 1 };
char buffer[buffer_size];
int buffer_offset;
bool buffer_dirty;
FILE *fp;
unsigned file_offset;
unsigned file_size;
mode file_mode;
void buffer_sync() {
if(!fp) return; //file not open
if(buffer_offset != (file_offset & ~buffer_mask)) {
buffer_flush();
buffer_offset = file_offset & ~buffer_mask;
fseek(fp, buffer_offset, SEEK_SET);
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
if(length) unsigned unused = fread(buffer, 1, length, fp);
}
}
void buffer_flush() {
if(!fp) return; //file not open
if(file_mode == mode::read) return; //buffer cannot be written to
if(buffer_offset < 0) return; //buffer unused
if(buffer_dirty == false) return; //buffer unmodified since read
fseek(fp, buffer_offset, SEEK_SET);
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
if(length) unsigned unused = fwrite(buffer, 1, length, fp);
buffer_offset = -1; //invalidate buffer
buffer_dirty = false;
}
};
}
#endif

View File

@ -1,213 +0,0 @@
#ifndef NALL_FILEMAP_HPP
#define NALL_FILEMAP_HPP
#include <nall/file.hpp>
#include <nall/stdint.hpp>
#include <nall/windows/utf8.hpp>
#include <stdio.h>
#include <stdlib.h>
#if defined(_WIN32)
#include <windows.h>
#else
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif
namespace nall {
class filemap {
public:
enum class mode : unsigned { read, write, readwrite, writeread };
bool open() const { return p_open(); }
bool open(const char *filename, mode mode_) { return p_open(filename, mode_); }
void close() { return p_close(); }
unsigned size() const { return p_size; }
uint8_t* data() { return p_handle; }
const uint8_t* data() const { return p_handle; }
filemap() : p_size(0), p_handle(0) { p_ctor(); }
filemap(const char *filename, mode mode_) : p_size(0), p_handle(0) { p_ctor(); p_open(filename, mode_); }
~filemap() { p_dtor(); }
private:
unsigned p_size;
uint8_t *p_handle;
#if defined(_WIN32)
//=============
//MapViewOfFile
//=============
HANDLE p_filehandle, p_maphandle;
bool p_open() const {
return p_handle;
}
bool p_open(const char *filename, mode mode_) {
if(file::exists(filename) && file::size(filename) == 0) {
p_handle = 0;
p_size = 0;
return true;
}
int desired_access, creation_disposition, flprotect, map_access;
switch(mode_) {
default: return false;
case mode::read:
desired_access = GENERIC_READ;
creation_disposition = OPEN_EXISTING;
flprotect = PAGE_READONLY;
map_access = FILE_MAP_READ;
break;
case mode::write:
//write access requires read access
desired_access = GENERIC_WRITE;
creation_disposition = CREATE_ALWAYS;
flprotect = PAGE_READWRITE;
map_access = FILE_MAP_ALL_ACCESS;
break;
case mode::readwrite:
desired_access = GENERIC_READ | GENERIC_WRITE;
creation_disposition = OPEN_EXISTING;
flprotect = PAGE_READWRITE;
map_access = FILE_MAP_ALL_ACCESS;
break;
case mode::writeread:
desired_access = GENERIC_READ | GENERIC_WRITE;
creation_disposition = CREATE_NEW;
flprotect = PAGE_READWRITE;
map_access = FILE_MAP_ALL_ACCESS;
break;
}
p_filehandle = CreateFileW(utf16_t(filename), desired_access, FILE_SHARE_READ, NULL,
creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL);
if(p_filehandle == INVALID_HANDLE_VALUE) return false;
p_size = GetFileSize(p_filehandle, NULL);
p_maphandle = CreateFileMapping(p_filehandle, NULL, flprotect, 0, p_size, NULL);
if(p_maphandle == INVALID_HANDLE_VALUE) {
CloseHandle(p_filehandle);
p_filehandle = INVALID_HANDLE_VALUE;
return false;
}
p_handle = (uint8_t*)MapViewOfFile(p_maphandle, map_access, 0, 0, p_size);
return p_handle;
}
void p_close() {
if(p_handle) {
UnmapViewOfFile(p_handle);
p_handle = 0;
}
if(p_maphandle != INVALID_HANDLE_VALUE) {
CloseHandle(p_maphandle);
p_maphandle = INVALID_HANDLE_VALUE;
}
if(p_filehandle != INVALID_HANDLE_VALUE) {
CloseHandle(p_filehandle);
p_filehandle = INVALID_HANDLE_VALUE;
}
}
void p_ctor() {
p_filehandle = INVALID_HANDLE_VALUE;
p_maphandle = INVALID_HANDLE_VALUE;
}
void p_dtor() {
close();
}
#else
//====
//mmap
//====
int p_fd;
bool p_open() const {
return p_handle;
}
bool p_open(const char *filename, mode mode_) {
if(file::exists(filename) && file::size(filename) == 0) {
p_handle = 0;
p_size = 0;
return true;
}
int open_flags, mmap_flags;
switch(mode_) {
default: return false;
case mode::read:
open_flags = O_RDONLY;
mmap_flags = PROT_READ;
break;
case mode::write:
open_flags = O_RDWR | O_CREAT; //mmap() requires read access
mmap_flags = PROT_WRITE;
break;
case mode::readwrite:
open_flags = O_RDWR;
mmap_flags = PROT_READ | PROT_WRITE;
break;
case mode::writeread:
open_flags = O_RDWR | O_CREAT;
mmap_flags = PROT_READ | PROT_WRITE;
break;
}
p_fd = ::open(filename, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if(p_fd < 0) return false;
struct stat p_stat;
fstat(p_fd, &p_stat);
p_size = p_stat.st_size;
p_handle = (uint8_t*)mmap(0, p_size, mmap_flags, MAP_SHARED, p_fd, 0);
if(p_handle == MAP_FAILED) {
p_handle = 0;
::close(p_fd);
p_fd = -1;
return false;
}
return p_handle;
}
void p_close() {
if(p_handle) {
munmap(p_handle, p_size);
p_handle = 0;
}
if(p_fd >= 0) {
::close(p_fd);
p_fd = -1;
}
}
void p_ctor() {
p_fd = -1;
}
void p_dtor() {
p_close();
}
#endif
};
}
#endif

View File

@ -1,60 +0,0 @@
#ifndef NALL_FUNCTION_HPP
#define NALL_FUNCTION_HPP
namespace nall {
template<typename T> class function;
template<typename R, typename... P> class function<R (P...)> {
struct container {
virtual R operator()(P... p) const = 0;
virtual container* copy() const = 0;
virtual ~container() {}
} *callback;
struct global : container {
R (*function)(P...);
R operator()(P... p) const { return function(std::forward<P>(p)...); }
container* copy() const { return new global(function); }
global(R (*function)(P...)) : function(function) {}
};
template<typename C> struct member : container {
R (C::*function)(P...);
C *object;
R operator()(P... p) const { return (object->*function)(std::forward<P>(p)...); }
container* copy() const { return new member(function, object); }
member(R (C::*function)(P...), C *object) : function(function), object(object) {}
};
template<typename L> struct lambda : container {
mutable L object;
R operator()(P... p) const { return object(std::forward<P>(p)...); }
container* copy() const { return new lambda(object); }
lambda(const L& object) : object(object) {}
};
public:
operator bool() const { return callback; }
R operator()(P... p) const { return (*callback)(std::forward<P>(p)...); }
void reset() { if(callback) { delete callback; callback = nullptr; } }
function& operator=(const function &source) {
if(this != &source) {
if(callback) { delete callback; callback = nullptr; }
if(source.callback) callback = source.callback->copy();
}
return *this;
}
function(const function &source) : callback(nullptr) { operator=(source); }
function() : callback(nullptr) {}
function(void *function) : callback(nullptr) { if(function) callback = new global((R (*)(P...))function); }
function(R (*function)(P...)) { callback = new global(function); }
template<typename C> function(R (C::*function)(P...), C *object) { callback = new member<C>(function, object); }
template<typename C> function(R (C::*function)(P...) const, C *object) { callback = new member<C>((R (C::*)(P...))function, object); }
template<typename L> function(const L& object) { callback = new lambda<L>(object); }
~function() { if(callback) delete callback; }
};
}
#endif

Some files were not shown because too many files have changed in this diff Show More