mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-22 23:41:44 +02:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c074c6e064 | ||
|
50420e3dd2 | ||
|
b08449215a | ||
|
9b452c9f5f | ||
|
3681961ca5 | ||
|
20ac95ee49 | ||
|
fdc41611cf | ||
|
839813d0f1 | ||
|
7f3cfa17b9 | ||
|
ae5d380d06 | ||
|
3ebc77c148 | ||
|
6ae0abe3d3 | ||
|
0955295475 | ||
|
7cdae5195a | ||
|
e2ee6689a0 | ||
|
55e507d5df | ||
|
a2d3b8ba15 | ||
|
1929ad47d2 | ||
|
7403e69307 | ||
|
19e1d89f00 | ||
|
aff00506c5 |
@@ -2,11 +2,10 @@ include ../nall/GNUmakefile
|
||||
|
||||
target := tomoko
|
||||
# target := loki
|
||||
profile := accuracy
|
||||
# console := true
|
||||
|
||||
flags += -I. -I.. -O3
|
||||
objects := libco
|
||||
objects := libco audio video resource
|
||||
|
||||
# profile-guided optimization mode
|
||||
# pgo := instrument
|
||||
@@ -54,6 +53,11 @@ compile = \
|
||||
|
||||
all: build;
|
||||
|
||||
obj/libco.o: ../libco/libco.c $(call rwildcard,../libco/)
|
||||
obj/audio.o: audio/audio.cpp $(call rwildcard,audio/)
|
||||
obj/video.o: video/video.cpp $(call rwildcard,video/)
|
||||
obj/resource.o: resource/resource.cpp $(call rwildcard,resource/)
|
||||
|
||||
ui := target-$(target)
|
||||
include $(ui)/GNUmakefile
|
||||
|
||||
|
90
higan/audio/audio.cpp
Normal file
90
higan/audio/audio.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
#include "stream.cpp"
|
||||
Audio audio;
|
||||
|
||||
auto Audio::reset(maybe<uint> channels_, maybe<double> frequency_) -> void {
|
||||
if(channels_) channels = channels_();
|
||||
if(frequency_) frequency = frequency_();
|
||||
|
||||
streams.reset();
|
||||
reverb.reset();
|
||||
|
||||
reverb.resize(channels);
|
||||
for(auto c : range(channels)) {
|
||||
reverb[c].resize(7);
|
||||
reverb[c][0].resize(1229);
|
||||
reverb[c][1].resize(1559);
|
||||
reverb[c][2].resize(1907);
|
||||
reverb[c][3].resize(4057);
|
||||
reverb[c][4].resize(8117);
|
||||
reverb[c][5].resize(8311);
|
||||
reverb[c][6].resize(9931);
|
||||
}
|
||||
}
|
||||
|
||||
auto Audio::setInterface(Interface* interface) -> void {
|
||||
this->interface = interface;
|
||||
}
|
||||
|
||||
auto Audio::setVolume(double volume) -> void {
|
||||
this->volume = volume;
|
||||
}
|
||||
|
||||
auto Audio::setBalance(double balance) -> void {
|
||||
this->balance = balance;
|
||||
}
|
||||
|
||||
auto Audio::setReverb(bool enabled) -> void {
|
||||
this->reverbEnable = enabled;
|
||||
}
|
||||
|
||||
auto Audio::createStream(uint channels, double frequency) -> shared_pointer<Stream> {
|
||||
shared_pointer<Stream> stream = new Stream;
|
||||
stream->reset(channels, frequency, this->frequency);
|
||||
streams.append(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
auto Audio::process() -> void {
|
||||
while(true) {
|
||||
for(auto& stream : streams) {
|
||||
if(!stream->pending()) return;
|
||||
}
|
||||
|
||||
double samples[channels] = {0};
|
||||
for(auto& stream : streams) {
|
||||
double buffer[16];
|
||||
uint length = stream->read(buffer), offset = 0;
|
||||
|
||||
for(auto c : range(channels)) {
|
||||
samples[c] += buffer[offset];
|
||||
if(++offset >= length) offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for(auto c : range(channels)) {
|
||||
samples[c] /= streams.size();
|
||||
|
||||
if(reverbEnable) {
|
||||
samples[c] *= 0.125;
|
||||
for(auto n : range(7)) samples[c] += 0.125 * reverb[c][n].last();
|
||||
for(auto n : range(7)) reverb[c][n].write(samples[c]);
|
||||
samples[c] *= 8.000;
|
||||
}
|
||||
|
||||
samples[c] *= volume;
|
||||
}
|
||||
|
||||
if(channels == 2) {
|
||||
if(balance < 0.0) samples[1] *= 1.0 + balance;
|
||||
if(balance > 0.0) samples[0] *= 1.0 - balance;
|
||||
}
|
||||
|
||||
interface->audioSample(samples, channels);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
65
higan/audio/audio.hpp
Normal file
65
higan/audio/audio.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/dsp/iir/biquad.hpp>
|
||||
#include <nall/dsp/resampler/cubic.hpp>
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
struct Interface;
|
||||
struct Audio;
|
||||
struct Stream;
|
||||
|
||||
struct Audio {
|
||||
auto reset(maybe<uint> channels = nothing, maybe<double> frequency = nothing) -> void;
|
||||
auto setInterface(Interface*) -> void;
|
||||
|
||||
auto setVolume(double volume) -> void;
|
||||
auto setBalance(double balance) -> void;
|
||||
auto setReverb(bool enabled) -> void;
|
||||
|
||||
auto createStream(uint channels, double frequency) -> shared_pointer<Stream>;
|
||||
|
||||
private:
|
||||
auto process() -> void;
|
||||
|
||||
Interface* interface = nullptr;
|
||||
vector<shared_pointer<Stream>> streams;
|
||||
|
||||
uint channels = 0;
|
||||
double frequency = 0.0;
|
||||
|
||||
double volume = 1.0;
|
||||
double balance = 0.0;
|
||||
|
||||
bool reverbEnable = false;
|
||||
vector<vector<queue<double>>> reverb;
|
||||
|
||||
friend class Stream;
|
||||
};
|
||||
|
||||
struct Stream {
|
||||
auto reset(uint channels, double inputFrequency, double outputFrequency) -> void;
|
||||
|
||||
auto pending() const -> bool;
|
||||
auto read(double* samples) -> uint;
|
||||
auto write(const double* samples) -> void;
|
||||
|
||||
template<typename... P> auto sample(P&&... p) -> void {
|
||||
double samples[sizeof...(P)] = {forward<P>(p)...};
|
||||
write(samples);
|
||||
}
|
||||
|
||||
private:
|
||||
const uint order = 6; //Nth-order filter (must be an even number)
|
||||
struct Channel {
|
||||
vector<DSP::IIR::Biquad> iir;
|
||||
DSP::Resampler::Cubic resampler;
|
||||
};
|
||||
vector<Channel> channels;
|
||||
|
||||
friend class Audio;
|
||||
};
|
||||
|
||||
extern Audio audio;
|
||||
|
||||
}
|
35
higan/audio/stream.cpp
Normal file
35
higan/audio/stream.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
auto Stream::reset(uint channels_, double inputFrequency, double outputFrequency) -> void {
|
||||
channels.reset();
|
||||
channels.resize(channels_);
|
||||
|
||||
for(auto& channel : channels) {
|
||||
if(outputFrequency / inputFrequency <= 0.5) {
|
||||
channel.iir.resize(order / 2);
|
||||
for(auto phase : range(order / 2)) {
|
||||
double q = DSP::IIR::Biquad::butterworth(order, phase);
|
||||
channel.iir[phase].reset(DSP::IIR::Biquad::Type::LowPass, 20000.0 / inputFrequency, q);
|
||||
}
|
||||
}
|
||||
|
||||
channel.resampler.reset(inputFrequency, outputFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
auto Stream::pending() const -> bool {
|
||||
return channels && channels[0].resampler.pending();
|
||||
}
|
||||
|
||||
auto Stream::read(double* samples) -> uint {
|
||||
for(auto c : range(channels)) samples[c] = channels[c].resampler.read();
|
||||
return channels.size();
|
||||
}
|
||||
|
||||
auto Stream::write(const double* samples) -> void {
|
||||
for(auto c : range(channels)) {
|
||||
double sample = samples[c] + 1e-25; //constant offset used to suppress denormals
|
||||
for(auto& iir : channels[c].iir) sample = iir.process(sample);
|
||||
channels[c].resampler.write(sample);
|
||||
}
|
||||
|
||||
audio.process();
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
objects += emulator
|
||||
|
||||
obj/emulator.o: emulator/emulator.cpp $(call rwildcard,emulator/)
|
@@ -1,34 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
auto Interface::videoColor(uint16 r, uint16 g, uint16 b) -> uint32 {
|
||||
double saturation = 1.0;
|
||||
double gamma = 1.0;
|
||||
double luminance = 1.0;
|
||||
|
||||
if(saturation != 1.0) {
|
||||
uint16 grayscale = uclamp<16>((r + g + b) / 3);
|
||||
double inverse = max(0.0, 1.0 - saturation);
|
||||
r = uclamp<16>(r * saturation + grayscale * inverse);
|
||||
g = uclamp<16>(g * saturation + grayscale * inverse);
|
||||
b = uclamp<16>(b * saturation + grayscale * inverse);
|
||||
}
|
||||
|
||||
if(gamma != 1.0) {
|
||||
double reciprocal = 1.0 / 32767.0;
|
||||
r = r > 32767 ? r : uint16(32767 * pow(r * reciprocal, gamma));
|
||||
g = g > 32767 ? g : uint16(32767 * pow(g * reciprocal, gamma));
|
||||
b = b > 32767 ? b : uint16(32767 * pow(b * reciprocal, gamma));
|
||||
}
|
||||
|
||||
if(luminance != 1.0) {
|
||||
r = uclamp<16>(r * luminance);
|
||||
g = uclamp<16>(g * luminance);
|
||||
b = uclamp<16>(b * luminance);
|
||||
}
|
||||
|
||||
return 255 << 24 | (r >> 8) << 16 | (g >> 8) << 8 | (b >> 8) << 0;
|
||||
}
|
||||
|
||||
}
|
@@ -1,23 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/nall.hpp>
|
||||
#include <nall/dsp.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <audio/audio.hpp>
|
||||
#include <video/video.hpp>
|
||||
#include <resource/resource.hpp>
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "098";
|
||||
static const string Version = "099";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
||||
#if defined(PROFILE_ACCURACY)
|
||||
static const string Profile = "Accuracy";
|
||||
#elif defined(PROFILE_BALANCED)
|
||||
static const string Profile = "Balanced";
|
||||
#elif defined(PROFILE_PERFORMANCE)
|
||||
static const string Profile = "Performance";
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "interface.hpp"
|
||||
|
@@ -17,13 +17,13 @@ struct Interface {
|
||||
} capability;
|
||||
} information;
|
||||
|
||||
struct Media {
|
||||
struct Medium {
|
||||
uint id;
|
||||
string name;
|
||||
string type;
|
||||
bool bootable; //false for cartridge slots (eg Sufami Turbo cartridges)
|
||||
};
|
||||
vector<Media> media;
|
||||
vector<Medium> media;
|
||||
|
||||
struct Device {
|
||||
uint id;
|
||||
@@ -35,23 +35,22 @@ struct Interface {
|
||||
string name;
|
||||
uintptr guid; //user data field
|
||||
};
|
||||
vector<Input> input;
|
||||
vector<uint> order;
|
||||
vector<Input> inputs;
|
||||
};
|
||||
|
||||
struct Port {
|
||||
uint id;
|
||||
string name;
|
||||
vector<Device> device;
|
||||
vector<Device> devices;
|
||||
};
|
||||
vector<Port> port;
|
||||
vector<Port> ports;
|
||||
|
||||
struct Bind {
|
||||
virtual auto loadRequest(uint, string, string, bool) -> void {}
|
||||
virtual auto loadRequest(uint, string, bool) -> void {}
|
||||
virtual auto saveRequest(uint, string) -> void {}
|
||||
virtual auto videoRefresh(const uint32*, uint, uint, uint) -> void {}
|
||||
virtual auto audioSample(int16, int16) -> void {}
|
||||
virtual auto audioSample(const double*, uint) -> void {}
|
||||
virtual auto inputPoll(uint, uint, uint) -> int16 { return 0; }
|
||||
virtual auto inputRumble(uint, uint, uint, bool) -> void {}
|
||||
virtual auto dipSettings(const Markup::Node&) -> uint { return 0; }
|
||||
@@ -65,7 +64,7 @@ struct Interface {
|
||||
auto loadRequest(uint id, string path, bool required) -> void { return bind->loadRequest(id, path, required); }
|
||||
auto saveRequest(uint id, string path) -> void { return bind->saveRequest(id, path); }
|
||||
auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void { return bind->videoRefresh(data, pitch, width, height); }
|
||||
auto audioSample(int16 lsample, int16 rsample) -> void { return bind->audioSample(lsample, rsample); }
|
||||
auto audioSample(const double* samples, uint channels) -> void { return bind->audioSample(samples, channels); }
|
||||
auto inputPoll(uint port, uint device, uint input) -> int16 { return bind->inputPoll(port, device, input); }
|
||||
auto inputRumble(uint port, uint device, uint input, bool enable) -> void { return bind->inputRumble(port, device, input, enable); }
|
||||
auto dipSettings(const Markup::Node& node) -> uint { return bind->dipSettings(node); }
|
||||
@@ -75,7 +74,13 @@ struct Interface {
|
||||
//information
|
||||
virtual auto manifest() -> string = 0;
|
||||
virtual auto title() -> string = 0;
|
||||
|
||||
//video information
|
||||
virtual auto videoFrequency() -> double = 0;
|
||||
virtual auto videoColors() -> uint32 { return 1 << 19; }
|
||||
virtual auto videoColor(uint32 color) -> uint64 { return 0; }
|
||||
|
||||
//audio information
|
||||
virtual auto audioFrequency() -> double = 0;
|
||||
|
||||
//media interface
|
||||
|
@@ -57,7 +57,7 @@ auto APU::main() -> void {
|
||||
//output = filter.run_lopass(output);
|
||||
output = sclamp<16>(output);
|
||||
|
||||
interface->audioSample(output, output);
|
||||
stream->sample(output / 32768.0);
|
||||
|
||||
tick();
|
||||
}
|
||||
@@ -89,6 +89,7 @@ auto APU::power() -> void {
|
||||
|
||||
auto APU::reset() -> void {
|
||||
create(APU::Enter, 21'477'272);
|
||||
stream = Emulator::audio.createStream(1, 21'477'272.0 / 12.0);
|
||||
|
||||
pulse[0].reset();
|
||||
pulse[1].reset();
|
||||
|
@@ -1,4 +1,6 @@
|
||||
struct APU : Thread {
|
||||
shared_pointer<Emulator::Stream> stream;
|
||||
|
||||
APU();
|
||||
|
||||
static auto Enter() -> void;
|
||||
|
@@ -1,22 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
//license: GPLv3
|
||||
//started: 2011-09-05
|
||||
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/r6502/r6502.hpp>
|
||||
|
||||
namespace Famicom {
|
||||
namespace Info {
|
||||
static const string Name = "bnes";
|
||||
static const uint SerializerVersion = 2;
|
||||
static const uint SerializerVersion = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bnes - Famicom emulator
|
||||
authors: byuu, Ryphecha
|
||||
license: GPLv3
|
||||
project started: 2011-09-05
|
||||
*/
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
namespace Famicom {
|
||||
@@ -27,7 +22,7 @@ namespace Famicom {
|
||||
|
||||
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
|
||||
if(thread) co_delete(thread);
|
||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||
thread = co_create(65'536 * sizeof(void*), entrypoint);
|
||||
this->frequency = frequency;
|
||||
clock = 0;
|
||||
}
|
||||
|
@@ -15,12 +15,15 @@ auto Input::latch(bool data) -> void {
|
||||
}
|
||||
|
||||
auto Input::data(bool port) -> bool {
|
||||
//table to convert native button ordering to Emulator::Interface ordering
|
||||
static const uint lookup[] = {5, 4, 6, 7, 0, 1, 2, 3};
|
||||
|
||||
bool result = 0;
|
||||
|
||||
if(port == 0) {
|
||||
if(port1 == Device::Joypad) {
|
||||
if(counter1 >= 8) return 1;
|
||||
result = interface->inputPoll(0, 0u, counter1);
|
||||
result = interface->inputPoll(0, 0u, lookup[counter1]);
|
||||
if(latchdata == 0) counter1++;
|
||||
}
|
||||
}
|
||||
@@ -28,7 +31,7 @@ auto Input::data(bool port) -> bool {
|
||||
if(port == 1) {
|
||||
if(port2 == Device::Joypad) {
|
||||
if(counter2 >= 8) return 1;
|
||||
result = interface->inputPoll(1, 0u, counter2);
|
||||
result = interface->inputPoll(1, 0u, lookup[counter2]);
|
||||
if(latchdata == 0) counter2++;
|
||||
}
|
||||
}
|
||||
|
@@ -22,25 +22,24 @@ Interface::Interface() {
|
||||
media.append({ID::Famicom, "Famicom", "fc", true});
|
||||
|
||||
{ Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
||||
device.input.append({0, 0, "A" });
|
||||
device.input.append({1, 0, "B" });
|
||||
device.input.append({2, 0, "Select"});
|
||||
device.input.append({3, 0, "Start" });
|
||||
device.input.append({4, 0, "Up" });
|
||||
device.input.append({5, 0, "Down" });
|
||||
device.input.append({6, 0, "Left" });
|
||||
device.input.append({7, 0, "Right" });
|
||||
device.order = {4, 5, 6, 7, 1, 0, 2, 3};
|
||||
this->device.append(device);
|
||||
device.inputs.append({0, 0, "Up" });
|
||||
device.inputs.append({1, 0, "Down" });
|
||||
device.inputs.append({2, 0, "Left" });
|
||||
device.inputs.append({3, 0, "Right" });
|
||||
device.inputs.append({4, 0, "B" });
|
||||
device.inputs.append({5, 0, "A" });
|
||||
device.inputs.append({6, 0, "Select"});
|
||||
device.inputs.append({7, 0, "Start" });
|
||||
devices.append(device);
|
||||
}
|
||||
|
||||
port.append({0, "Port 1"});
|
||||
port.append({1, "Port 2"});
|
||||
ports.append({0, "Port 1"});
|
||||
ports.append({1, "Port 2"});
|
||||
|
||||
for(auto& device : this->device) {
|
||||
for(auto& port : this->port) {
|
||||
for(auto& device : devices) {
|
||||
for(auto& port : ports) {
|
||||
if(device.portmask & (1 << port.id)) {
|
||||
port.device.append(device);
|
||||
port.devices.append(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +57,61 @@ auto Interface::videoFrequency() -> double {
|
||||
return 21477272.0 / (262.0 * 1364.0 - 4.0);
|
||||
}
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
return 1 << 9;
|
||||
}
|
||||
|
||||
auto Interface::videoColor(uint32 n) -> uint64 {
|
||||
double saturation = 2.0;
|
||||
double hue = 0.0;
|
||||
double contrast = 1.0;
|
||||
double brightness = 1.0;
|
||||
double gamma = settings.colorEmulation ? 1.8 : 2.2;
|
||||
|
||||
int color = (n & 0x0f), level = color < 0xe ? (n >> 4) & 3 : 1;
|
||||
|
||||
static const double black = 0.518, white = 1.962, attenuation = 0.746;
|
||||
static const double levels[8] = {
|
||||
0.350, 0.518, 0.962, 1.550,
|
||||
1.094, 1.506, 1.962, 1.962,
|
||||
};
|
||||
|
||||
double lo_and_hi[2] = {
|
||||
levels[level + 4 * (color == 0x0)],
|
||||
levels[level + 4 * (color < 0xd)],
|
||||
};
|
||||
|
||||
double y = 0.0, i = 0.0, q = 0.0;
|
||||
auto wave = [](int p, int color) { return (color + p + 8) % 12 < 6; };
|
||||
for(int p : range(12)) {
|
||||
double spot = lo_and_hi[wave(p, color)];
|
||||
|
||||
if(((n & 0x040) && wave(p, 12))
|
||||
|| ((n & 0x080) && wave(p, 4))
|
||||
|| ((n & 0x100) && wave(p, 8))
|
||||
) spot *= attenuation;
|
||||
|
||||
double v = (spot - black) / (white - black);
|
||||
|
||||
v = (v - 0.5) * contrast + 0.5;
|
||||
v *= brightness / 12.0;
|
||||
|
||||
y += v;
|
||||
i += v * cos((Math::Pi / 6.0) * (p + hue));
|
||||
q += v * sin((Math::Pi / 6.0) * (p + hue));
|
||||
}
|
||||
|
||||
i *= saturation;
|
||||
q *= saturation;
|
||||
|
||||
auto gammaAdjust = [=](double f) { return f < 0.0 ? 0.0 : pow(f, 2.2 / gamma); };
|
||||
uint64 r = uclamp<16>(65535.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q));
|
||||
uint64 g = uclamp<16>(65535.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q));
|
||||
uint64 b = uclamp<16>(65535.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q));
|
||||
|
||||
return r << 32 | g << 16 | b << 0;
|
||||
}
|
||||
|
||||
auto Interface::audioFrequency() -> double {
|
||||
return 21477272.0 / 12.0;
|
||||
}
|
||||
@@ -182,7 +236,11 @@ auto Interface::get(const string& name) -> any {
|
||||
}
|
||||
|
||||
auto Interface::set(const string& name, const any& value) -> bool {
|
||||
if(name == "Color Emulation" && value.is<bool>()) return settings.colorEmulation = value.get<bool>(), true;
|
||||
if(name == "Color Emulation" && value.is<bool>()) {
|
||||
settings.colorEmulation = value.get<bool>();
|
||||
system.configureVideoPalette();
|
||||
return true;
|
||||
}
|
||||
if(name == "Scanline Emulation" && value.is<bool>()) return settings.scanlineEmulation = value.get<bool>(), true;
|
||||
return false;
|
||||
}
|
||||
|
@@ -28,6 +28,8 @@ struct Interface : Emulator::Interface {
|
||||
auto manifest() -> string;
|
||||
auto title() -> string;
|
||||
auto videoFrequency() -> double;
|
||||
auto videoColors() -> uint32;
|
||||
auto videoColor(uint32 color) -> uint64;
|
||||
auto audioFrequency() -> double;
|
||||
|
||||
auto loaded() -> bool;
|
||||
@@ -53,7 +55,7 @@ struct Interface : Emulator::Interface {
|
||||
auto set(const string& name, const any& value) -> bool override;
|
||||
|
||||
private:
|
||||
vector<Device> device;
|
||||
vector<Device> devices;
|
||||
};
|
||||
|
||||
struct Settings {
|
||||
|
@@ -3,7 +3,6 @@
|
||||
namespace Famicom {
|
||||
|
||||
PPU ppu;
|
||||
#include "video.cpp"
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
@@ -43,10 +42,13 @@ auto PPU::scanline() -> void {
|
||||
|
||||
auto PPU::frame() -> void {
|
||||
status.field ^= 1;
|
||||
video.refresh();
|
||||
scheduler.exit(Scheduler::Event::Frame);
|
||||
}
|
||||
|
||||
auto PPU::refresh() -> void {
|
||||
Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240);
|
||||
}
|
||||
|
||||
auto PPU::power() -> void {
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,3 @@
|
||||
#include "video.hpp"
|
||||
|
||||
struct PPU : Thread {
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
@@ -7,6 +5,7 @@ struct PPU : Thread {
|
||||
|
||||
auto scanline() -> void;
|
||||
auto frame() -> void;
|
||||
auto refresh() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
@@ -1,94 +0,0 @@
|
||||
Video video;
|
||||
|
||||
Video::Video() {
|
||||
output = new uint32[256 * 480];
|
||||
paletteLiteral = new uint32[1 << 9];
|
||||
paletteStandard = new uint32[1 << 9];
|
||||
paletteEmulation = new uint32[1 << 9];
|
||||
}
|
||||
|
||||
auto Video::reset() -> void {
|
||||
memory::fill(output(), 256 * 480);
|
||||
|
||||
for(auto color : range(1 << 9)) {
|
||||
paletteLiteral[color] = color;
|
||||
paletteStandard[color] = generateColor(color, 2.0, 0.0, 1.0, 1.0, 2.2);
|
||||
paletteEmulation[color] = generateColor(color, 2.0, 0.0, 1.0, 1.0, 1.8);
|
||||
}
|
||||
}
|
||||
|
||||
auto Video::refresh() -> void {
|
||||
auto output = this->output();
|
||||
auto& palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
|
||||
|
||||
if(settings.scanlineEmulation) {
|
||||
for(uint y = 0; y < 240; y++) {
|
||||
auto source = ppu.buffer + y * 256;
|
||||
auto targetLo = output + y * 512;
|
||||
auto targetHi = output + y * 512 + 256;
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
auto color = palette[*source++];
|
||||
*targetLo++ = color;
|
||||
*targetHi++ = (255 << 24) | ((color & 0xfefefe) >> 1);
|
||||
}
|
||||
}
|
||||
interface->videoRefresh(output, 256 * sizeof(uint32), 256, 480);
|
||||
} else {
|
||||
for(uint y = 0; y < 240; y++) {
|
||||
auto source = ppu.buffer + y * 256;
|
||||
auto target = output + y * 256;
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
*target++ = palette[*source++];
|
||||
}
|
||||
}
|
||||
interface->videoRefresh(output, 256 * sizeof(uint32), 256, 240);
|
||||
}
|
||||
}
|
||||
|
||||
auto Video::generateColor(
|
||||
uint n, double saturation, double hue,
|
||||
double contrast, double brightness, double gamma
|
||||
) -> uint32 {
|
||||
int color = (n & 0x0f), level = color < 0xe ? (n >> 4) & 3 : 1;
|
||||
|
||||
static const double black = 0.518, white = 1.962, attenuation = 0.746;
|
||||
static const double levels[8] = {
|
||||
0.350, 0.518, 0.962, 1.550,
|
||||
1.094, 1.506, 1.962, 1.962,
|
||||
};
|
||||
|
||||
double lo_and_hi[2] = {
|
||||
levels[level + 4 * (color == 0x0)],
|
||||
levels[level + 4 * (color < 0xd)],
|
||||
};
|
||||
|
||||
double y = 0.0, i = 0.0, q = 0.0;
|
||||
auto wave = [](int p, int color) { return (color + p + 8) % 12 < 6; };
|
||||
for(int p : range(12)) {
|
||||
double spot = lo_and_hi[wave(p, color)];
|
||||
|
||||
if(((n & 0x040) && wave(p, 12))
|
||||
|| ((n & 0x080) && wave(p, 4))
|
||||
|| ((n & 0x100) && wave(p, 8))
|
||||
) spot *= attenuation;
|
||||
|
||||
double v = (spot - black) / (white - black);
|
||||
|
||||
v = (v - 0.5) * contrast + 0.5;
|
||||
v *= brightness / 12.0;
|
||||
|
||||
y += v;
|
||||
i += v * std::cos((3.141592653 / 6.0) * (p + hue));
|
||||
q += v * std::sin((3.141592653 / 6.0) * (p + hue));
|
||||
}
|
||||
|
||||
i *= saturation;
|
||||
q *= saturation;
|
||||
|
||||
auto gammaAdjust = [=](double f) { return f < 0.0 ? 0.0 : std::pow(f, 2.2 / gamma); };
|
||||
uint r = uclamp<16>(65535.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q));
|
||||
uint g = uclamp<16>(65535.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q));
|
||||
uint b = uclamp<16>(65535.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q));
|
||||
|
||||
return interface->videoColor(r, g, b);
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
struct Video {
|
||||
Video();
|
||||
|
||||
auto reset() -> void;
|
||||
auto refresh() -> void;
|
||||
|
||||
private:
|
||||
auto generateColor(uint, double, double, double, double, double) -> uint32;
|
||||
|
||||
unique_pointer<uint32[]> output;
|
||||
unique_pointer<uint32[]> paletteLiteral;
|
||||
unique_pointer<uint32[]> paletteStandard;
|
||||
unique_pointer<uint32[]> paletteEmulation;
|
||||
};
|
||||
|
||||
extern Video video;
|
@@ -13,6 +13,7 @@ auto Scheduler::enter(Mode mode_) -> Event {
|
||||
mode = mode_;
|
||||
host = co_active();
|
||||
co_switch(resume);
|
||||
if(event == Event::Frame) ppu.refresh();
|
||||
return event;
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Famicom {
|
||||
|
||||
#include "video.cpp"
|
||||
#include "serialization.cpp"
|
||||
System system;
|
||||
|
||||
@@ -42,13 +43,20 @@ auto System::power() -> void {
|
||||
}
|
||||
|
||||
auto System::reset() -> void {
|
||||
Emulator::video.reset();
|
||||
Emulator::video.setInterface(interface);
|
||||
configureVideoPalette();
|
||||
configureVideoEffects();
|
||||
|
||||
Emulator::audio.reset();
|
||||
Emulator::audio.setInterface(interface);
|
||||
|
||||
cartridge.reset();
|
||||
cpu.reset();
|
||||
apu.reset();
|
||||
ppu.reset();
|
||||
input.reset();
|
||||
scheduler.reset();
|
||||
video.reset();
|
||||
}
|
||||
|
||||
auto System::init() -> void {
|
||||
|
@@ -12,6 +12,11 @@ struct System {
|
||||
auto init() -> void;
|
||||
auto term() -> void;
|
||||
|
||||
//video.cpp
|
||||
auto configureVideoPalette() -> void;
|
||||
auto configureVideoEffects() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize() -> serializer;
|
||||
auto unserialize(serializer&) -> bool;
|
||||
|
||||
|
6
higan/fc/system/video.cpp
Normal file
6
higan/fc/system/video.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
auto System::configureVideoPalette() -> void {
|
||||
Emulator::video.setPalette();
|
||||
}
|
||||
|
||||
auto System::configureVideoEffects() -> void {
|
||||
}
|
@@ -25,7 +25,12 @@ auto APU::main() -> void {
|
||||
hipass(sequencer.left, sequencer.leftBias);
|
||||
hipass(sequencer.right, sequencer.rightBias);
|
||||
|
||||
interface->audioSample(sequencer.left, sequencer.right);
|
||||
if(!system.sgb()) {
|
||||
stream->sample(sequencer.left / 32768.0, sequencer.right / 32768.0);
|
||||
} else {
|
||||
double samples[] = {sequencer.left / 32768.0, sequencer.right / 32768.0};
|
||||
interface->audioSample(samples, 2);
|
||||
}
|
||||
|
||||
if(cycle == 0) { //512hz
|
||||
if(phase == 0 || phase == 2 || phase == 4 || phase == 6) { //256hz
|
||||
@@ -58,6 +63,7 @@ auto APU::hipass(int16& sample, int64& bias) -> void {
|
||||
|
||||
auto APU::power() -> void {
|
||||
create(Enter, 2 * 1024 * 1024);
|
||||
if(!system.sgb()) stream = Emulator::audio.createStream(2, 2 * 1024 * 1024);
|
||||
for(uint n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
|
||||
|
||||
square1.power();
|
||||
|
@@ -1,4 +1,6 @@
|
||||
struct APU : Thread, MMIO {
|
||||
shared_pointer<Emulator::Stream> stream;
|
||||
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto hipass(int16& sample, int64& bias) -> void;
|
||||
|
@@ -4,6 +4,7 @@ namespace GameBoy {
|
||||
|
||||
#include "mbc0/mbc0.cpp"
|
||||
#include "mbc1/mbc1.cpp"
|
||||
#include "mbc1m/mbc1m.cpp"
|
||||
#include "mbc2/mbc2.cpp"
|
||||
#include "mbc3/mbc3.cpp"
|
||||
#include "mbc5/mbc5.cpp"
|
||||
@@ -40,6 +41,7 @@ auto Cartridge::load(System::Revision revision) -> void {
|
||||
auto mapperid = document["board/mapper"].text();
|
||||
if(mapperid == "none" ) information.mapper = Mapper::MBC0;
|
||||
if(mapperid == "MBC1" ) information.mapper = Mapper::MBC1;
|
||||
if(mapperid == "MBC1M") information.mapper = Mapper::MBC1M;
|
||||
if(mapperid == "MBC2" ) information.mapper = Mapper::MBC2;
|
||||
if(mapperid == "MBC3" ) information.mapper = Mapper::MBC3;
|
||||
if(mapperid == "MBC5" ) information.mapper = Mapper::MBC5;
|
||||
@@ -70,6 +72,7 @@ auto Cartridge::load(System::Revision revision) -> void {
|
||||
switch(information.mapper) { default:
|
||||
case Mapper::MBC0: mapper = &mbc0; break;
|
||||
case Mapper::MBC1: mapper = &mbc1; break;
|
||||
case Mapper::MBC1M: mapper = &mbc1m; break;
|
||||
case Mapper::MBC2: mapper = &mbc2; break;
|
||||
case Mapper::MBC3: mapper = &mbc3; break;
|
||||
case Mapper::MBC5: mapper = &mbc5; break;
|
||||
@@ -139,6 +142,7 @@ auto Cartridge::power() -> void {
|
||||
|
||||
mbc0.power();
|
||||
mbc1.power();
|
||||
mbc1m.power();
|
||||
mbc2.power();
|
||||
mbc3.power();
|
||||
mbc5.power();
|
||||
|
@@ -16,6 +16,7 @@ struct Cartridge : MMIO, property<Cartridge> {
|
||||
|
||||
#include "mbc0/mbc0.hpp"
|
||||
#include "mbc1/mbc1.hpp"
|
||||
#include "mbc1m/mbc1m.hpp"
|
||||
#include "mbc2/mbc2.hpp"
|
||||
#include "mbc3/mbc3.hpp"
|
||||
#include "mbc5/mbc5.hpp"
|
||||
@@ -26,6 +27,7 @@ struct Cartridge : MMIO, property<Cartridge> {
|
||||
enum Mapper : uint {
|
||||
MBC0,
|
||||
MBC1,
|
||||
MBC1M,
|
||||
MBC2,
|
||||
MBC3,
|
||||
MBC5,
|
||||
|
@@ -9,7 +9,7 @@ auto Cartridge::HuC3::mmio_read(uint16 addr) -> uint8 {
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //$a000-bfff
|
||||
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
|
||||
return 0xff;
|
||||
return 0x01; //does not return open collection
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
|
40
higan/gb/cartridge/mbc1m/mbc1m.cpp
Normal file
40
higan/gb/cartridge/mbc1m/mbc1m.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
auto Cartridge::MBC1M::mmio_read(uint16 addr) -> uint8 {
|
||||
if((addr & 0xc000) == 0x0000) { //$0000-3fff
|
||||
if(!modeSelect) return cartridge.rom_read(addr & 0x3fff);
|
||||
return cartridge.rom_read((romHi << 4) * 0x4000 + (addr & 0x3fff));
|
||||
}
|
||||
|
||||
if((addr & 0xc000) == 0x4000) { //$4000-7fff
|
||||
return cartridge.rom_read((romHi << 4 | romLo) * 0x4000 + (addr & 0x3fff));
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //$a000-bfff
|
||||
return cartridge.ram_read(addr & 0x1fff);
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
auto Cartridge::MBC1M::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x2000) { //$2000-3fff
|
||||
romLo = data.bits(0,3);
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x4000) { //$4000-5fff
|
||||
romHi = data.bits(0,1);
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x6000) { //$6000-7fff
|
||||
modeSelect = data.bit(0);
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //$a000-bfff
|
||||
cartridge.ram_write(addr & 0x1fff, data);
|
||||
}
|
||||
}
|
||||
|
||||
auto Cartridge::MBC1M::power() -> void {
|
||||
romHi = 0;
|
||||
romLo = 1;
|
||||
modeSelect = 0;
|
||||
}
|
9
higan/gb/cartridge/mbc1m/mbc1m.hpp
Normal file
9
higan/gb/cartridge/mbc1m/mbc1m.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
struct MBC1M : MMIO {
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
uint4 romLo;
|
||||
uint2 romHi;
|
||||
uint1 modeSelect;
|
||||
} mbc1m;
|
@@ -7,6 +7,10 @@ auto Cartridge::serialize(serializer& s) -> void {
|
||||
s.integer(mbc1.ram_select);
|
||||
s.integer(mbc1.mode_select);
|
||||
|
||||
s.integer(mbc1m.romLo);
|
||||
s.integer(mbc1m.romHi);
|
||||
s.integer(mbc1m.modeSelect);
|
||||
|
||||
s.integer(mbc2.ram_enable);
|
||||
s.integer(mbc2.rom_select);
|
||||
|
||||
|
@@ -14,10 +14,10 @@ auto CPU::Enter() -> void {
|
||||
|
||||
auto CPU::main() -> void {
|
||||
interrupt_test();
|
||||
exec();
|
||||
instruction();
|
||||
}
|
||||
|
||||
auto CPU::interrupt_raise(CPU::Interrupt id) -> void {
|
||||
auto CPU::raise(CPU::Interrupt id) -> void {
|
||||
if(id == Interrupt::Vblank) {
|
||||
status.interrupt_request_vblank = 1;
|
||||
if(status.interrupt_enable_vblank) r.halt = false;
|
||||
@@ -45,42 +45,32 @@ auto CPU::interrupt_raise(CPU::Interrupt id) -> void {
|
||||
}
|
||||
|
||||
auto CPU::interrupt_test() -> void {
|
||||
if(r.ime) {
|
||||
if(status.interrupt_request_vblank && status.interrupt_enable_vblank) {
|
||||
status.interrupt_request_vblank = 0;
|
||||
return interrupt_exec(0x0040);
|
||||
}
|
||||
if(!r.ime) return;
|
||||
|
||||
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);
|
||||
}
|
||||
if(status.interrupt_request_vblank && status.interrupt_enable_vblank) {
|
||||
status.interrupt_request_vblank = 0;
|
||||
return interrupt(0x0040);
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::interrupt_exec(uint16 pc) -> void {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
r.ime = 0;
|
||||
op_write(--r[SP], r[PC] >> 8);
|
||||
op_write(--r[SP], r[PC] >> 0);
|
||||
r[PC] = pc;
|
||||
if(status.interrupt_request_stat && status.interrupt_enable_stat) {
|
||||
status.interrupt_request_stat = 0;
|
||||
return interrupt(0x0048);
|
||||
}
|
||||
|
||||
if(status.interrupt_request_timer && status.interrupt_enable_timer) {
|
||||
status.interrupt_request_timer = 0;
|
||||
return interrupt(0x0050);
|
||||
}
|
||||
|
||||
if(status.interrupt_request_serial && status.interrupt_enable_serial) {
|
||||
status.interrupt_request_serial = 0;
|
||||
return interrupt(0x0058);
|
||||
}
|
||||
|
||||
if(status.interrupt_request_joypad && status.interrupt_enable_joypad) {
|
||||
status.interrupt_request_joypad = 0;
|
||||
return interrupt(0x0060);
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::stop() -> bool {
|
||||
|
@@ -3,9 +3,8 @@ struct CPU : Processor::LR35902, Thread, MMIO {
|
||||
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto interrupt_raise(Interrupt id) -> void;
|
||||
auto raise(Interrupt id) -> void;
|
||||
auto interrupt_test() -> void;
|
||||
auto interrupt_exec(uint16 pc) -> void;
|
||||
auto stop() -> bool;
|
||||
auto power() -> void;
|
||||
|
||||
@@ -18,9 +17,9 @@ struct CPU : Processor::LR35902, Thread, MMIO {
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
|
||||
//memory.cpp
|
||||
auto op_io() -> void;
|
||||
auto op_read(uint16 addr) -> uint8;
|
||||
auto op_write(uint16 addr, uint8 data) -> void;
|
||||
auto io() -> void override;
|
||||
auto read(uint16 addr) -> uint8 override;
|
||||
auto write(uint16 addr, uint8 data) -> void override;
|
||||
auto cycle_edge() -> void;
|
||||
auto dma_read(uint16 addr) -> uint8;
|
||||
auto dma_write(uint16 addr, uint8 data) -> void;
|
||||
|
@@ -1,15 +1,15 @@
|
||||
auto CPU::op_io() -> void {
|
||||
auto CPU::io() -> void {
|
||||
cycle_edge();
|
||||
add_clocks(4);
|
||||
}
|
||||
|
||||
auto CPU::op_read(uint16 addr) -> uint8 {
|
||||
auto CPU::read(uint16 addr) -> uint8 {
|
||||
cycle_edge();
|
||||
add_clocks(4);
|
||||
return bus.read(addr);
|
||||
}
|
||||
|
||||
auto CPU::op_write(uint16 addr, uint8 data) -> void {
|
||||
auto CPU::write(uint16 addr, uint8 data) -> void {
|
||||
cycle_edge();
|
||||
add_clocks(4);
|
||||
bus.write(addr, data);
|
||||
|
@@ -29,7 +29,7 @@ auto CPU::mmio_joyp_poll() -> void {
|
||||
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);
|
||||
if(status.joyp != 0x0f) raise(Interrupt::Joypad);
|
||||
}
|
||||
|
||||
auto CPU::mmio_read(uint16 addr) -> uint8 {
|
||||
|
@@ -3,9 +3,7 @@
|
||||
// 154 scanlines/frame
|
||||
|
||||
auto CPU::add_clocks(uint clocks) -> void {
|
||||
if(system.sgb()) system._clocksExecuted += clocks;
|
||||
|
||||
while(clocks--) {
|
||||
for(auto n : range(clocks)) {
|
||||
if(++status.clock == 0) {
|
||||
cartridge.mbc3.second();
|
||||
}
|
||||
@@ -25,14 +23,17 @@ auto CPU::add_clocks(uint clocks) -> void {
|
||||
if(apu.clock < 0) co_switch(apu.thread);
|
||||
}
|
||||
|
||||
if(system.sgb()) scheduler.exit(Scheduler::Event::Step);
|
||||
if(system.sgb()) {
|
||||
system._clocksExecuted += clocks;
|
||||
scheduler.exit(Scheduler::Event::Step);
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::timer_262144hz() -> void {
|
||||
if(status.timer_enable && status.timer_clock == 1) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
interrupt_raise(Interrupt::Timer);
|
||||
raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +42,7 @@ auto CPU::timer_65536hz() -> void {
|
||||
if(status.timer_enable && status.timer_clock == 2) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
interrupt_raise(Interrupt::Timer);
|
||||
raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +51,7 @@ auto CPU::timer_16384hz() -> void {
|
||||
if(status.timer_enable && status.timer_clock == 3) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
interrupt_raise(Interrupt::Timer);
|
||||
raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +60,7 @@ auto CPU::timer_8192hz() -> void {
|
||||
if(status.serial_transfer && status.serial_clock) {
|
||||
if(--status.serial_bits == 0) {
|
||||
status.serial_transfer = 0;
|
||||
interrupt_raise(Interrupt::Serial);
|
||||
raise(Interrupt::Serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +69,7 @@ auto CPU::timer_4096hz() -> void {
|
||||
if(status.timer_enable && status.timer_clock == 0) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
interrupt_raise(Interrupt::Timer);
|
||||
raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,22 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
//license: GPLv3
|
||||
//started: 2010-12-27
|
||||
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/lr35902/lr35902.hpp>
|
||||
|
||||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const string Name = "bgb";
|
||||
static const uint SerializerVersion = 4;
|
||||
static const uint SerializerVersion = 5;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bgb - Game Boy, Super Game Boy, and Game Boy Color emulator
|
||||
author: byuu
|
||||
license: GPLv3
|
||||
project started: 2010-12-27
|
||||
*/
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
namespace GameBoy {
|
||||
@@ -27,7 +22,7 @@ namespace GameBoy {
|
||||
|
||||
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
|
||||
if(thread) co_delete(thread);
|
||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||
thread = co_create(65'536 * sizeof(void*), entrypoint);
|
||||
this->frequency = frequency;
|
||||
clock = 0;
|
||||
}
|
||||
|
@@ -25,19 +25,18 @@ Interface::Interface() {
|
||||
|
||||
{
|
||||
Device device{0, ID::Device, "Controller"};
|
||||
device.input.append({0, 0, "Up" });
|
||||
device.input.append({1, 0, "Down" });
|
||||
device.input.append({2, 0, "Left" });
|
||||
device.input.append({3, 0, "Right" });
|
||||
device.input.append({4, 0, "B" });
|
||||
device.input.append({5, 0, "A" });
|
||||
device.input.append({6, 0, "Select"});
|
||||
device.input.append({7, 0, "Start" });
|
||||
device.order = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
this->device.append(device);
|
||||
device.inputs.append({0, 0, "Up" });
|
||||
device.inputs.append({1, 0, "Down" });
|
||||
device.inputs.append({2, 0, "Left" });
|
||||
device.inputs.append({3, 0, "Right" });
|
||||
device.inputs.append({4, 0, "B" });
|
||||
device.inputs.append({5, 0, "A" });
|
||||
device.inputs.append({6, 0, "Select"});
|
||||
device.inputs.append({7, 0, "Start" });
|
||||
devices.append(device);
|
||||
}
|
||||
|
||||
port.append({0, "Device", {device[0]}});
|
||||
ports.append({0, "Device", {devices[0]}});
|
||||
}
|
||||
|
||||
auto Interface::manifest() -> string {
|
||||
@@ -52,6 +51,67 @@ auto Interface::videoFrequency() -> double {
|
||||
return 4194304.0 / (154.0 * 456.0);
|
||||
}
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
return !system.cgb() ? 1 << 2 : 1 << 15;
|
||||
}
|
||||
|
||||
auto Interface::videoColor(uint32 color) -> uint64 {
|
||||
if(!system.cgb()) {
|
||||
if(!settings.colorEmulation) {
|
||||
uint64 L = image::normalize(3 - color, 2, 16);
|
||||
return L << 32 | L << 16 | L << 0;
|
||||
} else {
|
||||
#define DMG_PALETTE_GREEN
|
||||
//#define DMG_PALETTE_YELLOW
|
||||
//#define DMG_PALETTE_WHITE
|
||||
|
||||
const uint16 monochrome[4][3] = {
|
||||
#if defined(DMG_PALETTE_GREEN)
|
||||
{0xaeae, 0xd9d9, 0x2727},
|
||||
{0x5858, 0xa0a0, 0x2828},
|
||||
{0x2020, 0x6262, 0x2929},
|
||||
{0x1a1a, 0x4545, 0x2a2a},
|
||||
#elif defined(DMG_PALETTE_YELLOW)
|
||||
{0xffff, 0xf7f7, 0x7b7b},
|
||||
{0xb5b5, 0xaeae, 0x4a4a},
|
||||
{0x6b6b, 0x6969, 0x3131},
|
||||
{0x2121, 0x2020, 0x1010},
|
||||
#elif defined(DMG_PALETTE_WHITE)
|
||||
{0xffff, 0xffff, 0xffff},
|
||||
{0xaaaa, 0xaaaa, 0xaaaa},
|
||||
{0x5555, 0x5555, 0x5555},
|
||||
{0x0000, 0x0000, 0x0000},
|
||||
#endif
|
||||
};
|
||||
|
||||
uint64 R = monochrome[color][0];
|
||||
uint64 G = monochrome[color][1];
|
||||
uint64 B = monochrome[color][2];
|
||||
|
||||
return R << 32 | G << 16 | B << 0;
|
||||
}
|
||||
} else {
|
||||
uint r = color.bits( 0, 4);
|
||||
uint g = color.bits( 5, 9);
|
||||
uint b = color.bits(10,14);
|
||||
|
||||
uint64_t R = image::normalize(r, 5, 16);
|
||||
uint64_t G = image::normalize(g, 5, 16);
|
||||
uint64_t B = image::normalize(b, 5, 16);
|
||||
|
||||
if(settings.colorEmulation) {
|
||||
R = (r * 26 + g * 4 + b * 2);
|
||||
G = ( g * 24 + b * 8);
|
||||
B = (r * 6 + g * 4 + b * 22);
|
||||
R = image::normalize(min(960, R), 10, 16);
|
||||
G = image::normalize(min(960, G), 10, 16);
|
||||
B = image::normalize(min(960, B), 10, 16);
|
||||
}
|
||||
|
||||
return R << 32 | G << 16 | B << 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::audioFrequency() -> double {
|
||||
return 4194304.0 / 2.0;
|
||||
}
|
||||
@@ -195,8 +255,18 @@ auto Interface::get(const string& name) -> any {
|
||||
}
|
||||
|
||||
auto Interface::set(const string& name, const any& value) -> bool {
|
||||
if(name == "Blur Emulation" && value.is<bool>()) return settings.blurEmulation = value.get<bool>(), true;
|
||||
if(name == "Color Emulation" && value.is<bool>()) return settings.colorEmulation = value.get<bool>(), true;
|
||||
if(name == "Blur Emulation" && value.is<bool>()) {
|
||||
settings.blurEmulation = value.get<bool>();
|
||||
system.configureVideoEffects();
|
||||
return true;
|
||||
}
|
||||
|
||||
if(name == "Color Emulation" && value.is<bool>()) {
|
||||
settings.colorEmulation = value.get<bool>();
|
||||
system.configureVideoPalette();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -30,6 +30,8 @@ struct Interface : Emulator::Interface {
|
||||
auto manifest() -> string;
|
||||
auto title() -> string;
|
||||
auto videoFrequency() -> double;
|
||||
auto videoColors() -> uint32;
|
||||
auto videoColor(uint32 color) -> uint64;
|
||||
auto audioFrequency() -> double;
|
||||
|
||||
auto loaded() -> bool;
|
||||
@@ -67,7 +69,7 @@ struct Interface : Emulator::Interface {
|
||||
auto joypWrite(bool p15, bool p14) -> void;
|
||||
|
||||
private:
|
||||
vector<Device> device;
|
||||
vector<Device> devices;
|
||||
};
|
||||
|
||||
struct Settings {
|
||||
|
@@ -37,6 +37,7 @@ auto PPU::cgb_read_tile(bool select, uint x, uint y, uint& attr, uint& data) ->
|
||||
|
||||
auto PPU::cgb_scanline() -> void {
|
||||
px = 0;
|
||||
if(!enabled()) return;
|
||||
|
||||
const uint Height = (status.ob_size == 0 ? 8 : 16);
|
||||
sprites = 0;
|
||||
@@ -68,7 +69,7 @@ auto PPU::cgb_run() -> void {
|
||||
ob.priority = 0;
|
||||
|
||||
uint color = 0x7fff;
|
||||
if(status.display_enable) {
|
||||
if(enabled()) {
|
||||
cgb_run_bg();
|
||||
if(status.window_display_enable) cgb_run_window();
|
||||
if(status.ob_enable) cgb_run_ob();
|
||||
|
@@ -19,6 +19,7 @@ auto PPU::dmg_read_tile(bool select, uint x, uint y, uint& data) -> void {
|
||||
|
||||
auto PPU::dmg_scanline() -> void {
|
||||
px = 0;
|
||||
if(!enabled()) return;
|
||||
|
||||
const uint Height = (status.ob_size == 0 ? 8 : 16);
|
||||
sprites = 0;
|
||||
@@ -59,7 +60,7 @@ auto PPU::dmg_run() -> void {
|
||||
ob.palette = 0;
|
||||
|
||||
uint color = 0;
|
||||
if(status.display_enable) {
|
||||
if(enabled()) {
|
||||
if(status.bg_enable) dmg_run_bg();
|
||||
if(status.window_display_enable) dmg_run_window();
|
||||
if(status.ob_enable) dmg_run_ob();
|
||||
|
@@ -24,18 +24,12 @@ auto PPU::mmio_read(uint16 addr) -> uint8 {
|
||||
}
|
||||
|
||||
if(addr == 0xff41) { //STAT
|
||||
uint 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);
|
||||
| (status.mode << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff42) { //SCY
|
||||
@@ -145,6 +139,13 @@ auto PPU::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
status.interrupt_oam = data & 0x20;
|
||||
status.interrupt_vblank = data & 0x10;
|
||||
status.interrupt_hblank = data & 0x08;
|
||||
|
||||
//hardware bug: writes to STAT on DMG,SGB during vblank triggers STAT IRQ
|
||||
//note: this behavior isn't entirely correct; more research is needed ...
|
||||
if(!system.cgb() && status.mode == 1) {
|
||||
cpu.raise(CPU::Interrupt::Stat);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -1,21 +1,15 @@
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
//LY = 0-153
|
||||
//Raster = 0-143
|
||||
//Vblank = 144-153
|
||||
|
||||
//LX = 0-455
|
||||
|
||||
namespace GameBoy {
|
||||
|
||||
PPU ppu;
|
||||
#include "video.cpp"
|
||||
|
||||
#include "mmio.cpp"
|
||||
#include "dmg.cpp"
|
||||
#include "cgb.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto PPU::enabled() const -> bool { return status.display_enable; }
|
||||
|
||||
auto PPU::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), ppu.main();
|
||||
}
|
||||
@@ -24,51 +18,65 @@ auto PPU::main() -> void {
|
||||
status.lx = 0;
|
||||
interface->lcdScanline(); //Super Game Boy notification
|
||||
|
||||
if(status.display_enable) {
|
||||
//LYC of zero triggers on LY==153
|
||||
if((status.lyc && status.ly == status.lyc) || (!status.lyc && status.ly == 153)) {
|
||||
if(status.interrupt_lyc) cpu.interrupt_raise(CPU::Interrupt::Stat);
|
||||
}
|
||||
|
||||
if(status.ly <= 143) {
|
||||
scanline();
|
||||
if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat);
|
||||
}
|
||||
|
||||
if(status.ly == 144) {
|
||||
if(status.interrupt_vblank) cpu.interrupt_raise(CPU::Interrupt::Stat);
|
||||
else if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat); //hardware quirk
|
||||
cpu.interrupt_raise(CPU::Interrupt::Vblank);
|
||||
}
|
||||
}
|
||||
|
||||
add_clocks(92);
|
||||
|
||||
if(status.ly <= 143) {
|
||||
mode(2);
|
||||
scanline();
|
||||
wait(92);
|
||||
|
||||
mode(3);
|
||||
for(auto n : range(160)) {
|
||||
if(status.display_enable) run();
|
||||
add_clocks(1);
|
||||
run();
|
||||
wait(1);
|
||||
}
|
||||
|
||||
if(status.display_enable) {
|
||||
if(status.interrupt_hblank) cpu.interrupt_raise(CPU::Interrupt::Stat);
|
||||
cpu.hblank();
|
||||
}
|
||||
mode(0);
|
||||
if(enabled()) cpu.hblank();
|
||||
wait(204);
|
||||
} else {
|
||||
add_clocks(160);
|
||||
mode(1);
|
||||
wait(456);
|
||||
}
|
||||
|
||||
add_clocks(204);
|
||||
status.ly++;
|
||||
|
||||
if(++status.ly == 154) {
|
||||
status.ly = 0;
|
||||
video.refresh();
|
||||
if(status.ly == 144) {
|
||||
if(enabled()) cpu.raise(CPU::Interrupt::Vblank);
|
||||
scheduler.exit(Scheduler::Event::Frame);
|
||||
}
|
||||
|
||||
if(status.ly == 154) {
|
||||
status.ly = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::add_clocks(uint clocks) -> void {
|
||||
auto PPU::mode(uint mode) -> void {
|
||||
status.mode = mode;
|
||||
}
|
||||
|
||||
auto PPU::stat() -> void {
|
||||
bool irq = status.irq;
|
||||
|
||||
status.irq = status.interrupt_hblank && status.mode == 0;
|
||||
status.irq |= status.interrupt_vblank && status.mode == 1;
|
||||
status.irq |= status.interrupt_oam && status.mode == 2;
|
||||
status.irq |= status.interrupt_lyc && coincidence();
|
||||
|
||||
if(!irq && status.irq) cpu.raise(CPU::Interrupt::Stat);
|
||||
}
|
||||
|
||||
auto PPU::coincidence() -> bool {
|
||||
uint ly = status.ly;
|
||||
if(ly == 153 && status.lx >= 92) ly = 0; //LYC=0 triggers early during LY=153
|
||||
return ly == status.lyc;
|
||||
}
|
||||
|
||||
auto PPU::refresh() -> void {
|
||||
if(!system.sgb()) Emulator::video.refresh(screen, 160 * sizeof(uint32), 160, 144);
|
||||
}
|
||||
|
||||
auto PPU::wait(uint clocks) -> void {
|
||||
while(clocks--) {
|
||||
stat();
|
||||
if(status.dma_active) {
|
||||
uint hi = status.dma_clock++;
|
||||
uint lo = hi & (cpu.status.speed_double ? 1 : 3);
|
||||
@@ -92,10 +100,10 @@ auto PPU::add_clocks(uint clocks) -> void {
|
||||
}
|
||||
|
||||
auto PPU::hflip(uint data) const -> uint {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
auto PPU::power() -> void {
|
||||
@@ -141,6 +149,7 @@ auto PPU::power() -> void {
|
||||
for(auto& n : bgpd) n = 0x0000;
|
||||
for(auto& n : obpd) n = 0x0000;
|
||||
|
||||
status.irq = false;
|
||||
status.lx = 0;
|
||||
|
||||
status.display_enable = 0;
|
||||
@@ -156,6 +165,7 @@ auto PPU::power() -> void {
|
||||
status.interrupt_oam = 0;
|
||||
status.interrupt_vblank = 0;
|
||||
status.interrupt_hblank = 0;
|
||||
status.mode = 0;
|
||||
|
||||
status.scy = 0;
|
||||
status.scx = 0;
|
||||
|
@@ -1,9 +1,13 @@
|
||||
#include "video.hpp"
|
||||
|
||||
struct PPU : Thread, MMIO {
|
||||
auto enabled() const -> bool;
|
||||
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto add_clocks(uint clocks) -> void;
|
||||
auto mode(uint) -> void;
|
||||
auto stat() -> void;
|
||||
auto coincidence() -> bool;
|
||||
auto refresh() -> void;
|
||||
auto wait(uint clocks) -> void;
|
||||
|
||||
auto hflip(uint data) const -> uint;
|
||||
|
||||
@@ -43,6 +47,7 @@ struct PPU : Thread, MMIO {
|
||||
function<auto () -> void> run;
|
||||
|
||||
struct Status {
|
||||
bool irq; //STAT IRQ line
|
||||
uint lx;
|
||||
|
||||
//$ff40 LCDC
|
||||
@@ -60,6 +65,7 @@ struct PPU : Thread, MMIO {
|
||||
bool interrupt_oam;
|
||||
bool interrupt_vblank;
|
||||
bool interrupt_hblank;
|
||||
uint2 mode;
|
||||
|
||||
//$ff42 SCY
|
||||
uint8 scy;
|
||||
|
@@ -9,6 +9,7 @@ auto PPU::serialize(serializer& s) -> void {
|
||||
s.array(bgpd);
|
||||
s.array(obpd);
|
||||
|
||||
s.integer(status.irq);
|
||||
s.integer(status.lx);
|
||||
|
||||
s.integer(status.display_enable);
|
||||
@@ -24,6 +25,7 @@ auto PPU::serialize(serializer& s) -> void {
|
||||
s.integer(status.interrupt_oam);
|
||||
s.integer(status.interrupt_vblank);
|
||||
s.integer(status.interrupt_hblank);
|
||||
s.integer(status.mode);
|
||||
|
||||
s.integer(status.scy);
|
||||
s.integer(status.scx);
|
||||
|
@@ -1,105 +0,0 @@
|
||||
Video video;
|
||||
|
||||
Video::Video() {
|
||||
output = new uint32[160 * 144];
|
||||
paletteLiteral = new uint32[1 << 15];
|
||||
paletteStandard = new uint32[1 << 15];
|
||||
paletteEmulation = new uint32[1 << 15];
|
||||
}
|
||||
|
||||
auto Video::power() -> void {
|
||||
memory::fill(output(), 160 * 144 * sizeof(uint32));
|
||||
|
||||
if(system.dmg()) {
|
||||
for(auto color : range(1 << 2)) {
|
||||
paletteLiteral[color] = color;
|
||||
|
||||
uint L = image::normalize(3 - color, 2, 16);
|
||||
paletteStandard[color] = interface->videoColor(L, L, L);
|
||||
|
||||
uint R = monochrome[color][0];
|
||||
uint G = monochrome[color][1];
|
||||
uint B = monochrome[color][2];
|
||||
paletteEmulation[color] = interface->videoColor(R, G, B);
|
||||
}
|
||||
}
|
||||
|
||||
if(system.sgb()) {
|
||||
for(auto color : range(1 << 2)) {
|
||||
paletteLiteral[color] = color;
|
||||
paletteStandard[color] = color;
|
||||
paletteEmulation[color] = color;
|
||||
}
|
||||
}
|
||||
|
||||
if(system.cgb()) {
|
||||
for(auto color : range(1 << 15)) {
|
||||
paletteLiteral[color] = color;
|
||||
|
||||
uint r = (uint5)(color >> 0);
|
||||
uint g = (uint5)(color >> 5);
|
||||
uint b = (uint5)(color >> 10);
|
||||
|
||||
uint R = image::normalize(r, 5, 16);
|
||||
uint G = image::normalize(g, 5, 16);
|
||||
uint B = image::normalize(b, 5, 16);
|
||||
paletteStandard[color] = interface->videoColor(R, G, B);
|
||||
|
||||
R = (r * 26 + g * 4 + b * 2);
|
||||
G = ( g * 24 + b * 8);
|
||||
B = (r * 6 + g * 4 + b * 22);
|
||||
R = image::normalize(min(960, R), 10, 16);
|
||||
G = image::normalize(min(960, G), 10, 16);
|
||||
B = image::normalize(min(960, B), 10, 16);
|
||||
paletteEmulation[color] = interface->videoColor(R, G, B);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Video::refresh() -> void {
|
||||
auto output = this->output();
|
||||
auto& palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
|
||||
|
||||
for(uint y = 0; y < 144; y++) {
|
||||
auto source = ppu.screen + y * 160;
|
||||
auto target = output + y * 160;
|
||||
|
||||
if(settings.blurEmulation) {
|
||||
for(uint x = 0; x < 160; x++) {
|
||||
auto a = palette[*source++];
|
||||
auto b = *target;
|
||||
*target++ = (a + b - ((a ^ b) & 0x01010101)) >> 1;
|
||||
}
|
||||
} else {
|
||||
for(uint x = 0; x < 160; x++) {
|
||||
auto color = palette[*source++];
|
||||
*target++ = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface->videoRefresh(output, 4 * 160, 160, 144);
|
||||
}
|
||||
|
||||
#define DMG_PALETTE_GREEN
|
||||
//#define DMG_PALETTE_YELLOW
|
||||
//#define DMG_PALETTE_WHITE
|
||||
|
||||
const uint16 Video::monochrome[4][3] = {
|
||||
#if defined(DMG_PALETTE_GREEN)
|
||||
{0xaeae, 0xd9d9, 0x2727},
|
||||
{0x5858, 0xa0a0, 0x2828},
|
||||
{0x2020, 0x6262, 0x2929},
|
||||
{0x1a1a, 0x4545, 0x2a2a},
|
||||
#elif defined(DMG_PALETTE_YELLOW)
|
||||
{0xffff, 0xf7f7, 0x7b7b},
|
||||
{0xb5b5, 0xaeae, 0x4a4a},
|
||||
{0x6b6b, 0x6969, 0x3131},
|
||||
{0x2121, 0x2020, 0x1010},
|
||||
#else //DMG_PALETTE_WHITE
|
||||
{0xffff, 0xffff, 0xffff},
|
||||
{0xaaaa, 0xaaaa, 0xaaaa},
|
||||
{0x5555, 0x5555, 0x5555},
|
||||
{0x0000, 0x0000, 0x0000},
|
||||
#endif
|
||||
};
|
@@ -1,16 +0,0 @@
|
||||
struct Video {
|
||||
Video();
|
||||
|
||||
auto power() -> void;
|
||||
auto refresh() -> void;
|
||||
|
||||
private:
|
||||
unique_pointer<uint32[]> output;
|
||||
unique_pointer<uint32[]> paletteLiteral;
|
||||
unique_pointer<uint32[]> paletteStandard;
|
||||
unique_pointer<uint32[]> paletteEmulation;
|
||||
|
||||
static const uint16 monochrome[4][3];
|
||||
};
|
||||
|
||||
extern Video video;
|
@@ -13,6 +13,7 @@ auto Scheduler::enter(Mode mode_) -> Event {
|
||||
mode = mode_;
|
||||
host = co_active();
|
||||
co_switch(resume);
|
||||
if(event == Event::Frame) ppu.refresh();
|
||||
return event;
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace GameBoy {
|
||||
|
||||
#include "video.cpp"
|
||||
#include "serialization.cpp"
|
||||
System system;
|
||||
|
||||
@@ -59,12 +60,21 @@ auto System::unload() -> void {
|
||||
}
|
||||
|
||||
auto System::power() -> void {
|
||||
if(!system.sgb()) {
|
||||
Emulator::video.reset();
|
||||
Emulator::video.setInterface(interface);
|
||||
configureVideoPalette();
|
||||
configureVideoEffects();
|
||||
|
||||
Emulator::audio.reset();
|
||||
Emulator::audio.setInterface(interface);
|
||||
}
|
||||
|
||||
bus.power();
|
||||
cartridge.power();
|
||||
cpu.power();
|
||||
ppu.power();
|
||||
apu.power();
|
||||
video.power();
|
||||
scheduler.power();
|
||||
|
||||
_clocksExecuted = 0;
|
||||
|
@@ -29,6 +29,10 @@ struct System {
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
|
||||
//video.cpp
|
||||
auto configureVideoPalette() -> void;
|
||||
auto configureVideoEffects() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize() -> serializer;
|
||||
auto unserialize(serializer&) -> bool;
|
||||
|
9
higan/gb/system/video.cpp
Normal file
9
higan/gb/system/video.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
auto System::configureVideoPalette() -> void {
|
||||
if(sgb()) return;
|
||||
Emulator::video.setPalette();
|
||||
}
|
||||
|
||||
auto System::configureVideoEffects() -> void {
|
||||
if(sgb()) return;
|
||||
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
|
||||
}
|
@@ -63,7 +63,7 @@ auto APU::main() -> void {
|
||||
if(regs.bias.amplitude == 3) lsample &= ~15, rsample &= ~15;
|
||||
|
||||
if(cpu.regs.mode == CPU::Registers::Mode::Stop) lsample = 0, rsample = 0;
|
||||
interface->audioSample(sclamp<16>(lsample << 6), sclamp<16>(rsample << 6)); //should be <<5, use <<6 for added volume
|
||||
stream->sample(sclamp<16>(lsample << 6) / 32768.0, sclamp<16>(rsample << 6) / 32768.0); //should be <<5; use <<6 for added volume
|
||||
step(512);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ auto APU::step(uint clocks) -> void {
|
||||
|
||||
auto APU::power() -> void {
|
||||
create(APU::Enter, 16'777'216);
|
||||
stream = Emulator::audio.createStream(2, 16'777'216.0 / 512.0);
|
||||
|
||||
square1.power();
|
||||
square2.power();
|
||||
|
@@ -1,4 +1,6 @@
|
||||
struct APU : Thread, MMIO {
|
||||
shared_pointer<Emulator::Stream> stream;
|
||||
|
||||
#include "registers.hpp"
|
||||
|
||||
static auto Enter() -> void;
|
||||
|
@@ -1,10 +1,10 @@
|
||||
auto CPU::bus_idle() -> void {
|
||||
auto CPU::busIdle() -> void {
|
||||
prefetch_step(1);
|
||||
}
|
||||
|
||||
auto CPU::bus_read(unsigned mode, uint32 addr) -> uint32 {
|
||||
unsigned wait = bus_wait(mode, addr);
|
||||
unsigned word = pipeline.fetch.instruction;
|
||||
auto CPU::busRead(uint mode, uint32 addr) -> uint32 {
|
||||
uint wait = busWait(mode, addr);
|
||||
uint word = pipeline.fetch.instruction;
|
||||
|
||||
if(addr >= 0x1000'0000) {
|
||||
prefetch_step(wait);
|
||||
@@ -35,8 +35,8 @@ auto CPU::bus_read(unsigned mode, uint32 addr) -> uint32 {
|
||||
return word;
|
||||
}
|
||||
|
||||
auto CPU::bus_write(unsigned mode, uint32 addr, uint32 word) -> void {
|
||||
unsigned wait = bus_wait(mode, addr);
|
||||
auto CPU::busWrite(uint mode, uint32 addr, uint32 word) -> void {
|
||||
uint wait = busWait(mode, addr);
|
||||
|
||||
if(addr >= 0x1000'0000) {
|
||||
prefetch_step(wait);
|
||||
@@ -57,7 +57,7 @@ auto CPU::bus_write(unsigned mode, uint32 addr, uint32 word) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::bus_wait(unsigned mode, uint32 addr) -> unsigned {
|
||||
auto CPU::busWait(uint mode, uint32 addr) -> uint {
|
||||
if(addr >= 0x1000'0000) return 1; //unmapped
|
||||
if(addr < 0x0200'0000) return 1;
|
||||
if(addr < 0x0300'0000) return (16 - regs.memory.control.ewramwait) * (mode & Word ? 2 : 1);
|
||||
@@ -65,9 +65,9 @@ auto CPU::bus_wait(unsigned mode, uint32 addr) -> unsigned {
|
||||
if(addr < 0x0700'0000) return mode & Word ? 2 : 1;
|
||||
if(addr < 0x0800'0000) return 1;
|
||||
|
||||
static unsigned timings[] = {5, 4, 3, 9};
|
||||
unsigned n = timings[regs.wait.control.nwait[addr >> 25 & 3]];
|
||||
unsigned s = regs.wait.control.swait[addr >> 25 & 3];
|
||||
static uint timings[] = {5, 4, 3, 9};
|
||||
uint n = timings[regs.wait.control.nwait[addr >> 25 & 3]];
|
||||
uint s = regs.wait.control.swait[addr >> 25 & 3];
|
||||
|
||||
switch(addr & 0x0e00'0000) {
|
||||
case 0x0800'0000: s = s ? 2 : 3; break;
|
||||
@@ -79,7 +79,7 @@ auto CPU::bus_wait(unsigned mode, uint32 addr) -> unsigned {
|
||||
bool sequential = (mode & Sequential);
|
||||
if((addr & 0x1fffe) == 0) sequential = false; //N cycle on 16-bit ROM crossing 128KB page boundary (RAM S==N)
|
||||
|
||||
unsigned clocks = sequential ? s : n;
|
||||
uint clocks = sequential ? s : n;
|
||||
if(mode & Word) clocks += s; //16-bit bus requires two transfers for words
|
||||
return clocks;
|
||||
}
|
||||
|
@@ -91,12 +91,15 @@ auto CPU::sync_step(uint clocks) -> void {
|
||||
}
|
||||
|
||||
auto CPU::keypad_run() -> void {
|
||||
if(regs.keypad.control.enable == false) return;
|
||||
//lookup table to convert button indexes to Emulator::Interface indexes
|
||||
static const uint lookup[] = {5, 4, 8, 9, 3, 2, 0, 1, 7, 6};
|
||||
|
||||
if(!regs.keypad.control.enable) return;
|
||||
|
||||
bool test = regs.keypad.control.condition; //0 = OR, 1 = AND
|
||||
for(auto n : range(10)) {
|
||||
if(regs.keypad.control.flag[n] == false) continue;
|
||||
bool input = interface->inputPoll(0, 0, n);
|
||||
if(!regs.keypad.control.flag[n]) continue;
|
||||
bool input = interface->inputPoll(0, 0, lookup[n]);
|
||||
if(regs.keypad.control.condition == 0) test |= input;
|
||||
if(regs.keypad.control.condition == 1) test &= input;
|
||||
}
|
||||
|
@@ -39,10 +39,10 @@ struct CPU : Processor::ARM, Thread, MMIO {
|
||||
auto power() -> void;
|
||||
|
||||
//bus.cpp
|
||||
auto bus_idle() -> void override;
|
||||
auto bus_read(uint mode, uint32 addr) -> uint32 override;
|
||||
auto bus_write(uint mode, uint32 addr, uint32 word) -> void override;
|
||||
auto bus_wait(uint mode, uint32 addr) -> uint;
|
||||
auto busIdle() -> void override;
|
||||
auto busRead(uint mode, uint32 addr) -> uint32 override;
|
||||
auto busWrite(uint mode, uint32 addr, uint32 word) -> void override;
|
||||
auto busWait(uint mode, uint32 addr) -> uint;
|
||||
|
||||
//mmio.cpp
|
||||
auto read(uint32 addr) -> uint8;
|
||||
|
@@ -39,7 +39,7 @@ auto CPU::dma_exec(Registers::DMA& dma) -> void {
|
||||
uint32 addr = dma.run.source;
|
||||
if(mode & Word) addr &= ~3;
|
||||
if(mode & Half) addr &= ~1;
|
||||
dma.data = bus_read(mode, addr);
|
||||
dma.data = busRead(mode, addr);
|
||||
}
|
||||
|
||||
if(dma.run.target < 0x0200'0000) {
|
||||
@@ -48,7 +48,7 @@ auto CPU::dma_exec(Registers::DMA& dma) -> void {
|
||||
uint32 addr = dma.run.target;
|
||||
if(mode & Word) addr &= ~3;
|
||||
if(mode & Half) addr &= ~1;
|
||||
bus_write(mode, addr, dma.data);
|
||||
busWrite(mode, addr, dma.data);
|
||||
}
|
||||
|
||||
switch(dma.control.sourcemode) {
|
||||
|
@@ -61,9 +61,10 @@ auto CPU::read(uint32 addr) -> uint8 {
|
||||
|
||||
//KEYINPUT
|
||||
case 0x04000130: {
|
||||
static const uint lookup[] = {5, 4, 8, 9, 3, 2, 0, 1};
|
||||
if(auto result = player.keyinput()) return result() >> 0;
|
||||
uint8 result = 0;
|
||||
for(uint n = 0; n < 8; n++) result |= interface->inputPoll(0, 0, n) << n;
|
||||
for(uint n = 0; n < 8; n++) result |= interface->inputPoll(0, 0, lookup[n]) << n;
|
||||
if((result & 0xc0) == 0xc0) result &= (uint8)~0xc0; //up+down cannot be pressed simultaneously
|
||||
if((result & 0x30) == 0x30) result &= (uint8)~0x30; //left+right cannot be pressed simultaneously
|
||||
return result ^ 0xff;
|
||||
@@ -71,8 +72,8 @@ auto CPU::read(uint32 addr) -> uint8 {
|
||||
case 0x04000131: {
|
||||
if(auto result = player.keyinput()) return result() >> 8;
|
||||
uint8 result = 0;
|
||||
result |= interface->inputPoll(0, 0, 8) << 0;
|
||||
result |= interface->inputPoll(0, 0, 9) << 1;
|
||||
result |= interface->inputPoll(0, 0, 7) << 0;
|
||||
result |= interface->inputPoll(0, 0, 6) << 1;
|
||||
return result ^ 0x03;
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,7 @@ auto CPU::prefetch_sync(uint32 addr) -> void {
|
||||
|
||||
prefetch.addr = addr;
|
||||
prefetch.load = addr;
|
||||
prefetch.wait = bus_wait(Half | Nonsequential, prefetch.load);
|
||||
prefetch.wait = busWait(Half | Nonsequential, prefetch.load);
|
||||
}
|
||||
|
||||
auto CPU::prefetch_step(uint clocks) -> void {
|
||||
@@ -14,7 +14,7 @@ auto CPU::prefetch_step(uint clocks) -> void {
|
||||
if(--prefetch.wait) continue;
|
||||
prefetch.slot[prefetch.load >> 1 & 7] = cartridge.read(Half, prefetch.load);
|
||||
prefetch.load += 2;
|
||||
prefetch.wait = bus_wait(Half | Sequential, prefetch.load);
|
||||
prefetch.wait = busWait(Half | Sequential, prefetch.load);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,14 @@ auto CPU::prefetch_wait() -> void {
|
||||
if(!regs.wait.control.prefetch || active.dma || prefetch.full()) return;
|
||||
|
||||
prefetch_step(prefetch.wait);
|
||||
prefetch.wait = bus_wait(Half | Nonsequential, prefetch.load);
|
||||
prefetch.wait = busWait(Half | Nonsequential, prefetch.load);
|
||||
}
|
||||
|
||||
auto CPU::prefetch_read() -> uint16 {
|
||||
if(prefetch.empty()) prefetch_step(prefetch.wait);
|
||||
else prefetch_step(1);
|
||||
|
||||
if(prefetch.full()) prefetch.wait = bus_wait(Half | Sequential, prefetch.load);
|
||||
if(prefetch.full()) prefetch.wait = busWait(Half | Sequential, prefetch.load);
|
||||
|
||||
uint16 half = prefetch.slot[prefetch.addr >> 1 & 7];
|
||||
prefetch.addr += 2;
|
||||
|
@@ -1,22 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
//license: GPLv3
|
||||
//started: 2012-03-19
|
||||
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/arm/arm.hpp>
|
||||
|
||||
namespace GameBoyAdvance {
|
||||
namespace Info {
|
||||
static const string Name = "bgba";
|
||||
static const uint SerializerVersion = 3;
|
||||
static const uint SerializerVersion = 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bgba - Game Boy Advance emulator
|
||||
authors: byuu, Cydrak
|
||||
license: GPLv3
|
||||
project started: 2012-03-19
|
||||
*/
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
namespace GameBoyAdvance {
|
||||
@@ -39,7 +34,7 @@ namespace GameBoyAdvance {
|
||||
|
||||
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
|
||||
if(thread) co_delete(thread);
|
||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||
thread = co_create(65'536 * sizeof(void*), entrypoint);
|
||||
this->frequency = frequency;
|
||||
clock = 0;
|
||||
}
|
||||
|
@@ -22,22 +22,21 @@ Interface::Interface() {
|
||||
media.append({ID::GameBoyAdvance, "Game Boy Advance", "gba", true});
|
||||
|
||||
{ Device device{0, ID::Device, "Controller"};
|
||||
device.input.append({ 0, 0, "A" });
|
||||
device.input.append({ 1, 0, "B" });
|
||||
device.input.append({ 2, 0, "Select"});
|
||||
device.input.append({ 3, 0, "Start" });
|
||||
device.input.append({ 4, 0, "Right" });
|
||||
device.input.append({ 5, 0, "Left" });
|
||||
device.input.append({ 6, 0, "Up" });
|
||||
device.input.append({ 7, 0, "Down" });
|
||||
device.input.append({ 8, 0, "R" });
|
||||
device.input.append({ 9, 0, "L" });
|
||||
device.input.append({10, 2, "Rumble"});
|
||||
device.order = {6, 7, 5, 4, 1, 0, 9, 8, 2, 3, 10};
|
||||
this->device.append(device);
|
||||
device.inputs.append({ 0, 0, "Up" });
|
||||
device.inputs.append({ 1, 0, "Down" });
|
||||
device.inputs.append({ 2, 0, "Left" });
|
||||
device.inputs.append({ 3, 0, "Right" });
|
||||
device.inputs.append({ 4, 0, "B" });
|
||||
device.inputs.append({ 5, 0, "A" });
|
||||
device.inputs.append({ 6, 0, "L" });
|
||||
device.inputs.append({ 7, 0, "R" });
|
||||
device.inputs.append({ 8, 0, "Select"});
|
||||
device.inputs.append({ 9, 0, "Start" });
|
||||
device.inputs.append({10, 2, "Rumble"});
|
||||
devices.append(device);
|
||||
}
|
||||
|
||||
port.append({0, "Device", {device[0]}});
|
||||
ports.append({0, "Device", {devices[0]}});
|
||||
}
|
||||
|
||||
auto Interface::manifest() -> string {
|
||||
@@ -52,6 +51,32 @@ auto Interface::videoFrequency() -> double {
|
||||
return 16777216.0 / (228.0 * 1232.0);
|
||||
}
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
return 1 << 15;
|
||||
}
|
||||
|
||||
auto Interface::videoColor(uint32 color) -> uint64 {
|
||||
uint R = color.bits( 0, 4);
|
||||
uint G = color.bits( 5, 9);
|
||||
uint B = color.bits(10,14);
|
||||
|
||||
uint64 r = image::normalize(R, 5, 16);
|
||||
uint64 g = image::normalize(G, 5, 16);
|
||||
uint64 b = image::normalize(B, 5, 16);
|
||||
|
||||
if(settings.colorEmulation) {
|
||||
double lcdGamma = 4.0, outGamma = 2.2;
|
||||
double lb = pow(B / 31.0, lcdGamma);
|
||||
double lg = pow(G / 31.0, lcdGamma);
|
||||
double lr = pow(R / 31.0, lcdGamma);
|
||||
r = pow(( 0 * lb + 50 * lg + 255 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
|
||||
g = pow(( 30 * lb + 230 * lg + 10 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
|
||||
b = pow((220 * lb + 10 * lg + 50 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
|
||||
}
|
||||
|
||||
return r << 32 | g << 16 | b << 0;
|
||||
}
|
||||
|
||||
auto Interface::audioFrequency() -> double {
|
||||
return 16777216.0 / 512.0;
|
||||
}
|
||||
@@ -169,8 +194,18 @@ auto Interface::get(const string& name) -> any {
|
||||
}
|
||||
|
||||
auto Interface::set(const string& name, const any& value) -> bool {
|
||||
if(name == "Blur Emulation" && value.is<bool>()) return settings.blurEmulation = value.get<bool>(), true;
|
||||
if(name == "Color Emulation" && value.is<bool>()) return settings.colorEmulation = value.get<bool>(), true;
|
||||
if(name == "Blur Emulation" && value.is<bool>()) {
|
||||
settings.blurEmulation = value.get<bool>();
|
||||
system.configureVideoEffects();
|
||||
return true;
|
||||
}
|
||||
|
||||
if(name == "Color Emulation" && value.is<bool>()) {
|
||||
settings.colorEmulation = value.get<bool>();
|
||||
system.configureVideoPalette();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -28,6 +28,8 @@ struct Interface : Emulator::Interface {
|
||||
auto manifest() -> string;
|
||||
auto title() -> string;
|
||||
auto videoFrequency() -> double;
|
||||
auto videoColors() -> uint32;
|
||||
auto videoColor(uint32 color) -> uint64;
|
||||
auto audioFrequency() -> double;
|
||||
|
||||
auto loaded() -> bool;
|
||||
@@ -50,7 +52,7 @@ struct Interface : Emulator::Interface {
|
||||
auto set(const string& name, const any& value) -> bool override;
|
||||
|
||||
private:
|
||||
vector<Device> device;
|
||||
vector<Device> devices;
|
||||
};
|
||||
|
||||
struct Settings {
|
||||
|
@@ -13,8 +13,6 @@
|
||||
namespace GameBoyAdvance {
|
||||
|
||||
PPU ppu;
|
||||
#include "video.cpp"
|
||||
|
||||
#include "background.cpp"
|
||||
#include "object.cpp"
|
||||
#include "mosaic.cpp"
|
||||
@@ -180,8 +178,11 @@ auto PPU::scanline() -> void {
|
||||
|
||||
auto PPU::frame() -> void {
|
||||
player.frame();
|
||||
video.refresh();
|
||||
scheduler.exit(Scheduler::Event::Frame);
|
||||
}
|
||||
|
||||
auto PPU::refresh() -> void {
|
||||
Emulator::video.refresh(output, 240 * sizeof(uint32), 240, 160);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
#include "video.hpp"
|
||||
|
||||
struct PPU : Thread, MMIO {
|
||||
#include "registers.hpp"
|
||||
#include "state.hpp"
|
||||
@@ -14,6 +12,7 @@ struct PPU : Thread, MMIO {
|
||||
auto power() -> void;
|
||||
auto scanline() -> void;
|
||||
auto frame() -> void;
|
||||
auto refresh() -> void;
|
||||
|
||||
auto read(uint32 addr) -> uint8;
|
||||
auto write(uint32 addr, uint8 byte) -> void;
|
||||
|
@@ -1,59 +0,0 @@
|
||||
Video video;
|
||||
|
||||
Video::Video() {
|
||||
output = new uint32[240 * 160];
|
||||
paletteLiteral = new uint32[1 << 15];
|
||||
paletteStandard = new uint32[1 << 15];
|
||||
paletteEmulation = new uint32[1 << 15];
|
||||
}
|
||||
|
||||
auto Video::power() -> void {
|
||||
memory::fill(output(), 240 * 160 * sizeof(uint32));
|
||||
|
||||
for(auto color : range(1 << 15)) {
|
||||
paletteLiteral[color] = color;
|
||||
|
||||
uint B = (uint5)(color >> 10);
|
||||
uint G = (uint5)(color >> 5);
|
||||
uint R = (uint5)(color >> 0);
|
||||
|
||||
uint b = image::normalize(B, 5, 16);
|
||||
uint g = image::normalize(G, 5, 16);
|
||||
uint r = image::normalize(R, 5, 16);
|
||||
paletteStandard[color] = interface->videoColor(r, g, b);
|
||||
|
||||
double lcdGamma = 4.0, outGamma = 2.2;
|
||||
double lb = pow(B / 31.0, lcdGamma);
|
||||
double lg = pow(G / 31.0, lcdGamma);
|
||||
double lr = pow(R / 31.0, lcdGamma);
|
||||
b = pow((220 * lb + 10 * lg + 50 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
|
||||
g = pow(( 30 * lb + 230 * lg + 10 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
|
||||
r = pow(( 0 * lb + 50 * lg + 255 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
|
||||
paletteEmulation[color] = interface->videoColor(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
auto Video::refresh() -> void {
|
||||
auto output = this->output();
|
||||
auto& palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
|
||||
|
||||
for(uint y = 0; y < 160; y++) {
|
||||
auto source = ppu.output + y * 240;
|
||||
auto target = output + y * 240;
|
||||
|
||||
if(settings.blurEmulation) {
|
||||
for(uint x = 0; x < 240; x++) {
|
||||
auto a = palette[*source++];
|
||||
auto b = *target;
|
||||
*target++ = (a + b - ((a ^ b) & 0x01010101)) >> 1;
|
||||
}
|
||||
} else {
|
||||
for(uint x = 0; x < 240; x++) {
|
||||
auto color = palette[*source++];
|
||||
*target++ = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface->videoRefresh(output, 240 * sizeof(uint32), 240, 160);
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
struct Video {
|
||||
Video();
|
||||
|
||||
auto power() -> void;
|
||||
auto refresh() -> void;
|
||||
|
||||
unique_pointer<uint32[]> output;
|
||||
unique_pointer<uint32[]> paletteLiteral;
|
||||
unique_pointer<uint32[]> paletteStandard;
|
||||
unique_pointer<uint32[]> paletteEmulation;
|
||||
};
|
||||
|
||||
extern Video video;
|
@@ -13,6 +13,7 @@ auto Scheduler::enter(Mode mode_) -> Event {
|
||||
mode = mode_;
|
||||
host = co_active();
|
||||
co_switch(resume);
|
||||
if(event == Event::Frame) ppu.refresh();
|
||||
return event;
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace GameBoyAdvance {
|
||||
|
||||
#include "bios.cpp"
|
||||
#include "video.cpp"
|
||||
#include "serialization.cpp"
|
||||
BIOS bios;
|
||||
System system;
|
||||
@@ -16,13 +17,20 @@ auto System::term() -> void {
|
||||
}
|
||||
|
||||
auto System::power() -> void {
|
||||
Emulator::video.reset();
|
||||
Emulator::video.setInterface(interface);
|
||||
configureVideoPalette();
|
||||
configureVideoEffects();
|
||||
|
||||
Emulator::audio.reset();
|
||||
Emulator::audio.setInterface(interface);
|
||||
|
||||
bus.power();
|
||||
player.power();
|
||||
cpu.power();
|
||||
ppu.power();
|
||||
apu.power();
|
||||
cartridge.power();
|
||||
video.power();
|
||||
scheduler.power();
|
||||
}
|
||||
|
||||
|
@@ -25,6 +25,11 @@ struct System {
|
||||
auto run() -> void;
|
||||
auto runToSave() -> void;
|
||||
|
||||
//video.cpp
|
||||
auto configureVideoPalette() -> void;
|
||||
auto configureVideoEffects() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize() -> serializer;
|
||||
auto unserialize(serializer&) -> bool;
|
||||
|
||||
|
7
higan/gba/system/video.cpp
Normal file
7
higan/gba/system/video.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
auto System::configureVideoPalette() -> void {
|
||||
Emulator::video.setPalette();
|
||||
}
|
||||
|
||||
auto System::configureVideoEffects() -> void {
|
||||
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
|
||||
}
|
@@ -31,16 +31,16 @@ auto ARM::exec() -> void {
|
||||
|
||||
auto ARM::idle() -> void {
|
||||
pipeline.nonsequential = true;
|
||||
return bus_idle();
|
||||
return busIdle();
|
||||
}
|
||||
|
||||
auto ARM::read(unsigned mode, uint32 addr) -> uint32 {
|
||||
return bus_read(mode, addr);
|
||||
return busRead(mode, addr);
|
||||
}
|
||||
|
||||
auto ARM::load(unsigned mode, uint32 addr) -> uint32 {
|
||||
pipeline.nonsequential = true;
|
||||
uint32 word = bus_read(Load | mode, addr);
|
||||
uint32 word = busRead(Load | mode, addr);
|
||||
|
||||
if(mode & Half) {
|
||||
addr &= 1;
|
||||
@@ -64,7 +64,7 @@ auto ARM::load(unsigned mode, uint32 addr) -> uint32 {
|
||||
|
||||
auto ARM::write(unsigned mode, uint32 addr, uint32 word) -> void {
|
||||
pipeline.nonsequential = true;
|
||||
return bus_write(mode, addr, word);
|
||||
return busWrite(mode, addr, word);
|
||||
}
|
||||
|
||||
auto ARM::store(unsigned mode, uint32 addr, uint32 word) -> void {
|
||||
@@ -73,7 +73,7 @@ auto ARM::store(unsigned mode, uint32 addr, uint32 word) -> void {
|
||||
if(mode & Half) { word &= 0xffff; word |= word << 16; }
|
||||
if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
||||
|
||||
return bus_write(Store | mode, addr, word);
|
||||
return busWrite(Store | mode, addr, word);
|
||||
}
|
||||
|
||||
auto ARM::vector(uint32 addr, Processor::Mode mode) -> void {
|
||||
|
@@ -25,9 +25,9 @@ struct ARM {
|
||||
#include "disassembler.hpp"
|
||||
|
||||
virtual auto step(unsigned clocks) -> void = 0;
|
||||
virtual auto bus_idle() -> void = 0;
|
||||
virtual auto bus_read(unsigned mode, uint32 addr) -> uint32 = 0;
|
||||
virtual auto bus_write(unsigned mode, uint32 addr, uint32 word) -> void = 0;
|
||||
virtual auto busIdle() -> void = 0;
|
||||
virtual auto busRead(unsigned mode, uint32 addr) -> uint32 = 0;
|
||||
virtual auto busWrite(unsigned mode, uint32 addr, uint32 word) -> void = 0;
|
||||
|
||||
//arm.cpp
|
||||
auto power() -> void;
|
||||
|
@@ -406,7 +406,7 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
||||
output.append(load ? "ldm" : "stm", conditions[condition], indices[index], " ");
|
||||
output.append(registers[rn], writeback ? "!" : "", ",{");
|
||||
for(unsigned n = 0; n < 16; n++) if(list & (1 << n)) output.append(registers[n], ",");
|
||||
output.rtrim(",");
|
||||
output.trimRight(",", 1L);
|
||||
output.append("}", s ? "^" : "");
|
||||
|
||||
return output;
|
||||
@@ -679,7 +679,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
||||
if(list & (1 << l)) output.append(registers[l], ",");
|
||||
}
|
||||
if(branch) output.append(load == 0 ? "lr," : "pc,");
|
||||
output.rtrim(",");
|
||||
output.trimRight(",", 1L);
|
||||
output.append("}");
|
||||
|
||||
return output;
|
||||
@@ -696,7 +696,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
||||
for(unsigned l = 0; l < 8; l++) {
|
||||
if(list & (1 << l)) output.append(registers[l], ",");
|
||||
}
|
||||
output.rtrim(",");
|
||||
output.trimRight(",", 1L);
|
||||
output.append("}");
|
||||
|
||||
return output;
|
||||
|
@@ -27,7 +27,7 @@ auto ARM::arm_opcode(uint32 rm) {
|
||||
|
||||
if(exceptionMode() && d == 15 && save) {
|
||||
cpsr() = spsr();
|
||||
processor.setMode((Processor::Mode)cpsr().m);
|
||||
processor.setMode((Processor::Mode)(uint)cpsr().m);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ auto ARM::arm_move_to_status(uint32 rm) {
|
||||
psr.f = rm & 0x00000040;
|
||||
psr.t = rm & 0x00000020;
|
||||
psr.m = rm & 0x0000001f;
|
||||
if(source == 0) processor.setMode((Processor::Mode)psr.m);
|
||||
if(source == 0) processor.setMode((Processor::Mode)(uint)psr.m);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,7 +548,7 @@ auto ARM::arm_op_move_multiple() {
|
||||
if(s && (list & 0x8000)) {
|
||||
if(mode() != Processor::Mode::USR && mode() != Processor::Mode::SYS) {
|
||||
cpsr() = spsr();
|
||||
processor.setMode((Processor::Mode)cpsr().m);
|
||||
processor.setMode((Processor::Mode)(uint)cpsr().m);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@@ -19,33 +19,24 @@ struct GPR {
|
||||
};
|
||||
|
||||
struct PSR {
|
||||
inline operator uint32_t() const {
|
||||
return (n << 31) + (z << 30) + (c << 29) + (v << 28)
|
||||
+ (i << 7) + (f << 6) + (t << 5) + (m << 0);
|
||||
}
|
||||
union {
|
||||
uint32_t data = 0;
|
||||
BitField<uint32_t, 31> n; //negative
|
||||
BitField<uint32_t, 30> z; //zero
|
||||
BitField<uint32_t, 29> c; //carry
|
||||
BitField<uint32_t, 28> v; //overflow
|
||||
BitField<uint32_t, 7> i; //irq
|
||||
BitField<uint32_t, 6> f; //fiq
|
||||
BitField<uint32_t, 5> t; //thumb
|
||||
BitField<uint32_t, 4, 0> m; //mode
|
||||
};
|
||||
|
||||
inline auto operator=(uint32_t d) {
|
||||
n = d & (1 << 31);
|
||||
z = d & (1 << 30);
|
||||
c = d & (1 << 29);
|
||||
v = d & (1 << 28);
|
||||
i = d & (1 << 7);
|
||||
f = d & (1 << 6);
|
||||
t = d & (1 << 5);
|
||||
m = d & 31;
|
||||
return *this;
|
||||
}
|
||||
PSR() = default;
|
||||
PSR(const PSR& value) { data = value.data; }
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool n = false; //negative
|
||||
bool z = false; //zero
|
||||
bool c = false; //carry
|
||||
bool v = false; //overflow
|
||||
bool i = false; //irq
|
||||
bool f = false; //fiq
|
||||
bool t = false; //thumb
|
||||
uint m = 0; //mode
|
||||
inline operator uint() const { return data & 0xf00000ff; }
|
||||
inline auto& operator=(uint value) { return data = value, *this; }
|
||||
inline auto& operator=(const PSR& value) { return data = value.data, *this; }
|
||||
};
|
||||
|
||||
struct Pipeline {
|
||||
@@ -125,6 +116,6 @@ alwaysinline auto cpsr() -> PSR& { return processor.cpsr; }
|
||||
alwaysinline auto spsr() -> PSR& { return *processor.spsr; }
|
||||
alwaysinline auto carryout() -> bool& { return processor.carryout; }
|
||||
alwaysinline auto instruction() -> uint32 { return pipeline.execute.instruction; }
|
||||
alwaysinline auto mode() -> Processor::Mode { return (Processor::Mode)processor.cpsr.m; }
|
||||
alwaysinline auto privilegedMode() const -> bool { return (Processor::Mode)processor.cpsr.m != Processor::Mode::USR; }
|
||||
alwaysinline auto exceptionMode() const -> bool { return privilegedMode() && (Processor::Mode)processor.cpsr.m != Processor::Mode::SYS; }
|
||||
alwaysinline auto mode() -> Processor::Mode { return (Processor::Mode)(uint)processor.cpsr.m; }
|
||||
alwaysinline auto privilegedMode() const -> bool { return (Processor::Mode)(uint)processor.cpsr.m != Processor::Mode::USR; }
|
||||
alwaysinline auto exceptionMode() const -> bool { return privilegedMode() && (Processor::Mode)(uint)processor.cpsr.m != Processor::Mode::SYS; }
|
||||
|
@@ -1,14 +1,3 @@
|
||||
auto ARM::PSR::serialize(serializer& s) -> void {
|
||||
s.integer(n);
|
||||
s.integer(z);
|
||||
s.integer(c);
|
||||
s.integer(v);
|
||||
s.integer(i);
|
||||
s.integer(f);
|
||||
s.integer(t);
|
||||
s.integer(m);
|
||||
}
|
||||
|
||||
auto ARM::serialize(serializer& s) -> void {
|
||||
s.integer(processor.r0.data);
|
||||
s.integer(processor.r1.data);
|
||||
@@ -34,26 +23,26 @@ auto ARM::serialize(serializer& s) -> void {
|
||||
s.integer(processor.fiq.r12.data);
|
||||
s.integer(processor.fiq.sp.data);
|
||||
s.integer(processor.fiq.lr.data);
|
||||
processor.fiq.spsr.serialize(s);
|
||||
s.integer(processor.fiq.spsr.data);
|
||||
|
||||
s.integer(processor.irq.sp.data);
|
||||
s.integer(processor.irq.lr.data);
|
||||
processor.irq.spsr.serialize(s);
|
||||
s.integer(processor.irq.spsr.data);
|
||||
|
||||
s.integer(processor.svc.sp.data);
|
||||
s.integer(processor.svc.lr.data);
|
||||
processor.svc.spsr.serialize(s);
|
||||
s.integer(processor.svc.spsr.data);
|
||||
|
||||
s.integer(processor.abt.sp.data);
|
||||
s.integer(processor.abt.lr.data);
|
||||
processor.abt.spsr.serialize(s);
|
||||
s.integer(processor.abt.spsr.data);
|
||||
|
||||
s.integer(processor.und.sp.data);
|
||||
s.integer(processor.und.lr.data);
|
||||
processor.und.spsr.serialize(s);
|
||||
s.integer(processor.und.spsr.data);
|
||||
|
||||
s.integer(processor.pc.data);
|
||||
processor.cpsr.serialize(s);
|
||||
s.integer(processor.cpsr.data);
|
||||
s.integer(processor.carryout);
|
||||
s.integer(processor.irqline);
|
||||
|
||||
@@ -68,5 +57,5 @@ auto ARM::serialize(serializer& s) -> void {
|
||||
|
||||
s.integer(crash);
|
||||
|
||||
processor.setMode((Processor::Mode)cpsr().m);
|
||||
processor.setMode((Processor::Mode)(uint)cpsr().m);
|
||||
}
|
||||
|
@@ -1,21 +1,14 @@
|
||||
auto GSU::disassemble_opcode(char* output) -> void {
|
||||
auto GSU::disassembleOpcode(char* output) -> void {
|
||||
*output = 0;
|
||||
|
||||
if(!regs.sfr.alt2) {
|
||||
if(!regs.sfr.alt1) {
|
||||
disassemble_alt0(output);
|
||||
} else {
|
||||
disassemble_alt1(output);
|
||||
}
|
||||
} else {
|
||||
if(!regs.sfr.alt1) {
|
||||
disassemble_alt2(output);
|
||||
} else {
|
||||
disassemble_alt3(output);
|
||||
}
|
||||
switch(regs.sfr.alt2 << 1 | regs.sfr.alt1 << 0) {
|
||||
case 0: disassembleAlt0(output); break;
|
||||
case 1: disassembleAlt1(output); break;
|
||||
case 2: disassembleAlt2(output); break;
|
||||
case 3: disassembleAlt3(output); break;
|
||||
}
|
||||
|
||||
unsigned length = strlen(output);
|
||||
uint length = strlen(output);
|
||||
while(length++ < 20) strcat(output, " ");
|
||||
}
|
||||
|
||||
@@ -34,10 +27,10 @@ auto GSU::disassemble_opcode(char* output) -> void {
|
||||
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14: case id+15
|
||||
|
||||
#define op0 regs.pipeline
|
||||
#define op1 bus_read((regs.pbr << 16) + regs.r[15] + 0)
|
||||
#define op2 bus_read((regs.pbr << 16) + regs.r[15] + 1)
|
||||
#define op1 read((regs.pbr << 16) + regs.r[15] + 0)
|
||||
#define op2 read((regs.pbr << 16) + regs.r[15] + 1)
|
||||
|
||||
auto GSU::disassemble_alt0(char* output) -> void {
|
||||
auto GSU::disassembleAlt0(char* output) -> void {
|
||||
char t[256] = "";
|
||||
switch(op0) {
|
||||
case (0x00): sprintf(t, "stop"); break;
|
||||
@@ -94,7 +87,7 @@ auto GSU::disassemble_alt0(char* output) -> void {
|
||||
strcat(output, t);
|
||||
}
|
||||
|
||||
auto GSU::disassemble_alt1(char* output) -> void {
|
||||
auto GSU::disassembleAlt1(char* output) -> void {
|
||||
char t[256] = "";
|
||||
switch(op0) {
|
||||
case (0x00): sprintf(t, "stop"); break;
|
||||
@@ -151,7 +144,7 @@ auto GSU::disassemble_alt1(char* output) -> void {
|
||||
strcat(output, t);
|
||||
}
|
||||
|
||||
auto GSU::disassemble_alt2(char* output) -> void {
|
||||
auto GSU::disassembleAlt2(char* output) -> void {
|
||||
char t[256] = "";
|
||||
switch(op0) {
|
||||
case (0x00): sprintf(t, "stop"); break;
|
||||
@@ -208,7 +201,7 @@ auto GSU::disassemble_alt2(char* output) -> void {
|
||||
strcat(output, t);
|
||||
}
|
||||
|
||||
auto GSU::disassemble_alt3(char* output) -> void {
|
||||
auto GSU::disassembleAlt3(char* output) -> void {
|
||||
char t[256] = "";
|
||||
switch(op0) {
|
||||
case (0x00): sprintf(t, "stop"); break;
|
||||
|
@@ -8,7 +8,7 @@
|
||||
namespace Processor {
|
||||
|
||||
#include "instructions.cpp"
|
||||
#include "table.cpp"
|
||||
#include "switch.cpp"
|
||||
#include "serialization.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
@@ -16,7 +16,11 @@ auto GSU::power() -> void {
|
||||
}
|
||||
|
||||
auto GSU::reset() -> void {
|
||||
for(auto& r : regs.r) r = 0x0000;
|
||||
for(auto& r : regs.r) {
|
||||
r.data = 0x0000;
|
||||
r.modified = false;
|
||||
}
|
||||
|
||||
regs.sfr = 0x0000;
|
||||
regs.pbr = 0x00;
|
||||
regs.rombr = 0x00;
|
||||
|
@@ -5,7 +5,7 @@ namespace Processor {
|
||||
struct GSU {
|
||||
#include "registers.hpp"
|
||||
|
||||
virtual auto step(unsigned clocks) -> void = 0;
|
||||
virtual auto step(uint clocks) -> void = 0;
|
||||
|
||||
virtual auto stop() -> void = 0;
|
||||
virtual auto color(uint8 source) -> uint8 = 0;
|
||||
@@ -13,116 +13,74 @@ struct GSU {
|
||||
virtual auto rpix(uint8 x, uint8 y) -> uint8 = 0;
|
||||
|
||||
virtual auto pipe() -> uint8 = 0;
|
||||
virtual auto rombuffer_sync() -> void = 0;
|
||||
virtual auto rombuffer_read() -> uint8 = 0;
|
||||
virtual auto rambuffer_sync() -> void = 0;
|
||||
virtual auto rambuffer_read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto rambuffer_write(uint16 addr, uint8 data) -> void = 0;
|
||||
virtual auto cache_flush() -> void = 0;
|
||||
virtual auto syncROMBuffer() -> void = 0;
|
||||
virtual auto readROMBuffer() -> uint8 = 0;
|
||||
virtual auto syncRAMBuffer() -> void = 0;
|
||||
virtual auto readRAMBuffer(uint16 addr) -> uint8 = 0;
|
||||
virtual auto writeRAMBuffer(uint16 addr, uint8 data) -> void = 0;
|
||||
virtual auto flushCache() -> void = 0;
|
||||
|
||||
virtual auto bus_read(uint24 addr, uint8 data = 0x00) -> uint8 = 0;
|
||||
virtual auto bus_write(uint24 addr, uint8 data) -> void = 0;
|
||||
virtual auto read(uint24 addr, uint8 data = 0x00) -> uint8 = 0;
|
||||
virtual auto write(uint24 addr, uint8 data) -> void = 0;
|
||||
|
||||
//gsu.cpp
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
//instructions.cpp
|
||||
template<int> auto op_adc_i();
|
||||
template<int> auto op_adc_r();
|
||||
template<int> auto op_add_i();
|
||||
template<int> auto op_add_r();
|
||||
auto op_add_adc(uint n);
|
||||
auto op_alt1();
|
||||
auto op_alt2();
|
||||
auto op_alt3();
|
||||
template<int> auto op_and_i();
|
||||
template<int> auto op_and_r();
|
||||
auto op_asr();
|
||||
auto op_bge();
|
||||
auto op_bcc();
|
||||
auto op_bcs();
|
||||
auto op_beq();
|
||||
template<int> auto op_bic_i();
|
||||
template<int> auto op_bic_r();
|
||||
auto op_blt();
|
||||
auto op_bmi();
|
||||
auto op_bne();
|
||||
auto op_bpl();
|
||||
auto op_bra();
|
||||
auto op_bvc();
|
||||
auto op_bvs();
|
||||
auto op_and_bic(uint n);
|
||||
auto op_asr_div2();
|
||||
auto op_branch(bool c);
|
||||
auto op_cache();
|
||||
auto op_cmode();
|
||||
template<int> auto op_cmp_r();
|
||||
auto op_color();
|
||||
template<int> auto op_dec_r();
|
||||
auto op_div2();
|
||||
auto op_fmult();
|
||||
template<int> auto op_from_r();
|
||||
auto op_color_cmode();
|
||||
auto op_dec(uint n);
|
||||
auto op_fmult_lmult();
|
||||
auto op_from_moves(uint n);
|
||||
auto op_getb();
|
||||
auto op_getbl();
|
||||
auto op_getbh();
|
||||
auto op_getbs();
|
||||
auto op_getc();
|
||||
auto op_getc_ramb_romb();
|
||||
auto op_hib();
|
||||
template<int> auto op_ibt_r();
|
||||
template<int> auto op_inc_r();
|
||||
template<int> auto op_iwt_r();
|
||||
template<int> auto op_jmp_r();
|
||||
template<int> auto op_ldb_ir();
|
||||
template<int> auto op_ldw_ir();
|
||||
template<int> auto op_link();
|
||||
template<int> auto op_ljmp_r();
|
||||
template<int> auto op_lm_r();
|
||||
template<int> auto op_lms_r();
|
||||
auto op_lmult();
|
||||
auto op_ibt_lms_sms(uint n);
|
||||
auto op_inc(uint n);
|
||||
auto op_iwt_lm_sm(uint n);
|
||||
auto op_jmp_ljmp(uint n);
|
||||
auto op_link(uint n);
|
||||
auto op_load(uint n);
|
||||
auto op_lob();
|
||||
auto op_loop();
|
||||
auto op_lsr();
|
||||
auto op_merge();
|
||||
template<int> auto op_mult_i();
|
||||
template<int> auto op_mult_r();
|
||||
auto op_mult_umult(uint n);
|
||||
auto op_nop();
|
||||
auto op_not();
|
||||
template<int> auto op_or_i();
|
||||
template<int> auto op_or_r();
|
||||
auto op_plot();
|
||||
auto op_ramb();
|
||||
auto op_or_xor(uint n);
|
||||
auto op_plot_rpix();
|
||||
auto op_rol();
|
||||
auto op_romb();
|
||||
auto op_ror();
|
||||
auto op_rpix();
|
||||
template<int> auto op_sbc_r();
|
||||
auto op_sbk();
|
||||
auto op_sex();
|
||||
template<int> auto op_sm_r();
|
||||
template<int> auto op_sms_r();
|
||||
template<int> auto op_stb_ir();
|
||||
auto op_store(uint n);
|
||||
auto op_stop();
|
||||
template<int> auto op_stw_ir();
|
||||
template<int> auto op_sub_i();
|
||||
template<int> auto op_sub_r();
|
||||
auto op_sub_sbc_cmp(uint n);
|
||||
auto op_swap();
|
||||
template<int> auto op_to_r();
|
||||
template<int> auto op_umult_i();
|
||||
template<int> auto op_umult_r();
|
||||
template<int> auto op_with_r();
|
||||
template<int> auto op_xor_i();
|
||||
template<int> auto op_xor_r();
|
||||
auto op_to_move(uint n);
|
||||
auto op_with(uint n);
|
||||
|
||||
//table.cpp
|
||||
auto (GSU::*opcode_table[1024])() -> void;
|
||||
auto initialize_opcode_table() -> void;
|
||||
//switch.cpp
|
||||
auto instruction(uint8 opcode) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassemble_opcode(char* output) -> void;
|
||||
auto disassemble_alt0(char* output) -> void;
|
||||
auto disassemble_alt1(char* output) -> void;
|
||||
auto disassemble_alt2(char* output) -> void;
|
||||
auto disassemble_alt3(char* output) -> void;
|
||||
auto disassembleOpcode(char* output) -> void;
|
||||
auto disassembleAlt0(char* output) -> void;
|
||||
auto disassembleAlt1(char* output) -> void;
|
||||
auto disassembleAlt2(char* output) -> void;
|
||||
auto disassembleAlt3(char* output) -> void;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -4,9 +4,8 @@ auto GSU::op_stop() {
|
||||
regs.sfr.irq = 1;
|
||||
stop();
|
||||
}
|
||||
|
||||
regs.sfr.g = 0;
|
||||
regs.pipeline = 0x01;
|
||||
regs.pipeline = 0x01; //nop
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
@@ -19,7 +18,7 @@ auto GSU::op_nop() {
|
||||
auto GSU::op_cache() {
|
||||
if(regs.cbr != (regs.r[15] & 0xfff0)) {
|
||||
regs.cbr = regs.r[15] & 0xfff0;
|
||||
cache_flush();
|
||||
flushCache();
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
@@ -44,75 +43,25 @@ auto GSU::op_rol() {
|
||||
}
|
||||
|
||||
//$05 bra e
|
||||
auto GSU::op_bra() {
|
||||
regs.r[15] += (int8)pipe();
|
||||
}
|
||||
|
||||
//$06 blt e
|
||||
auto GSU::op_blt() {
|
||||
int e = (int8)pipe();
|
||||
if((regs.sfr.s ^ regs.sfr.ov) == 0) regs.r[15] += e;
|
||||
}
|
||||
|
||||
//$07 bge e
|
||||
auto GSU::op_bge() {
|
||||
int e = (int8)pipe();
|
||||
if((regs.sfr.s ^ regs.sfr.ov) == 1) regs.r[15] += e;
|
||||
}
|
||||
|
||||
//$08 bne e
|
||||
auto GSU::op_bne() {
|
||||
int e = (int8)pipe();
|
||||
if(regs.sfr.z == 0) regs.r[15] += e;
|
||||
}
|
||||
|
||||
//$09 beq e
|
||||
auto GSU::op_beq() {
|
||||
int e = (int8)pipe();
|
||||
if(regs.sfr.z == 1) regs.r[15] += e;
|
||||
}
|
||||
|
||||
//$0a bpl e
|
||||
auto GSU::op_bpl() {
|
||||
int e = (int8)pipe();
|
||||
if(regs.sfr.s == 0) regs.r[15] += e;
|
||||
}
|
||||
|
||||
//$0b bmi e
|
||||
auto GSU::op_bmi() {
|
||||
int e = (int8)pipe();
|
||||
if(regs.sfr.s == 1) regs.r[15] += e;
|
||||
}
|
||||
|
||||
//$0c bcc e
|
||||
auto GSU::op_bcc() {
|
||||
int e = (int8)pipe();
|
||||
if(regs.sfr.cy == 0) regs.r[15] += e;
|
||||
}
|
||||
|
||||
//$0d bcs e
|
||||
auto GSU::op_bcs() {
|
||||
int e = (int8)pipe();
|
||||
if(regs.sfr.cy == 1) regs.r[15] += e;
|
||||
}
|
||||
|
||||
//$0e bvc e
|
||||
auto GSU::op_bvc() {
|
||||
int e = (int8)pipe();
|
||||
if(regs.sfr.ov == 0) regs.r[15] += e;
|
||||
}
|
||||
|
||||
//$0f bvs e
|
||||
auto GSU::op_bvs() {
|
||||
int e = (int8)pipe();
|
||||
if(regs.sfr.ov == 1) regs.r[15] += e;
|
||||
auto GSU::op_branch(bool c) {
|
||||
auto d = (int8)pipe();
|
||||
if(c) regs.r[15] += d;
|
||||
}
|
||||
|
||||
//$10-1f(b0): to rN
|
||||
//$10-1f(b1): move rN
|
||||
template<int n>
|
||||
auto GSU::op_to_r() {
|
||||
if(regs.sfr.b == 0) {
|
||||
//$10-1f(b0) to rN
|
||||
//$10-1f(b1) move rN
|
||||
auto GSU::op_to_move(uint n) {
|
||||
if(!regs.sfr.b) {
|
||||
regs.dreg = n;
|
||||
} else {
|
||||
regs.r[n] = regs.sr();
|
||||
@@ -120,28 +69,19 @@ auto GSU::op_to_r() {
|
||||
}
|
||||
}
|
||||
|
||||
//$20-2f: with rN
|
||||
template<int n>
|
||||
auto GSU::op_with_r() {
|
||||
//$20-2f with rN
|
||||
auto GSU::op_with(uint n) {
|
||||
regs.sreg = n;
|
||||
regs.dreg = n;
|
||||
regs.sfr.b = 1;
|
||||
}
|
||||
|
||||
//$30-3b(alt0): stw (rN)
|
||||
template<int n>
|
||||
auto GSU::op_stw_ir() {
|
||||
//$30-3b(alt0) stw (rN)
|
||||
//$30-3b(alt1) stb (rN)
|
||||
auto GSU::op_store(uint n) {
|
||||
regs.ramaddr = regs.r[n];
|
||||
rambuffer_write(regs.ramaddr ^ 0, regs.sr() >> 0);
|
||||
rambuffer_write(regs.ramaddr ^ 1, regs.sr() >> 8);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$30-3b(alt1): stb (rN)
|
||||
template<int n>
|
||||
auto GSU::op_stb_ir() {
|
||||
regs.ramaddr = regs.r[n];
|
||||
rambuffer_write(regs.ramaddr, regs.sr());
|
||||
writeRAMBuffer(regs.ramaddr, regs.sr());
|
||||
if(!regs.sfr.alt1) writeRAMBuffer(regs.ramaddr ^ 1, regs.sr() >> 8);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
@@ -173,41 +113,30 @@ auto GSU::op_alt3() {
|
||||
regs.sfr.alt2 = 1;
|
||||
}
|
||||
|
||||
//$40-4b(alt0): ldw (rN)
|
||||
template<int n>
|
||||
auto GSU::op_ldw_ir() {
|
||||
//$40-4b(alt0) ldw (rN)
|
||||
//$40-4b(alt1) ldb (rN)
|
||||
auto GSU::op_load(uint n) {
|
||||
regs.ramaddr = regs.r[n];
|
||||
uint16_t data;
|
||||
data = rambuffer_read(regs.ramaddr ^ 0) << 0;
|
||||
data |= rambuffer_read(regs.ramaddr ^ 1) << 8;
|
||||
regs.dr() = data;
|
||||
regs.dr() = readRAMBuffer(regs.ramaddr);
|
||||
if(!regs.sfr.alt1) regs.dr() |= readRAMBuffer(regs.ramaddr ^ 1) << 8;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$40-4b(alt1): ldb (rN)
|
||||
template<int n>
|
||||
auto GSU::op_ldb_ir() {
|
||||
regs.ramaddr = regs.r[n];
|
||||
regs.dr() = rambuffer_read(regs.ramaddr);
|
||||
//$4c(alt0) plot
|
||||
//$4c(alt1) rpix
|
||||
auto GSU::op_plot_rpix() {
|
||||
if(!regs.sfr.alt1) {
|
||||
plot(regs.r[1], regs.r[2]);
|
||||
regs.r[1]++;
|
||||
} else {
|
||||
regs.dr() = rpix(regs.r[1], regs.r[2]);
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$4c(alt0): plot
|
||||
auto GSU::op_plot() {
|
||||
plot(regs.r[1], regs.r[2]);
|
||||
regs.r[1]++;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$4c(alt1): rpix
|
||||
auto GSU::op_rpix() {
|
||||
regs.dr() = rpix(regs.r[1], regs.r[2]);
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$4d: swap
|
||||
//$4d swap
|
||||
auto GSU::op_swap() {
|
||||
regs.dr() = (regs.sr() >> 8) | (regs.sr() << 8);
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
@@ -215,19 +144,18 @@ auto GSU::op_swap() {
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$4e(alt0): color
|
||||
auto GSU::op_color() {
|
||||
regs.colr = color(regs.sr());
|
||||
//$4e(alt0) color
|
||||
//$4e(alt1) cmode
|
||||
auto GSU::op_color_cmode() {
|
||||
if(!regs.sfr.alt1) {
|
||||
regs.colr = color(regs.sr());
|
||||
} else {
|
||||
regs.por = regs.sr();
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$4e(alt1): cmode
|
||||
auto GSU::op_cmode() {
|
||||
regs.por = regs.sr();
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$4f: not
|
||||
//$4f not
|
||||
auto GSU::op_not() {
|
||||
regs.dr() = ~regs.sr();
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
@@ -235,102 +163,37 @@ auto GSU::op_not() {
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$50-5f(alt0): add rN
|
||||
template<int n>
|
||||
auto GSU::op_add_r() {
|
||||
int r = regs.sr() + regs.r[n];
|
||||
regs.sfr.ov = ~(regs.sr() ^ regs.r[n]) & (regs.r[n] ^ r) & 0x8000;
|
||||
regs.sfr.s = (r & 0x8000);
|
||||
regs.sfr.cy = (r >= 0x10000);
|
||||
regs.sfr.z = ((uint16_t)r == 0);
|
||||
regs.dr() = r;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$50-5f(alt1): adc rN
|
||||
template<int n>
|
||||
auto GSU::op_adc_r() {
|
||||
int r = regs.sr() + regs.r[n] + regs.sfr.cy;
|
||||
regs.sfr.ov = ~(regs.sr() ^ regs.r[n]) & (regs.r[n] ^ r) & 0x8000;
|
||||
regs.sfr.s = (r & 0x8000);
|
||||
regs.sfr.cy = (r >= 0x10000);
|
||||
regs.sfr.z = ((uint16_t)r == 0);
|
||||
regs.dr() = r;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$50-5f(alt2): add #N
|
||||
template<int n>
|
||||
auto GSU::op_add_i() {
|
||||
int r = regs.sr() + n;
|
||||
//$50-5f(alt0) add rN
|
||||
//$50-5f(alt1) adc rN
|
||||
//$50-5f(alt2) add #N
|
||||
//$50-5f(alt3) adc #N
|
||||
auto GSU::op_add_adc(uint n) {
|
||||
if(!regs.sfr.alt2) n = regs.r[n];
|
||||
int r = regs.sr() + n + (regs.sfr.alt1 ? regs.sfr.cy : 0);
|
||||
regs.sfr.ov = ~(regs.sr() ^ n) & (n ^ r) & 0x8000;
|
||||
regs.sfr.s = (r & 0x8000);
|
||||
regs.sfr.cy = (r >= 0x10000);
|
||||
regs.sfr.z = ((uint16_t)r == 0);
|
||||
regs.sfr.z = ((uint16)r == 0);
|
||||
regs.dr() = r;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$50-5f(alt3): adc #N
|
||||
template<int n>
|
||||
auto GSU::op_adc_i() {
|
||||
int r = regs.sr() + n + regs.sfr.cy;
|
||||
regs.sfr.ov = ~(regs.sr() ^ n) & (n ^ r) & 0x8000;
|
||||
regs.sfr.s = (r & 0x8000);
|
||||
regs.sfr.cy = (r >= 0x10000);
|
||||
regs.sfr.z = ((uint16_t)r == 0);
|
||||
regs.dr() = r;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$60-6f(alt0): sub rN
|
||||
template<int n>
|
||||
auto GSU::op_sub_r() {
|
||||
int r = regs.sr() - regs.r[n];
|
||||
regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000;
|
||||
regs.sfr.s = (r & 0x8000);
|
||||
regs.sfr.cy = (r >= 0);
|
||||
regs.sfr.z = ((uint16_t)r == 0);
|
||||
regs.dr() = r;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$60-6f(alt1): sbc rN
|
||||
template<int n>
|
||||
auto GSU::op_sbc_r() {
|
||||
int r = regs.sr() - regs.r[n] - !regs.sfr.cy;
|
||||
regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000;
|
||||
regs.sfr.s = (r & 0x8000);
|
||||
regs.sfr.cy = (r >= 0);
|
||||
regs.sfr.z = ((uint16_t)r == 0);
|
||||
regs.dr() = r;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$60-6f(alt2): sub #N
|
||||
template<int n>
|
||||
auto GSU::op_sub_i() {
|
||||
int r = regs.sr() - n;
|
||||
//$60-6f(alt0) sub rN
|
||||
//$60-6f(alt1) sbc rN
|
||||
//$60-6f(alt2) sub #N
|
||||
//$60-6f(alt3) cmp rN
|
||||
auto GSU::op_sub_sbc_cmp(uint n) {
|
||||
if(!regs.sfr.alt2 || regs.sfr.alt1) n = regs.r[n];
|
||||
int r = regs.sr() - n - (!regs.sfr.alt2 && regs.sfr.alt1 ? !regs.sfr.cy : 0);
|
||||
regs.sfr.ov = (regs.sr() ^ n) & (regs.sr() ^ r) & 0x8000;
|
||||
regs.sfr.s = (r & 0x8000);
|
||||
regs.sfr.cy = (r >= 0);
|
||||
regs.sfr.z = ((uint16_t)r == 0);
|
||||
regs.dr() = r;
|
||||
regs.sfr.z = ((uint16)r == 0);
|
||||
if(!regs.sfr.alt2 || !regs.sfr.alt1) regs.dr() = r;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$60-6f(alt3): cmp rN
|
||||
template<int n>
|
||||
auto GSU::op_cmp_r() {
|
||||
int r = regs.sr() - regs.r[n];
|
||||
regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000;
|
||||
regs.sfr.s = (r & 0x8000);
|
||||
regs.sfr.cy = (r >= 0);
|
||||
regs.sfr.z = ((uint16_t)r == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$70: merge
|
||||
//$70 merge
|
||||
auto GSU::op_merge() {
|
||||
regs.dr() = (regs.r[7] & 0xff00) | (regs.r[8] >> 8);
|
||||
regs.sfr.ov = (regs.dr() & 0xc0c0);
|
||||
@@ -340,97 +203,45 @@ auto GSU::op_merge() {
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$71-7f(alt0): and rN
|
||||
template<int n>
|
||||
auto GSU::op_and_r() {
|
||||
regs.dr() = regs.sr() & regs.r[n];
|
||||
//$71-7f(alt0) and rN
|
||||
//$71-7f(alt1) bic rN
|
||||
//$71-7f(alt2) and #N
|
||||
//$71-7f(alt3) bic #N
|
||||
auto GSU::op_and_bic(uint n) {
|
||||
if(!regs.sfr.alt2) n = regs.r[n];
|
||||
regs.dr() = regs.sr() & (regs.sfr.alt1 ? ~n : n);
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$71-7f(alt1): bic rN
|
||||
template<int n>
|
||||
auto GSU::op_bic_r() {
|
||||
regs.dr() = regs.sr() & ~regs.r[n];
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$71-7f(alt2): and #N
|
||||
template<int n>
|
||||
auto GSU::op_and_i() {
|
||||
regs.dr() = regs.sr() & n;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$71-7f(alt3): bic #N
|
||||
template<int n>
|
||||
auto GSU::op_bic_i() {
|
||||
regs.dr() = regs.sr() & ~n;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$80-8f(alt0): mult rN
|
||||
template<int n>
|
||||
auto GSU::op_mult_r() {
|
||||
regs.dr() = (int8)regs.sr() * (int8)regs.r[n];
|
||||
//$80-8f(alt0) mult rN
|
||||
//$80-8f(alt1) umult rN
|
||||
//$80-8f(alt2) mult #N
|
||||
//$80-8f(alt3) umult #N
|
||||
auto GSU::op_mult_umult(uint n) {
|
||||
if(!regs.sfr.alt2) n = regs.r[n];
|
||||
regs.dr() = (!regs.sfr.alt1 ? ((int8)regs.sr() * (int8)n) : ((uint8)regs.sr() * (uint8)n));
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
if(!regs.cfgr.ms0) step(regs.clsr ? 1 : 2);
|
||||
}
|
||||
|
||||
//$80-8f(alt1): umult rN
|
||||
template<int n>
|
||||
auto GSU::op_umult_r() {
|
||||
regs.dr() = (uint8)regs.sr() * (uint8)regs.r[n];
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
if(!regs.cfgr.ms0) step(regs.clsr ? 1 : 2);
|
||||
}
|
||||
|
||||
//$80-8f(alt2): mult #N
|
||||
template<int n>
|
||||
auto GSU::op_mult_i() {
|
||||
regs.dr() = (int8)regs.sr() * (int8)n;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
if(!regs.cfgr.ms0) step(regs.clsr ? 1 : 2);
|
||||
}
|
||||
|
||||
//$80-8f(alt3): umult #N
|
||||
template<int n>
|
||||
auto GSU::op_umult_i() {
|
||||
regs.dr() = (uint8)regs.sr() * (uint8)n;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
if(!regs.cfgr.ms0) step(regs.clsr ? 1 : 2);
|
||||
}
|
||||
|
||||
//$90: sbk
|
||||
//$90 sbk
|
||||
auto GSU::op_sbk() {
|
||||
rambuffer_write(regs.ramaddr ^ 0, regs.sr() >> 0);
|
||||
rambuffer_write(regs.ramaddr ^ 1, regs.sr() >> 8);
|
||||
writeRAMBuffer(regs.ramaddr ^ 0, regs.sr() >> 0);
|
||||
writeRAMBuffer(regs.ramaddr ^ 1, regs.sr() >> 8);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$91-94: link #N
|
||||
template<int n>
|
||||
auto GSU::op_link() {
|
||||
//$91-94 link #N
|
||||
auto GSU::op_link(uint n) {
|
||||
regs.r[11] = regs.r[15] + n;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$95: sex
|
||||
//$95 sex
|
||||
auto GSU::op_sex() {
|
||||
regs.dr() = (int8)regs.sr();
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
@@ -438,25 +249,17 @@ auto GSU::op_sex() {
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$96(alt0): asr
|
||||
auto GSU::op_asr() {
|
||||
//$96(alt0) asr
|
||||
//$96(alt1) div2
|
||||
auto GSU::op_asr_div2() {
|
||||
regs.sfr.cy = (regs.sr() & 1);
|
||||
regs.dr() = (int16_t)regs.sr() >> 1;
|
||||
regs.dr() = ((int16)regs.sr() >> 1) + (regs.sfr.alt1 ? ((regs.sr() + 1) >> 16) : 0);
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$96(alt1): div2
|
||||
auto GSU::op_div2() {
|
||||
regs.sfr.cy = (regs.sr() & 1);
|
||||
regs.dr() = ((int16_t)regs.sr() >> 1) + ((regs.sr() + 1) >> 16);
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$97: ror
|
||||
//$97 ror
|
||||
auto GSU::op_ror() {
|
||||
bool carry = (regs.sr() & 1);
|
||||
regs.dr() = (regs.sfr.cy << 15) | (regs.sr() >> 1);
|
||||
@@ -466,24 +269,21 @@ auto GSU::op_ror() {
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$98-9d(alt0): jmp rN
|
||||
template<int n>
|
||||
auto GSU::op_jmp_r() {
|
||||
regs.r[15] = regs.r[n];
|
||||
//$98-9d(alt0) jmp rN
|
||||
//$98-9d(alt1) ljmp rN
|
||||
auto GSU::op_jmp_ljmp(uint n) {
|
||||
if(!regs.sfr.alt1) {
|
||||
regs.r[15] = regs.r[n];
|
||||
} else {
|
||||
regs.pbr = regs.r[n] & 0x7f;
|
||||
regs.r[15] = regs.sr();
|
||||
regs.cbr = regs.r[15] & 0xfff0;
|
||||
flushCache();
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$98-9d(alt1): ljmp rN
|
||||
template<int n>
|
||||
auto GSU::op_ljmp_r() {
|
||||
regs.pbr = regs.r[n] & 0x7f;
|
||||
regs.r[15] = regs.sr();
|
||||
regs.cbr = regs.r[15] & 0xfff0;
|
||||
cache_flush();
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$9e: lob
|
||||
//$9e lob
|
||||
auto GSU::op_lob() {
|
||||
regs.dr() = regs.sr() & 0xff;
|
||||
regs.sfr.s = (regs.dr() & 0x80);
|
||||
@@ -491,9 +291,11 @@ auto GSU::op_lob() {
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$9f(alt0): fmult
|
||||
auto GSU::op_fmult() {
|
||||
uint32_t result = (int16_t)regs.sr() * (int16_t)regs.r[6];
|
||||
//$9f(alt0) fmult
|
||||
//$9f(alt1) lmult
|
||||
auto GSU::op_fmult_lmult() {
|
||||
uint32 result = (int16)regs.sr() * (int16)regs.r[6];
|
||||
if(regs.sfr.alt1) regs.r[4] = result;
|
||||
regs.dr() = result >> 16;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.cy = (result & 0x8000);
|
||||
@@ -502,50 +304,28 @@ auto GSU::op_fmult() {
|
||||
step((regs.cfgr.ms0 ? 3 : 7) * (regs.clsr ? 1 : 2));
|
||||
}
|
||||
|
||||
//$9f(alt1): lmult
|
||||
auto GSU::op_lmult() {
|
||||
uint32_t result = (int16_t)regs.sr() * (int16_t)regs.r[6];
|
||||
regs.r[4] = result;
|
||||
regs.dr() = result >> 16;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.cy = (result & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
step((regs.cfgr.ms0 ? 3 : 7) * (regs.clsr ? 1 : 2));
|
||||
}
|
||||
|
||||
//$a0-af(alt0): ibt rN,#pp
|
||||
template<int n>
|
||||
auto GSU::op_ibt_r() {
|
||||
regs.r[n] = (int8)pipe();
|
||||
//$a0-af(alt0) ibt rN,#pp
|
||||
//$a0-af(alt1) lms rN,(yy)
|
||||
//$a0-af(alt2) sms (yy),rN
|
||||
auto GSU::op_ibt_lms_sms(uint n) {
|
||||
if(regs.sfr.alt1) {
|
||||
regs.ramaddr = pipe() << 1;
|
||||
uint8 lo = readRAMBuffer(regs.ramaddr ^ 0) << 0;
|
||||
regs.r[n] = readRAMBuffer(regs.ramaddr ^ 1) << 8 | lo;
|
||||
} else if(regs.sfr.alt2) {
|
||||
regs.ramaddr = pipe() << 1;
|
||||
writeRAMBuffer(regs.ramaddr ^ 0, regs.r[n] >> 0);
|
||||
writeRAMBuffer(regs.ramaddr ^ 1, regs.r[n] >> 8);
|
||||
} else {
|
||||
regs.r[n] = (int8)pipe();
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$a0-af(alt1): lms rN,(yy)
|
||||
template<int n>
|
||||
auto GSU::op_lms_r() {
|
||||
regs.ramaddr = pipe() << 1;
|
||||
uint16_t data;
|
||||
data = rambuffer_read(regs.ramaddr ^ 0) << 0;
|
||||
data |= rambuffer_read(regs.ramaddr ^ 1) << 8;
|
||||
regs.r[n] = data;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$a0-af(alt2): sms (yy),rN
|
||||
template<int n>
|
||||
auto GSU::op_sms_r() {
|
||||
regs.ramaddr = pipe() << 1;
|
||||
rambuffer_write(regs.ramaddr ^ 0, regs.r[n] >> 0);
|
||||
rambuffer_write(regs.ramaddr ^ 1, regs.r[n] >> 8);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$b0-bf(b0): from rN
|
||||
//$b0-bf(b1): moves rN
|
||||
template<int n>
|
||||
auto GSU::op_from_r() {
|
||||
if(regs.sfr.b == 0) {
|
||||
//$b0-bf(b0) from rN
|
||||
//$b0-bf(b1) moves rN
|
||||
auto GSU::op_from_moves(uint n) {
|
||||
if(!regs.sfr.b) {
|
||||
regs.sreg = n;
|
||||
} else {
|
||||
regs.dr() = regs.r[n];
|
||||
@@ -556,7 +336,7 @@ auto GSU::op_from_r() {
|
||||
}
|
||||
}
|
||||
|
||||
//$c0: hib
|
||||
//$c0 hib
|
||||
auto GSU::op_hib() {
|
||||
regs.dr() = regs.sr() >> 8;
|
||||
regs.sfr.s = (regs.dr() & 0x80);
|
||||
@@ -564,132 +344,81 @@ auto GSU::op_hib() {
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$c1-cf(alt0): or rN
|
||||
template<int n>
|
||||
auto GSU::op_or_r() {
|
||||
regs.dr() = regs.sr() | regs.r[n];
|
||||
//$c1-cf(alt0) or rN
|
||||
//$c1-cf(alt1) xor rN
|
||||
//$c1-cf(alt2) or #N
|
||||
//$c1-cf(alt3) xor #N
|
||||
auto GSU::op_or_xor(uint n) {
|
||||
if(!regs.sfr.alt2) n = regs.r[n];
|
||||
regs.dr() = (!regs.sfr.alt1 ? (regs.sr() | n) : (regs.sr() ^ n));
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$c1-cf(alt1): xor rN
|
||||
template<int n>
|
||||
auto GSU::op_xor_r() {
|
||||
regs.dr() = regs.sr() ^ regs.r[n];
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$c1-cf(alt2): or #N
|
||||
template<int n>
|
||||
auto GSU::op_or_i() {
|
||||
regs.dr() = regs.sr() | n;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$c1-cf(alt3): xor #N
|
||||
template<int n>
|
||||
auto GSU::op_xor_i() {
|
||||
regs.dr() = regs.sr() ^ n;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$d0-de: inc rN
|
||||
template<int n>
|
||||
auto GSU::op_inc_r() {
|
||||
//$d0-de inc rN
|
||||
auto GSU::op_inc(uint n) {
|
||||
regs.r[n]++;
|
||||
regs.sfr.s = (regs.r[n] & 0x8000);
|
||||
regs.sfr.z = (regs.r[n] == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$df(alt0): getc
|
||||
auto GSU::op_getc() {
|
||||
regs.colr = color(rombuffer_read());
|
||||
//$df(alt0) getc
|
||||
//$df(alt2) ramb
|
||||
//$df(alt3) romb
|
||||
auto GSU::op_getc_ramb_romb() {
|
||||
if(!regs.sfr.alt2) {
|
||||
regs.colr = color(readROMBuffer());
|
||||
} else if(!regs.sfr.alt1) {
|
||||
syncRAMBuffer();
|
||||
regs.rambr = regs.sr() & 0x01;
|
||||
} else {
|
||||
syncROMBuffer();
|
||||
regs.rombr = regs.sr() & 0x7f;
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$df(alt2): ramb
|
||||
auto GSU::op_ramb() {
|
||||
rambuffer_sync();
|
||||
regs.rambr = regs.sr() & 0x01;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$df(alt3): romb
|
||||
auto GSU::op_romb() {
|
||||
rombuffer_sync();
|
||||
regs.rombr = regs.sr() & 0x7f;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$e0-ee: dec rN
|
||||
template<int n>
|
||||
auto GSU::op_dec_r() {
|
||||
//$e0-ee dec rN
|
||||
auto GSU::op_dec(uint n) {
|
||||
regs.r[n]--;
|
||||
regs.sfr.s = (regs.r[n] & 0x8000);
|
||||
regs.sfr.z = (regs.r[n] == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$ef(alt0): getb
|
||||
//$ef(alt0) getb
|
||||
//$ef(alt1) getbh
|
||||
//$ef(alt2) getbl
|
||||
//$ef(alt3) getbs
|
||||
auto GSU::op_getb() {
|
||||
regs.dr() = rombuffer_read();
|
||||
switch(regs.sfr.alt2 << 1 | regs.sfr.alt1 << 0) {
|
||||
case 0: regs.dr() = readROMBuffer(); break;
|
||||
case 1: regs.dr() = readROMBuffer() << 8 | (uint8)regs.sr(); break;
|
||||
case 2: regs.dr() = (regs.sr() & 0xff00) | readROMBuffer(); break;
|
||||
case 3: regs.dr() = (int8)readROMBuffer(); break;
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$ef(alt1): getbh
|
||||
auto GSU::op_getbh() {
|
||||
regs.dr() = (rombuffer_read() << 8) | (regs.sr() & 0x00ff);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$ef(alt2): getbl
|
||||
auto GSU::op_getbl() {
|
||||
regs.dr() = (regs.sr() & 0xff00) | (rombuffer_read() << 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$ef(alt3): getbs
|
||||
auto GSU::op_getbs() {
|
||||
regs.dr() = (int8)rombuffer_read();
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$f0-ff(alt0): iwt rN,#xx
|
||||
template<int n>
|
||||
auto GSU::op_iwt_r() {
|
||||
uint16_t data;
|
||||
data = pipe() << 0;
|
||||
data |= pipe() << 8;
|
||||
regs.r[n] = data;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$f0-ff(alt1): lm rN,(xx)
|
||||
template<int n>
|
||||
auto GSU::op_lm_r() {
|
||||
regs.ramaddr = pipe() << 0;
|
||||
regs.ramaddr |= pipe() << 8;
|
||||
uint16_t data;
|
||||
data = rambuffer_read(regs.ramaddr ^ 0) << 0;
|
||||
data |= rambuffer_read(regs.ramaddr ^ 1) << 8;
|
||||
regs.r[n] = data;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$f0-ff(alt2): sm (xx),rN
|
||||
template<int n>
|
||||
auto GSU::op_sm_r() {
|
||||
regs.ramaddr = pipe() << 0;
|
||||
regs.ramaddr |= pipe() << 8;
|
||||
rambuffer_write(regs.ramaddr ^ 0, regs.r[n] >> 0);
|
||||
rambuffer_write(regs.ramaddr ^ 1, regs.r[n] >> 8);
|
||||
//$f0-ff(alt0) iwt rN,#xx
|
||||
//$f0-ff(alt1) lm rN,(xx)
|
||||
//$f0-ff(alt2) sm (xx),rN
|
||||
auto GSU::op_iwt_lm_sm(uint n) {
|
||||
if(regs.sfr.alt1) {
|
||||
regs.ramaddr = pipe() << 0;
|
||||
regs.ramaddr |= pipe() << 8;
|
||||
uint8 lo = readRAMBuffer(regs.ramaddr ^ 0) << 0;
|
||||
regs.r[n] = readRAMBuffer(regs.ramaddr ^ 1) << 8 | lo;
|
||||
} else if(regs.sfr.alt2) {
|
||||
regs.ramaddr = pipe() << 0;
|
||||
regs.ramaddr |= pipe() << 8;
|
||||
writeRAMBuffer(regs.ramaddr ^ 0, regs.r[n] >> 0);
|
||||
writeRAMBuffer(regs.ramaddr ^ 1, regs.r[n] >> 8);
|
||||
} else {
|
||||
uint8 lo = pipe();
|
||||
regs.r[n] = pipe() << 8 | lo;
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
@@ -1,87 +1,71 @@
|
||||
//accepts a callback binding so r14 writes can trigger ROM buffering transparently
|
||||
struct reg16_t {
|
||||
struct Register {
|
||||
uint16 data = 0;
|
||||
function<auto (uint16) -> void> modify;
|
||||
bool modified = false;
|
||||
|
||||
inline operator unsigned() const {
|
||||
inline operator uint() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
inline auto assign(uint16 i) -> uint16 {
|
||||
if(modify) modify(i);
|
||||
else data = i;
|
||||
return data;
|
||||
inline auto assign(uint value) -> uint16 {
|
||||
modified = true;
|
||||
return data = value;
|
||||
}
|
||||
|
||||
inline auto operator++() { return assign(data + 1); }
|
||||
inline auto operator--() { return assign(data - 1); }
|
||||
inline auto operator++(int) { unsigned r = data; assign(data + 1); return r; }
|
||||
inline auto operator--(int) { unsigned r = data; assign(data - 1); return r; }
|
||||
inline auto operator = (unsigned i) { return assign(i); }
|
||||
inline auto operator |= (unsigned i) { return assign(data | i); }
|
||||
inline auto operator ^= (unsigned i) { return assign(data ^ i); }
|
||||
inline auto operator &= (unsigned i) { return assign(data & i); }
|
||||
inline auto operator <<= (unsigned i) { return assign(data << i); }
|
||||
inline auto operator >>= (unsigned i) { return assign(data >> i); }
|
||||
inline auto operator += (unsigned i) { return assign(data + i); }
|
||||
inline auto operator -= (unsigned i) { return assign(data - i); }
|
||||
inline auto operator *= (unsigned i) { return assign(data * i); }
|
||||
inline auto operator /= (unsigned i) { return assign(data / i); }
|
||||
inline auto operator %= (unsigned i) { return assign(data % i); }
|
||||
inline auto operator++(int) { uint r = data; assign(data + 1); return r; }
|
||||
inline auto operator--(int) { uint r = data; assign(data - 1); return r; }
|
||||
inline auto operator = (uint i) { return assign(i); }
|
||||
inline auto operator |= (uint i) { return assign(data | i); }
|
||||
inline auto operator ^= (uint i) { return assign(data ^ i); }
|
||||
inline auto operator &= (uint i) { return assign(data & i); }
|
||||
inline auto operator <<= (uint i) { return assign(data << i); }
|
||||
inline auto operator >>= (uint i) { return assign(data >> i); }
|
||||
inline auto operator += (uint i) { return assign(data + i); }
|
||||
inline auto operator -= (uint i) { return assign(data - i); }
|
||||
inline auto operator *= (uint i) { return assign(data * i); }
|
||||
inline auto operator /= (uint i) { return assign(data / i); }
|
||||
inline auto operator %= (uint i) { return assign(data % i); }
|
||||
|
||||
inline auto operator = (const reg16_t& i) { return assign(i); }
|
||||
inline auto operator = (const Register& value) { return assign(value); }
|
||||
|
||||
reg16_t() = default;
|
||||
reg16_t(const reg16_t&) = delete;
|
||||
Register() = default;
|
||||
Register(const Register&) = delete;
|
||||
};
|
||||
|
||||
struct sfr_t {
|
||||
bool irq; //interrupt flag
|
||||
bool b; //WITH flag
|
||||
bool ih; //immediate higher 8-bit flag
|
||||
bool il; //immediate lower 8-bit flag
|
||||
bool alt2; //ALT2 mode
|
||||
bool alt1; //ALT2 instruction mode
|
||||
bool r; //ROM r14 read flag
|
||||
bool g; //GO flag
|
||||
bool ov; //overflow flag
|
||||
bool s; //sign flag
|
||||
bool cy; //carry flag
|
||||
bool z; //zero flag
|
||||
struct SFR {
|
||||
union {
|
||||
uint16_t data = 0;
|
||||
BitField<uint16_t, 15> irq; //interrupt flag
|
||||
BitField<uint16_t, 12> b; //with flag
|
||||
BitField<uint16_t, 11> ih; //immediate higher 8-bit flag
|
||||
BitField<uint16_t, 10> il; //immediate lower 8-bit flag
|
||||
BitField<uint16_t, 9> alt2; //alt2 instruction mode
|
||||
BitField<uint16_t, 8> alt1; //alt1 instruction mode
|
||||
BitField<uint16_t, 6> r; //ROM r14 read flag
|
||||
BitField<uint16_t, 5> g; //go flag
|
||||
BitField<uint16_t, 4> ov; //overflow flag
|
||||
BitField<uint16_t, 3> s; //sign flag
|
||||
BitField<uint16_t, 2> cy; //carry flag
|
||||
BitField<uint16_t, 1> z; //zero flag
|
||||
BitField<uint16_t, 9, 8> alt; //instruction mode (composite flag)
|
||||
};
|
||||
|
||||
operator unsigned() const {
|
||||
return (irq << 15) | (b << 12) | (ih << 11) | (il << 10) | (alt2 << 9) | (alt1 << 8)
|
||||
| (r << 6) | (g << 5) | (ov << 4) | (s << 3) | (cy << 2) | (z << 1);
|
||||
}
|
||||
|
||||
auto& operator=(uint16_t data) {
|
||||
irq = data & 0x8000;
|
||||
b = data & 0x1000;
|
||||
ih = data & 0x0800;
|
||||
il = data & 0x0400;
|
||||
alt2 = data & 0x0200;
|
||||
alt1 = data & 0x0100;
|
||||
r = data & 0x0040;
|
||||
g = data & 0x0020;
|
||||
ov = data & 0x0010;
|
||||
s = data & 0x0008;
|
||||
cy = data & 0x0004;
|
||||
z = data & 0x0002;
|
||||
return *this;
|
||||
}
|
||||
inline operator uint() const { return data & 0x9f7e; }
|
||||
inline auto& operator=(const uint value) { return data = value, *this; }
|
||||
};
|
||||
|
||||
struct scmr_t {
|
||||
unsigned ht;
|
||||
struct SCMR {
|
||||
uint ht;
|
||||
bool ron;
|
||||
bool ran;
|
||||
unsigned md;
|
||||
uint md;
|
||||
|
||||
operator unsigned() const {
|
||||
operator uint() const {
|
||||
return ((ht >> 1) << 5) | (ron << 4) | (ran << 3) | ((ht & 1) << 2) | (md);
|
||||
}
|
||||
|
||||
auto& operator=(uint8 data) {
|
||||
auto& operator=(uint data) {
|
||||
ht = (bool)(data & 0x20) << 1;
|
||||
ht |= (bool)(data & 0x04) << 0;
|
||||
ron = data & 0x10;
|
||||
@@ -91,18 +75,18 @@ struct scmr_t {
|
||||
}
|
||||
};
|
||||
|
||||
struct por_t {
|
||||
struct POR {
|
||||
bool obj;
|
||||
bool freezehigh;
|
||||
bool highnibble;
|
||||
bool dither;
|
||||
bool transparent;
|
||||
|
||||
operator unsigned() const {
|
||||
operator uint() const {
|
||||
return (obj << 4) | (freezehigh << 3) | (highnibble << 2) | (dither << 1) | (transparent);
|
||||
}
|
||||
|
||||
auto& operator=(uint8 data) {
|
||||
auto& operator=(uint data) {
|
||||
obj = data & 0x10;
|
||||
freezehigh = data & 0x08;
|
||||
highnibble = data & 0x04;
|
||||
@@ -112,48 +96,49 @@ struct por_t {
|
||||
}
|
||||
};
|
||||
|
||||
struct cfgr_t {
|
||||
struct CFGR {
|
||||
bool irq;
|
||||
bool ms0;
|
||||
|
||||
operator unsigned() const {
|
||||
operator uint() const {
|
||||
return (irq << 7) | (ms0 << 5);
|
||||
}
|
||||
|
||||
auto& operator=(uint8 data) {
|
||||
auto& operator=(uint data) {
|
||||
irq = data & 0x80;
|
||||
ms0 = data & 0x20;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct regs_t {
|
||||
struct Registers {
|
||||
uint8 pipeline;
|
||||
uint16 ramaddr;
|
||||
|
||||
reg16_t r[16]; //general purpose registers
|
||||
sfr_t sfr; //status flag register
|
||||
Register r[16]; //general purpose registers
|
||||
SFR sfr; //status flag register
|
||||
uint8 pbr; //program bank register
|
||||
uint8 rombr; //game pack ROM bank register
|
||||
bool rambr; //game pack RAM bank register
|
||||
uint16 cbr; //cache base register
|
||||
uint8 scbr; //screen base register
|
||||
scmr_t scmr; //screen mode register
|
||||
SCMR scmr; //screen mode register
|
||||
uint8 colr; //color register
|
||||
por_t por; //plot option register
|
||||
POR por; //plot option register
|
||||
bool bramr; //back-up RAM register
|
||||
uint8 vcr; //version code register
|
||||
cfgr_t cfgr; //config register
|
||||
CFGR cfgr; //config register
|
||||
bool clsr; //clock select register
|
||||
|
||||
unsigned romcl; //clock ticks until romdr is valid
|
||||
uint romcl; //clock ticks until romdr is valid
|
||||
uint8 romdr; //ROM buffer data register
|
||||
|
||||
unsigned ramcl; //clock ticks until ramdr is valid
|
||||
uint ramcl; //clock ticks until ramdr is valid
|
||||
uint16 ramar; //RAM buffer address register
|
||||
uint8 ramdr; //RAM buffer data register
|
||||
|
||||
unsigned sreg, dreg;
|
||||
uint sreg;
|
||||
uint dreg;
|
||||
auto& sr() { return r[sreg]; } //source register (from)
|
||||
auto& dr() { return r[dreg]; } //destination register (to)
|
||||
|
||||
@@ -167,12 +152,12 @@ struct regs_t {
|
||||
}
|
||||
} regs;
|
||||
|
||||
struct cache_t {
|
||||
struct Cache {
|
||||
uint8 buffer[512];
|
||||
bool valid[32];
|
||||
} cache;
|
||||
|
||||
struct pixelcache_t {
|
||||
struct PixelCache {
|
||||
uint16 offset;
|
||||
uint8 bitpend;
|
||||
uint8 data[8];
|
||||
|
@@ -2,36 +2,12 @@ auto GSU::serialize(serializer& s) -> void {
|
||||
s.integer(regs.pipeline);
|
||||
s.integer(regs.ramaddr);
|
||||
|
||||
s.integer(regs.r[ 0].data);
|
||||
s.integer(regs.r[ 1].data);
|
||||
s.integer(regs.r[ 2].data);
|
||||
s.integer(regs.r[ 3].data);
|
||||
s.integer(regs.r[ 4].data);
|
||||
s.integer(regs.r[ 5].data);
|
||||
s.integer(regs.r[ 6].data);
|
||||
s.integer(regs.r[ 7].data);
|
||||
s.integer(regs.r[ 8].data);
|
||||
s.integer(regs.r[ 9].data);
|
||||
s.integer(regs.r[10].data);
|
||||
s.integer(regs.r[11].data);
|
||||
s.integer(regs.r[12].data);
|
||||
s.integer(regs.r[13].data);
|
||||
s.integer(regs.r[14].data);
|
||||
s.integer(regs.r[15].data);
|
||||
|
||||
s.integer(regs.sfr.irq);
|
||||
s.integer(regs.sfr.b);
|
||||
s.integer(regs.sfr.ih);
|
||||
s.integer(regs.sfr.il);
|
||||
s.integer(regs.sfr.alt2);
|
||||
s.integer(regs.sfr.alt1);
|
||||
s.integer(regs.sfr.r);
|
||||
s.integer(regs.sfr.g);
|
||||
s.integer(regs.sfr.ov);
|
||||
s.integer(regs.sfr.s);
|
||||
s.integer(regs.sfr.cy);
|
||||
s.integer(regs.sfr.z);
|
||||
for(auto n : range(16)) {
|
||||
s.integer(regs.r[n].data);
|
||||
s.integer(regs.r[n].modified);
|
||||
}
|
||||
|
||||
s.integer(regs.sfr.data);
|
||||
s.integer(regs.pbr);
|
||||
s.integer(regs.rombr);
|
||||
s.integer(regs.rambr);
|
||||
@@ -72,9 +48,9 @@ auto GSU::serialize(serializer& s) -> void {
|
||||
s.array(cache.buffer);
|
||||
s.array(cache.valid);
|
||||
|
||||
for(unsigned i = 0; i < 2; i++) {
|
||||
s.integer(pixelcache[i].offset);
|
||||
s.integer(pixelcache[i].bitpend);
|
||||
s.array(pixelcache[i].data);
|
||||
for(uint n : range(2)) {
|
||||
s.integer(pixelcache[n].offset);
|
||||
s.integer(pixelcache[n].bitpend);
|
||||
s.array(pixelcache[n].data);
|
||||
}
|
||||
}
|
||||
|
94
higan/processor/gsu/switch.cpp
Normal file
94
higan/processor/gsu/switch.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
auto GSU::instruction(uint8 opcode) -> void {
|
||||
#define op(id, name, ...) \
|
||||
case id: return op_##name(__VA_ARGS__); \
|
||||
|
||||
#define op4(id, name) \
|
||||
case id+ 0: return op_##name((uint4)opcode); \
|
||||
case id+ 1: return op_##name((uint4)opcode); \
|
||||
case id+ 2: return op_##name((uint4)opcode); \
|
||||
case id+ 3: return op_##name((uint4)opcode); \
|
||||
|
||||
#define op6(id, name) \
|
||||
op4(id, name) \
|
||||
case id+ 4: return op_##name((uint4)opcode); \
|
||||
case id+ 5: return op_##name((uint4)opcode); \
|
||||
|
||||
#define op12(id, name) \
|
||||
op6(id, name) \
|
||||
case id+ 6: return op_##name((uint4)opcode); \
|
||||
case id+ 7: return op_##name((uint4)opcode); \
|
||||
case id+ 8: return op_##name((uint4)opcode); \
|
||||
case id+ 9: return op_##name((uint4)opcode); \
|
||||
case id+10: return op_##name((uint4)opcode); \
|
||||
case id+11: return op_##name((uint4)opcode); \
|
||||
|
||||
#define op15(id, name) \
|
||||
op12(id, name) \
|
||||
case id+12: return op_##name((uint4)opcode); \
|
||||
case id+13: return op_##name((uint4)opcode); \
|
||||
case id+14: return op_##name((uint4)opcode); \
|
||||
|
||||
#define op16(id, name) \
|
||||
op15(id, name) \
|
||||
case id+15: return op_##name((uint4)opcode); \
|
||||
|
||||
switch(opcode) {
|
||||
op (0x00, stop)
|
||||
op (0x01, nop)
|
||||
op (0x02, cache)
|
||||
op (0x03, lsr)
|
||||
op (0x04, rol)
|
||||
op (0x05, branch, 1) //bra
|
||||
op (0x06, branch, (regs.sfr.s ^ regs.sfr.ov) == 0) //blt
|
||||
op (0x07, branch, (regs.sfr.s ^ regs.sfr.ov) == 1) //bge
|
||||
op (0x08, branch, regs.sfr.z == 0) //bne
|
||||
op (0x09, branch, regs.sfr.z == 1) //beq
|
||||
op (0x0a, branch, regs.sfr.s == 0) //bpl
|
||||
op (0x0b, branch, regs.sfr.s == 1) //bmi
|
||||
op (0x0c, branch, regs.sfr.cy == 0) //bcc
|
||||
op (0x0d, branch, regs.sfr.cy == 1) //bcs
|
||||
op (0x0e, branch, regs.sfr.ov == 0) //bvc
|
||||
op (0x0f, branch, regs.sfr.ov == 1) //bvs
|
||||
op16(0x10, to_move)
|
||||
op16(0x20, with)
|
||||
op12(0x30, store)
|
||||
op (0x3c, loop)
|
||||
op (0x3d, alt1)
|
||||
op (0x3e, alt2)
|
||||
op (0x3f, alt3)
|
||||
op12(0x40, load)
|
||||
op (0x4c, plot_rpix)
|
||||
op (0x4d, swap)
|
||||
op (0x4e, color_cmode)
|
||||
op (0x4f, not)
|
||||
op16(0x50, add_adc)
|
||||
op16(0x60, sub_sbc_cmp)
|
||||
op (0x70, merge)
|
||||
op15(0x71, and_bic)
|
||||
op16(0x80, mult_umult)
|
||||
op (0x90, sbk)
|
||||
op4 (0x91, link)
|
||||
op (0x95, sex)
|
||||
op (0x96, asr_div2)
|
||||
op (0x97, ror)
|
||||
op6 (0x98, jmp_ljmp)
|
||||
op (0x9e, lob)
|
||||
op (0x9f, fmult_lmult)
|
||||
op16(0xa0, ibt_lms_sms)
|
||||
op16(0xb0, from_moves)
|
||||
op (0xc0, hib)
|
||||
op15(0xc1, or_xor)
|
||||
op15(0xd0, inc)
|
||||
op15(0xe0, dec)
|
||||
op (0xdf, getc_ramb_romb)
|
||||
op (0xef, getb)
|
||||
op16(0xf0, iwt_lm_sm)
|
||||
}
|
||||
|
||||
#undef op
|
||||
#undef op4
|
||||
#undef op6
|
||||
#undef op12
|
||||
#undef op15
|
||||
#undef op16
|
||||
}
|
@@ -1,266 +0,0 @@
|
||||
auto GSU::initialize_opcode_table() -> void {
|
||||
#define op4(id, name) \
|
||||
op(id+ 0, name< 1>) op(id+ 1, name< 2>) op(id+ 2, name< 3>) op(id+ 3, name< 4>)
|
||||
|
||||
#define op6(id, name) \
|
||||
op(id+ 0, name< 8>) op(id+ 1, name< 9>) op(id+ 2, name<10>) op(id+ 3, name<11>) \
|
||||
op(id+ 4, name<12>) op(id+ 5, name<13>)
|
||||
|
||||
#define op12(id, name) \
|
||||
op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \
|
||||
op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \
|
||||
op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>)
|
||||
|
||||
#define op15l(id, name) \
|
||||
op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \
|
||||
op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \
|
||||
op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>) \
|
||||
op(id+12, name<12>) op(id+13, name<13>) op(id+14, name<14>)
|
||||
|
||||
#define op15h(id, name) \
|
||||
op(id+ 0, name< 1>) op(id+ 1, name< 2>) op(id+ 2, name< 3>) op(id+ 3, name< 4>) \
|
||||
op(id+ 4, name< 5>) op(id+ 5, name< 6>) op(id+ 6, name< 7>) op(id+ 7, name< 8>) \
|
||||
op(id+ 8, name< 9>) op(id+ 9, name<10>) op(id+10, name<11>) op(id+11, name<12>) \
|
||||
op(id+12, name<13>) op(id+13, name<14>) op(id+14, name<15>)
|
||||
|
||||
#define op16(id, name) \
|
||||
op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \
|
||||
op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \
|
||||
op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>) \
|
||||
op(id+12, name<12>) op(id+13, name<13>) op(id+14, name<14>) op(id+15, name<15>)
|
||||
|
||||
//======
|
||||
// ALT0
|
||||
//======
|
||||
|
||||
#define op(id, name) opcode_table[ 0 + id] = &GSU::op_##name;
|
||||
op (0x00, stop)
|
||||
op (0x01, nop)
|
||||
op (0x02, cache)
|
||||
op (0x03, lsr)
|
||||
op (0x04, rol)
|
||||
op (0x05, bra)
|
||||
op (0x06, blt)
|
||||
op (0x07, bge)
|
||||
op (0x08, bne)
|
||||
op (0x09, beq)
|
||||
op (0x0a, bpl)
|
||||
op (0x0b, bmi)
|
||||
op (0x0c, bcc)
|
||||
op (0x0d, bcs)
|
||||
op (0x0e, bvc)
|
||||
op (0x0f, bvs)
|
||||
op16 (0x10, to_r)
|
||||
op16 (0x20, with_r)
|
||||
op12 (0x30, stw_ir)
|
||||
op (0x3c, loop)
|
||||
op (0x3d, alt1)
|
||||
op (0x3e, alt2)
|
||||
op (0x3f, alt3)
|
||||
op12 (0x40, ldw_ir)
|
||||
op (0x4c, plot)
|
||||
op (0x4d, swap)
|
||||
op (0x4e, color)
|
||||
op (0x4f, not)
|
||||
op16 (0x50, add_r)
|
||||
op16 (0x60, sub_r)
|
||||
op (0x70, merge)
|
||||
op15h(0x71, and_r)
|
||||
op16 (0x80, mult_r)
|
||||
op (0x90, sbk)
|
||||
op4 (0x91, link)
|
||||
op (0x95, sex)
|
||||
op (0x96, asr)
|
||||
op (0x97, ror)
|
||||
op6 (0x98, jmp_r)
|
||||
op (0x9e, lob)
|
||||
op (0x9f, fmult)
|
||||
op16 (0xa0, ibt_r)
|
||||
op16 (0xb0, from_r)
|
||||
op (0xc0, hib)
|
||||
op15h(0xc1, or_r)
|
||||
op15l(0xd0, inc_r)
|
||||
op (0xdf, getc)
|
||||
op15l(0xe0, dec_r)
|
||||
op (0xef, getb)
|
||||
op16 (0xf0, iwt_r)
|
||||
#undef op
|
||||
|
||||
//======
|
||||
// ALT1
|
||||
//======
|
||||
|
||||
#define op(id, name) opcode_table[256 + id] = &GSU::op_##name;
|
||||
op (0x00, stop)
|
||||
op (0x01, nop)
|
||||
op (0x02, cache)
|
||||
op (0x03, lsr)
|
||||
op (0x04, rol)
|
||||
op (0x05, bra)
|
||||
op (0x06, blt)
|
||||
op (0x07, bge)
|
||||
op (0x08, bne)
|
||||
op (0x09, beq)
|
||||
op (0x0a, bpl)
|
||||
op (0x0b, bmi)
|
||||
op (0x0c, bcc)
|
||||
op (0x0d, bcs)
|
||||
op (0x0e, bvc)
|
||||
op (0x0f, bvs)
|
||||
op16 (0x10, to_r)
|
||||
op16 (0x20, with_r)
|
||||
op12 (0x30, stb_ir)
|
||||
op (0x3c, loop)
|
||||
op (0x3d, alt1)
|
||||
op (0x3e, alt2)
|
||||
op (0x3f, alt3)
|
||||
op12 (0x40, ldb_ir)
|
||||
op (0x4c, rpix)
|
||||
op (0x4d, swap)
|
||||
op (0x4e, cmode)
|
||||
op (0x4f, not)
|
||||
op16 (0x50, adc_r)
|
||||
op16 (0x60, sbc_r)
|
||||
op (0x70, merge)
|
||||
op15h(0x71, bic_r)
|
||||
op16 (0x80, umult_r)
|
||||
op (0x90, sbk)
|
||||
op4 (0x91, link)
|
||||
op (0x95, sex)
|
||||
op (0x96, div2)
|
||||
op (0x97, ror)
|
||||
op6 (0x98, ljmp_r)
|
||||
op (0x9e, lob)
|
||||
op (0x9f, lmult)
|
||||
op16 (0xa0, lms_r)
|
||||
op16 (0xb0, from_r)
|
||||
op (0xc0, hib)
|
||||
op15h(0xc1, xor_r)
|
||||
op15l(0xd0, inc_r)
|
||||
op (0xdf, getc)
|
||||
op15l(0xe0, dec_r)
|
||||
op (0xef, getbh)
|
||||
op16 (0xf0, lm_r)
|
||||
#undef op
|
||||
|
||||
//======
|
||||
// ALT2
|
||||
//======
|
||||
|
||||
#define op(id, name) opcode_table[512 + id] = &GSU::op_##name;
|
||||
op (0x00, stop)
|
||||
op (0x01, nop)
|
||||
op (0x02, cache)
|
||||
op (0x03, lsr)
|
||||
op (0x04, rol)
|
||||
op (0x05, bra)
|
||||
op (0x06, blt)
|
||||
op (0x07, bge)
|
||||
op (0x08, bne)
|
||||
op (0x09, beq)
|
||||
op (0x0a, bpl)
|
||||
op (0x0b, bmi)
|
||||
op (0x0c, bcc)
|
||||
op (0x0d, bcs)
|
||||
op (0x0e, bvc)
|
||||
op (0x0f, bvs)
|
||||
op16 (0x10, to_r)
|
||||
op16 (0x20, with_r)
|
||||
op12 (0x30, stw_ir)
|
||||
op (0x3c, loop)
|
||||
op (0x3d, alt1)
|
||||
op (0x3e, alt2)
|
||||
op (0x3f, alt3)
|
||||
op12 (0x40, ldw_ir)
|
||||
op (0x4c, plot)
|
||||
op (0x4d, swap)
|
||||
op (0x4e, color)
|
||||
op (0x4f, not)
|
||||
op16 (0x50, add_i)
|
||||
op16 (0x60, sub_i)
|
||||
op (0x70, merge)
|
||||
op15h(0x71, and_i)
|
||||
op16 (0x80, mult_i)
|
||||
op (0x90, sbk)
|
||||
op4 (0x91, link)
|
||||
op (0x95, sex)
|
||||
op (0x96, asr)
|
||||
op (0x97, ror)
|
||||
op6 (0x98, jmp_r)
|
||||
op (0x9e, lob)
|
||||
op (0x9f, fmult)
|
||||
op16 (0xa0, sms_r)
|
||||
op16 (0xb0, from_r)
|
||||
op (0xc0, hib)
|
||||
op15h(0xc1, or_i)
|
||||
op15l(0xd0, inc_r)
|
||||
op (0xdf, ramb)
|
||||
op15l(0xe0, dec_r)
|
||||
op (0xef, getbl)
|
||||
op16 (0xf0, sm_r)
|
||||
#undef op
|
||||
|
||||
//======
|
||||
// ALT3
|
||||
//======
|
||||
|
||||
#define op(id, name) opcode_table[768 + id] = &GSU::op_##name;
|
||||
op (0x00, stop)
|
||||
op (0x01, nop)
|
||||
op (0x02, cache)
|
||||
op (0x03, lsr)
|
||||
op (0x04, rol)
|
||||
op (0x05, bra)
|
||||
op (0x06, blt)
|
||||
op (0x07, bge)
|
||||
op (0x08, bne)
|
||||
op (0x09, beq)
|
||||
op (0x0a, bpl)
|
||||
op (0x0b, bmi)
|
||||
op (0x0c, bcc)
|
||||
op (0x0d, bcs)
|
||||
op (0x0e, bvc)
|
||||
op (0x0f, bvs)
|
||||
op16 (0x10, to_r)
|
||||
op16 (0x20, with_r)
|
||||
op12 (0x30, stb_ir)
|
||||
op (0x3c, loop)
|
||||
op (0x3d, alt1)
|
||||
op (0x3e, alt2)
|
||||
op (0x3f, alt3)
|
||||
op12 (0x40, ldb_ir)
|
||||
op (0x4c, rpix)
|
||||
op (0x4d, swap)
|
||||
op (0x4e, cmode)
|
||||
op (0x4f, not)
|
||||
op16 (0x50, adc_i)
|
||||
op16 (0x60, cmp_r)
|
||||
op (0x70, merge)
|
||||
op15h(0x71, bic_i)
|
||||
op16 (0x80, umult_i)
|
||||
op (0x90, sbk)
|
||||
op4 (0x91, link)
|
||||
op (0x95, sex)
|
||||
op (0x96, div2)
|
||||
op (0x97, ror)
|
||||
op6 (0x98, ljmp_r)
|
||||
op (0x9e, lob)
|
||||
op (0x9f, lmult)
|
||||
op16 (0xa0, lms_r)
|
||||
op16 (0xb0, from_r)
|
||||
op (0xc0, hib)
|
||||
op15h(0xc1, xor_i)
|
||||
op15l(0xd0, inc_r)
|
||||
op (0xdf, romb)
|
||||
op15l(0xe0, dec_r)
|
||||
op (0xef, getbs)
|
||||
op16 (0xf0, lm_r)
|
||||
#undef op
|
||||
|
||||
#undef op4
|
||||
#undef op6
|
||||
#undef op12
|
||||
#undef op15l
|
||||
#undef op15h
|
||||
#undef op16
|
||||
}
|
@@ -10,8 +10,8 @@ namespace Processor {
|
||||
auto HG51B::exec(uint24 addr) -> void {
|
||||
if(regs.halt) return;
|
||||
addr = addr + regs.pc * 2;
|
||||
opcode = bus_read(addr++) << 0;
|
||||
opcode |= bus_read(addr++) << 8;
|
||||
opcode = read(addr++) << 0;
|
||||
opcode |= read(addr++) << 8;
|
||||
regs.pc = (regs.pc & 0xffff00) | ((regs.pc + 1) & 0x0000ff);
|
||||
instruction();
|
||||
}
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//Hitachi HG51B169 (HG51BS family/derivative?)
|
||||
|
||||
#pragma once
|
||||
|
||||
//Hitachi HG51B169 (HG51BS family/derivative?)
|
||||
|
||||
namespace Processor {
|
||||
|
||||
struct HG51B {
|
||||
auto exec(uint24 addr) -> void;
|
||||
virtual auto bus_read(uint24 addr) -> uint8 = 0;
|
||||
virtual auto bus_write(uint24 addr, uint8 data) -> void = 0;
|
||||
virtual auto read(uint24 addr) -> uint8 = 0;
|
||||
virtual auto write(uint24 addr, uint8 data) -> void = 0;
|
||||
|
||||
auto power() -> void;
|
||||
auto serialize(serializer&) -> void;
|
||||
@@ -25,8 +25,8 @@ protected:
|
||||
auto instruction() -> void;
|
||||
|
||||
//registers.cpp
|
||||
auto reg_read(uint8 addr) const -> uint24;
|
||||
auto reg_write(uint8 addr, uint24 data) -> void;
|
||||
auto regRead(uint8 addr) const -> uint24;
|
||||
auto regWrite(uint8 addr, uint24 data) -> void;
|
||||
|
||||
struct Registers {
|
||||
bool halt;
|
||||
|
@@ -34,7 +34,7 @@ auto HG51B::sa() -> uint {
|
||||
//Register-or-Immediate: most opcodes can load from a register or immediate
|
||||
auto HG51B::ri() -> uint {
|
||||
if(opcode & 0x0400) return opcode & 0xff;
|
||||
return reg_read(opcode & 0xff);
|
||||
return regRead(opcode & 0xff);
|
||||
}
|
||||
|
||||
//New-PC: determine jump target address; opcode.d9 = long jump flag (1 = yes)
|
||||
@@ -115,7 +115,7 @@ auto HG51B::instruction() -> void {
|
||||
else if((opcode & 0xffff) == 0x4000) {
|
||||
//0100 0000 0000 0000
|
||||
//rdbus
|
||||
regs.busdata = bus_read(regs.busaddr++);
|
||||
regs.busdata = read(regs.busaddr++);
|
||||
}
|
||||
|
||||
else if((opcode & 0xf800) == 0x4800) {
|
||||
@@ -306,7 +306,7 @@ auto HG51B::instruction() -> void {
|
||||
else if((opcode & 0xff00) == 0xe000) {
|
||||
//1110 0000 .... ....
|
||||
//st r,a
|
||||
reg_write(opcode & 0xff, regs.a);
|
||||
regWrite(opcode & 0xff, regs.a);
|
||||
}
|
||||
|
||||
else if((opcode & 0xfb00) == 0xe800) {
|
||||
@@ -333,10 +333,10 @@ auto HG51B::instruction() -> void {
|
||||
else if((opcode & 0xff00) == 0xf000) {
|
||||
//1111 0000 .... ....
|
||||
//swap a,r
|
||||
uint24 source = reg_read(opcode & 0xff);
|
||||
uint24 source = regRead(opcode & 0xff);
|
||||
uint24 target = regs.a;
|
||||
regs.a = source;
|
||||
reg_write(opcode & 0xff, target);
|
||||
regWrite(opcode & 0xff, target);
|
||||
}
|
||||
|
||||
else if((opcode & 0xffff) == 0xfc00) {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
auto HG51B::reg_read(uint8 addr) const -> uint24 {
|
||||
auto HG51B::regRead(uint8 addr) const -> uint24 {
|
||||
switch(addr) {
|
||||
case 0x00: return regs.a;
|
||||
case 0x01: return regs.acch;
|
||||
@@ -44,7 +44,7 @@ auto HG51B::reg_read(uint8 addr) const -> uint24 {
|
||||
return 0x000000;
|
||||
}
|
||||
|
||||
auto HG51B::reg_write(uint8 addr, uint24 data) -> void {
|
||||
auto HG51B::regWrite(uint8 addr, uint24 data) -> void {
|
||||
switch(addr) {
|
||||
case 0x00: regs.a = data; return;
|
||||
case 0x01: regs.acch = data; return;
|
||||
|
@@ -20,10 +20,10 @@ auto LR35902::disassemble(uint16 pc) -> string {
|
||||
}
|
||||
|
||||
auto LR35902::disassembleOpcode(uint16 pc) -> string {
|
||||
uint8 opcode = debugger_read(pc);
|
||||
uint8 p0 = debugger_read(pc + 1);
|
||||
uint8 p1 = debugger_read(pc + 2);
|
||||
uint8 p2 = debugger_read(pc + 3);
|
||||
uint8 opcode = debuggerRead(pc);
|
||||
uint8 p0 = debuggerRead(pc + 1);
|
||||
uint8 p1 = debuggerRead(pc + 2);
|
||||
uint8 p2 = debuggerRead(pc + 3);
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00: return { "nop" };
|
||||
@@ -288,10 +288,10 @@ auto LR35902::disassembleOpcode(uint16 pc) -> string {
|
||||
}
|
||||
|
||||
auto LR35902::disassembleOpcodeCB(uint16 pc) -> string {
|
||||
uint8 opcode = debugger_read(pc);
|
||||
uint8 p0 = debugger_read(pc + 1);
|
||||
uint8 p1 = debugger_read(pc + 2);
|
||||
uint8 p2 = debugger_read(pc + 3);
|
||||
uint8 opcode = debuggerRead(pc);
|
||||
uint8 p0 = debuggerRead(pc + 1);
|
||||
uint8 p1 = debuggerRead(pc + 2);
|
||||
uint8 p2 = debuggerRead(pc + 3);
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00: return { "rlc b" };
|
||||
|
@@ -2,115 +2,115 @@ auto LR35902::op_xx() {
|
||||
}
|
||||
|
||||
auto LR35902::op_cb() {
|
||||
execCB();
|
||||
instructionCB();
|
||||
}
|
||||
|
||||
//8-bit load commands
|
||||
|
||||
template<uint x, uint y> auto LR35902::op_ld_r_r() {
|
||||
auto LR35902::op_ld_r_r(uint x, uint y) {
|
||||
r[x] = r[y];
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_ld_r_n() {
|
||||
r[x] = op_read(r[PC]++);
|
||||
auto LR35902::op_ld_r_n(uint x) {
|
||||
r[x] = read(r[PC]++);
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_ld_r_hl() {
|
||||
r[x] = op_read(r[HL]);
|
||||
auto LR35902::op_ld_r_hl(uint x) {
|
||||
r[x] = read(r[HL]);
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_ld_hl_r() {
|
||||
op_write(r[HL], r[x]);
|
||||
auto LR35902::op_ld_hl_r(uint x) {
|
||||
write(r[HL], r[x]);
|
||||
}
|
||||
|
||||
auto LR35902::op_ld_hl_n() {
|
||||
op_write(r[HL], op_read(r[PC]++));
|
||||
write(r[HL], read(r[PC]++));
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_ld_a_rr() {
|
||||
r[A] = op_read(r[x]);
|
||||
auto LR35902::op_ld_a_rr(uint x) {
|
||||
r[A] = read(r[x]);
|
||||
}
|
||||
|
||||
auto LR35902::op_ld_a_nn() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
r[A] = op_read((hi << 8) | (lo << 0));
|
||||
uint8 lo = read(r[PC]++);
|
||||
uint8 hi = read(r[PC]++);
|
||||
r[A] = read((hi << 8) | (lo << 0));
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_ld_rr_a() {
|
||||
op_write(r[x], r[A]);
|
||||
auto LR35902::op_ld_rr_a(uint x) {
|
||||
write(r[x], r[A]);
|
||||
}
|
||||
|
||||
auto LR35902::op_ld_nn_a() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
op_write((hi << 8) | (lo << 0), r[A]);
|
||||
uint8 lo = read(r[PC]++);
|
||||
uint8 hi = read(r[PC]++);
|
||||
write((hi << 8) | (lo << 0), r[A]);
|
||||
}
|
||||
|
||||
auto LR35902::op_ld_a_ffn() {
|
||||
r[A] = op_read(0xff00 + op_read(r[PC]++));
|
||||
r[A] = read(0xff00 + read(r[PC]++));
|
||||
}
|
||||
|
||||
auto LR35902::op_ld_ffn_a() {
|
||||
op_write(0xff00 + op_read(r[PC]++), r[A]);
|
||||
write(0xff00 + read(r[PC]++), r[A]);
|
||||
}
|
||||
|
||||
auto LR35902::op_ld_a_ffc() {
|
||||
r[A] = op_read(0xff00 + r[C]);
|
||||
r[A] = read(0xff00 + r[C]);
|
||||
}
|
||||
|
||||
auto LR35902::op_ld_ffc_a() {
|
||||
op_write(0xff00 + r[C], r[A]);
|
||||
write(0xff00 + r[C], r[A]);
|
||||
}
|
||||
|
||||
auto LR35902::op_ldi_hl_a() {
|
||||
op_write(r[HL], r[A]);
|
||||
write(r[HL], r[A]);
|
||||
r[HL]++;
|
||||
}
|
||||
|
||||
auto LR35902::op_ldi_a_hl() {
|
||||
r[A] = op_read(r[HL]);
|
||||
r[A] = read(r[HL]);
|
||||
r[HL]++;
|
||||
}
|
||||
|
||||
auto LR35902::op_ldd_hl_a() {
|
||||
op_write(r[HL], r[A]);
|
||||
write(r[HL], r[A]);
|
||||
r[HL]--;
|
||||
}
|
||||
|
||||
auto LR35902::op_ldd_a_hl() {
|
||||
r[A] = op_read(r[HL]);
|
||||
r[A] = read(r[HL]);
|
||||
r[HL]--;
|
||||
}
|
||||
|
||||
//16-bit load commands
|
||||
|
||||
template<uint x> auto LR35902::op_ld_rr_nn() {
|
||||
r[x] = op_read(r[PC]++) << 0;
|
||||
r[x] |= op_read(r[PC]++) << 8;
|
||||
auto LR35902::op_ld_rr_nn(uint x) {
|
||||
r[x] = read(r[PC]++) << 0;
|
||||
r[x] |= read(r[PC]++) << 8;
|
||||
}
|
||||
|
||||
auto LR35902::op_ld_nn_sp() {
|
||||
uint16 addr = op_read(r[PC]++) << 0;
|
||||
addr |= op_read(r[PC]++) << 8;
|
||||
op_write(addr + 0, r[SP] >> 0);
|
||||
op_write(addr + 1, r[SP] >> 8);
|
||||
uint16 addr = read(r[PC]++) << 0;
|
||||
addr |= read(r[PC]++) << 8;
|
||||
write(addr + 0, r[SP] >> 0);
|
||||
write(addr + 1, r[SP] >> 8);
|
||||
}
|
||||
|
||||
auto LR35902::op_ld_sp_hl() {
|
||||
r[SP] = r[HL];
|
||||
op_io();
|
||||
io();
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_push_rr() {
|
||||
op_io();
|
||||
op_write(--r[SP], r[x] >> 8);
|
||||
op_write(--r[SP], r[x] >> 0);
|
||||
auto LR35902::op_push_rr(uint x) {
|
||||
io();
|
||||
write(--r[SP], r[x] >> 8);
|
||||
write(--r[SP], r[x] >> 0);
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_pop_rr() {
|
||||
r[x] = op_read(r[SP]++) << 0;
|
||||
r[x] |= op_read(r[SP]++) << 8;
|
||||
auto LR35902::op_pop_rr(uint x) {
|
||||
r[x] = read(r[SP]++) << 0;
|
||||
r[x] |= read(r[SP]++) << 8;
|
||||
}
|
||||
|
||||
//8-bit arithmetic commands
|
||||
@@ -125,9 +125,9 @@ auto LR35902::opi_add_a(uint8 x) {
|
||||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_add_a_r() { opi_add_a(r[x]); }
|
||||
auto LR35902::op_add_a_n() { opi_add_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_add_a_hl() { opi_add_a(op_read(r[HL])); }
|
||||
auto LR35902::op_add_a_r(uint x) { opi_add_a(r[x]); }
|
||||
auto LR35902::op_add_a_n() { opi_add_a(read(r[PC]++)); }
|
||||
auto LR35902::op_add_a_hl() { opi_add_a(read(r[HL])); }
|
||||
|
||||
auto LR35902::opi_adc_a(uint8 x) {
|
||||
uint16 rh = r[A] + x + r.f.c;
|
||||
@@ -139,9 +139,9 @@ auto LR35902::opi_adc_a(uint8 x) {
|
||||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_adc_a_r() { opi_adc_a(r[x]); }
|
||||
auto LR35902::op_adc_a_n() { opi_adc_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_adc_a_hl() { opi_adc_a(op_read(r[HL])); }
|
||||
auto LR35902::op_adc_a_r(uint x) { opi_adc_a(r[x]); }
|
||||
auto LR35902::op_adc_a_n() { opi_adc_a(read(r[PC]++)); }
|
||||
auto LR35902::op_adc_a_hl() { opi_adc_a(read(r[HL])); }
|
||||
|
||||
auto LR35902::opi_sub_a(uint8 x) {
|
||||
uint16 rh = r[A] - x;
|
||||
@@ -153,9 +153,9 @@ auto LR35902::opi_sub_a(uint8 x) {
|
||||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_sub_a_r() { opi_sub_a(r[x]); }
|
||||
auto LR35902::op_sub_a_n() { opi_sub_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_sub_a_hl() { opi_sub_a(op_read(r[HL])); }
|
||||
auto LR35902::op_sub_a_r(uint x) { opi_sub_a(r[x]); }
|
||||
auto LR35902::op_sub_a_n() { opi_sub_a(read(r[PC]++)); }
|
||||
auto LR35902::op_sub_a_hl() { opi_sub_a(read(r[HL])); }
|
||||
|
||||
auto LR35902::opi_sbc_a(uint8 x) {
|
||||
uint16 rh = r[A] - x - r.f.c;
|
||||
@@ -167,9 +167,9 @@ auto LR35902::opi_sbc_a(uint8 x) {
|
||||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_sbc_a_r() { opi_sbc_a(r[x]); }
|
||||
auto LR35902::op_sbc_a_n() { opi_sbc_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_sbc_a_hl() { opi_sbc_a(op_read(r[HL])); }
|
||||
auto LR35902::op_sbc_a_r(uint x) { opi_sbc_a(r[x]); }
|
||||
auto LR35902::op_sbc_a_n() { opi_sbc_a(read(r[PC]++)); }
|
||||
auto LR35902::op_sbc_a_hl() { opi_sbc_a(read(r[HL])); }
|
||||
|
||||
auto LR35902::opi_and_a(uint8 x) {
|
||||
r[A] &= x;
|
||||
@@ -179,9 +179,9 @@ auto LR35902::opi_and_a(uint8 x) {
|
||||
r.f.c = 0;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_and_a_r() { opi_and_a(r[x]); }
|
||||
auto LR35902::op_and_a_n() { opi_and_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_and_a_hl() { opi_and_a(op_read(r[HL])); }
|
||||
auto LR35902::op_and_a_r(uint x) { opi_and_a(r[x]); }
|
||||
auto LR35902::op_and_a_n() { opi_and_a(read(r[PC]++)); }
|
||||
auto LR35902::op_and_a_hl() { opi_and_a(read(r[HL])); }
|
||||
|
||||
auto LR35902::opi_xor_a(uint8 x) {
|
||||
r[A] ^= x;
|
||||
@@ -191,9 +191,9 @@ auto LR35902::opi_xor_a(uint8 x) {
|
||||
r.f.c = 0;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_xor_a_r() { opi_xor_a(r[x]); }
|
||||
auto LR35902::op_xor_a_n() { opi_xor_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_xor_a_hl() { opi_xor_a(op_read(r[HL])); }
|
||||
auto LR35902::op_xor_a_r(uint x) { opi_xor_a(r[x]); }
|
||||
auto LR35902::op_xor_a_n() { opi_xor_a(read(r[PC]++)); }
|
||||
auto LR35902::op_xor_a_hl() { opi_xor_a(read(r[HL])); }
|
||||
|
||||
auto LR35902::opi_or_a(uint8 x) {
|
||||
r[A] |= x;
|
||||
@@ -203,9 +203,9 @@ auto LR35902::opi_or_a(uint8 x) {
|
||||
r.f.c = 0;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_or_a_r() { opi_or_a(r[x]); }
|
||||
auto LR35902::op_or_a_n() { opi_or_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_or_a_hl() { opi_or_a(op_read(r[HL])); }
|
||||
auto LR35902::op_or_a_r(uint x) { opi_or_a(r[x]); }
|
||||
auto LR35902::op_or_a_n() { opi_or_a(read(r[PC]++)); }
|
||||
auto LR35902::op_or_a_hl() { opi_or_a(read(r[HL])); }
|
||||
|
||||
auto LR35902::opi_cp_a(uint8 x) {
|
||||
uint16 rh = r[A] - x;
|
||||
@@ -216,11 +216,11 @@ auto LR35902::opi_cp_a(uint8 x) {
|
||||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_cp_a_r() { opi_cp_a(r[x]); }
|
||||
auto LR35902::op_cp_a_n() { opi_cp_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_cp_a_hl() { opi_cp_a(op_read(r[HL])); }
|
||||
auto LR35902::op_cp_a_r(uint x) { opi_cp_a(r[x]); }
|
||||
auto LR35902::op_cp_a_n() { opi_cp_a(read(r[PC]++)); }
|
||||
auto LR35902::op_cp_a_hl() { opi_cp_a(read(r[HL])); }
|
||||
|
||||
template<uint x> auto LR35902::op_inc_r() {
|
||||
auto LR35902::op_inc_r(uint x) {
|
||||
r[x]++;
|
||||
r.f.z = r[x] == 0;
|
||||
r.f.n = 0;
|
||||
@@ -228,14 +228,14 @@ template<uint x> auto LR35902::op_inc_r() {
|
||||
}
|
||||
|
||||
auto LR35902::op_inc_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
op_write(r[HL], ++n);
|
||||
uint8 n = read(r[HL]);
|
||||
write(r[HL], ++n);
|
||||
r.f.z = n == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = (n & 0x0f) == 0x00;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_dec_r() {
|
||||
auto LR35902::op_dec_r(uint x) {
|
||||
r[x]--;
|
||||
r.f.z = r[x] == 0;
|
||||
r.f.n = 1;
|
||||
@@ -243,8 +243,8 @@ template<uint x> auto LR35902::op_dec_r() {
|
||||
}
|
||||
|
||||
auto LR35902::op_dec_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
op_write(r[HL], --n);
|
||||
uint8 n = read(r[HL]);
|
||||
write(r[HL], --n);
|
||||
r.f.z = n == 0;
|
||||
r.f.n = 1;
|
||||
r.f.h = (n & 0x0f) == 0x0f;
|
||||
@@ -276,8 +276,8 @@ auto LR35902::op_cpl() {
|
||||
|
||||
//16-bit arithmetic commands
|
||||
|
||||
template<uint x> auto LR35902::op_add_hl_rr() {
|
||||
op_io();
|
||||
auto LR35902::op_add_hl_rr(uint x) {
|
||||
io();
|
||||
uint32 rb = (r[HL] + r[x]);
|
||||
uint32 rn = (r[HL] & 0xfff) + (r[x] & 0xfff);
|
||||
r[HL] = rb;
|
||||
@@ -286,35 +286,35 @@ template<uint x> auto LR35902::op_add_hl_rr() {
|
||||
r.f.c = rb > 0xffff;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_inc_rr() {
|
||||
op_io();
|
||||
auto LR35902::op_inc_rr(uint x) {
|
||||
io();
|
||||
r[x]++;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_dec_rr() {
|
||||
op_io();
|
||||
auto LR35902::op_dec_rr(uint x) {
|
||||
io();
|
||||
r[x]--;
|
||||
}
|
||||
|
||||
auto LR35902::op_add_sp_n() {
|
||||
int n = (int8)op_read(r[PC]++);
|
||||
int n = (int8)read(r[PC]++);
|
||||
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;
|
||||
op_io();
|
||||
op_io();
|
||||
io();
|
||||
io();
|
||||
}
|
||||
|
||||
auto LR35902::op_ld_hl_sp_n() {
|
||||
int n = (int8)op_read(r[PC]++);
|
||||
int n = (int8)read(r[PC]++);
|
||||
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;
|
||||
op_io();
|
||||
io();
|
||||
}
|
||||
|
||||
//rotate/shift commands
|
||||
@@ -353,7 +353,7 @@ auto LR35902::op_rra() {
|
||||
r.f.c = c;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_rlc_r() {
|
||||
auto LR35902::op_rlc_r(uint x) {
|
||||
r[x] = (r[x] << 1) | (r[x] >> 7);
|
||||
r.f.z = r[x] == 0;
|
||||
r.f.n = 0;
|
||||
@@ -362,16 +362,16 @@ template<uint x> auto LR35902::op_rlc_r() {
|
||||
}
|
||||
|
||||
auto LR35902::op_rlc_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
uint8 n = read(r[HL]);
|
||||
n = (n << 1) | (n >> 7);
|
||||
op_write(r[HL], n);
|
||||
write(r[HL], n);
|
||||
r.f.z = n == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 0;
|
||||
r.f.c = n & 0x01;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_rl_r() {
|
||||
auto LR35902::op_rl_r(uint x) {
|
||||
bool c = r[x] & 0x80;
|
||||
r[x] = (r[x] << 1) | (r.f.c << 0);
|
||||
r.f.z = r[x] == 0;
|
||||
@@ -381,17 +381,17 @@ template<uint x> auto LR35902::op_rl_r() {
|
||||
}
|
||||
|
||||
auto LR35902::op_rl_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
uint8 n = read(r[HL]);
|
||||
bool c = n & 0x80;
|
||||
n = (n << 1) | (r.f.c << 0);
|
||||
op_write(r[HL], n);
|
||||
write(r[HL], n);
|
||||
r.f.z = n == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 0;
|
||||
r.f.c = c;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_rrc_r() {
|
||||
auto LR35902::op_rrc_r(uint x) {
|
||||
r[x] = (r[x] >> 1) | (r[x] << 7);
|
||||
r.f.z = r[x] == 0;
|
||||
r.f.n = 0;
|
||||
@@ -400,16 +400,16 @@ template<uint x> auto LR35902::op_rrc_r() {
|
||||
}
|
||||
|
||||
auto LR35902::op_rrc_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
uint8 n = read(r[HL]);
|
||||
n = (n >> 1) | (n << 7);
|
||||
op_write(r[HL], n);
|
||||
write(r[HL], n);
|
||||
r.f.z = n == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 0;
|
||||
r.f.c = n & 0x80;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_rr_r() {
|
||||
auto LR35902::op_rr_r(uint x) {
|
||||
bool c = r[x] & 0x01;
|
||||
r[x] = (r[x] >> 1) | (r.f.c << 7);
|
||||
r.f.z = r[x] == 0;
|
||||
@@ -419,17 +419,17 @@ template<uint x> auto LR35902::op_rr_r() {
|
||||
}
|
||||
|
||||
auto LR35902::op_rr_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
uint8 n = read(r[HL]);
|
||||
bool c = n & 0x01;
|
||||
n = (n >> 1) | (r.f.c << 7);
|
||||
op_write(r[HL], n);
|
||||
write(r[HL], n);
|
||||
r.f.z = n == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 0;
|
||||
r.f.c = c;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_sla_r() {
|
||||
auto LR35902::op_sla_r(uint x) {
|
||||
bool c = r[x] & 0x80;
|
||||
r[x] <<= 1;
|
||||
r.f.z = r[x] == 0;
|
||||
@@ -439,17 +439,17 @@ template<uint x> auto LR35902::op_sla_r() {
|
||||
}
|
||||
|
||||
auto LR35902::op_sla_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
uint8 n = read(r[HL]);
|
||||
bool c = n & 0x80;
|
||||
n <<= 1;
|
||||
op_write(r[HL], n);
|
||||
write(r[HL], n);
|
||||
r.f.z = n == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 0;
|
||||
r.f.c = c;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_swap_r() {
|
||||
auto LR35902::op_swap_r(uint x) {
|
||||
r[x] = (r[x] << 4) | (r[x] >> 4);
|
||||
r.f.z = r[x] == 0;
|
||||
r.f.n = 0;
|
||||
@@ -458,16 +458,16 @@ template<uint x> auto LR35902::op_swap_r() {
|
||||
}
|
||||
|
||||
auto LR35902::op_swap_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
uint8 n = read(r[HL]);
|
||||
n = (n << 4) | (n >> 4);
|
||||
op_write(r[HL], n);
|
||||
write(r[HL], n);
|
||||
r.f.z = n == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 0;
|
||||
r.f.c = 0;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_sra_r() {
|
||||
auto LR35902::op_sra_r(uint x) {
|
||||
bool c = r[x] & 0x01;
|
||||
r[x] = (int8)r[x] >> 1;
|
||||
r.f.z = r[x] == 0;
|
||||
@@ -477,17 +477,17 @@ template<uint x> auto LR35902::op_sra_r() {
|
||||
}
|
||||
|
||||
auto LR35902::op_sra_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
uint8 n = read(r[HL]);
|
||||
bool c = n & 0x01;
|
||||
n = (int8)n >> 1;
|
||||
op_write(r[HL], n);
|
||||
write(r[HL], n);
|
||||
r.f.z = n == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 0;
|
||||
r.f.c = c;
|
||||
}
|
||||
|
||||
template<uint x> auto LR35902::op_srl_r() {
|
||||
auto LR35902::op_srl_r(uint x) {
|
||||
bool c = r[x] & 0x01;
|
||||
r[x] >>= 1;
|
||||
r.f.z = r[x] == 0;
|
||||
@@ -497,10 +497,10 @@ template<uint x> auto LR35902::op_srl_r() {
|
||||
}
|
||||
|
||||
auto LR35902::op_srl_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
uint8 n = read(r[HL]);
|
||||
bool c = n & 0x01;
|
||||
n >>= 1;
|
||||
op_write(r[HL], n);
|
||||
write(r[HL], n);
|
||||
r.f.z = n == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 0;
|
||||
@@ -509,37 +509,37 @@ auto LR35902::op_srl_hl() {
|
||||
|
||||
//single-bit commands
|
||||
|
||||
template<uint b, uint x> auto LR35902::op_bit_n_r() {
|
||||
auto LR35902::op_bit_n_r(uint b, uint x) {
|
||||
r.f.z = (r[x] & (1 << b)) == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 1;
|
||||
}
|
||||
|
||||
template<uint b> auto LR35902::op_bit_n_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
auto LR35902::op_bit_n_hl(uint b) {
|
||||
uint8 n = read(r[HL]);
|
||||
r.f.z = (n & (1 << b)) == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 1;
|
||||
}
|
||||
|
||||
template<uint b, uint x> auto LR35902::op_set_n_r() {
|
||||
auto LR35902::op_set_n_r(uint b, uint x) {
|
||||
r[x] |= 1 << b;
|
||||
}
|
||||
|
||||
template<uint b> auto LR35902::op_set_n_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
auto LR35902::op_set_n_hl(uint b) {
|
||||
uint8 n = read(r[HL]);
|
||||
n |= 1 << b;
|
||||
op_write(r[HL], n);
|
||||
write(r[HL], n);
|
||||
}
|
||||
|
||||
template<uint b, uint x> auto LR35902::op_res_n_r() {
|
||||
auto LR35902::op_res_n_r(uint b, uint x) {
|
||||
r[x] &= ~(1 << b);
|
||||
}
|
||||
|
||||
template<uint b> auto LR35902::op_res_n_hl() {
|
||||
uint n = op_read(r[HL]);
|
||||
auto LR35902::op_res_n_hl(uint b) {
|
||||
uint n = read(r[HL]);
|
||||
n &= ~(1 << b);
|
||||
op_write(r[HL], n);
|
||||
write(r[HL], n);
|
||||
}
|
||||
|
||||
//control commands
|
||||
@@ -561,13 +561,13 @@ auto LR35902::op_nop() {
|
||||
|
||||
auto LR35902::op_halt() {
|
||||
r.halt = true;
|
||||
while(r.halt == true) op_io();
|
||||
while(r.halt) io();
|
||||
}
|
||||
|
||||
auto LR35902::op_stop() {
|
||||
if(stop()) return;
|
||||
r.stop = true;
|
||||
while(r.stop == true) op_io();
|
||||
while(r.stop) io();
|
||||
}
|
||||
|
||||
auto LR35902::op_di() {
|
||||
@@ -582,87 +582,87 @@ auto LR35902::op_ei() {
|
||||
//jump commands
|
||||
|
||||
auto LR35902::op_jp_nn() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
uint8 lo = read(r[PC]++);
|
||||
uint8 hi = read(r[PC]++);
|
||||
r[PC] = (hi << 8) | (lo << 0);
|
||||
op_io();
|
||||
io();
|
||||
}
|
||||
|
||||
auto LR35902::op_jp_hl() {
|
||||
r[PC] = r[HL];
|
||||
}
|
||||
|
||||
template<uint x, bool y> auto LR35902::op_jp_f_nn() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
auto LR35902::op_jp_f_nn(uint x, bool y) {
|
||||
uint8 lo = read(r[PC]++);
|
||||
uint8 hi = read(r[PC]++);
|
||||
if(r.f[x] == y) {
|
||||
r[PC] = (hi << 8) | (lo << 0);
|
||||
op_io();
|
||||
io();
|
||||
}
|
||||
}
|
||||
|
||||
auto LR35902::op_jr_n() {
|
||||
int8 n = op_read(r[PC]++);
|
||||
int8 n = read(r[PC]++);
|
||||
r[PC] += n;
|
||||
op_io();
|
||||
io();
|
||||
}
|
||||
|
||||
template<uint x, bool y> auto LR35902::op_jr_f_n() {
|
||||
int8 n = op_read(r[PC]++);
|
||||
auto LR35902::op_jr_f_n(uint x, bool y) {
|
||||
int8 n = read(r[PC]++);
|
||||
if(r.f[x] == y) {
|
||||
r[PC] += n;
|
||||
op_io();
|
||||
io();
|
||||
}
|
||||
}
|
||||
|
||||
auto LR35902::op_call_nn() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
op_io();
|
||||
op_write(--r[SP], r[PC] >> 8);
|
||||
op_write(--r[SP], r[PC] >> 0);
|
||||
uint8 lo = read(r[PC]++);
|
||||
uint8 hi = read(r[PC]++);
|
||||
io();
|
||||
write(--r[SP], r[PC] >> 8);
|
||||
write(--r[SP], r[PC] >> 0);
|
||||
r[PC] = (hi << 8) | (lo << 0);
|
||||
}
|
||||
|
||||
template<uint x, bool y> auto LR35902::op_call_f_nn() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
auto LR35902::op_call_f_nn(uint x, bool y) {
|
||||
uint8 lo = read(r[PC]++);
|
||||
uint8 hi = read(r[PC]++);
|
||||
if(r.f[x] == y) {
|
||||
op_io();
|
||||
op_write(--r[SP], r[PC] >> 8);
|
||||
op_write(--r[SP], r[PC] >> 0);
|
||||
io();
|
||||
write(--r[SP], r[PC] >> 8);
|
||||
write(--r[SP], r[PC] >> 0);
|
||||
r[PC] = (hi << 8) | (lo << 0);
|
||||
}
|
||||
}
|
||||
|
||||
auto LR35902::op_ret() {
|
||||
uint8 lo = op_read(r[SP]++);
|
||||
uint8 hi = op_read(r[SP]++);
|
||||
uint8 lo = read(r[SP]++);
|
||||
uint8 hi = read(r[SP]++);
|
||||
r[PC] = (hi << 8) | (lo << 0);
|
||||
op_io();
|
||||
io();
|
||||
}
|
||||
|
||||
template<uint x, bool y> auto LR35902::op_ret_f() {
|
||||
op_io();
|
||||
auto LR35902::op_ret_f(uint x, bool y) {
|
||||
io();
|
||||
if(r.f[x] == y) {
|
||||
uint8 lo = op_read(r[SP]++);
|
||||
uint8 hi = op_read(r[SP]++);
|
||||
uint8 lo = read(r[SP]++);
|
||||
uint8 hi = read(r[SP]++);
|
||||
r[PC] = (hi << 8) | (lo << 0);
|
||||
op_io();
|
||||
io();
|
||||
}
|
||||
}
|
||||
|
||||
auto LR35902::op_reti() {
|
||||
uint8 lo = op_read(r[SP]++);
|
||||
uint8 hi = op_read(r[SP]++);
|
||||
uint8 lo = read(r[SP]++);
|
||||
uint8 hi = read(r[SP]++);
|
||||
r[PC] = (hi << 8) | (lo << 0);
|
||||
op_io();
|
||||
io();
|
||||
r.ime = 1;
|
||||
}
|
||||
|
||||
template<uint n> auto LR35902::op_rst_n() {
|
||||
op_io();
|
||||
op_write(--r[SP], r[PC] >> 8);
|
||||
op_write(--r[SP], r[PC] >> 0);
|
||||
auto LR35902::op_rst_n(uint n) {
|
||||
io();
|
||||
write(--r[SP], r[PC] >> 8);
|
||||
write(--r[SP], r[PC] >> 0);
|
||||
r[PC] = n;
|
||||
}
|
||||
|
@@ -14,241 +14,250 @@ auto LR35902::power() -> void {
|
||||
r.ime = false;
|
||||
}
|
||||
|
||||
auto LR35902::exec() -> void {
|
||||
uint8 opcode = op_read(r[PC]++);
|
||||
switch(opcode) {
|
||||
auto LR35902::interrupt(uint16 vector) -> void {
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
r.ime = 0;
|
||||
write(--r[SP], r[PC] >> 8);
|
||||
write(--r[SP], r[PC] >> 0);
|
||||
r[PC] = vector;
|
||||
}
|
||||
|
||||
auto LR35902::instruction() -> void {
|
||||
switch(auto opcode = read(r[PC]++)) {
|
||||
case 0x00: return op_nop();
|
||||
case 0x01: return op_ld_rr_nn<BC>();
|
||||
case 0x02: return op_ld_rr_a<BC>();
|
||||
case 0x03: return op_inc_rr<BC>();
|
||||
case 0x04: return op_inc_r<B>();
|
||||
case 0x05: return op_dec_r<B>();
|
||||
case 0x06: return op_ld_r_n<B>();
|
||||
case 0x01: return op_ld_rr_nn(BC);
|
||||
case 0x02: return op_ld_rr_a(BC);
|
||||
case 0x03: return op_inc_rr(BC);
|
||||
case 0x04: return op_inc_r(B);
|
||||
case 0x05: return op_dec_r(B);
|
||||
case 0x06: return op_ld_r_n(B);
|
||||
case 0x07: return op_rlca();
|
||||
case 0x08: return op_ld_nn_sp();
|
||||
case 0x09: return op_add_hl_rr<BC>();
|
||||
case 0x0a: return op_ld_a_rr<BC>();
|
||||
case 0x0b: return op_dec_rr<BC>();
|
||||
case 0x0c: return op_inc_r<C>();
|
||||
case 0x0d: return op_dec_r<C>();
|
||||
case 0x0e: return op_ld_r_n<C>();
|
||||
case 0x09: return op_add_hl_rr(BC);
|
||||
case 0x0a: return op_ld_a_rr(BC);
|
||||
case 0x0b: return op_dec_rr(BC);
|
||||
case 0x0c: return op_inc_r(C);
|
||||
case 0x0d: return op_dec_r(C);
|
||||
case 0x0e: return op_ld_r_n(C);
|
||||
case 0x0f: return op_rrca();
|
||||
case 0x10: return op_stop();
|
||||
case 0x11: return op_ld_rr_nn<DE>();
|
||||
case 0x12: return op_ld_rr_a<DE>();
|
||||
case 0x13: return op_inc_rr<DE>();
|
||||
case 0x14: return op_inc_r<D>();
|
||||
case 0x15: return op_dec_r<D>();
|
||||
case 0x16: return op_ld_r_n<D>();
|
||||
case 0x11: return op_ld_rr_nn(DE);
|
||||
case 0x12: return op_ld_rr_a(DE);
|
||||
case 0x13: return op_inc_rr(DE);
|
||||
case 0x14: return op_inc_r(D);
|
||||
case 0x15: return op_dec_r(D);
|
||||
case 0x16: return op_ld_r_n(D);
|
||||
case 0x17: return op_rla();
|
||||
case 0x18: return op_jr_n();
|
||||
case 0x19: return op_add_hl_rr<DE>();
|
||||
case 0x1a: return op_ld_a_rr<DE>();
|
||||
case 0x1b: return op_dec_rr<DE>();
|
||||
case 0x1c: return op_inc_r<E>();
|
||||
case 0x1d: return op_dec_r<E>();
|
||||
case 0x1e: return op_ld_r_n<E>();
|
||||
case 0x19: return op_add_hl_rr(DE);
|
||||
case 0x1a: return op_ld_a_rr(DE);
|
||||
case 0x1b: return op_dec_rr(DE);
|
||||
case 0x1c: return op_inc_r(E);
|
||||
case 0x1d: return op_dec_r(E);
|
||||
case 0x1e: return op_ld_r_n(E);
|
||||
case 0x1f: return op_rra();
|
||||
case 0x20: return op_jr_f_n<ZF, 0>();
|
||||
case 0x21: return op_ld_rr_nn<HL>();
|
||||
case 0x20: return op_jr_f_n(ZF, 0);
|
||||
case 0x21: return op_ld_rr_nn(HL);
|
||||
case 0x22: return op_ldi_hl_a();
|
||||
case 0x23: return op_inc_rr<HL>();
|
||||
case 0x24: return op_inc_r<H>();
|
||||
case 0x25: return op_dec_r<H>();
|
||||
case 0x26: return op_ld_r_n<H>();
|
||||
case 0x23: return op_inc_rr(HL);
|
||||
case 0x24: return op_inc_r(H);
|
||||
case 0x25: return op_dec_r(H);
|
||||
case 0x26: return op_ld_r_n(H);
|
||||
case 0x27: return op_daa();
|
||||
case 0x28: return op_jr_f_n<ZF, 1>();
|
||||
case 0x29: return op_add_hl_rr<HL>();
|
||||
case 0x28: return op_jr_f_n(ZF, 1);
|
||||
case 0x29: return op_add_hl_rr(HL);
|
||||
case 0x2a: return op_ldi_a_hl();
|
||||
case 0x2b: return op_dec_rr<HL>();
|
||||
case 0x2c: return op_inc_r<L>();
|
||||
case 0x2d: return op_dec_r<L>();
|
||||
case 0x2e: return op_ld_r_n<L>();
|
||||
case 0x2b: return op_dec_rr(HL);
|
||||
case 0x2c: return op_inc_r(L);
|
||||
case 0x2d: return op_dec_r(L);
|
||||
case 0x2e: return op_ld_r_n(L);
|
||||
case 0x2f: return op_cpl();
|
||||
case 0x30: return op_jr_f_n<CF, 0>();
|
||||
case 0x31: return op_ld_rr_nn<SP>();
|
||||
case 0x30: return op_jr_f_n(CF, 0);
|
||||
case 0x31: return op_ld_rr_nn(SP);
|
||||
case 0x32: return op_ldd_hl_a();
|
||||
case 0x33: return op_inc_rr<SP>();
|
||||
case 0x33: return op_inc_rr(SP);
|
||||
case 0x34: return op_inc_hl();
|
||||
case 0x35: return op_dec_hl();
|
||||
case 0x36: return op_ld_hl_n();
|
||||
case 0x37: return op_scf();
|
||||
case 0x38: return op_jr_f_n<CF, 1>();
|
||||
case 0x39: return op_add_hl_rr<SP>();
|
||||
case 0x38: return op_jr_f_n(CF, 1);
|
||||
case 0x39: return op_add_hl_rr(SP);
|
||||
case 0x3a: return op_ldd_a_hl();
|
||||
case 0x3b: return op_dec_rr<SP>();
|
||||
case 0x3c: return op_inc_r<A>();
|
||||
case 0x3d: return op_dec_r<A>();
|
||||
case 0x3e: return op_ld_r_n<A>();
|
||||
case 0x3b: return op_dec_rr(SP);
|
||||
case 0x3c: return op_inc_r(A);
|
||||
case 0x3d: return op_dec_r(A);
|
||||
case 0x3e: return op_ld_r_n(A);
|
||||
case 0x3f: return op_ccf();
|
||||
case 0x40: return op_ld_r_r<B, B>();
|
||||
case 0x41: return op_ld_r_r<B, C>();
|
||||
case 0x42: return op_ld_r_r<B, D>();
|
||||
case 0x43: return op_ld_r_r<B, E>();
|
||||
case 0x44: return op_ld_r_r<B, H>();
|
||||
case 0x45: return op_ld_r_r<B, L>();
|
||||
case 0x46: return op_ld_r_hl<B>();
|
||||
case 0x47: return op_ld_r_r<B, A>();
|
||||
case 0x48: return op_ld_r_r<C, B>();
|
||||
case 0x49: return op_ld_r_r<C, C>();
|
||||
case 0x4a: return op_ld_r_r<C, D>();
|
||||
case 0x4b: return op_ld_r_r<C, E>();
|
||||
case 0x4c: return op_ld_r_r<C, H>();
|
||||
case 0x4d: return op_ld_r_r<C, L>();
|
||||
case 0x4e: return op_ld_r_hl<C>();
|
||||
case 0x4f: return op_ld_r_r<C, A>();
|
||||
case 0x50: return op_ld_r_r<D, B>();
|
||||
case 0x51: return op_ld_r_r<D, C>();
|
||||
case 0x52: return op_ld_r_r<D, D>();
|
||||
case 0x53: return op_ld_r_r<D, E>();
|
||||
case 0x54: return op_ld_r_r<D, H>();
|
||||
case 0x55: return op_ld_r_r<D, L>();
|
||||
case 0x56: return op_ld_r_hl<D>();
|
||||
case 0x57: return op_ld_r_r<D, A>();
|
||||
case 0x58: return op_ld_r_r<E, B>();
|
||||
case 0x59: return op_ld_r_r<E, C>();
|
||||
case 0x5a: return op_ld_r_r<E, D>();
|
||||
case 0x5b: return op_ld_r_r<E, E>();
|
||||
case 0x5c: return op_ld_r_r<E, H>();
|
||||
case 0x5d: return op_ld_r_r<E, L>();
|
||||
case 0x5e: return op_ld_r_hl<E>();
|
||||
case 0x5f: return op_ld_r_r<E, A>();
|
||||
case 0x60: return op_ld_r_r<H, B>();
|
||||
case 0x61: return op_ld_r_r<H, C>();
|
||||
case 0x62: return op_ld_r_r<H, D>();
|
||||
case 0x63: return op_ld_r_r<H, E>();
|
||||
case 0x64: return op_ld_r_r<H, H>();
|
||||
case 0x65: return op_ld_r_r<H, L>();
|
||||
case 0x66: return op_ld_r_hl<H>();
|
||||
case 0x67: return op_ld_r_r<H, A>();
|
||||
case 0x68: return op_ld_r_r<L, B>();
|
||||
case 0x69: return op_ld_r_r<L, C>();
|
||||
case 0x6a: return op_ld_r_r<L, D>();
|
||||
case 0x6b: return op_ld_r_r<L, E>();
|
||||
case 0x6c: return op_ld_r_r<L, H>();
|
||||
case 0x6d: return op_ld_r_r<L, L>();
|
||||
case 0x6e: return op_ld_r_hl<L>();
|
||||
case 0x6f: return op_ld_r_r<L, A>();
|
||||
case 0x70: return op_ld_hl_r<B>();
|
||||
case 0x71: return op_ld_hl_r<C>();
|
||||
case 0x72: return op_ld_hl_r<D>();
|
||||
case 0x73: return op_ld_hl_r<E>();
|
||||
case 0x74: return op_ld_hl_r<H>();
|
||||
case 0x75: return op_ld_hl_r<L>();
|
||||
case 0x40: return op_ld_r_r(B, B);
|
||||
case 0x41: return op_ld_r_r(B, C);
|
||||
case 0x42: return op_ld_r_r(B, D);
|
||||
case 0x43: return op_ld_r_r(B, E);
|
||||
case 0x44: return op_ld_r_r(B, H);
|
||||
case 0x45: return op_ld_r_r(B, L);
|
||||
case 0x46: return op_ld_r_hl(B);
|
||||
case 0x47: return op_ld_r_r(B, A);
|
||||
case 0x48: return op_ld_r_r(C, B);
|
||||
case 0x49: return op_ld_r_r(C, C);
|
||||
case 0x4a: return op_ld_r_r(C, D);
|
||||
case 0x4b: return op_ld_r_r(C, E);
|
||||
case 0x4c: return op_ld_r_r(C, H);
|
||||
case 0x4d: return op_ld_r_r(C, L);
|
||||
case 0x4e: return op_ld_r_hl(C);
|
||||
case 0x4f: return op_ld_r_r(C, A);
|
||||
case 0x50: return op_ld_r_r(D, B);
|
||||
case 0x51: return op_ld_r_r(D, C);
|
||||
case 0x52: return op_ld_r_r(D, D);
|
||||
case 0x53: return op_ld_r_r(D, E);
|
||||
case 0x54: return op_ld_r_r(D, H);
|
||||
case 0x55: return op_ld_r_r(D, L);
|
||||
case 0x56: return op_ld_r_hl(D);
|
||||
case 0x57: return op_ld_r_r(D, A);
|
||||
case 0x58: return op_ld_r_r(E, B);
|
||||
case 0x59: return op_ld_r_r(E, C);
|
||||
case 0x5a: return op_ld_r_r(E, D);
|
||||
case 0x5b: return op_ld_r_r(E, E);
|
||||
case 0x5c: return op_ld_r_r(E, H);
|
||||
case 0x5d: return op_ld_r_r(E, L);
|
||||
case 0x5e: return op_ld_r_hl(E);
|
||||
case 0x5f: return op_ld_r_r(E, A);
|
||||
case 0x60: return op_ld_r_r(H, B);
|
||||
case 0x61: return op_ld_r_r(H, C);
|
||||
case 0x62: return op_ld_r_r(H, D);
|
||||
case 0x63: return op_ld_r_r(H, E);
|
||||
case 0x64: return op_ld_r_r(H, H);
|
||||
case 0x65: return op_ld_r_r(H, L);
|
||||
case 0x66: return op_ld_r_hl(H);
|
||||
case 0x67: return op_ld_r_r(H, A);
|
||||
case 0x68: return op_ld_r_r(L, B);
|
||||
case 0x69: return op_ld_r_r(L, C);
|
||||
case 0x6a: return op_ld_r_r(L, D);
|
||||
case 0x6b: return op_ld_r_r(L, E);
|
||||
case 0x6c: return op_ld_r_r(L, H);
|
||||
case 0x6d: return op_ld_r_r(L, L);
|
||||
case 0x6e: return op_ld_r_hl(L);
|
||||
case 0x6f: return op_ld_r_r(L, A);
|
||||
case 0x70: return op_ld_hl_r(B);
|
||||
case 0x71: return op_ld_hl_r(C);
|
||||
case 0x72: return op_ld_hl_r(D);
|
||||
case 0x73: return op_ld_hl_r(E);
|
||||
case 0x74: return op_ld_hl_r(H);
|
||||
case 0x75: return op_ld_hl_r(L);
|
||||
case 0x76: return op_halt();
|
||||
case 0x77: return op_ld_hl_r<A>();
|
||||
case 0x78: return op_ld_r_r<A, B>();
|
||||
case 0x79: return op_ld_r_r<A, C>();
|
||||
case 0x7a: return op_ld_r_r<A, D>();
|
||||
case 0x7b: return op_ld_r_r<A, E>();
|
||||
case 0x7c: return op_ld_r_r<A, H>();
|
||||
case 0x7d: return op_ld_r_r<A, L>();
|
||||
case 0x7e: return op_ld_r_hl<A>();
|
||||
case 0x7f: return op_ld_r_r<A, A>();
|
||||
case 0x80: return op_add_a_r<B>();
|
||||
case 0x81: return op_add_a_r<C>();
|
||||
case 0x82: return op_add_a_r<D>();
|
||||
case 0x83: return op_add_a_r<E>();
|
||||
case 0x84: return op_add_a_r<H>();
|
||||
case 0x85: return op_add_a_r<L>();
|
||||
case 0x77: return op_ld_hl_r(A);
|
||||
case 0x78: return op_ld_r_r(A, B);
|
||||
case 0x79: return op_ld_r_r(A, C);
|
||||
case 0x7a: return op_ld_r_r(A, D);
|
||||
case 0x7b: return op_ld_r_r(A, E);
|
||||
case 0x7c: return op_ld_r_r(A, H);
|
||||
case 0x7d: return op_ld_r_r(A, L);
|
||||
case 0x7e: return op_ld_r_hl(A);
|
||||
case 0x7f: return op_ld_r_r(A, A);
|
||||
case 0x80: return op_add_a_r(B);
|
||||
case 0x81: return op_add_a_r(C);
|
||||
case 0x82: return op_add_a_r(D);
|
||||
case 0x83: return op_add_a_r(E);
|
||||
case 0x84: return op_add_a_r(H);
|
||||
case 0x85: return op_add_a_r(L);
|
||||
case 0x86: return op_add_a_hl();
|
||||
case 0x87: return op_add_a_r<A>();
|
||||
case 0x88: return op_adc_a_r<B>();
|
||||
case 0x89: return op_adc_a_r<C>();
|
||||
case 0x8a: return op_adc_a_r<D>();
|
||||
case 0x8b: return op_adc_a_r<E>();
|
||||
case 0x8c: return op_adc_a_r<H>();
|
||||
case 0x8d: return op_adc_a_r<L>();
|
||||
case 0x87: return op_add_a_r(A);
|
||||
case 0x88: return op_adc_a_r(B);
|
||||
case 0x89: return op_adc_a_r(C);
|
||||
case 0x8a: return op_adc_a_r(D);
|
||||
case 0x8b: return op_adc_a_r(E);
|
||||
case 0x8c: return op_adc_a_r(H);
|
||||
case 0x8d: return op_adc_a_r(L);
|
||||
case 0x8e: return op_adc_a_hl();
|
||||
case 0x8f: return op_adc_a_r<A>();
|
||||
case 0x90: return op_sub_a_r<B>();
|
||||
case 0x91: return op_sub_a_r<C>();
|
||||
case 0x92: return op_sub_a_r<D>();
|
||||
case 0x93: return op_sub_a_r<E>();
|
||||
case 0x94: return op_sub_a_r<H>();
|
||||
case 0x95: return op_sub_a_r<L>();
|
||||
case 0x8f: return op_adc_a_r(A);
|
||||
case 0x90: return op_sub_a_r(B);
|
||||
case 0x91: return op_sub_a_r(C);
|
||||
case 0x92: return op_sub_a_r(D);
|
||||
case 0x93: return op_sub_a_r(E);
|
||||
case 0x94: return op_sub_a_r(H);
|
||||
case 0x95: return op_sub_a_r(L);
|
||||
case 0x96: return op_sub_a_hl();
|
||||
case 0x97: return op_sub_a_r<A>();
|
||||
case 0x98: return op_sbc_a_r<B>();
|
||||
case 0x99: return op_sbc_a_r<C>();
|
||||
case 0x9a: return op_sbc_a_r<D>();
|
||||
case 0x9b: return op_sbc_a_r<E>();
|
||||
case 0x9c: return op_sbc_a_r<H>();
|
||||
case 0x9d: return op_sbc_a_r<L>();
|
||||
case 0x97: return op_sub_a_r(A);
|
||||
case 0x98: return op_sbc_a_r(B);
|
||||
case 0x99: return op_sbc_a_r(C);
|
||||
case 0x9a: return op_sbc_a_r(D);
|
||||
case 0x9b: return op_sbc_a_r(E);
|
||||
case 0x9c: return op_sbc_a_r(H);
|
||||
case 0x9d: return op_sbc_a_r(L);
|
||||
case 0x9e: return op_sbc_a_hl();
|
||||
case 0x9f: return op_sbc_a_r<A>();
|
||||
case 0xa0: return op_and_a_r<B>();
|
||||
case 0xa1: return op_and_a_r<C>();
|
||||
case 0xa2: return op_and_a_r<D>();
|
||||
case 0xa3: return op_and_a_r<E>();
|
||||
case 0xa4: return op_and_a_r<H>();
|
||||
case 0xa5: return op_and_a_r<L>();
|
||||
case 0x9f: return op_sbc_a_r(A);
|
||||
case 0xa0: return op_and_a_r(B);
|
||||
case 0xa1: return op_and_a_r(C);
|
||||
case 0xa2: return op_and_a_r(D);
|
||||
case 0xa3: return op_and_a_r(E);
|
||||
case 0xa4: return op_and_a_r(H);
|
||||
case 0xa5: return op_and_a_r(L);
|
||||
case 0xa6: return op_and_a_hl();
|
||||
case 0xa7: return op_and_a_r<A>();
|
||||
case 0xa8: return op_xor_a_r<B>();
|
||||
case 0xa9: return op_xor_a_r<C>();
|
||||
case 0xaa: return op_xor_a_r<D>();
|
||||
case 0xab: return op_xor_a_r<E>();
|
||||
case 0xac: return op_xor_a_r<H>();
|
||||
case 0xad: return op_xor_a_r<L>();
|
||||
case 0xa7: return op_and_a_r(A);
|
||||
case 0xa8: return op_xor_a_r(B);
|
||||
case 0xa9: return op_xor_a_r(C);
|
||||
case 0xaa: return op_xor_a_r(D);
|
||||
case 0xab: return op_xor_a_r(E);
|
||||
case 0xac: return op_xor_a_r(H);
|
||||
case 0xad: return op_xor_a_r(L);
|
||||
case 0xae: return op_xor_a_hl();
|
||||
case 0xaf: return op_xor_a_r<A>();
|
||||
case 0xb0: return op_or_a_r<B>();
|
||||
case 0xb1: return op_or_a_r<C>();
|
||||
case 0xb2: return op_or_a_r<D>();
|
||||
case 0xb3: return op_or_a_r<E>();
|
||||
case 0xb4: return op_or_a_r<H>();
|
||||
case 0xb5: return op_or_a_r<L>();
|
||||
case 0xaf: return op_xor_a_r(A);
|
||||
case 0xb0: return op_or_a_r(B);
|
||||
case 0xb1: return op_or_a_r(C);
|
||||
case 0xb2: return op_or_a_r(D);
|
||||
case 0xb3: return op_or_a_r(E);
|
||||
case 0xb4: return op_or_a_r(H);
|
||||
case 0xb5: return op_or_a_r(L);
|
||||
case 0xb6: return op_or_a_hl();
|
||||
case 0xb7: return op_or_a_r<A>();
|
||||
case 0xb8: return op_cp_a_r<B>();
|
||||
case 0xb9: return op_cp_a_r<C>();
|
||||
case 0xba: return op_cp_a_r<D>();
|
||||
case 0xbb: return op_cp_a_r<E>();
|
||||
case 0xbc: return op_cp_a_r<H>();
|
||||
case 0xbd: return op_cp_a_r<L>();
|
||||
case 0xb7: return op_or_a_r(A);
|
||||
case 0xb8: return op_cp_a_r(B);
|
||||
case 0xb9: return op_cp_a_r(C);
|
||||
case 0xba: return op_cp_a_r(D);
|
||||
case 0xbb: return op_cp_a_r(E);
|
||||
case 0xbc: return op_cp_a_r(H);
|
||||
case 0xbd: return op_cp_a_r(L);
|
||||
case 0xbe: return op_cp_a_hl();
|
||||
case 0xbf: return op_cp_a_r<A>();
|
||||
case 0xc0: return op_ret_f<ZF, 0>();
|
||||
case 0xc1: return op_pop_rr<BC>();
|
||||
case 0xc2: return op_jp_f_nn<ZF, 0>();
|
||||
case 0xbf: return op_cp_a_r(A);
|
||||
case 0xc0: return op_ret_f(ZF, 0);
|
||||
case 0xc1: return op_pop_rr(BC);
|
||||
case 0xc2: return op_jp_f_nn(ZF, 0);
|
||||
case 0xc3: return op_jp_nn();
|
||||
case 0xc4: return op_call_f_nn<ZF, 0>();
|
||||
case 0xc5: return op_push_rr<BC>();
|
||||
case 0xc4: return op_call_f_nn(ZF, 0);
|
||||
case 0xc5: return op_push_rr(BC);
|
||||
case 0xc6: return op_add_a_n();
|
||||
case 0xc7: return op_rst_n<0x00>();
|
||||
case 0xc8: return op_ret_f<ZF, 1>();
|
||||
case 0xc7: return op_rst_n(0x00);
|
||||
case 0xc8: return op_ret_f(ZF, 1);
|
||||
case 0xc9: return op_ret();
|
||||
case 0xca: return op_jp_f_nn<ZF, 1>();
|
||||
case 0xca: return op_jp_f_nn(ZF, 1);
|
||||
case 0xcb: return op_cb();
|
||||
case 0xcc: return op_call_f_nn<ZF, 1>();
|
||||
case 0xcc: return op_call_f_nn(ZF, 1);
|
||||
case 0xcd: return op_call_nn();
|
||||
case 0xce: return op_adc_a_n();
|
||||
case 0xcf: return op_rst_n<0x08>();
|
||||
case 0xd0: return op_ret_f<CF, 0>();
|
||||
case 0xd1: return op_pop_rr<DE>();
|
||||
case 0xd2: return op_jp_f_nn<CF, 0>();
|
||||
case 0xcf: return op_rst_n(0x08);
|
||||
case 0xd0: return op_ret_f(CF, 0);
|
||||
case 0xd1: return op_pop_rr(DE);
|
||||
case 0xd2: return op_jp_f_nn(CF, 0);
|
||||
case 0xd3: return op_xx();
|
||||
case 0xd4: return op_call_f_nn<CF, 0>();
|
||||
case 0xd5: return op_push_rr<DE>();
|
||||
case 0xd4: return op_call_f_nn(CF, 0);
|
||||
case 0xd5: return op_push_rr(DE);
|
||||
case 0xd6: return op_sub_a_n();
|
||||
case 0xd7: return op_rst_n<0x10>();
|
||||
case 0xd8: return op_ret_f<CF, 1>();
|
||||
case 0xd7: return op_rst_n(0x10);
|
||||
case 0xd8: return op_ret_f(CF, 1);
|
||||
case 0xd9: return op_reti();
|
||||
case 0xda: return op_jp_f_nn<CF, 1>();
|
||||
case 0xda: return op_jp_f_nn(CF, 1);
|
||||
case 0xdb: return op_xx();
|
||||
case 0xdc: return op_call_f_nn<CF, 1>();
|
||||
case 0xdc: return op_call_f_nn(CF, 1);
|
||||
case 0xdd: return op_xx();
|
||||
case 0xde: return op_sbc_a_n();
|
||||
case 0xdf: return op_rst_n<0x18>();
|
||||
case 0xdf: return op_rst_n(0x18);
|
||||
case 0xe0: return op_ld_ffn_a();
|
||||
case 0xe1: return op_pop_rr<HL>();
|
||||
case 0xe1: return op_pop_rr(HL);
|
||||
case 0xe2: return op_ld_ffc_a();
|
||||
case 0xe3: return op_xx();
|
||||
case 0xe4: return op_xx();
|
||||
case 0xe5: return op_push_rr<HL>();
|
||||
case 0xe5: return op_push_rr(HL);
|
||||
case 0xe6: return op_and_a_n();
|
||||
case 0xe7: return op_rst_n<0x20>();
|
||||
case 0xe7: return op_rst_n(0x20);
|
||||
case 0xe8: return op_add_sp_n();
|
||||
case 0xe9: return op_jp_hl();
|
||||
case 0xea: return op_ld_nn_a();
|
||||
@@ -256,15 +265,15 @@ auto LR35902::exec() -> void {
|
||||
case 0xec: return op_xx();
|
||||
case 0xed: return op_xx();
|
||||
case 0xee: return op_xor_a_n();
|
||||
case 0xef: return op_rst_n<0x28>();
|
||||
case 0xef: return op_rst_n(0x28);
|
||||
case 0xf0: return op_ld_a_ffn();
|
||||
case 0xf1: return op_pop_rr<AF>();
|
||||
case 0xf1: return op_pop_rr(AF);
|
||||
case 0xf2: return op_ld_a_ffc();
|
||||
case 0xf3: return op_di();
|
||||
case 0xf4: return op_xx();
|
||||
case 0xf5: return op_push_rr<AF>();
|
||||
case 0xf5: return op_push_rr(AF);
|
||||
case 0xf6: return op_or_a_n();
|
||||
case 0xf7: return op_rst_n<0x30>();
|
||||
case 0xf7: return op_rst_n(0x30);
|
||||
case 0xf8: return op_ld_hl_sp_n();
|
||||
case 0xf9: return op_ld_sp_hl();
|
||||
case 0xfa: return op_ld_a_nn();
|
||||
@@ -272,269 +281,268 @@ auto LR35902::exec() -> void {
|
||||
case 0xfc: return op_xx();
|
||||
case 0xfd: return op_xx();
|
||||
case 0xfe: return op_cp_a_n();
|
||||
case 0xff: return op_rst_n<0x38>();
|
||||
case 0xff: return op_rst_n(0x38);
|
||||
}
|
||||
}
|
||||
|
||||
auto LR35902::execCB() -> void {
|
||||
uint8 opcode = op_read(r[PC]++);
|
||||
switch(opcode) {
|
||||
case 0x00: return op_rlc_r<B>();
|
||||
case 0x01: return op_rlc_r<C>();
|
||||
case 0x02: return op_rlc_r<D>();
|
||||
case 0x03: return op_rlc_r<E>();
|
||||
case 0x04: return op_rlc_r<H>();
|
||||
case 0x05: return op_rlc_r<L>();
|
||||
auto LR35902::instructionCB() -> void {
|
||||
switch(auto opcode = read(r[PC]++)) {
|
||||
case 0x00: return op_rlc_r(B);
|
||||
case 0x01: return op_rlc_r(C);
|
||||
case 0x02: return op_rlc_r(D);
|
||||
case 0x03: return op_rlc_r(E);
|
||||
case 0x04: return op_rlc_r(H);
|
||||
case 0x05: return op_rlc_r(L);
|
||||
case 0x06: return op_rlc_hl();
|
||||
case 0x07: return op_rlc_r<A>();
|
||||
case 0x08: return op_rrc_r<B>();
|
||||
case 0x09: return op_rrc_r<C>();
|
||||
case 0x0a: return op_rrc_r<D>();
|
||||
case 0x0b: return op_rrc_r<E>();
|
||||
case 0x0c: return op_rrc_r<H>();
|
||||
case 0x0d: return op_rrc_r<L>();
|
||||
case 0x07: return op_rlc_r(A);
|
||||
case 0x08: return op_rrc_r(B);
|
||||
case 0x09: return op_rrc_r(C);
|
||||
case 0x0a: return op_rrc_r(D);
|
||||
case 0x0b: return op_rrc_r(E);
|
||||
case 0x0c: return op_rrc_r(H);
|
||||
case 0x0d: return op_rrc_r(L);
|
||||
case 0x0e: return op_rrc_hl();
|
||||
case 0x0f: return op_rrc_r<A>();
|
||||
case 0x10: return op_rl_r<B>();
|
||||
case 0x11: return op_rl_r<C>();
|
||||
case 0x12: return op_rl_r<D>();
|
||||
case 0x13: return op_rl_r<E>();
|
||||
case 0x14: return op_rl_r<H>();
|
||||
case 0x15: return op_rl_r<L>();
|
||||
case 0x0f: return op_rrc_r(A);
|
||||
case 0x10: return op_rl_r(B);
|
||||
case 0x11: return op_rl_r(C);
|
||||
case 0x12: return op_rl_r(D);
|
||||
case 0x13: return op_rl_r(E);
|
||||
case 0x14: return op_rl_r(H);
|
||||
case 0x15: return op_rl_r(L);
|
||||
case 0x16: return op_rl_hl();
|
||||
case 0x17: return op_rl_r<A>();
|
||||
case 0x18: return op_rr_r<B>();
|
||||
case 0x19: return op_rr_r<C>();
|
||||
case 0x1a: return op_rr_r<D>();
|
||||
case 0x1b: return op_rr_r<E>();
|
||||
case 0x1c: return op_rr_r<H>();
|
||||
case 0x1d: return op_rr_r<L>();
|
||||
case 0x17: return op_rl_r(A);
|
||||
case 0x18: return op_rr_r(B);
|
||||
case 0x19: return op_rr_r(C);
|
||||
case 0x1a: return op_rr_r(D);
|
||||
case 0x1b: return op_rr_r(E);
|
||||
case 0x1c: return op_rr_r(H);
|
||||
case 0x1d: return op_rr_r(L);
|
||||
case 0x1e: return op_rr_hl();
|
||||
case 0x1f: return op_rr_r<A>();
|
||||
case 0x20: return op_sla_r<B>();
|
||||
case 0x21: return op_sla_r<C>();
|
||||
case 0x22: return op_sla_r<D>();
|
||||
case 0x23: return op_sla_r<E>();
|
||||
case 0x24: return op_sla_r<H>();
|
||||
case 0x25: return op_sla_r<L>();
|
||||
case 0x1f: return op_rr_r(A);
|
||||
case 0x20: return op_sla_r(B);
|
||||
case 0x21: return op_sla_r(C);
|
||||
case 0x22: return op_sla_r(D);
|
||||
case 0x23: return op_sla_r(E);
|
||||
case 0x24: return op_sla_r(H);
|
||||
case 0x25: return op_sla_r(L);
|
||||
case 0x26: return op_sla_hl();
|
||||
case 0x27: return op_sla_r<A>();
|
||||
case 0x28: return op_sra_r<B>();
|
||||
case 0x29: return op_sra_r<C>();
|
||||
case 0x2a: return op_sra_r<D>();
|
||||
case 0x2b: return op_sra_r<E>();
|
||||
case 0x2c: return op_sra_r<H>();
|
||||
case 0x2d: return op_sra_r<L>();
|
||||
case 0x27: return op_sla_r(A);
|
||||
case 0x28: return op_sra_r(B);
|
||||
case 0x29: return op_sra_r(C);
|
||||
case 0x2a: return op_sra_r(D);
|
||||
case 0x2b: return op_sra_r(E);
|
||||
case 0x2c: return op_sra_r(H);
|
||||
case 0x2d: return op_sra_r(L);
|
||||
case 0x2e: return op_sra_hl();
|
||||
case 0x2f: return op_sra_r<A>();
|
||||
case 0x30: return op_swap_r<B>();
|
||||
case 0x31: return op_swap_r<C>();
|
||||
case 0x32: return op_swap_r<D>();
|
||||
case 0x33: return op_swap_r<E>();
|
||||
case 0x34: return op_swap_r<H>();
|
||||
case 0x35: return op_swap_r<L>();
|
||||
case 0x2f: return op_sra_r(A);
|
||||
case 0x30: return op_swap_r(B);
|
||||
case 0x31: return op_swap_r(C);
|
||||
case 0x32: return op_swap_r(D);
|
||||
case 0x33: return op_swap_r(E);
|
||||
case 0x34: return op_swap_r(H);
|
||||
case 0x35: return op_swap_r(L);
|
||||
case 0x36: return op_swap_hl();
|
||||
case 0x37: return op_swap_r<A>();
|
||||
case 0x38: return op_srl_r<B>();
|
||||
case 0x39: return op_srl_r<C>();
|
||||
case 0x3a: return op_srl_r<D>();
|
||||
case 0x3b: return op_srl_r<E>();
|
||||
case 0x3c: return op_srl_r<H>();
|
||||
case 0x3d: return op_srl_r<L>();
|
||||
case 0x37: return op_swap_r(A);
|
||||
case 0x38: return op_srl_r(B);
|
||||
case 0x39: return op_srl_r(C);
|
||||
case 0x3a: return op_srl_r(D);
|
||||
case 0x3b: return op_srl_r(E);
|
||||
case 0x3c: return op_srl_r(H);
|
||||
case 0x3d: return op_srl_r(L);
|
||||
case 0x3e: return op_srl_hl();
|
||||
case 0x3f: return op_srl_r<A>();
|
||||
case 0x40: return op_bit_n_r<0, B>();
|
||||
case 0x41: return op_bit_n_r<0, C>();
|
||||
case 0x42: return op_bit_n_r<0, D>();
|
||||
case 0x43: return op_bit_n_r<0, E>();
|
||||
case 0x44: return op_bit_n_r<0, H>();
|
||||
case 0x45: return op_bit_n_r<0, L>();
|
||||
case 0x46: return op_bit_n_hl<0>();
|
||||
case 0x47: return op_bit_n_r<0, A>();
|
||||
case 0x48: return op_bit_n_r<1, B>();
|
||||
case 0x49: return op_bit_n_r<1, C>();
|
||||
case 0x4a: return op_bit_n_r<1, D>();
|
||||
case 0x4b: return op_bit_n_r<1, E>();
|
||||
case 0x4c: return op_bit_n_r<1, H>();
|
||||
case 0x4d: return op_bit_n_r<1, L>();
|
||||
case 0x4e: return op_bit_n_hl<1>();
|
||||
case 0x4f: return op_bit_n_r<1, A>();
|
||||
case 0x50: return op_bit_n_r<2, B>();
|
||||
case 0x51: return op_bit_n_r<2, C>();
|
||||
case 0x52: return op_bit_n_r<2, D>();
|
||||
case 0x53: return op_bit_n_r<2, E>();
|
||||
case 0x54: return op_bit_n_r<2, H>();
|
||||
case 0x55: return op_bit_n_r<2, L>();
|
||||
case 0x56: return op_bit_n_hl<2>();
|
||||
case 0x57: return op_bit_n_r<2, A>();
|
||||
case 0x58: return op_bit_n_r<3, B>();
|
||||
case 0x59: return op_bit_n_r<3, C>();
|
||||
case 0x5a: return op_bit_n_r<3, D>();
|
||||
case 0x5b: return op_bit_n_r<3, E>();
|
||||
case 0x5c: return op_bit_n_r<3, H>();
|
||||
case 0x5d: return op_bit_n_r<3, L>();
|
||||
case 0x5e: return op_bit_n_hl<3>();
|
||||
case 0x5f: return op_bit_n_r<3, A>();
|
||||
case 0x60: return op_bit_n_r<4, B>();
|
||||
case 0x61: return op_bit_n_r<4, C>();
|
||||
case 0x62: return op_bit_n_r<4, D>();
|
||||
case 0x63: return op_bit_n_r<4, E>();
|
||||
case 0x64: return op_bit_n_r<4, H>();
|
||||
case 0x65: return op_bit_n_r<4, L>();
|
||||
case 0x66: return op_bit_n_hl<4>();
|
||||
case 0x67: return op_bit_n_r<4, A>();
|
||||
case 0x68: return op_bit_n_r<5, B>();
|
||||
case 0x69: return op_bit_n_r<5, C>();
|
||||
case 0x6a: return op_bit_n_r<5, D>();
|
||||
case 0x6b: return op_bit_n_r<5, E>();
|
||||
case 0x6c: return op_bit_n_r<5, H>();
|
||||
case 0x6d: return op_bit_n_r<5, L>();
|
||||
case 0x6e: return op_bit_n_hl<5>();
|
||||
case 0x6f: return op_bit_n_r<5, A>();
|
||||
case 0x70: return op_bit_n_r<6, B>();
|
||||
case 0x71: return op_bit_n_r<6, C>();
|
||||
case 0x72: return op_bit_n_r<6, D>();
|
||||
case 0x73: return op_bit_n_r<6, E>();
|
||||
case 0x74: return op_bit_n_r<6, H>();
|
||||
case 0x75: return op_bit_n_r<6, L>();
|
||||
case 0x76: return op_bit_n_hl<6>();
|
||||
case 0x77: return op_bit_n_r<6, A>();
|
||||
case 0x78: return op_bit_n_r<7, B>();
|
||||
case 0x79: return op_bit_n_r<7, C>();
|
||||
case 0x7a: return op_bit_n_r<7, D>();
|
||||
case 0x7b: return op_bit_n_r<7, E>();
|
||||
case 0x7c: return op_bit_n_r<7, H>();
|
||||
case 0x7d: return op_bit_n_r<7, L>();
|
||||
case 0x7e: return op_bit_n_hl<7>();
|
||||
case 0x7f: return op_bit_n_r<7, A>();
|
||||
case 0x80: return op_res_n_r<0, B>();
|
||||
case 0x81: return op_res_n_r<0, C>();
|
||||
case 0x82: return op_res_n_r<0, D>();
|
||||
case 0x83: return op_res_n_r<0, E>();
|
||||
case 0x84: return op_res_n_r<0, H>();
|
||||
case 0x85: return op_res_n_r<0, L>();
|
||||
case 0x86: return op_res_n_hl<0>();
|
||||
case 0x87: return op_res_n_r<0, A>();
|
||||
case 0x88: return op_res_n_r<1, B>();
|
||||
case 0x89: return op_res_n_r<1, C>();
|
||||
case 0x8a: return op_res_n_r<1, D>();
|
||||
case 0x8b: return op_res_n_r<1, E>();
|
||||
case 0x8c: return op_res_n_r<1, H>();
|
||||
case 0x8d: return op_res_n_r<1, L>();
|
||||
case 0x8e: return op_res_n_hl<1>();
|
||||
case 0x8f: return op_res_n_r<1, A>();
|
||||
case 0x90: return op_res_n_r<2, B>();
|
||||
case 0x91: return op_res_n_r<2, C>();
|
||||
case 0x92: return op_res_n_r<2, D>();
|
||||
case 0x93: return op_res_n_r<2, E>();
|
||||
case 0x94: return op_res_n_r<2, H>();
|
||||
case 0x95: return op_res_n_r<2, L>();
|
||||
case 0x96: return op_res_n_hl<2>();
|
||||
case 0x97: return op_res_n_r<2, A>();
|
||||
case 0x98: return op_res_n_r<3, B>();
|
||||
case 0x99: return op_res_n_r<3, C>();
|
||||
case 0x9a: return op_res_n_r<3, D>();
|
||||
case 0x9b: return op_res_n_r<3, E>();
|
||||
case 0x9c: return op_res_n_r<3, H>();
|
||||
case 0x9d: return op_res_n_r<3, L>();
|
||||
case 0x9e: return op_res_n_hl<3>();
|
||||
case 0x9f: return op_res_n_r<3, A>();
|
||||
case 0xa0: return op_res_n_r<4, B>();
|
||||
case 0xa1: return op_res_n_r<4, C>();
|
||||
case 0xa2: return op_res_n_r<4, D>();
|
||||
case 0xa3: return op_res_n_r<4, E>();
|
||||
case 0xa4: return op_res_n_r<4, H>();
|
||||
case 0xa5: return op_res_n_r<4, L>();
|
||||
case 0xa6: return op_res_n_hl<4>();
|
||||
case 0xa7: return op_res_n_r<4, A>();
|
||||
case 0xa8: return op_res_n_r<5, B>();
|
||||
case 0xa9: return op_res_n_r<5, C>();
|
||||
case 0xaa: return op_res_n_r<5, D>();
|
||||
case 0xab: return op_res_n_r<5, E>();
|
||||
case 0xac: return op_res_n_r<5, H>();
|
||||
case 0xad: return op_res_n_r<5, L>();
|
||||
case 0xae: return op_res_n_hl<5>();
|
||||
case 0xaf: return op_res_n_r<5, A>();
|
||||
case 0xb0: return op_res_n_r<6, B>();
|
||||
case 0xb1: return op_res_n_r<6, C>();
|
||||
case 0xb2: return op_res_n_r<6, D>();
|
||||
case 0xb3: return op_res_n_r<6, E>();
|
||||
case 0xb4: return op_res_n_r<6, H>();
|
||||
case 0xb5: return op_res_n_r<6, L>();
|
||||
case 0xb6: return op_res_n_hl<6>();
|
||||
case 0xb7: return op_res_n_r<6, A>();
|
||||
case 0xb8: return op_res_n_r<7, B>();
|
||||
case 0xb9: return op_res_n_r<7, C>();
|
||||
case 0xba: return op_res_n_r<7, D>();
|
||||
case 0xbb: return op_res_n_r<7, E>();
|
||||
case 0xbc: return op_res_n_r<7, H>();
|
||||
case 0xbd: return op_res_n_r<7, L>();
|
||||
case 0xbe: return op_res_n_hl<7>();
|
||||
case 0xbf: return op_res_n_r<7, A>();
|
||||
case 0xc0: return op_set_n_r<0, B>();
|
||||
case 0xc1: return op_set_n_r<0, C>();
|
||||
case 0xc2: return op_set_n_r<0, D>();
|
||||
case 0xc3: return op_set_n_r<0, E>();
|
||||
case 0xc4: return op_set_n_r<0, H>();
|
||||
case 0xc5: return op_set_n_r<0, L>();
|
||||
case 0xc6: return op_set_n_hl<0>();
|
||||
case 0xc7: return op_set_n_r<0, A>();
|
||||
case 0xc8: return op_set_n_r<1, B>();
|
||||
case 0xc9: return op_set_n_r<1, C>();
|
||||
case 0xca: return op_set_n_r<1, D>();
|
||||
case 0xcb: return op_set_n_r<1, E>();
|
||||
case 0xcc: return op_set_n_r<1, H>();
|
||||
case 0xcd: return op_set_n_r<1, L>();
|
||||
case 0xce: return op_set_n_hl<1>();
|
||||
case 0xcf: return op_set_n_r<1, A>();
|
||||
case 0xd0: return op_set_n_r<2, B>();
|
||||
case 0xd1: return op_set_n_r<2, C>();
|
||||
case 0xd2: return op_set_n_r<2, D>();
|
||||
case 0xd3: return op_set_n_r<2, E>();
|
||||
case 0xd4: return op_set_n_r<2, H>();
|
||||
case 0xd5: return op_set_n_r<2, L>();
|
||||
case 0xd6: return op_set_n_hl<2>();
|
||||
case 0xd7: return op_set_n_r<2, A>();
|
||||
case 0xd8: return op_set_n_r<3, B>();
|
||||
case 0xd9: return op_set_n_r<3, C>();
|
||||
case 0xda: return op_set_n_r<3, D>();
|
||||
case 0xdb: return op_set_n_r<3, E>();
|
||||
case 0xdc: return op_set_n_r<3, H>();
|
||||
case 0xdd: return op_set_n_r<3, L>();
|
||||
case 0xde: return op_set_n_hl<3>();
|
||||
case 0xdf: return op_set_n_r<3, A>();
|
||||
case 0xe0: return op_set_n_r<4, B>();
|
||||
case 0xe1: return op_set_n_r<4, C>();
|
||||
case 0xe2: return op_set_n_r<4, D>();
|
||||
case 0xe3: return op_set_n_r<4, E>();
|
||||
case 0xe4: return op_set_n_r<4, H>();
|
||||
case 0xe5: return op_set_n_r<4, L>();
|
||||
case 0xe6: return op_set_n_hl<4>();
|
||||
case 0xe7: return op_set_n_r<4, A>();
|
||||
case 0xe8: return op_set_n_r<5, B>();
|
||||
case 0xe9: return op_set_n_r<5, C>();
|
||||
case 0xea: return op_set_n_r<5, D>();
|
||||
case 0xeb: return op_set_n_r<5, E>();
|
||||
case 0xec: return op_set_n_r<5, H>();
|
||||
case 0xed: return op_set_n_r<5, L>();
|
||||
case 0xee: return op_set_n_hl<5>();
|
||||
case 0xef: return op_set_n_r<5, A>();
|
||||
case 0xf0: return op_set_n_r<6, B>();
|
||||
case 0xf1: return op_set_n_r<6, C>();
|
||||
case 0xf2: return op_set_n_r<6, D>();
|
||||
case 0xf3: return op_set_n_r<6, E>();
|
||||
case 0xf4: return op_set_n_r<6, H>();
|
||||
case 0xf5: return op_set_n_r<6, L>();
|
||||
case 0xf6: return op_set_n_hl<6>();
|
||||
case 0xf7: return op_set_n_r<6, A>();
|
||||
case 0xf8: return op_set_n_r<7, B>();
|
||||
case 0xf9: return op_set_n_r<7, C>();
|
||||
case 0xfa: return op_set_n_r<7, D>();
|
||||
case 0xfb: return op_set_n_r<7, E>();
|
||||
case 0xfc: return op_set_n_r<7, H>();
|
||||
case 0xfd: return op_set_n_r<7, L>();
|
||||
case 0xfe: return op_set_n_hl<7>();
|
||||
case 0xff: return op_set_n_r<7, A>();
|
||||
case 0x3f: return op_srl_r(A);
|
||||
case 0x40: return op_bit_n_r(0, B);
|
||||
case 0x41: return op_bit_n_r(0, C);
|
||||
case 0x42: return op_bit_n_r(0, D);
|
||||
case 0x43: return op_bit_n_r(0, E);
|
||||
case 0x44: return op_bit_n_r(0, H);
|
||||
case 0x45: return op_bit_n_r(0, L);
|
||||
case 0x46: return op_bit_n_hl(0);
|
||||
case 0x47: return op_bit_n_r(0, A);
|
||||
case 0x48: return op_bit_n_r(1, B);
|
||||
case 0x49: return op_bit_n_r(1, C);
|
||||
case 0x4a: return op_bit_n_r(1, D);
|
||||
case 0x4b: return op_bit_n_r(1, E);
|
||||
case 0x4c: return op_bit_n_r(1, H);
|
||||
case 0x4d: return op_bit_n_r(1, L);
|
||||
case 0x4e: return op_bit_n_hl(1);
|
||||
case 0x4f: return op_bit_n_r(1, A);
|
||||
case 0x50: return op_bit_n_r(2, B);
|
||||
case 0x51: return op_bit_n_r(2, C);
|
||||
case 0x52: return op_bit_n_r(2, D);
|
||||
case 0x53: return op_bit_n_r(2, E);
|
||||
case 0x54: return op_bit_n_r(2, H);
|
||||
case 0x55: return op_bit_n_r(2, L);
|
||||
case 0x56: return op_bit_n_hl(2);
|
||||
case 0x57: return op_bit_n_r(2, A);
|
||||
case 0x58: return op_bit_n_r(3, B);
|
||||
case 0x59: return op_bit_n_r(3, C);
|
||||
case 0x5a: return op_bit_n_r(3, D);
|
||||
case 0x5b: return op_bit_n_r(3, E);
|
||||
case 0x5c: return op_bit_n_r(3, H);
|
||||
case 0x5d: return op_bit_n_r(3, L);
|
||||
case 0x5e: return op_bit_n_hl(3);
|
||||
case 0x5f: return op_bit_n_r(3, A);
|
||||
case 0x60: return op_bit_n_r(4, B);
|
||||
case 0x61: return op_bit_n_r(4, C);
|
||||
case 0x62: return op_bit_n_r(4, D);
|
||||
case 0x63: return op_bit_n_r(4, E);
|
||||
case 0x64: return op_bit_n_r(4, H);
|
||||
case 0x65: return op_bit_n_r(4, L);
|
||||
case 0x66: return op_bit_n_hl(4);
|
||||
case 0x67: return op_bit_n_r(4, A);
|
||||
case 0x68: return op_bit_n_r(5, B);
|
||||
case 0x69: return op_bit_n_r(5, C);
|
||||
case 0x6a: return op_bit_n_r(5, D);
|
||||
case 0x6b: return op_bit_n_r(5, E);
|
||||
case 0x6c: return op_bit_n_r(5, H);
|
||||
case 0x6d: return op_bit_n_r(5, L);
|
||||
case 0x6e: return op_bit_n_hl(5);
|
||||
case 0x6f: return op_bit_n_r(5, A);
|
||||
case 0x70: return op_bit_n_r(6, B);
|
||||
case 0x71: return op_bit_n_r(6, C);
|
||||
case 0x72: return op_bit_n_r(6, D);
|
||||
case 0x73: return op_bit_n_r(6, E);
|
||||
case 0x74: return op_bit_n_r(6, H);
|
||||
case 0x75: return op_bit_n_r(6, L);
|
||||
case 0x76: return op_bit_n_hl(6);
|
||||
case 0x77: return op_bit_n_r(6, A);
|
||||
case 0x78: return op_bit_n_r(7, B);
|
||||
case 0x79: return op_bit_n_r(7, C);
|
||||
case 0x7a: return op_bit_n_r(7, D);
|
||||
case 0x7b: return op_bit_n_r(7, E);
|
||||
case 0x7c: return op_bit_n_r(7, H);
|
||||
case 0x7d: return op_bit_n_r(7, L);
|
||||
case 0x7e: return op_bit_n_hl(7);
|
||||
case 0x7f: return op_bit_n_r(7, A);
|
||||
case 0x80: return op_res_n_r(0, B);
|
||||
case 0x81: return op_res_n_r(0, C);
|
||||
case 0x82: return op_res_n_r(0, D);
|
||||
case 0x83: return op_res_n_r(0, E);
|
||||
case 0x84: return op_res_n_r(0, H);
|
||||
case 0x85: return op_res_n_r(0, L);
|
||||
case 0x86: return op_res_n_hl(0);
|
||||
case 0x87: return op_res_n_r(0, A);
|
||||
case 0x88: return op_res_n_r(1, B);
|
||||
case 0x89: return op_res_n_r(1, C);
|
||||
case 0x8a: return op_res_n_r(1, D);
|
||||
case 0x8b: return op_res_n_r(1, E);
|
||||
case 0x8c: return op_res_n_r(1, H);
|
||||
case 0x8d: return op_res_n_r(1, L);
|
||||
case 0x8e: return op_res_n_hl(1);
|
||||
case 0x8f: return op_res_n_r(1, A);
|
||||
case 0x90: return op_res_n_r(2, B);
|
||||
case 0x91: return op_res_n_r(2, C);
|
||||
case 0x92: return op_res_n_r(2, D);
|
||||
case 0x93: return op_res_n_r(2, E);
|
||||
case 0x94: return op_res_n_r(2, H);
|
||||
case 0x95: return op_res_n_r(2, L);
|
||||
case 0x96: return op_res_n_hl(2);
|
||||
case 0x97: return op_res_n_r(2, A);
|
||||
case 0x98: return op_res_n_r(3, B);
|
||||
case 0x99: return op_res_n_r(3, C);
|
||||
case 0x9a: return op_res_n_r(3, D);
|
||||
case 0x9b: return op_res_n_r(3, E);
|
||||
case 0x9c: return op_res_n_r(3, H);
|
||||
case 0x9d: return op_res_n_r(3, L);
|
||||
case 0x9e: return op_res_n_hl(3);
|
||||
case 0x9f: return op_res_n_r(3, A);
|
||||
case 0xa0: return op_res_n_r(4, B);
|
||||
case 0xa1: return op_res_n_r(4, C);
|
||||
case 0xa2: return op_res_n_r(4, D);
|
||||
case 0xa3: return op_res_n_r(4, E);
|
||||
case 0xa4: return op_res_n_r(4, H);
|
||||
case 0xa5: return op_res_n_r(4, L);
|
||||
case 0xa6: return op_res_n_hl(4);
|
||||
case 0xa7: return op_res_n_r(4, A);
|
||||
case 0xa8: return op_res_n_r(5, B);
|
||||
case 0xa9: return op_res_n_r(5, C);
|
||||
case 0xaa: return op_res_n_r(5, D);
|
||||
case 0xab: return op_res_n_r(5, E);
|
||||
case 0xac: return op_res_n_r(5, H);
|
||||
case 0xad: return op_res_n_r(5, L);
|
||||
case 0xae: return op_res_n_hl(5);
|
||||
case 0xaf: return op_res_n_r(5, A);
|
||||
case 0xb0: return op_res_n_r(6, B);
|
||||
case 0xb1: return op_res_n_r(6, C);
|
||||
case 0xb2: return op_res_n_r(6, D);
|
||||
case 0xb3: return op_res_n_r(6, E);
|
||||
case 0xb4: return op_res_n_r(6, H);
|
||||
case 0xb5: return op_res_n_r(6, L);
|
||||
case 0xb6: return op_res_n_hl(6);
|
||||
case 0xb7: return op_res_n_r(6, A);
|
||||
case 0xb8: return op_res_n_r(7, B);
|
||||
case 0xb9: return op_res_n_r(7, C);
|
||||
case 0xba: return op_res_n_r(7, D);
|
||||
case 0xbb: return op_res_n_r(7, E);
|
||||
case 0xbc: return op_res_n_r(7, H);
|
||||
case 0xbd: return op_res_n_r(7, L);
|
||||
case 0xbe: return op_res_n_hl(7);
|
||||
case 0xbf: return op_res_n_r(7, A);
|
||||
case 0xc0: return op_set_n_r(0, B);
|
||||
case 0xc1: return op_set_n_r(0, C);
|
||||
case 0xc2: return op_set_n_r(0, D);
|
||||
case 0xc3: return op_set_n_r(0, E);
|
||||
case 0xc4: return op_set_n_r(0, H);
|
||||
case 0xc5: return op_set_n_r(0, L);
|
||||
case 0xc6: return op_set_n_hl(0);
|
||||
case 0xc7: return op_set_n_r(0, A);
|
||||
case 0xc8: return op_set_n_r(1, B);
|
||||
case 0xc9: return op_set_n_r(1, C);
|
||||
case 0xca: return op_set_n_r(1, D);
|
||||
case 0xcb: return op_set_n_r(1, E);
|
||||
case 0xcc: return op_set_n_r(1, H);
|
||||
case 0xcd: return op_set_n_r(1, L);
|
||||
case 0xce: return op_set_n_hl(1);
|
||||
case 0xcf: return op_set_n_r(1, A);
|
||||
case 0xd0: return op_set_n_r(2, B);
|
||||
case 0xd1: return op_set_n_r(2, C);
|
||||
case 0xd2: return op_set_n_r(2, D);
|
||||
case 0xd3: return op_set_n_r(2, E);
|
||||
case 0xd4: return op_set_n_r(2, H);
|
||||
case 0xd5: return op_set_n_r(2, L);
|
||||
case 0xd6: return op_set_n_hl(2);
|
||||
case 0xd7: return op_set_n_r(2, A);
|
||||
case 0xd8: return op_set_n_r(3, B);
|
||||
case 0xd9: return op_set_n_r(3, C);
|
||||
case 0xda: return op_set_n_r(3, D);
|
||||
case 0xdb: return op_set_n_r(3, E);
|
||||
case 0xdc: return op_set_n_r(3, H);
|
||||
case 0xdd: return op_set_n_r(3, L);
|
||||
case 0xde: return op_set_n_hl(3);
|
||||
case 0xdf: return op_set_n_r(3, A);
|
||||
case 0xe0: return op_set_n_r(4, B);
|
||||
case 0xe1: return op_set_n_r(4, C);
|
||||
case 0xe2: return op_set_n_r(4, D);
|
||||
case 0xe3: return op_set_n_r(4, E);
|
||||
case 0xe4: return op_set_n_r(4, H);
|
||||
case 0xe5: return op_set_n_r(4, L);
|
||||
case 0xe6: return op_set_n_hl(4);
|
||||
case 0xe7: return op_set_n_r(4, A);
|
||||
case 0xe8: return op_set_n_r(5, B);
|
||||
case 0xe9: return op_set_n_r(5, C);
|
||||
case 0xea: return op_set_n_r(5, D);
|
||||
case 0xeb: return op_set_n_r(5, E);
|
||||
case 0xec: return op_set_n_r(5, H);
|
||||
case 0xed: return op_set_n_r(5, L);
|
||||
case 0xee: return op_set_n_hl(5);
|
||||
case 0xef: return op_set_n_r(5, A);
|
||||
case 0xf0: return op_set_n_r(6, B);
|
||||
case 0xf1: return op_set_n_r(6, C);
|
||||
case 0xf2: return op_set_n_r(6, D);
|
||||
case 0xf3: return op_set_n_r(6, E);
|
||||
case 0xf4: return op_set_n_r(6, H);
|
||||
case 0xf5: return op_set_n_r(6, L);
|
||||
case 0xf6: return op_set_n_hl(6);
|
||||
case 0xf7: return op_set_n_r(6, A);
|
||||
case 0xf8: return op_set_n_r(7, B);
|
||||
case 0xf9: return op_set_n_r(7, C);
|
||||
case 0xfa: return op_set_n_r(7, D);
|
||||
case 0xfb: return op_set_n_r(7, E);
|
||||
case 0xfc: return op_set_n_r(7, H);
|
||||
case 0xfd: return op_set_n_r(7, L);
|
||||
case 0xfe: return op_set_n_hl(7);
|
||||
case 0xff: return op_set_n_r(7, A);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -5,15 +5,16 @@
|
||||
namespace Processor {
|
||||
|
||||
struct LR35902 {
|
||||
virtual auto op_io() -> void = 0;
|
||||
virtual auto op_read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto op_write(uint16 addr, uint8 data) -> void = 0;
|
||||
virtual auto io() -> void = 0;
|
||||
virtual auto read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto write(uint16 addr, uint8 data) -> void = 0;
|
||||
virtual auto stop() -> bool = 0;
|
||||
virtual auto debugger_read(uint16 addr) -> uint8 { return 0u; }
|
||||
virtual auto debuggerRead(uint16 addr) -> uint8 { return 0; }
|
||||
|
||||
auto power() -> void;
|
||||
auto exec() -> void;
|
||||
auto execCB() -> void;
|
||||
auto interrupt(uint16 vector) -> void;
|
||||
auto instruction() -> void;
|
||||
auto instructionCB() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
@@ -24,14 +25,14 @@ privileged:
|
||||
auto op_cb();
|
||||
|
||||
//8-bit load commands
|
||||
template<uint x, uint y> auto op_ld_r_r();
|
||||
template<uint x> auto op_ld_r_n();
|
||||
template<uint x> auto op_ld_r_hl();
|
||||
template<uint x> auto op_ld_hl_r();
|
||||
auto op_ld_r_r(uint x, uint y);
|
||||
auto op_ld_r_n(uint x);
|
||||
auto op_ld_r_hl(uint x);
|
||||
auto op_ld_hl_r(uint x);
|
||||
auto op_ld_hl_n();
|
||||
template<uint x> auto op_ld_a_rr();
|
||||
auto op_ld_a_rr(uint x);
|
||||
auto op_ld_a_nn();
|
||||
template<uint x> auto op_ld_rr_a();
|
||||
auto op_ld_rr_a(uint x);
|
||||
auto op_ld_nn_a();
|
||||
auto op_ld_a_ffn();
|
||||
auto op_ld_ffn_a();
|
||||
@@ -43,64 +44,64 @@ privileged:
|
||||
auto op_ldd_a_hl();
|
||||
|
||||
//16-bit load commands
|
||||
template<uint x> auto op_ld_rr_nn();
|
||||
auto op_ld_rr_nn(uint x);
|
||||
auto op_ld_nn_sp();
|
||||
auto op_ld_sp_hl();
|
||||
template<uint x> auto op_push_rr();
|
||||
template<uint x> auto op_pop_rr();
|
||||
auto op_push_rr(uint x);
|
||||
auto op_pop_rr(uint x);
|
||||
|
||||
//8-bit arithmetic commands
|
||||
auto opi_add_a(uint8 x);
|
||||
template<uint x> auto op_add_a_r();
|
||||
auto op_add_a_r(uint x);
|
||||
auto op_add_a_n();
|
||||
auto op_add_a_hl();
|
||||
|
||||
auto opi_adc_a(uint8 x);
|
||||
template<uint x> auto op_adc_a_r();
|
||||
auto op_adc_a_r(uint x);
|
||||
auto op_adc_a_n();
|
||||
auto op_adc_a_hl();
|
||||
|
||||
auto opi_sub_a(uint8 x);
|
||||
template<uint x> auto op_sub_a_r();
|
||||
auto op_sub_a_r(uint x);
|
||||
auto op_sub_a_n();
|
||||
auto op_sub_a_hl();
|
||||
|
||||
auto opi_sbc_a(uint8 x);
|
||||
template<uint x> auto op_sbc_a_r();
|
||||
auto op_sbc_a_r(uint x);
|
||||
auto op_sbc_a_n();
|
||||
auto op_sbc_a_hl();
|
||||
|
||||
auto opi_and_a(uint8 x);
|
||||
template<uint x> auto op_and_a_r();
|
||||
auto op_and_a_r(uint x);
|
||||
auto op_and_a_n();
|
||||
auto op_and_a_hl();
|
||||
|
||||
auto opi_xor_a(uint8 x);
|
||||
template<uint x> auto op_xor_a_r();
|
||||
auto op_xor_a_r(uint x);
|
||||
auto op_xor_a_n();
|
||||
auto op_xor_a_hl();
|
||||
|
||||
auto opi_or_a(uint8 x);
|
||||
template<uint x> auto op_or_a_r();
|
||||
auto op_or_a_r(uint x);
|
||||
auto op_or_a_n();
|
||||
auto op_or_a_hl();
|
||||
|
||||
auto opi_cp_a(uint8 x);
|
||||
template<uint x> auto op_cp_a_r();
|
||||
auto op_cp_a_r(uint x);
|
||||
auto op_cp_a_n();
|
||||
auto op_cp_a_hl();
|
||||
|
||||
template<uint x> auto op_inc_r();
|
||||
auto op_inc_r(uint x);
|
||||
auto op_inc_hl();
|
||||
template<uint x> auto op_dec_r();
|
||||
auto op_dec_r(uint x);
|
||||
auto op_dec_hl();
|
||||
auto op_daa();
|
||||
auto op_cpl();
|
||||
|
||||
//16-bit arithmetic commands
|
||||
template<uint x> auto op_add_hl_rr();
|
||||
template<uint x> auto op_inc_rr();
|
||||
template<uint x> auto op_dec_rr();
|
||||
auto op_add_hl_rr(uint x);
|
||||
auto op_inc_rr(uint x);
|
||||
auto op_dec_rr(uint x);
|
||||
auto op_add_sp_n();
|
||||
auto op_ld_hl_sp_n();
|
||||
|
||||
@@ -109,30 +110,30 @@ privileged:
|
||||
auto op_rla();
|
||||
auto op_rrca();
|
||||
auto op_rra();
|
||||
template<uint x> auto op_rlc_r();
|
||||
auto op_rlc_r(uint x);
|
||||
auto op_rlc_hl();
|
||||
template<uint x> auto op_rl_r();
|
||||
auto op_rl_r(uint x);
|
||||
auto op_rl_hl();
|
||||
template<uint x> auto op_rrc_r();
|
||||
auto op_rrc_r(uint x);
|
||||
auto op_rrc_hl();
|
||||
template<uint x> auto op_rr_r();
|
||||
auto op_rr_r(uint x);
|
||||
auto op_rr_hl();
|
||||
template<uint x> auto op_sla_r();
|
||||
auto op_sla_r(uint x);
|
||||
auto op_sla_hl();
|
||||
template<uint x> auto op_swap_r();
|
||||
auto op_swap_r(uint x);
|
||||
auto op_swap_hl();
|
||||
template<uint x> auto op_sra_r();
|
||||
auto op_sra_r(uint x);
|
||||
auto op_sra_hl();
|
||||
template<uint x> auto op_srl_r();
|
||||
auto op_srl_r(uint x);
|
||||
auto op_srl_hl();
|
||||
|
||||
//single-bit commands
|
||||
template<uint b, uint x> auto op_bit_n_r();
|
||||
template<uint b> auto op_bit_n_hl();
|
||||
template<uint b, uint x> auto op_set_n_r();
|
||||
template<uint b> auto op_set_n_hl();
|
||||
template<uint b, uint x> auto op_res_n_r();
|
||||
template<uint b> auto op_res_n_hl();
|
||||
auto op_bit_n_r(uint b, uint x);
|
||||
auto op_bit_n_hl(uint b);
|
||||
auto op_set_n_r(uint b, uint x);
|
||||
auto op_set_n_hl(uint b);
|
||||
auto op_res_n_r(uint b, uint x);
|
||||
auto op_res_n_hl(uint b);
|
||||
|
||||
//control commands
|
||||
auto op_ccf();
|
||||
@@ -146,15 +147,15 @@ privileged:
|
||||
//jump commands
|
||||
auto op_jp_nn();
|
||||
auto op_jp_hl();
|
||||
template<uint x, bool y> auto op_jp_f_nn();
|
||||
auto op_jp_f_nn(uint x, bool y);
|
||||
auto op_jr_n();
|
||||
template<uint x, bool y> auto op_jr_f_n();
|
||||
auto op_jr_f_n(uint x, bool y);
|
||||
auto op_call_nn();
|
||||
template<uint x, bool y> auto op_call_f_nn();
|
||||
auto op_call_f_nn(uint x, bool y);
|
||||
auto op_ret();
|
||||
template<uint x, bool y> auto op_ret_f();
|
||||
auto op_ret_f(uint x, bool y);
|
||||
auto op_reti();
|
||||
template<uint n> auto op_rst_n();
|
||||
auto op_rst_n(uint n);
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassemble(uint16 pc) -> string;
|
||||
|
@@ -99,7 +99,7 @@ struct Registers {
|
||||
bool ime;
|
||||
|
||||
Register& operator[](unsigned r) {
|
||||
static Register* table[] = {&a, &f, &af, &b, &c, &bc, &d, &e, &de, &h, &l, &hl, &sp, &pc};
|
||||
static Register* const table[] = {&a, &f, &af, &b, &c, &bc, &d, &e, &de, &h, &l, &hl, &sp, &pc};
|
||||
return *table[r];
|
||||
}
|
||||
|
||||
|
@@ -165,9 +165,9 @@ L op_readpc();
|
||||
}
|
||||
}
|
||||
|
||||
auto R6502::opi_clear_flag(bool& flag) {
|
||||
auto R6502::opi_clear_flag(uint bit) {
|
||||
L op_readpc();
|
||||
flag = 0;
|
||||
regs.p &= ~(1 << bit);
|
||||
}
|
||||
|
||||
auto R6502::opi_decrement(uint8& r) {
|
||||
@@ -197,16 +197,14 @@ auto R6502::opi_push(uint8& r) {
|
||||
L op_writesp(r);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_absolute() {
|
||||
auto R6502::opi_read_absolute(fp op) {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
L rd = op_read(abs.w);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_absolute_x() {
|
||||
auto R6502::opi_read_absolute_x(fp op) {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page(abs.w, abs.w + regs.x);
|
||||
@@ -214,8 +212,7 @@ L rd = op_read(abs.w + regs.x);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_absolute_y() {
|
||||
auto R6502::opi_read_absolute_y(fp op) {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page(abs.w, abs.w + regs.y);
|
||||
@@ -223,14 +220,12 @@ L rd = op_read(abs.w + regs.y);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_immediate() {
|
||||
auto R6502::opi_read_immediate(fp op) {
|
||||
L rd = op_readpci();
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_indirect_zero_page_x() {
|
||||
auto R6502::opi_read_indirect_zero_page_x(fp op) {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
abs.l = op_readzp(zp++ + regs.x);
|
||||
@@ -239,8 +234,7 @@ L rd = op_read(abs.w);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_indirect_zero_page_y() {
|
||||
auto R6502::opi_read_indirect_zero_page_y(fp op) {
|
||||
rd = op_readpci();
|
||||
abs.l = op_readzp(rd++);
|
||||
abs.h = op_readzp(rd++);
|
||||
@@ -249,31 +243,27 @@ L rd = op_read(abs.w + regs.y);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_zero_page() {
|
||||
auto R6502::opi_read_zero_page(fp op) {
|
||||
zp = op_readpci();
|
||||
L rd = op_readzp(zp);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_zero_page_x() {
|
||||
auto R6502::opi_read_zero_page_x(fp op) {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
L rd = op_readzp(zp + regs.x);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_zero_page_y() {
|
||||
auto R6502::opi_read_zero_page_y(fp op) {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
L rd = op_readzp(zp + regs.y);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_rmw_absolute() {
|
||||
auto R6502::opi_rmw_absolute(fp op) {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
rd = op_read(abs.w);
|
||||
@@ -282,8 +272,7 @@ auto R6502::opi_rmw_absolute() {
|
||||
L op_write(abs.w, rd);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_rmw_absolute_x() {
|
||||
auto R6502::opi_rmw_absolute_x(fp op) {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page_always(abs.w, abs.w + regs.x);
|
||||
@@ -293,8 +282,7 @@ auto R6502::opi_rmw_absolute_x() {
|
||||
L op_write(abs.w + regs.x, rd);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_rmw_zero_page() {
|
||||
auto R6502::opi_rmw_zero_page(fp op) {
|
||||
zp = op_readpci();
|
||||
rd = op_readzp(zp);
|
||||
op_writezp(zp, rd);
|
||||
@@ -302,8 +290,7 @@ auto R6502::opi_rmw_zero_page() {
|
||||
L op_writezp(zp, rd);
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_rmw_zero_page_x() {
|
||||
auto R6502::opi_rmw_zero_page_x(fp op) {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
rd = op_readzp(zp + regs.x);
|
||||
@@ -312,13 +299,12 @@ auto R6502::opi_rmw_zero_page_x() {
|
||||
L op_writezp(zp + regs.x, rd);
|
||||
}
|
||||
|
||||
auto R6502::opi_set_flag(bool& flag) {
|
||||
auto R6502::opi_set_flag(uint bit) {
|
||||
L op_readpc();
|
||||
flag = 1;
|
||||
regs.p |= 1 << bit;
|
||||
}
|
||||
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_shift() {
|
||||
auto R6502::opi_shift(fp op) {
|
||||
L op_readpc();
|
||||
call(op);
|
||||
}
|
||||
|
@@ -49,94 +49,94 @@ auto R6502::exec() -> void {
|
||||
uint8 opcode = op_readpci();
|
||||
switch(opcode) {
|
||||
case 0x00: return op_brk();
|
||||
case 0x01: return opi_read_indirect_zero_page_x<&R6502::opf_ora>();
|
||||
case 0x01: return opi_read_indirect_zero_page_x(&R6502::opf_ora);
|
||||
I case 0x04: return opill_nop_zero_page();
|
||||
case 0x05: return opi_read_zero_page<&R6502::opf_ora>();
|
||||
case 0x06: return opi_rmw_zero_page<&R6502::opf_asl>();
|
||||
case 0x05: return opi_read_zero_page(&R6502::opf_ora);
|
||||
case 0x06: return opi_rmw_zero_page(&R6502::opf_asl);
|
||||
case 0x08: return op_php();
|
||||
case 0x09: return opi_read_immediate<&R6502::opf_ora>();
|
||||
case 0x0a: return opi_shift<&R6502::opf_sla>();
|
||||
case 0x09: return opi_read_immediate(&R6502::opf_ora);
|
||||
case 0x0a: return opi_shift(&R6502::opf_sla);
|
||||
I case 0x0c: return opill_nop_absolute();
|
||||
case 0x0d: return opi_read_absolute<&R6502::opf_ora>();
|
||||
case 0x0e: return opi_rmw_absolute<&R6502::opf_asl>();
|
||||
case 0x0d: return opi_read_absolute(&R6502::opf_ora);
|
||||
case 0x0e: return opi_rmw_absolute(&R6502::opf_asl);
|
||||
case 0x10: return opi_branch(regs.p.n == 0);
|
||||
case 0x11: return opi_read_indirect_zero_page_y<&R6502::opf_ora>();
|
||||
case 0x11: return opi_read_indirect_zero_page_y(&R6502::opf_ora);
|
||||
I case 0x14: return opill_nop_zero_page_x();
|
||||
case 0x15: return opi_read_zero_page_x<&R6502::opf_ora>();
|
||||
case 0x16: return opi_rmw_zero_page_x<&R6502::opf_asl>();
|
||||
case 0x18: return opi_clear_flag(regs.p.c);
|
||||
case 0x19: return opi_read_absolute_y<&R6502::opf_ora>();
|
||||
case 0x15: return opi_read_zero_page_x(&R6502::opf_ora);
|
||||
case 0x16: return opi_rmw_zero_page_x(&R6502::opf_asl);
|
||||
case 0x18: return opi_clear_flag(regs.p.c.bit);
|
||||
case 0x19: return opi_read_absolute_y(&R6502::opf_ora);
|
||||
I case 0x1a: return opill_nop_implied();
|
||||
I case 0x1c: return opill_nop_absolute_x();
|
||||
case 0x1d: return opi_read_absolute_x<&R6502::opf_ora>();
|
||||
case 0x1e: return opi_rmw_absolute_x<&R6502::opf_asl>();
|
||||
case 0x1d: return opi_read_absolute_x(&R6502::opf_ora);
|
||||
case 0x1e: return opi_rmw_absolute_x(&R6502::opf_asl);
|
||||
case 0x20: return op_jsr_absolute();
|
||||
case 0x21: return opi_read_indirect_zero_page_x<&R6502::opf_and>();
|
||||
case 0x24: return opi_read_zero_page<&R6502::opf_bit>();
|
||||
case 0x25: return opi_read_zero_page<&R6502::opf_and>();
|
||||
case 0x26: return opi_rmw_zero_page<&R6502::opf_rol>();
|
||||
case 0x21: return opi_read_indirect_zero_page_x(&R6502::opf_and);
|
||||
case 0x24: return opi_read_zero_page(&R6502::opf_bit);
|
||||
case 0x25: return opi_read_zero_page(&R6502::opf_and);
|
||||
case 0x26: return opi_rmw_zero_page(&R6502::opf_rol);
|
||||
case 0x28: return op_plp();
|
||||
case 0x29: return opi_read_immediate<&R6502::opf_and>();
|
||||
case 0x2a: return opi_shift<&R6502::opf_rla>();
|
||||
case 0x2c: return opi_read_absolute<&R6502::opf_bit>();
|
||||
case 0x2d: return opi_read_absolute<&R6502::opf_and>();
|
||||
case 0x2e: return opi_rmw_absolute<&R6502::opf_rol>();
|
||||
case 0x29: return opi_read_immediate(&R6502::opf_and);
|
||||
case 0x2a: return opi_shift(&R6502::opf_rla);
|
||||
case 0x2c: return opi_read_absolute(&R6502::opf_bit);
|
||||
case 0x2d: return opi_read_absolute(&R6502::opf_and);
|
||||
case 0x2e: return opi_rmw_absolute(&R6502::opf_rol);
|
||||
case 0x30: return opi_branch(regs.p.n == 1);
|
||||
case 0x31: return opi_read_indirect_zero_page_y<&R6502::opf_and>();
|
||||
case 0x31: return opi_read_indirect_zero_page_y(&R6502::opf_and);
|
||||
I case 0x34: return opill_nop_zero_page_x();
|
||||
case 0x35: return opi_read_zero_page_x<&R6502::opf_and>();
|
||||
case 0x36: return opi_rmw_zero_page_x<&R6502::opf_rol>();
|
||||
case 0x38: return opi_set_flag(regs.p.c);
|
||||
case 0x39: return opi_read_absolute_y<&R6502::opf_and>();
|
||||
case 0x35: return opi_read_zero_page_x(&R6502::opf_and);
|
||||
case 0x36: return opi_rmw_zero_page_x(&R6502::opf_rol);
|
||||
case 0x38: return opi_set_flag(regs.p.c.bit);
|
||||
case 0x39: return opi_read_absolute_y(&R6502::opf_and);
|
||||
I case 0x3a: return opill_nop_implied();
|
||||
I case 0x3c: return opill_nop_absolute_x();
|
||||
case 0x3d: return opi_read_absolute_x<&R6502::opf_and>();
|
||||
case 0x3e: return opi_rmw_absolute_x<&R6502::opf_rol>();
|
||||
case 0x3d: return opi_read_absolute_x(&R6502::opf_and);
|
||||
case 0x3e: return opi_rmw_absolute_x(&R6502::opf_rol);
|
||||
case 0x40: return op_rti();
|
||||
case 0x41: return opi_read_indirect_zero_page_x<&R6502::opf_eor>();
|
||||
case 0x41: return opi_read_indirect_zero_page_x(&R6502::opf_eor);
|
||||
I case 0x44: return opill_nop_zero_page();
|
||||
case 0x45: return opi_read_zero_page<&R6502::opf_eor>();
|
||||
case 0x46: return opi_rmw_zero_page<&R6502::opf_lsr>();
|
||||
case 0x45: return opi_read_zero_page(&R6502::opf_eor);
|
||||
case 0x46: return opi_rmw_zero_page(&R6502::opf_lsr);
|
||||
case 0x48: return opi_push(regs.a);
|
||||
case 0x49: return opi_read_immediate<&R6502::opf_eor>();
|
||||
case 0x4a: return opi_shift<&R6502::opf_sra>();
|
||||
case 0x49: return opi_read_immediate(&R6502::opf_eor);
|
||||
case 0x4a: return opi_shift(&R6502::opf_sra);
|
||||
case 0x4c: return op_jmp_absolute();
|
||||
case 0x4d: return opi_read_absolute<&R6502::opf_eor>();
|
||||
case 0x4e: return opi_rmw_absolute<&R6502::opf_lsr>();
|
||||
case 0x4d: return opi_read_absolute(&R6502::opf_eor);
|
||||
case 0x4e: return opi_rmw_absolute(&R6502::opf_lsr);
|
||||
case 0x50: return opi_branch(regs.p.v == 0);
|
||||
case 0x51: return opi_read_indirect_zero_page_y<&R6502::opf_eor>();
|
||||
case 0x51: return opi_read_indirect_zero_page_y(&R6502::opf_eor);
|
||||
I case 0x54: return opill_nop_zero_page_x();
|
||||
case 0x55: return opi_read_zero_page_x<&R6502::opf_eor>();
|
||||
case 0x56: return opi_rmw_zero_page_x<&R6502::opf_lsr>();
|
||||
case 0x58: return opi_clear_flag(regs.p.i);
|
||||
case 0x59: return opi_read_absolute_y<&R6502::opf_eor>();
|
||||
case 0x55: return opi_read_zero_page_x(&R6502::opf_eor);
|
||||
case 0x56: return opi_rmw_zero_page_x(&R6502::opf_lsr);
|
||||
case 0x58: return opi_clear_flag(regs.p.i.bit);
|
||||
case 0x59: return opi_read_absolute_y(&R6502::opf_eor);
|
||||
I case 0x5a: return opill_nop_implied();
|
||||
I case 0x5c: return opill_nop_absolute_x();
|
||||
case 0x5d: return opi_read_absolute_x<&R6502::opf_eor>();
|
||||
case 0x5e: return opi_rmw_absolute_x<&R6502::opf_lsr>();
|
||||
case 0x5d: return opi_read_absolute_x(&R6502::opf_eor);
|
||||
case 0x5e: return opi_rmw_absolute_x(&R6502::opf_lsr);
|
||||
case 0x60: return op_rts();
|
||||
case 0x61: return opi_read_indirect_zero_page_x<&R6502::opf_adc>();
|
||||
case 0x61: return opi_read_indirect_zero_page_x(&R6502::opf_adc);
|
||||
I case 0x64: return opill_nop_zero_page();
|
||||
case 0x65: return opi_read_zero_page<&R6502::opf_adc>();
|
||||
case 0x66: return opi_rmw_zero_page<&R6502::opf_ror>();
|
||||
case 0x65: return opi_read_zero_page(&R6502::opf_adc);
|
||||
case 0x66: return opi_rmw_zero_page(&R6502::opf_ror);
|
||||
case 0x68: return opi_pull(regs.a);
|
||||
case 0x69: return opi_read_immediate<&R6502::opf_adc>();
|
||||
case 0x6a: return opi_shift<&R6502::opf_rra>();
|
||||
case 0x69: return opi_read_immediate(&R6502::opf_adc);
|
||||
case 0x6a: return opi_shift(&R6502::opf_rra);
|
||||
I case 0x6b: return opill_arr_immediate();
|
||||
case 0x6c: return op_jmp_indirect_absolute();
|
||||
case 0x6d: return opi_read_absolute<&R6502::opf_adc>();
|
||||
case 0x6e: return opi_rmw_absolute<&R6502::opf_ror>();
|
||||
case 0x6d: return opi_read_absolute(&R6502::opf_adc);
|
||||
case 0x6e: return opi_rmw_absolute(&R6502::opf_ror);
|
||||
case 0x70: return opi_branch(regs.p.v == 1);
|
||||
I case 0x74: return opill_nop_zero_page_x();
|
||||
case 0x71: return opi_read_indirect_zero_page_y<&R6502::opf_adc>();
|
||||
case 0x75: return opi_read_zero_page_x<&R6502::opf_adc>();
|
||||
case 0x76: return opi_rmw_zero_page_x<&R6502::opf_ror>();
|
||||
case 0x78: return opi_set_flag(regs.p.i);
|
||||
case 0x79: return opi_read_absolute_y<&R6502::opf_adc>();
|
||||
case 0x71: return opi_read_indirect_zero_page_y(&R6502::opf_adc);
|
||||
case 0x75: return opi_read_zero_page_x(&R6502::opf_adc);
|
||||
case 0x76: return opi_rmw_zero_page_x(&R6502::opf_ror);
|
||||
case 0x78: return opi_set_flag(regs.p.i.bit);
|
||||
case 0x79: return opi_read_absolute_y(&R6502::opf_adc);
|
||||
I case 0x7a: return opill_nop_implied();
|
||||
I case 0x7c: return opill_nop_absolute_x();
|
||||
case 0x7d: return opi_read_absolute_x<&R6502::opf_adc>();
|
||||
case 0x7e: return opi_rmw_absolute_x<&R6502::opf_ror>();
|
||||
case 0x7d: return opi_read_absolute_x(&R6502::opf_adc);
|
||||
case 0x7e: return opi_rmw_absolute_x(&R6502::opf_ror);
|
||||
I case 0x80: return opill_nop_absolute();
|
||||
case 0x81: return opi_store_indirect_zero_page_x(regs.a);
|
||||
I case 0x82: return opill_nop_immediate();
|
||||
@@ -158,76 +158,76 @@ I case 0x89: return opill_nop_immediate();
|
||||
case 0x99: return opi_store_absolute_y(regs.a);
|
||||
case 0x9a: return opi_transfer(regs.x, regs.s, 0);
|
||||
case 0x9d: return opi_store_absolute_x(regs.a);
|
||||
case 0xa0: return opi_read_immediate<&R6502::opf_ldy>();
|
||||
case 0xa1: return opi_read_indirect_zero_page_x<&R6502::opf_lda>();
|
||||
case 0xa2: return opi_read_immediate<&R6502::opf_ldx>();
|
||||
case 0xa4: return opi_read_zero_page<&R6502::opf_ldy>();
|
||||
case 0xa5: return opi_read_zero_page<&R6502::opf_lda>();
|
||||
case 0xa6: return opi_read_zero_page<&R6502::opf_ldx>();
|
||||
case 0xa0: return opi_read_immediate(&R6502::opf_ldy);
|
||||
case 0xa1: return opi_read_indirect_zero_page_x(&R6502::opf_lda);
|
||||
case 0xa2: return opi_read_immediate(&R6502::opf_ldx);
|
||||
case 0xa4: return opi_read_zero_page(&R6502::opf_ldy);
|
||||
case 0xa5: return opi_read_zero_page(&R6502::opf_lda);
|
||||
case 0xa6: return opi_read_zero_page(&R6502::opf_ldx);
|
||||
case 0xa8: return opi_transfer(regs.a, regs.y, 1);
|
||||
case 0xa9: return opi_read_immediate<&R6502::opf_lda>();
|
||||
case 0xa9: return opi_read_immediate(&R6502::opf_lda);
|
||||
case 0xaa: return opi_transfer(regs.a, regs.x, 1);
|
||||
case 0xac: return opi_read_absolute<&R6502::opf_ldy>();
|
||||
case 0xad: return opi_read_absolute<&R6502::opf_lda>();
|
||||
case 0xae: return opi_read_absolute<&R6502::opf_ldx>();
|
||||
case 0xac: return opi_read_absolute(&R6502::opf_ldy);
|
||||
case 0xad: return opi_read_absolute(&R6502::opf_lda);
|
||||
case 0xae: return opi_read_absolute(&R6502::opf_ldx);
|
||||
case 0xb0: return opi_branch(regs.p.c == 1);
|
||||
case 0xb1: return opi_read_indirect_zero_page_y<&R6502::opf_lda>();
|
||||
case 0xb4: return opi_read_zero_page_x<&R6502::opf_ldy>();
|
||||
case 0xb5: return opi_read_zero_page_x<&R6502::opf_lda>();
|
||||
case 0xb6: return opi_read_zero_page_y<&R6502::opf_ldx>();
|
||||
case 0xb8: return opi_clear_flag(regs.p.v);
|
||||
case 0xb9: return opi_read_absolute_y<&R6502::opf_lda>();
|
||||
case 0xb1: return opi_read_indirect_zero_page_y(&R6502::opf_lda);
|
||||
case 0xb4: return opi_read_zero_page_x(&R6502::opf_ldy);
|
||||
case 0xb5: return opi_read_zero_page_x(&R6502::opf_lda);
|
||||
case 0xb6: return opi_read_zero_page_y(&R6502::opf_ldx);
|
||||
case 0xb8: return opi_clear_flag(regs.p.v.bit);
|
||||
case 0xb9: return opi_read_absolute_y(&R6502::opf_lda);
|
||||
case 0xba: return opi_transfer(regs.s, regs.x, 1);
|
||||
case 0xbc: return opi_read_absolute_x<&R6502::opf_ldy>();
|
||||
case 0xbd: return opi_read_absolute_x<&R6502::opf_lda>();
|
||||
case 0xbe: return opi_read_absolute_y<&R6502::opf_ldx>();
|
||||
case 0xc0: return opi_read_immediate<&R6502::opf_cpy>();
|
||||
case 0xc1: return opi_read_indirect_zero_page_x<&R6502::opf_cmp>();
|
||||
case 0xbc: return opi_read_absolute_x(&R6502::opf_ldy);
|
||||
case 0xbd: return opi_read_absolute_x(&R6502::opf_lda);
|
||||
case 0xbe: return opi_read_absolute_y(&R6502::opf_ldx);
|
||||
case 0xc0: return opi_read_immediate(&R6502::opf_cpy);
|
||||
case 0xc1: return opi_read_indirect_zero_page_x(&R6502::opf_cmp);
|
||||
I case 0xc2: return opill_nop_immediate();
|
||||
case 0xc4: return opi_read_zero_page<&R6502::opf_cpy>();
|
||||
case 0xc5: return opi_read_zero_page<&R6502::opf_cmp>();
|
||||
case 0xc6: return opi_rmw_zero_page<&R6502::opf_dec>();
|
||||
case 0xc4: return opi_read_zero_page(&R6502::opf_cpy);
|
||||
case 0xc5: return opi_read_zero_page(&R6502::opf_cmp);
|
||||
case 0xc6: return opi_rmw_zero_page(&R6502::opf_dec);
|
||||
case 0xc8: return opi_increment(regs.y);
|
||||
case 0xc9: return opi_read_immediate<&R6502::opf_cmp>();
|
||||
case 0xc9: return opi_read_immediate(&R6502::opf_cmp);
|
||||
case 0xca: return opi_decrement(regs.x);
|
||||
case 0xcc: return opi_read_absolute<&R6502::opf_cpy>();
|
||||
case 0xcd: return opi_read_absolute<&R6502::opf_cmp>();
|
||||
case 0xce: return opi_rmw_absolute<&R6502::opf_dec>();
|
||||
case 0xcc: return opi_read_absolute(&R6502::opf_cpy);
|
||||
case 0xcd: return opi_read_absolute(&R6502::opf_cmp);
|
||||
case 0xce: return opi_rmw_absolute(&R6502::opf_dec);
|
||||
case 0xd0: return opi_branch(regs.p.z == 0);
|
||||
case 0xd1: return opi_read_indirect_zero_page_y<&R6502::opf_cmp>();
|
||||
case 0xd1: return opi_read_indirect_zero_page_y(&R6502::opf_cmp);
|
||||
I case 0xd4: return opill_nop_zero_page_x();
|
||||
case 0xd5: return opi_read_zero_page_x<&R6502::opf_cmp>();
|
||||
case 0xd6: return opi_rmw_zero_page_x<&R6502::opf_dec>();
|
||||
case 0xd8: return opi_clear_flag(regs.p.d);
|
||||
case 0xd9: return opi_read_absolute_y<&R6502::opf_cmp>();
|
||||
case 0xd5: return opi_read_zero_page_x(&R6502::opf_cmp);
|
||||
case 0xd6: return opi_rmw_zero_page_x(&R6502::opf_dec);
|
||||
case 0xd8: return opi_clear_flag(regs.p.d.bit);
|
||||
case 0xd9: return opi_read_absolute_y(&R6502::opf_cmp);
|
||||
I case 0xda: return opill_nop_implied();
|
||||
I case 0xdc: return opill_nop_absolute_x();
|
||||
case 0xdd: return opi_read_absolute_x<&R6502::opf_cmp>();
|
||||
case 0xde: return opi_rmw_absolute_x<&R6502::opf_dec>();
|
||||
case 0xe0: return opi_read_immediate<&R6502::opf_cpx>();
|
||||
case 0xe1: return opi_read_indirect_zero_page_x<&R6502::opf_sbc>();
|
||||
case 0xdd: return opi_read_absolute_x(&R6502::opf_cmp);
|
||||
case 0xde: return opi_rmw_absolute_x(&R6502::opf_dec);
|
||||
case 0xe0: return opi_read_immediate(&R6502::opf_cpx);
|
||||
case 0xe1: return opi_read_indirect_zero_page_x(&R6502::opf_sbc);
|
||||
I case 0xe2: return opill_nop_immediate();
|
||||
case 0xe4: return opi_read_zero_page<&R6502::opf_cpx>();
|
||||
case 0xe5: return opi_read_zero_page<&R6502::opf_sbc>();
|
||||
case 0xe6: return opi_rmw_zero_page<&R6502::opf_inc>();
|
||||
case 0xe4: return opi_read_zero_page(&R6502::opf_cpx);
|
||||
case 0xe5: return opi_read_zero_page(&R6502::opf_sbc);
|
||||
case 0xe6: return opi_rmw_zero_page(&R6502::opf_inc);
|
||||
case 0xe8: return opi_increment(regs.x);
|
||||
case 0xe9: return opi_read_immediate<&R6502::opf_sbc>();
|
||||
case 0xe9: return opi_read_immediate(&R6502::opf_sbc);
|
||||
case 0xea: return op_nop();
|
||||
I case 0xeb: return opi_read_immediate<&R6502::opf_sbc>();
|
||||
case 0xec: return opi_read_absolute<&R6502::opf_cpx>();
|
||||
case 0xed: return opi_read_absolute<&R6502::opf_sbc>();
|
||||
case 0xee: return opi_rmw_absolute<&R6502::opf_inc>();
|
||||
I case 0xeb: return opi_read_immediate(&R6502::opf_sbc);
|
||||
case 0xec: return opi_read_absolute(&R6502::opf_cpx);
|
||||
case 0xed: return opi_read_absolute(&R6502::opf_sbc);
|
||||
case 0xee: return opi_rmw_absolute(&R6502::opf_inc);
|
||||
case 0xf0: return opi_branch(regs.p.z == 1);
|
||||
case 0xf1: return opi_read_indirect_zero_page_y<&R6502::opf_sbc>();
|
||||
case 0xf1: return opi_read_indirect_zero_page_y(&R6502::opf_sbc);
|
||||
I case 0xf4: return opill_nop_zero_page_x();
|
||||
case 0xf5: return opi_read_zero_page_x<&R6502::opf_sbc>();
|
||||
case 0xf6: return opi_rmw_zero_page_x<&R6502::opf_inc>();
|
||||
case 0xf8: return opi_set_flag(regs.p.d);
|
||||
case 0xf9: return opi_read_absolute_y<&R6502::opf_sbc>();
|
||||
case 0xf5: return opi_read_zero_page_x(&R6502::opf_sbc);
|
||||
case 0xf6: return opi_rmw_zero_page_x(&R6502::opf_inc);
|
||||
case 0xf8: return opi_set_flag(regs.p.d.bit);
|
||||
case 0xf9: return opi_read_absolute_y(&R6502::opf_sbc);
|
||||
I case 0xfa: return opill_nop_implied();
|
||||
I case 0xfc: return opill_nop_absolute_x();
|
||||
case 0xfd: return opi_read_absolute_x<&R6502::opf_sbc>();
|
||||
case 0xfe: return opi_rmw_absolute_x<&R6502::opf_inc>();
|
||||
case 0xfd: return opi_read_absolute_x(&R6502::opf_sbc);
|
||||
case 0xfe: return opi_rmw_absolute_x(&R6502::opf_inc);
|
||||
}
|
||||
|
||||
//unimplemented opcode
|
||||
|
@@ -57,27 +57,29 @@ struct R6502 {
|
||||
auto opf_sla();
|
||||
auto opf_sra();
|
||||
|
||||
using fp = auto (R6502::*)() -> void;
|
||||
|
||||
auto opi_branch(bool condition);
|
||||
auto opi_clear_flag(bool& flag);
|
||||
auto opi_clear_flag(uint bit);
|
||||
auto opi_decrement(uint8& r);
|
||||
auto opi_increment(uint8& r);
|
||||
auto opi_pull(uint8& r);
|
||||
auto opi_push(uint8& r);
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_absolute();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_absolute_x();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_absolute_y();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_immediate();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_indirect_zero_page_x();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_indirect_zero_page_y();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_zero_page();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_zero_page_x();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_zero_page_y();
|
||||
template<auto (R6502::*op)() -> void> auto opi_rmw_absolute();
|
||||
template<auto (R6502::*op)() -> void> auto opi_rmw_absolute_x();
|
||||
template<auto (R6502::*op)() -> void> auto opi_rmw_zero_page();
|
||||
template<auto (R6502::*op)() -> void> auto opi_rmw_zero_page_x();
|
||||
auto opi_set_flag(bool& flag);
|
||||
template<auto (R6502::*op)() -> void> auto opi_shift();
|
||||
auto opi_read_absolute(fp);
|
||||
auto opi_read_absolute_x(fp);
|
||||
auto opi_read_absolute_y(fp);
|
||||
auto opi_read_immediate(fp);
|
||||
auto opi_read_indirect_zero_page_x(fp);
|
||||
auto opi_read_indirect_zero_page_y(fp);
|
||||
auto opi_read_zero_page(fp);
|
||||
auto opi_read_zero_page_x(fp);
|
||||
auto opi_read_zero_page_y(fp);
|
||||
auto opi_rmw_absolute(fp);
|
||||
auto opi_rmw_absolute_x(fp);
|
||||
auto opi_rmw_zero_page(fp);
|
||||
auto opi_rmw_zero_page_x(fp);
|
||||
auto opi_set_flag(uint bit);
|
||||
auto opi_shift(fp);
|
||||
auto opi_store_absolute(uint8& r);
|
||||
auto opi_store_absolute_x(uint8& r);
|
||||
auto opi_store_absolute_y(uint8& r);
|
||||
|
@@ -1,15 +1,19 @@
|
||||
struct Flags {
|
||||
inline operator uint() {
|
||||
return (n << 7) | (v << 6) | (d << 3) | (i << 2) | (z << 1) | (c << 0);
|
||||
}
|
||||
union {
|
||||
uint8_t data = 0;
|
||||
BitField<uint8_t, 7> n;
|
||||
BitField<uint8_t, 6> v;
|
||||
BitField<uint8_t, 3> d;
|
||||
BitField<uint8_t, 2> i;
|
||||
BitField<uint8_t, 1> z;
|
||||
BitField<uint8_t, 0> c;
|
||||
};
|
||||
|
||||
inline auto operator=(uint8 data) -> Flags& {
|
||||
n = data & 0x80; v = data & 0x40;
|
||||
d = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool n, v, d, i, z, c;
|
||||
inline operator uint() { return data; }
|
||||
inline auto& operator =(uint value) { return data = value, *this; }
|
||||
inline auto& operator&=(uint value) { return data &= value, *this; }
|
||||
inline auto& operator|=(uint value) { return data |= value, *this; }
|
||||
inline auto& operator^=(uint value) { return data ^= value, *this; }
|
||||
};
|
||||
|
||||
struct Registers {
|
||||
@@ -22,7 +26,8 @@ struct Registers {
|
||||
struct Register16 {
|
||||
union {
|
||||
uint16_t w;
|
||||
struct { uint8_t order_lsb2(l, h); };
|
||||
BitField<uint16_t, 0, 7> l;
|
||||
BitField<uint16_t, 8, 15> h;
|
||||
};
|
||||
} abs, iabs;
|
||||
|
||||
|
@@ -5,12 +5,7 @@ auto R6502::serialize(serializer& s) -> void {
|
||||
s.integer(regs.x);
|
||||
s.integer(regs.y);
|
||||
s.integer(regs.s);
|
||||
s.integer(regs.p.n);
|
||||
s.integer(regs.p.v);
|
||||
s.integer(regs.p.d);
|
||||
s.integer(regs.p.i);
|
||||
s.integer(regs.p.z);
|
||||
s.integer(regs.p.c);
|
||||
s.integer(regs.p.data);
|
||||
|
||||
s.integer(abs.w);
|
||||
s.integer(iabs.w);
|
||||
|
@@ -1,327 +1,327 @@
|
||||
auto R65816::op_adc_b() {
|
||||
int result;
|
||||
|
||||
if(!regs.p.d) {
|
||||
result = regs.a.l + rd.l + regs.p.c;
|
||||
if(!r.p.d) {
|
||||
result = r.a.l + rd.l + r.p.c;
|
||||
} else {
|
||||
result = (regs.a.l & 0x0f) + (rd.l & 0x0f) + (regs.p.c << 0);
|
||||
result = (r.a.l & 0x0f) + (rd.l & 0x0f) + (r.p.c << 0);
|
||||
if(result > 0x09) result += 0x06;
|
||||
regs.p.c = result > 0x0f;
|
||||
result = (regs.a.l & 0xf0) + (rd.l & 0xf0) + (regs.p.c << 4) + (result & 0x0f);
|
||||
r.p.c = result > 0x0f;
|
||||
result = (r.a.l & 0xf0) + (rd.l & 0xf0) + (r.p.c << 4) + (result & 0x0f);
|
||||
}
|
||||
|
||||
regs.p.v = ~(regs.a.l ^ rd.l) & (regs.a.l ^ result) & 0x80;
|
||||
if(regs.p.d && result > 0x9f) result += 0x60;
|
||||
regs.p.c = result > 0xff;
|
||||
regs.p.n = result & 0x80;
|
||||
regs.p.z = (uint8_t)result == 0;
|
||||
r.p.v = ~(r.a.l ^ rd.l) & (r.a.l ^ result) & 0x80;
|
||||
if(r.p.d && result > 0x9f) result += 0x60;
|
||||
r.p.c = result > 0xff;
|
||||
r.p.n = result & 0x80;
|
||||
r.p.z = (uint8)result == 0;
|
||||
|
||||
regs.a.l = result;
|
||||
r.a.l = result;
|
||||
}
|
||||
|
||||
auto R65816::op_adc_w() {
|
||||
int result;
|
||||
|
||||
if(!regs.p.d) {
|
||||
result = regs.a.w + rd.w + regs.p.c;
|
||||
if(!r.p.d) {
|
||||
result = r.a.w + rd.w + r.p.c;
|
||||
} else {
|
||||
result = (regs.a.w & 0x000f) + (rd.w & 0x000f) + (regs.p.c << 0);
|
||||
result = (r.a.w & 0x000f) + (rd.w & 0x000f) + (r.p.c << 0);
|
||||
if(result > 0x0009) result += 0x0006;
|
||||
regs.p.c = result > 0x000f;
|
||||
result = (regs.a.w & 0x00f0) + (rd.w & 0x00f0) + (regs.p.c << 4) + (result & 0x000f);
|
||||
r.p.c = result > 0x000f;
|
||||
result = (r.a.w & 0x00f0) + (rd.w & 0x00f0) + (r.p.c << 4) + (result & 0x000f);
|
||||
if(result > 0x009f) result += 0x0060;
|
||||
regs.p.c = result > 0x00ff;
|
||||
result = (regs.a.w & 0x0f00) + (rd.w & 0x0f00) + (regs.p.c << 8) + (result & 0x00ff);
|
||||
r.p.c = result > 0x00ff;
|
||||
result = (r.a.w & 0x0f00) + (rd.w & 0x0f00) + (r.p.c << 8) + (result & 0x00ff);
|
||||
if(result > 0x09ff) result += 0x0600;
|
||||
regs.p.c = result > 0x0fff;
|
||||
result = (regs.a.w & 0xf000) + (rd.w & 0xf000) + (regs.p.c << 12) + (result & 0x0fff);
|
||||
r.p.c = result > 0x0fff;
|
||||
result = (r.a.w & 0xf000) + (rd.w & 0xf000) + (r.p.c << 12) + (result & 0x0fff);
|
||||
}
|
||||
|
||||
regs.p.v = ~(regs.a.w ^ rd.w) & (regs.a.w ^ result) & 0x8000;
|
||||
if(regs.p.d && result > 0x9fff) result += 0x6000;
|
||||
regs.p.c = result > 0xffff;
|
||||
regs.p.n = result & 0x8000;
|
||||
regs.p.z = (uint16_t)result == 0;
|
||||
r.p.v = ~(r.a.w ^ rd.w) & (r.a.w ^ result) & 0x8000;
|
||||
if(r.p.d && result > 0x9fff) result += 0x6000;
|
||||
r.p.c = result > 0xffff;
|
||||
r.p.n = result & 0x8000;
|
||||
r.p.z = (uint16)result == 0;
|
||||
|
||||
regs.a.w = result;
|
||||
r.a.w = result;
|
||||
}
|
||||
|
||||
auto R65816::op_and_b() {
|
||||
regs.a.l &= rd.l;
|
||||
regs.p.n = regs.a.l & 0x80;
|
||||
regs.p.z = regs.a.l == 0;
|
||||
r.a.l &= rd.l;
|
||||
r.p.n = r.a.l & 0x80;
|
||||
r.p.z = r.a.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_and_w() {
|
||||
regs.a.w &= rd.w;
|
||||
regs.p.n = regs.a.w & 0x8000;
|
||||
regs.p.z = regs.a.w == 0;
|
||||
r.a.w &= rd.w;
|
||||
r.p.n = r.a.w & 0x8000;
|
||||
r.p.z = r.a.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_bit_b() {
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.v = rd.l & 0x40;
|
||||
regs.p.z = (rd.l & regs.a.l) == 0;
|
||||
r.p.n = rd.l & 0x80;
|
||||
r.p.v = rd.l & 0x40;
|
||||
r.p.z = (rd.l & r.a.l) == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_bit_w() {
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.v = rd.w & 0x4000;
|
||||
regs.p.z = (rd.w & regs.a.w) == 0;
|
||||
r.p.n = rd.w & 0x8000;
|
||||
r.p.v = rd.w & 0x4000;
|
||||
r.p.z = (rd.w & r.a.w) == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_cmp_b() {
|
||||
int r = regs.a.l - rd.l;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
int result = r.a.l - rd.l;
|
||||
r.p.n = result & 0x80;
|
||||
r.p.z = (uint8)result == 0;
|
||||
r.p.c = result >= 0;
|
||||
}
|
||||
|
||||
auto R65816::op_cmp_w() {
|
||||
int r = regs.a.w - rd.w;
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
int result = r.a.w - rd.w;
|
||||
r.p.n = result & 0x8000;
|
||||
r.p.z = (uint16)result == 0;
|
||||
r.p.c = result >= 0;
|
||||
}
|
||||
|
||||
auto R65816::op_cpx_b() {
|
||||
int r = regs.x.l - rd.l;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
int result = r.x.l - rd.l;
|
||||
r.p.n = result & 0x80;
|
||||
r.p.z = (uint8)result == 0;
|
||||
r.p.c = result >= 0;
|
||||
}
|
||||
|
||||
auto R65816::op_cpx_w() {
|
||||
int r = regs.x.w - rd.w;
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
int result = r.x.w - rd.w;
|
||||
r.p.n = result & 0x8000;
|
||||
r.p.z = (uint16)result == 0;
|
||||
r.p.c = result >= 0;
|
||||
}
|
||||
|
||||
auto R65816::op_cpy_b() {
|
||||
int r = regs.y.l - rd.l;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
int result = r.y.l - rd.l;
|
||||
r.p.n = result & 0x80;
|
||||
r.p.z = (uint8)result == 0;
|
||||
r.p.c = result >= 0;
|
||||
}
|
||||
|
||||
auto R65816::op_cpy_w() {
|
||||
int r = regs.y.w - rd.w;
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
int result = r.y.w - rd.w;
|
||||
r.p.n = result & 0x8000;
|
||||
r.p.z = (uint16)result == 0;
|
||||
r.p.c = result >= 0;
|
||||
}
|
||||
|
||||
auto R65816::op_eor_b() {
|
||||
regs.a.l ^= rd.l;
|
||||
regs.p.n = regs.a.l & 0x80;
|
||||
regs.p.z = regs.a.l == 0;
|
||||
r.a.l ^= rd.l;
|
||||
r.p.n = r.a.l & 0x80;
|
||||
r.p.z = r.a.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_eor_w() {
|
||||
regs.a.w ^= rd.w;
|
||||
regs.p.n = regs.a.w & 0x8000;
|
||||
regs.p.z = regs.a.w == 0;
|
||||
r.a.w ^= rd.w;
|
||||
r.p.n = r.a.w & 0x8000;
|
||||
r.p.z = r.a.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_lda_b() {
|
||||
regs.a.l = rd.l;
|
||||
regs.p.n = regs.a.l & 0x80;
|
||||
regs.p.z = regs.a.l == 0;
|
||||
r.a.l = rd.l;
|
||||
r.p.n = r.a.l & 0x80;
|
||||
r.p.z = r.a.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_lda_w() {
|
||||
regs.a.w = rd.w;
|
||||
regs.p.n = regs.a.w & 0x8000;
|
||||
regs.p.z = regs.a.w == 0;
|
||||
r.a.w = rd.w;
|
||||
r.p.n = r.a.w & 0x8000;
|
||||
r.p.z = r.a.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_ldx_b() {
|
||||
regs.x.l = rd.l;
|
||||
regs.p.n = regs.x.l & 0x80;
|
||||
regs.p.z = regs.x.l == 0;
|
||||
r.x.l = rd.l;
|
||||
r.p.n = r.x.l & 0x80;
|
||||
r.p.z = r.x.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_ldx_w() {
|
||||
regs.x.w = rd.w;
|
||||
regs.p.n = regs.x.w & 0x8000;
|
||||
regs.p.z = regs.x.w == 0;
|
||||
r.x.w = rd.w;
|
||||
r.p.n = r.x.w & 0x8000;
|
||||
r.p.z = r.x.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_ldy_b() {
|
||||
regs.y.l = rd.l;
|
||||
regs.p.n = regs.y.l & 0x80;
|
||||
regs.p.z = regs.y.l == 0;
|
||||
r.y.l = rd.l;
|
||||
r.p.n = r.y.l & 0x80;
|
||||
r.p.z = r.y.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_ldy_w() {
|
||||
regs.y.w = rd.w;
|
||||
regs.p.n = regs.y.w & 0x8000;
|
||||
regs.p.z = regs.y.w == 0;
|
||||
r.y.w = rd.w;
|
||||
r.p.n = r.y.w & 0x8000;
|
||||
r.p.z = r.y.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_ora_b() {
|
||||
regs.a.l |= rd.l;
|
||||
regs.p.n = regs.a.l & 0x80;
|
||||
regs.p.z = regs.a.l == 0;
|
||||
r.a.l |= rd.l;
|
||||
r.p.n = r.a.l & 0x80;
|
||||
r.p.z = r.a.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_ora_w() {
|
||||
regs.a.w |= rd.w;
|
||||
regs.p.n = regs.a.w & 0x8000;
|
||||
regs.p.z = regs.a.w == 0;
|
||||
r.a.w |= rd.w;
|
||||
r.p.n = r.a.w & 0x8000;
|
||||
r.p.z = r.a.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_sbc_b() {
|
||||
int result;
|
||||
rd.l ^= 0xff;
|
||||
|
||||
if(!regs.p.d) {
|
||||
result = regs.a.l + rd.l + regs.p.c;
|
||||
if(!r.p.d) {
|
||||
result = r.a.l + rd.l + r.p.c;
|
||||
} else {
|
||||
result = (regs.a.l & 0x0f) + (rd.l & 0x0f) + (regs.p.c << 0);
|
||||
result = (r.a.l & 0x0f) + (rd.l & 0x0f) + (r.p.c << 0);
|
||||
if(result <= 0x0f) result -= 0x06;
|
||||
regs.p.c = result > 0x0f;
|
||||
result = (regs.a.l & 0xf0) + (rd.l & 0xf0) + (regs.p.c << 4) + (result & 0x0f);
|
||||
r.p.c = result > 0x0f;
|
||||
result = (r.a.l & 0xf0) + (rd.l & 0xf0) + (r.p.c << 4) + (result & 0x0f);
|
||||
}
|
||||
|
||||
regs.p.v = ~(regs.a.l ^ rd.l) & (regs.a.l ^ result) & 0x80;
|
||||
if(regs.p.d && result <= 0xff) result -= 0x60;
|
||||
regs.p.c = result > 0xff;
|
||||
regs.p.n = result & 0x80;
|
||||
regs.p.z = (uint8_t)result == 0;
|
||||
r.p.v = ~(r.a.l ^ rd.l) & (r.a.l ^ result) & 0x80;
|
||||
if(r.p.d && result <= 0xff) result -= 0x60;
|
||||
r.p.c = result > 0xff;
|
||||
r.p.n = result & 0x80;
|
||||
r.p.z = (uint8_t)result == 0;
|
||||
|
||||
regs.a.l = result;
|
||||
r.a.l = result;
|
||||
}
|
||||
|
||||
auto R65816::op_sbc_w() {
|
||||
int result;
|
||||
rd.w ^= 0xffff;
|
||||
|
||||
if(!regs.p.d) {
|
||||
result = regs.a.w + rd.w + regs.p.c;
|
||||
if(!r.p.d) {
|
||||
result = r.a.w + rd.w + r.p.c;
|
||||
} else {
|
||||
result = (regs.a.w & 0x000f) + (rd.w & 0x000f) + (regs.p.c << 0);
|
||||
result = (r.a.w & 0x000f) + (rd.w & 0x000f) + (r.p.c << 0);
|
||||
if(result <= 0x000f) result -= 0x0006;
|
||||
regs.p.c = result > 0x000f;
|
||||
result = (regs.a.w & 0x00f0) + (rd.w & 0x00f0) + (regs.p.c << 4) + (result & 0x000f);
|
||||
r.p.c = result > 0x000f;
|
||||
result = (r.a.w & 0x00f0) + (rd.w & 0x00f0) + (r.p.c << 4) + (result & 0x000f);
|
||||
if(result <= 0x00ff) result -= 0x0060;
|
||||
regs.p.c = result > 0x00ff;
|
||||
result = (regs.a.w & 0x0f00) + (rd.w & 0x0f00) + (regs.p.c << 8) + (result & 0x00ff);
|
||||
r.p.c = result > 0x00ff;
|
||||
result = (r.a.w & 0x0f00) + (rd.w & 0x0f00) + (r.p.c << 8) + (result & 0x00ff);
|
||||
if(result <= 0x0fff) result -= 0x0600;
|
||||
regs.p.c = result > 0x0fff;
|
||||
result = (regs.a.w & 0xf000) + (rd.w & 0xf000) + (regs.p.c << 12) + (result & 0x0fff);
|
||||
r.p.c = result > 0x0fff;
|
||||
result = (r.a.w & 0xf000) + (rd.w & 0xf000) + (r.p.c << 12) + (result & 0x0fff);
|
||||
}
|
||||
|
||||
regs.p.v = ~(regs.a.w ^ rd.w) & (regs.a.w ^ result) & 0x8000;
|
||||
if(regs.p.d && result <= 0xffff) result -= 0x6000;
|
||||
regs.p.c = result > 0xffff;
|
||||
regs.p.n = result & 0x8000;
|
||||
regs.p.z = (uint16_t)result == 0;
|
||||
r.p.v = ~(r.a.w ^ rd.w) & (r.a.w ^ result) & 0x8000;
|
||||
if(r.p.d && result <= 0xffff) result -= 0x6000;
|
||||
r.p.c = result > 0xffff;
|
||||
r.p.n = result & 0x8000;
|
||||
r.p.z = (uint16_t)result == 0;
|
||||
|
||||
regs.a.w = result;
|
||||
r.a.w = result;
|
||||
}
|
||||
|
||||
auto R65816::op_inc_b() {
|
||||
rd.l++;
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
r.p.n = rd.l & 0x80;
|
||||
r.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_inc_w() {
|
||||
rd.w++;
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
r.p.n = rd.w & 0x8000;
|
||||
r.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_dec_b() {
|
||||
rd.l--;
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
r.p.n = rd.l & 0x80;
|
||||
r.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_dec_w() {
|
||||
rd.w--;
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
r.p.n = rd.w & 0x8000;
|
||||
r.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_asl_b() {
|
||||
regs.p.c = rd.l & 0x80;
|
||||
r.p.c = rd.l & 0x80;
|
||||
rd.l <<= 1;
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
r.p.n = rd.l & 0x80;
|
||||
r.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_asl_w() {
|
||||
regs.p.c = rd.w & 0x8000;
|
||||
r.p.c = rd.w & 0x8000;
|
||||
rd.w <<= 1;
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
r.p.n = rd.w & 0x8000;
|
||||
r.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_lsr_b() {
|
||||
regs.p.c = rd.l & 1;
|
||||
r.p.c = rd.l & 1;
|
||||
rd.l >>= 1;
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
r.p.n = rd.l & 0x80;
|
||||
r.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_lsr_w() {
|
||||
regs.p.c = rd.w & 1;
|
||||
r.p.c = rd.w & 1;
|
||||
rd.w >>= 1;
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
r.p.n = rd.w & 0x8000;
|
||||
r.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_rol_b() {
|
||||
unsigned carry = (unsigned)regs.p.c;
|
||||
regs.p.c = rd.l & 0x80;
|
||||
auto carry = (uint)r.p.c;
|
||||
r.p.c = rd.l & 0x80;
|
||||
rd.l = (rd.l << 1) | carry;
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
r.p.n = rd.l & 0x80;
|
||||
r.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_rol_w() {
|
||||
unsigned carry = (unsigned)regs.p.c;
|
||||
regs.p.c = rd.w & 0x8000;
|
||||
auto carry = (uint)r.p.c;
|
||||
r.p.c = rd.w & 0x8000;
|
||||
rd.w = (rd.w << 1) | carry;
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
r.p.n = rd.w & 0x8000;
|
||||
r.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_ror_b() {
|
||||
unsigned carry = (unsigned)regs.p.c << 7;
|
||||
regs.p.c = rd.l & 1;
|
||||
auto carry = (uint)r.p.c << 7;
|
||||
r.p.c = rd.l & 1;
|
||||
rd.l = carry | (rd.l >> 1);
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
r.p.n = rd.l & 0x80;
|
||||
r.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_ror_w() {
|
||||
unsigned carry = (unsigned)regs.p.c << 15;
|
||||
regs.p.c = rd.w & 1;
|
||||
auto carry = (uint)r.p.c << 15;
|
||||
r.p.c = rd.w & 1;
|
||||
rd.w = carry | (rd.w >> 1);
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
r.p.n = rd.w & 0x8000;
|
||||
r.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
auto R65816::op_trb_b() {
|
||||
regs.p.z = (rd.l & regs.a.l) == 0;
|
||||
rd.l &= ~regs.a.l;
|
||||
r.p.z = (rd.l & r.a.l) == 0;
|
||||
rd.l &= ~r.a.l;
|
||||
}
|
||||
|
||||
auto R65816::op_trb_w() {
|
||||
regs.p.z = (rd.w & regs.a.w) == 0;
|
||||
rd.w &= ~regs.a.w;
|
||||
r.p.z = (rd.w & r.a.w) == 0;
|
||||
rd.w &= ~r.a.w;
|
||||
}
|
||||
|
||||
auto R65816::op_tsb_b() {
|
||||
regs.p.z = (rd.l & regs.a.l) == 0;
|
||||
rd.l |= regs.a.l;
|
||||
r.p.z = (rd.l & r.a.l) == 0;
|
||||
rd.l |= r.a.l;
|
||||
}
|
||||
|
||||
auto R65816::op_tsb_w() {
|
||||
regs.p.z = (rd.w & regs.a.w) == 0;
|
||||
rd.w |= regs.a.w;
|
||||
r.p.z = (rd.w & r.a.w) == 0;
|
||||
rd.w |= r.a.w;
|
||||
}
|
||||
|
@@ -23,93 +23,93 @@ auto R65816::dreadl(uint24 addr) -> uint24 {
|
||||
}
|
||||
|
||||
auto R65816::decode(uint8 mode, uint24 addr) -> uint24 {
|
||||
uint24 r = 0;
|
||||
uint24 a = 0;
|
||||
|
||||
switch(mode) {
|
||||
case OPTYPE_DP:
|
||||
r = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||
a = (r.d + (addr & 0xffff)) & 0xffff;
|
||||
break;
|
||||
case OPTYPE_DPX:
|
||||
r = (regs.d + regs.x + (addr & 0xffff)) & 0xffff;
|
||||
a = (r.d + r.x + (addr & 0xffff)) & 0xffff;
|
||||
break;
|
||||
case OPTYPE_DPY:
|
||||
r = (regs.d + regs.y + (addr & 0xffff)) & 0xffff;
|
||||
a = (r.d + r.y + (addr & 0xffff)) & 0xffff;
|
||||
break;
|
||||
case OPTYPE_IDP:
|
||||
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||
r = (regs.db << 16) + dreadw(addr);
|
||||
addr = (r.d + (addr & 0xffff)) & 0xffff;
|
||||
a = (r.db << 16) + dreadw(addr);
|
||||
break;
|
||||
case OPTYPE_IDPX:
|
||||
addr = (regs.d + regs.x + (addr & 0xffff)) & 0xffff;
|
||||
r = (regs.db << 16) + dreadw(addr);
|
||||
addr = (r.d + r.x + (addr & 0xffff)) & 0xffff;
|
||||
a = (r.db << 16) + dreadw(addr);
|
||||
break;
|
||||
case OPTYPE_IDPY:
|
||||
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||
r = (regs.db << 16) + dreadw(addr) + regs.y;
|
||||
addr = (r.d + (addr & 0xffff)) & 0xffff;
|
||||
a = (r.db << 16) + dreadw(addr) + r.y;
|
||||
break;
|
||||
case OPTYPE_ILDP:
|
||||
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||
r = dreadl(addr);
|
||||
addr = (r.d + (addr & 0xffff)) & 0xffff;
|
||||
a = dreadl(addr);
|
||||
break;
|
||||
case OPTYPE_ILDPY:
|
||||
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||
r = dreadl(addr) + regs.y;
|
||||
addr = (r.d + (addr & 0xffff)) & 0xffff;
|
||||
a = dreadl(addr) + r.y;
|
||||
break;
|
||||
case OPTYPE_ADDR:
|
||||
r = (regs.db << 16) + (addr & 0xffff);
|
||||
a = (r.db << 16) + (addr & 0xffff);
|
||||
break;
|
||||
case OPTYPE_ADDR_PC:
|
||||
r = (regs.pc.b << 16) + (addr & 0xffff);
|
||||
a = (r.pc.b << 16) + (addr & 0xffff);
|
||||
break;
|
||||
case OPTYPE_ADDRX:
|
||||
r = (regs.db << 16) + (addr & 0xffff) + regs.x;
|
||||
a = (r.db << 16) + (addr & 0xffff) + r.x;
|
||||
break;
|
||||
case OPTYPE_ADDRY:
|
||||
r = (regs.db << 16) + (addr & 0xffff) + regs.y;
|
||||
a = (r.db << 16) + (addr & 0xffff) + r.y;
|
||||
break;
|
||||
case OPTYPE_IADDR_PC:
|
||||
r = (regs.pc.b << 16) + (addr & 0xffff);
|
||||
a = (r.pc.b << 16) + (addr & 0xffff);
|
||||
break;
|
||||
case OPTYPE_IADDRX:
|
||||
r = (regs.pc.b << 16) + ((addr + regs.x) & 0xffff);
|
||||
a = (r.pc.b << 16) + ((addr + r.x) & 0xffff);
|
||||
break;
|
||||
case OPTYPE_ILADDR:
|
||||
r = addr;
|
||||
a = addr;
|
||||
break;
|
||||
case OPTYPE_LONG:
|
||||
r = addr;
|
||||
a = addr;
|
||||
break;
|
||||
case OPTYPE_LONGX:
|
||||
r = (addr + regs.x);
|
||||
a = (addr + r.x);
|
||||
break;
|
||||
case OPTYPE_SR:
|
||||
r = (regs.s + (addr & 0xff)) & 0xffff;
|
||||
a = (r.s + (addr & 0xff)) & 0xffff;
|
||||
break;
|
||||
case OPTYPE_ISRY:
|
||||
addr = (regs.s + (addr & 0xff)) & 0xffff;
|
||||
r = (regs.db << 16) + dreadw(addr) + regs.y;
|
||||
addr = (r.s + (addr & 0xff)) & 0xffff;
|
||||
a = (r.db << 16) + dreadw(addr) + r.y;
|
||||
break;
|
||||
case OPTYPE_RELB:
|
||||
r = (regs.pc.b << 16) + ((regs.pc.w + 2) & 0xffff);
|
||||
r += int8(addr);
|
||||
a = (r.pc.b << 16) + ((r.pc.w + 2) & 0xffff);
|
||||
a += int8(addr);
|
||||
break;
|
||||
case OPTYPE_RELW:
|
||||
r = (regs.pc.b << 16) + ((regs.pc.w + 3) & 0xffff);
|
||||
r += (int16)addr;
|
||||
a = (r.pc.b << 16) + ((r.pc.w + 3) & 0xffff);
|
||||
a += (int16)addr;
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
return a;
|
||||
}
|
||||
|
||||
auto R65816::disassemble() -> string {
|
||||
return disassemble(regs.pc.d, regs.e, regs.p.m, regs.p.x);
|
||||
return disassemble(r.pc.d, r.e, r.p.m, r.p.x);
|
||||
}
|
||||
|
||||
auto R65816::disassemble(uint24 addr, bool e, bool m, bool x) -> string {
|
||||
string s;
|
||||
|
||||
reg24_t pc;
|
||||
Reg24 pc;
|
||||
pc.d = addr;
|
||||
s = {hex(pc, 6), " "};
|
||||
|
||||
@@ -403,23 +403,23 @@ auto R65816::disassemble(uint24 addr, bool e, bool m, bool x) -> string {
|
||||
#undef x8
|
||||
|
||||
s.append(t, " A:{0} X:{1} Y:{2} S:{3} D:{4} B:{5} ", format{
|
||||
hex(regs.a.w, 4), hex(regs.x.w, 4), hex(regs.y.w, 4),
|
||||
hex(regs.s.w, 4), hex(regs.d.w, 4), hex(regs.db, 2)
|
||||
hex(r.a.w, 4), hex(r.x.w, 4), hex(r.y.w, 4),
|
||||
hex(r.s.w, 4), hex(r.d.w, 4), hex(r.db, 2)
|
||||
});
|
||||
|
||||
if(regs.e) {
|
||||
if(r.e) {
|
||||
s.append(
|
||||
regs.p.n ? 'N' : 'n', regs.p.v ? 'V' : 'v',
|
||||
regs.p.m ? '1' : '0', regs.p.x ? 'B' : 'b',
|
||||
regs.p.d ? 'D' : 'd', regs.p.i ? 'I' : 'i',
|
||||
regs.p.z ? 'Z' : 'z', regs.p.c ? 'C' : 'c'
|
||||
r.p.n ? 'N' : 'n', r.p.v ? 'V' : 'v',
|
||||
r.p.m ? '1' : '0', r.p.x ? 'B' : 'b',
|
||||
r.p.d ? 'D' : 'd', r.p.i ? 'I' : 'i',
|
||||
r.p.z ? 'Z' : 'z', r.p.c ? 'C' : 'c'
|
||||
);
|
||||
} else {
|
||||
s.append(
|
||||
regs.p.n ? 'N' : 'n', regs.p.v ? 'V' : 'v',
|
||||
regs.p.m ? 'M' : 'm', regs.p.x ? 'X' : 'x',
|
||||
regs.p.d ? 'D' : 'd', regs.p.i ? 'I' : 'i',
|
||||
regs.p.z ? 'Z' : 'z', regs.p.c ? 'C' : 'c'
|
||||
r.p.n ? 'N' : 'n', r.p.v ? 'V' : 'v',
|
||||
r.p.m ? 'M' : 'm', r.p.x ? 'X' : 'x',
|
||||
r.p.d ? 'D' : 'd', r.p.i ? 'I' : 'i',
|
||||
r.p.z ? 'Z' : 'z', r.p.c ? 'C' : 'c'
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -1,77 +1,81 @@
|
||||
alwaysinline auto readpc() -> uint8 {
|
||||
return read((regs.pc.b << 16) + regs.pc.w++);
|
||||
alwaysinline auto readPC() -> uint8 {
|
||||
return read(r.pc.b << 16 | uint16(r.pc.w++));
|
||||
}
|
||||
|
||||
alwaysinline auto readstack() -> uint8 {
|
||||
regs.e ? regs.s.l++ : regs.s.w++;
|
||||
return read(regs.s.w);
|
||||
alwaysinline auto readSP() -> uint8 {
|
||||
r.e ? r.s.l++ : r.s.w++;
|
||||
return read(r.s.w);
|
||||
}
|
||||
|
||||
alwaysinline auto readstackn() -> uint8 {
|
||||
return read(++regs.s.w);
|
||||
alwaysinline auto readSPn() -> uint8 {
|
||||
return read(++r.s.w);
|
||||
}
|
||||
|
||||
alwaysinline auto readaddr(uint32 addr) -> uint8 {
|
||||
return read(addr & 0xffff);
|
||||
alwaysinline auto readAddr(uint addr) -> uint8 {
|
||||
return read(uint16(addr));
|
||||
}
|
||||
|
||||
alwaysinline auto readlong(uint32 addr) -> uint8 {
|
||||
return read(addr & 0xffffff);
|
||||
alwaysinline auto readLong(uint addr) -> uint8 {
|
||||
return read(uint24(addr));
|
||||
}
|
||||
|
||||
alwaysinline auto readdbr(uint32 addr) -> uint8 {
|
||||
return read(((regs.db << 16) + addr) & 0xffffff);
|
||||
alwaysinline auto readDB(uint addr) -> uint8 {
|
||||
return read(r.db << 16 | uint16(addr));
|
||||
}
|
||||
|
||||
alwaysinline auto readpbr(uint32 addr) -> uint8 {
|
||||
return read((regs.pc.b << 16) + (addr & 0xffff));
|
||||
alwaysinline auto readPB(uint addr) -> uint8 {
|
||||
return read(r.pc.b << 16 | uint16(addr));
|
||||
}
|
||||
|
||||
alwaysinline auto readdp(uint32 addr) -> uint8 {
|
||||
if(regs.e && regs.d.l == 0x00) {
|
||||
return read((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff));
|
||||
alwaysinline auto readDP(uint addr) -> uint8 {
|
||||
if(r.e && r.d.l == 0x00) {
|
||||
return read(r.d | uint8(addr));
|
||||
} else {
|
||||
return read((regs.d + (addr & 0xffff)) & 0xffff);
|
||||
return read(uint16(r.d + addr));
|
||||
}
|
||||
}
|
||||
|
||||
alwaysinline auto readsp(uint32 addr) -> uint8 {
|
||||
return read((regs.s + (addr & 0xffff)) & 0xffff);
|
||||
alwaysinline auto readDPn(uint addr) -> uint8 {
|
||||
return read(uint16(r.d + addr));
|
||||
}
|
||||
|
||||
alwaysinline auto writestack(uint8 data) -> void {
|
||||
write(regs.s.w, data);
|
||||
regs.e ? regs.s.l-- : regs.s.w--;
|
||||
alwaysinline auto readSP(uint addr) -> uint8 {
|
||||
return read(uint16(r.s + addr));
|
||||
}
|
||||
|
||||
alwaysinline auto writestackn(uint8 data) -> void {
|
||||
write(regs.s.w--, data);
|
||||
alwaysinline auto writeSP(uint8 data) -> void {
|
||||
write(r.s.w, data);
|
||||
r.e ? r.s.l-- : r.s.w--;
|
||||
}
|
||||
|
||||
alwaysinline auto writeaddr(uint32 addr, uint8 data) -> void {
|
||||
write(addr & 0xffff, data);
|
||||
alwaysinline auto writeSPn(uint8 data) -> void {
|
||||
write(r.s.w--, data);
|
||||
}
|
||||
|
||||
alwaysinline auto writelong(uint32 addr, uint8 data) -> void {
|
||||
write(addr & 0xffffff, data);
|
||||
alwaysinline auto writeAddr(uint addr, uint8 data) -> void {
|
||||
write(uint16(addr), data);
|
||||
}
|
||||
|
||||
alwaysinline auto writedbr(uint32 addr, uint8 data) -> void {
|
||||
write(((regs.db << 16) + addr) & 0xffffff, data);
|
||||
alwaysinline auto writeLong(uint addr, uint8 data) -> void {
|
||||
write(uint24(addr), data);
|
||||
}
|
||||
|
||||
alwaysinline auto writepbr(uint32 addr, uint8 data) -> void {
|
||||
write((regs.pc.b << 16) + (addr & 0xffff), data);
|
||||
alwaysinline auto writeDB(uint addr, uint8 data) -> void {
|
||||
write(r.db << 16 | uint16(addr), data);
|
||||
}
|
||||
|
||||
alwaysinline auto writedp(uint32 addr, uint8 data) -> void {
|
||||
if(regs.e && regs.d.l == 0x00) {
|
||||
write((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff), data);
|
||||
alwaysinline auto writePB(uint addr, uint8 data) -> void {
|
||||
write(r.pc.b << 16 | uint16(addr), data);
|
||||
}
|
||||
|
||||
alwaysinline auto writeDP(uint addr, uint8 data) -> void {
|
||||
if(r.e && r.d.l == 0x00) {
|
||||
write(r.d | uint8(addr), data);
|
||||
} else {
|
||||
write((regs.d + (addr & 0xffff)) & 0xffff, data);
|
||||
write(uint16(r.d + addr), data);
|
||||
}
|
||||
}
|
||||
|
||||
alwaysinline auto writesp(uint32 addr, uint8 data) -> void {
|
||||
write((regs.s + (addr & 0xffff)) & 0xffff, data);
|
||||
alwaysinline auto writeSP(uint addr, uint8 data) -> void {
|
||||
write(uint16(r.s + addr), data);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user