Remove (old) BSNES' unmanaged source and the binary
This commit is contained in:
parent
3cc3440f22
commit
86ea977dd7
|
@ -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.
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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();
|
||||
};
|
|
@ -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
|
|
@ -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();
|
||||
};
|
|
@ -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
|
|
@ -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();
|
||||
};
|
|
@ -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
|
|
@ -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();
|
||||
};
|
|
@ -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
|
|
@ -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();
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -1,5 +0,0 @@
|
|||
struct MBC0 : MMIO {
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
} mbc0;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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);
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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);
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
|
@ -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
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
unsigned vram_addr(uint16 addr) const;
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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 },
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
Loading…
Reference in New Issue