Update to bsnes v107r6 beta release.

byuu says:

  - converted (u)int(8,16,32,64) from Natural/Integer<T> to
    (u)int(8,16,32,64)_t types
  - SFC: mostly rewritten WDC65816 CPU core
  - removed 487KiB of code! (unused CPU cores from other higan cores)
This commit is contained in:
Tim Allen 2019-07-12 18:48:24 +10:00
parent a03d91882c
commit 52f34ea470
215 changed files with 2906 additions and 17861 deletions

91
bsnes/emulator/bits.hpp Normal file
View File

@ -0,0 +1,91 @@
#pragma once
struct BitsCaptureLo{};
struct BitsCaptureHi{};
struct BitsLo {
const uint lo;
inline BitsLo(uint lo) : lo(lo) {}
};
struct BitsHi {
const uint hi;
inline BitsHi(uint hi) : hi(hi) {}
};
struct BitsRange {
const uint lo, hi;
inline BitsRange(uint lo, uint hi) : lo(lo), hi(hi) {}
};
inline auto operator*(BitsCaptureLo, uint lhs) { return BitsLo{lhs}; }
inline auto operator*(uint rhs, BitsCaptureHi) { return BitsHi{rhs}; }
inline auto operator-(const BitsLo& lhs, const BitsHi& rhs) { return BitsRange{lhs.lo, rhs.hi}; }
template<typename T> struct Bits {
T& value;
using type =
conditional_t<sizeof(T) <= 1, uint8_t,
conditional_t<sizeof(T) <= 2, uint16_t,
conditional_t<sizeof(T) <= 4, uint32_t,
conditional_t<sizeof(T) <= 8, uint64_t,
void>>>>;
const uint lo;
const type mask;
inline Bits(T& value, BitsRange range) : value(value), lo(range.lo), mask(~0ull >> 64 - (range.hi - range.lo + 1) << range.lo) {}
inline Bits(const Bits& source) { operator=((uint64_t)source); }
inline auto operator=(const Bits& source) -> Bits& { return operator=((uint64_t)source); }
inline operator type() const {
return (value & mask) >> lo;
}
template<typename U> inline auto operator=(U source) -> Bits& {
value = value & ~mask | source << lo & mask;
return *this;
}
template<typename U> inline auto operator&=(U source) -> Bits& {
value = value & (~mask | source << lo & mask);
return *this;
}
template<typename U> inline auto operator^=(U source) -> Bits& {
value = value ^ source << lo & mask;
return *this;
}
template<typename U> inline auto operator|=(U source) -> Bits& {
value = value | source << lo & mask;
return *this;
}
};
template<typename T> struct Bits<const T> {
T value;
using type =
conditional_t<sizeof(T) <= 1, uint8_t,
conditional_t<sizeof(T) <= 2, uint16_t,
conditional_t<sizeof(T) <= 4, uint32_t,
conditional_t<sizeof(T) <= 8, uint64_t,
void>>>>;
const uint lo;
const type mask;
inline Bits(const T& value, BitsRange range) : value(value), lo(range.lo), mask(~0ull >> 64 - (range.hi - range.lo + 1) << range.lo) {}
Bits(const Bits& source) = delete;
auto operator=(const Bits& source) -> Bits& = delete;
inline operator type() const {
return (value & mask) >> lo;
}
};
#define bits(value,range) Bits<decltype(value)>{value,BitsCaptureLo{}*range*BitsCaptureHi{}}
#define bit1(value,index) Bits<decltype(value)>{value,BitsRange{(uint)index,(uint)index}}
#define bit8(value,index) Bits<decltype(value)>{value,BitsRange{(uint)index*8,(uint)index*8+7}}
#define cbits(value,range) Bits<const decltype(value)>{value,BitsCaptureLo{}*range*BitsCaptureHi{}}
#define cbit1(value,index) Bits<const decltype(value)>{value,BitsRange{(uint)index,(uint)index}}
#define cbit8(value,index) Bits<const decltype(value)>{value,BitsRange{(uint)index*8,(uint)index*8+7}}

View File

@ -22,6 +22,7 @@
using namespace nall;
#include <libco/libco.h>
#include <emulator/bits.hpp>
#include <emulator/types.hpp>
#include <emulator/memory/readable.hpp>
#include <emulator/memory/writable.hpp>
@ -31,7 +32,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "bsnes";
static const string Version = "107.5";
static const string Version = "107.6";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org/";

View File

@ -16,7 +16,7 @@ struct Platform {
virtual auto path(uint id) -> string { return ""; }
virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> vfs::shared::file { return {}; }
virtual auto load(uint id, string name, string type, vector<string> options = {}) -> Load { return {}; }
virtual auto videoFrame(const uint16_t* data, uint pitch, uint width, uint height, uint scale) -> void {}
virtual auto videoFrame(const uint16* data, uint pitch, uint width, uint height, uint scale) -> void {}
virtual auto audioFrame(const double* samples, uint channels) -> void {}
virtual auto inputPoll(uint port, uint device, uint input) -> int16 { return 0; }
virtual auto inputRumble(uint port, uint device, uint input, bool enable) -> void {}

View File

@ -65,10 +65,10 @@ struct Random {
if((random() & 1) == 0) hivalue = ~lovalue;
for(uint32 address : range(size)) {
uint8 value = address.bit(lobit) ? lovalue : hivalue;
if(address.bit(hibit)) value = ~value;
if((random() & 511) == 0) value.bit(random() & 7) ^= 1;
if((random() & 2047) == 0) value.bit(random() & 7) ^= 1;
uint8 value = bit1(address,lobit) ? lovalue : hivalue;
if(bit1(address,hibit)) value = ~value;
if((random() & 511) == 0) bit1(value,random() & 7) ^= 1;
if((random() & 2047) == 0) bit1(value,random() & 7) ^= 1;
data[address] = value;
}
}

View File

@ -1,3 +1,5 @@
#pragma once
using int1 = nall::Integer< 1>;
using int2 = nall::Integer< 2>;
using int3 = nall::Integer< 3>;
@ -5,7 +7,8 @@ using int4 = nall::Integer< 4>;
using int5 = nall::Integer< 5>;
using int6 = nall::Integer< 6>;
using int7 = nall::Integer< 7>;
using int8 = nall::Integer< 8>;
using int8 = int8_t;
//using int8 = nall::Integer< 8>;
using int9 = nall::Integer< 9>;
using int10 = nall::Integer<10>;
using int11 = nall::Integer<11>;
@ -13,7 +16,8 @@ using int12 = nall::Integer<12>;
using int13 = nall::Integer<13>;
using int14 = nall::Integer<14>;
using int15 = nall::Integer<15>;
using int16 = nall::Integer<16>;
using int16 = int16_t;
//using int16 = nall::Integer<16>;
using int17 = nall::Integer<17>;
using int18 = nall::Integer<18>;
using int19 = nall::Integer<19>;
@ -29,7 +33,8 @@ using int28 = nall::Integer<28>;
using int29 = nall::Integer<29>;
using int30 = nall::Integer<30>;
using int31 = nall::Integer<31>;
using int32 = nall::Integer<32>;
using int32 = int32_t;
//using int32 = nall::Integer<32>;
using int33 = nall::Integer<33>;
using int34 = nall::Integer<34>;
using int35 = nall::Integer<35>;
@ -61,7 +66,8 @@ using int60 = nall::Integer<60>;
using int61 = nall::Integer<61>;
using int62 = nall::Integer<62>;
using int63 = nall::Integer<63>;
using int64 = nall::Integer<64>;
using int64 = int64_t;
//using int64 = nall::Integer<64>;
using uint1 = nall::Natural< 1>;
using uint2 = nall::Natural< 2>;
@ -70,7 +76,8 @@ using uint4 = nall::Natural< 4>;
using uint5 = nall::Natural< 5>;
using uint6 = nall::Natural< 6>;
using uint7 = nall::Natural< 7>;
using uint8 = nall::Natural< 8>;
using uint8 = uint8_t;
//using uint8 = nall::Natural< 8>;
using uint9 = nall::Natural< 9>;
using uint10 = nall::Natural<10>;
using uint11 = nall::Natural<11>;
@ -78,7 +85,8 @@ using uint12 = nall::Natural<12>;
using uint13 = nall::Natural<13>;
using uint14 = nall::Natural<14>;
using uint15 = nall::Natural<15>;
using uint16 = nall::Natural<16>;
using uint16 = uint16_t;
//using uint16 = nall::Natural<16>;
using uint17 = nall::Natural<17>;
using uint18 = nall::Natural<18>;
using uint19 = nall::Natural<19>;
@ -94,7 +102,8 @@ using uint28 = nall::Natural<28>;
using uint29 = nall::Natural<29>;
using uint30 = nall::Natural<30>;
using uint31 = nall::Natural<31>;
using uint32 = nall::Natural<32>;
using uint32 = uint32_t;
//using uint32 = nall::Natural<32>;
using uint33 = nall::Natural<33>;
using uint34 = nall::Natural<34>;
using uint35 = nall::Natural<35>;
@ -126,4 +135,5 @@ using uint60 = nall::Natural<60>;
using uint61 = nall::Natural<61>;
using uint62 = nall::Natural<62>;
using uint63 = nall::Natural<63>;
using uint64 = nall::Natural<64>;
using uint64 = uint64_t;
//using uint64 = nall::Natural<64>;

View File

@ -30,9 +30,9 @@ auto Video::setPalette() -> void {
palette = new uint32[colors];
for(auto index : range(colors)) {
uint64 color = interface->color(index);
uint16 b = color.bits( 0,15);
uint16 g = color.bits(16,31);
uint16 r = color.bits(32,47);
uint16 b = bits(color, 0-15);
uint16 g = bits(color,16-31);
uint16 r = bits(color,32-47);
uint16 a = 0xffff;
if(saturation != 1.0) {

View File

@ -62,31 +62,31 @@ auto APU::Noise::read(uint16 addr) -> uint8 {
auto APU::Noise::write(uint16 addr, uint8 data) -> void {
if(addr == 0xff20) { //NR41
length = 64 - (data & 0x3f);
length = 64 - bits(data,0-5);
}
if(addr == 0xff21) { //NR42
envelopeVolume = data.bits(7,4);
envelopeDirection = data.bit (3);
envelopeFrequency = data.bits(2,0);
envelopeVolume = bits(data,4-7);
envelopeDirection = bit1(data,3);
envelopeFrequency = bits(data,0-2);
if(!dacEnable()) enable = false;
}
if(addr == 0xff22) { //NR43
frequency = data.bits(7,4);
narrow = data.bit (3);
divisor = data.bits(2,0);
frequency = bits(data,4-7);
narrow = bit1(data,3);
divisor = bits(data,0-2);
period = getPeriod();
}
if(addr == 0xff23) { //NR44
if((apu.phase & 1) && !counter && (data & 0x40)) {
if(bit1(apu.phase,0) && !counter && bit1(data,6)) {
if(length && --length == 0) enable = false;
}
counter = data.bit(6);
counter = bit1(data,6);
if(data.bit(7)) {
if(bit1(data,7)) {
enable = dacEnable();
lfsr = -1;
envelopePeriod = envelopeFrequency ? (uint)envelopeFrequency : 8;
@ -94,7 +94,7 @@ auto APU::Noise::write(uint16 addr, uint8 data) -> void {
if(!length) {
length = 64;
if(apu.phase.bit(0) && counter) length--;
if(bit1(apu.phase,0) && counter) length--;
}
}
}

View File

@ -66,26 +66,26 @@ auto APU::Sequencer::read(uint16 addr) -> uint8 {
auto APU::Sequencer::write(uint16 addr, uint8 data) -> void {
if(addr == 0xff24) { //NR50
leftEnable = data.bit (7);
leftVolume = data.bits(6,4);
rightEnable = data.bit (3);
rightVolume = data.bits(2,0);
leftEnable = bit1(data,7);
leftVolume = bits(data,4-6);
rightEnable = bit1(data,3);
rightVolume = bits(data,0-2);
}
if(addr == 0xff25) { //NR51
noise.leftEnable = data.bit(7);
wave.leftEnable = data.bit(6);
square2.leftEnable = data.bit(5);
square1.leftEnable = data.bit(4);
noise.rightEnable = data.bit(3);
wave.rightEnable = data.bit(2);
square2.rightEnable = data.bit(1);
square1.rightEnable = data.bit(0);
noise.leftEnable = bit1(data,7);
wave.leftEnable = bit1(data,6);
square2.leftEnable = bit1(data,5);
square1.leftEnable = bit1(data,4);
noise.rightEnable = bit1(data,3);
wave.rightEnable = bit1(data,2);
square2.rightEnable = bit1(data,1);
square1.rightEnable = bit1(data,0);
}
if(addr == 0xff26) { //NR52
if(enable != data.bit(7)) {
enable = data.bit(7);
if(enable != bit1(data,7)) {
enable = bit1(data,7);
if(!enable) {
//power(bool) resets length counters when true (eg for CGB only)

View File

@ -86,37 +86,37 @@ auto APU::Square1::read(uint16 addr) -> uint8 {
auto APU::Square1::write(uint16 addr, uint8 data) -> void {
if(addr == 0xff10) { //NR10
if(sweepEnable && sweepNegate && !data.bit(3)) enable = false;
sweepFrequency = data.bits(6,4);
sweepDirection = data.bit (3);
sweepShift = data.bits(2,0);
if(sweepEnable && sweepNegate && !bit1(data,3)) enable = false;
sweepFrequency = bits(data,4-6);
sweepDirection = bit1(data,3);
sweepShift = bits(data,0-2);
}
if(addr == 0xff11) { //NR11
duty = data.bits(7,6);
length = 64 - data.bits(5,0);
duty = bits(data,6-7);
length = 64 - bits(data,0-5);
}
if(addr == 0xff12) { //NR12
envelopeVolume = data.bits(7,4);
envelopeDirection = data.bit (3);
envelopeFrequency = data.bits(2,0);
envelopeVolume = bits(data,4-7);
envelopeDirection = bit1(data,3);
envelopeFrequency = bits(data,0-2);
if(!dacEnable()) enable = false;
}
if(addr == 0xff13) { //NR13
frequency.bits(7,0) = data;
bits(frequency,0-7) = data;
}
if(addr == 0xff14) { //NR14
if(apu.phase.bit(0) && !counter && data.bit(6)) {
if(bit1(apu.phase,0) && !counter && bit1(data,6)) {
if(length && --length == 0) enable = false;
}
counter = data.bit(6);
frequency.bits(10,8) = data.bits(2,0);
counter = bit1(data,6);
bits(frequency,8-10) = (uint)bits(data,0-2);
if(data.bit(7)) {
if(bit1(data,7)) {
enable = dacEnable();
period = 2 * (2048 - frequency);
envelopePeriod = envelopeFrequency ? (uint)envelopeFrequency : 8;
@ -124,7 +124,7 @@ auto APU::Square1::write(uint16 addr, uint8 data) -> void {
if(!length) {
length = 64;
if(apu.phase.bit(0) && counter) length--;
if(bit1(apu.phase,0) && counter) length--;
}
frequencyShadow = frequency;

View File

@ -60,30 +60,30 @@ auto APU::Square2::read(uint16 addr) -> uint8 {
auto APU::Square2::write(uint16 addr, uint8 data) -> void {
if(addr == 0xff16) { //NR21
duty = data.bits(7,6);
length = 64 - data.bits(5,0);
duty = bits(data,6-7);
length = 64 - bits(data,0-5);
}
if(addr == 0xff17) { //NR22
envelopeVolume = data.bits(7,4);
envelopeDirection = data.bit (3);
envelopeFrequency = data.bits(2,0);
envelopeVolume = bits(data,4-7);
envelopeDirection = bit1(data,3);
envelopeFrequency = bits(data,0-2);
if(!dacEnable()) enable = false;
}
if(addr == 0xff18) { //NR23
frequency.bits(7,0) = data;
bits(frequency,0-7) = data;
}
if(addr == 0xff19) { //NR24
if(apu.phase.bit(0) && !counter && data.bit(6)) {
if(bit1(apu.phase,0) && !counter && bit1(data,6)) {
if(length && --length == 0) enable = false;
}
counter = data.bit(6);
frequency.bits(10,8) = data.bits(2,0);
counter = bit1(data,6);
bits(frequency,8-10) = (uint)bits(data,0-2);
if(data.bit(7)) {
if(bit1(data,7)) {
enable = dacEnable();
period = 2 * (2048 - frequency);
envelopePeriod = envelopeFrequency ? (uint)envelopeFrequency : 8;
@ -91,7 +91,7 @@ auto APU::Square2::write(uint16 addr, uint8 data) -> void {
if(!length) {
length = 64;
if(apu.phase.bit(0) && counter) length--;
if(bit1(apu.phase,0) && counter) length--;
}
}
}

View File

@ -59,7 +59,7 @@ auto APU::Wave::read(uint16 addr) -> uint8 {
auto APU::Wave::write(uint16 addr, uint8 data) -> void {
if(addr == 0xff1a) { //NR30
dacEnable = data.bit(7);
dacEnable = bit1(data,7);
if(!dacEnable) enable = false;
}
@ -68,22 +68,22 @@ auto APU::Wave::write(uint16 addr, uint8 data) -> void {
}
if(addr == 0xff1c) { //NR32
volume = data.bits(6,5);
volume = bits(data,5-6);
}
if(addr == 0xff1d) { //NR33
frequency.bits(7,0) = data;
bits(frequency,0-7) = data;
}
if(addr == 0xff1e) { //NR34
if(apu.phase.bit(0) && !counter && data.bit(6)) {
if(bit1(apu.phase,0) && !counter && bit1(data,6)) {
if(length && --length == 0) enable = false;
}
counter = data.bit(6);
frequency.bits(10,8) = data.bits(2,0);
counter = bit1(data,6);
bits(frequency,8-10) = (uint)bits(data,0-2);
if(data.bit(7)) {
if(bit1(data,7)) {
if(!Model::GameBoyColor() && patternHold) {
//DMG,SGB trigger while channel is being read corrupts wave RAM
if((patternOffset >> 1) <= 3) {
@ -106,7 +106,7 @@ auto APU::Wave::write(uint16 addr, uint8 data) -> void {
if(!length) {
length = 256;
if(apu.phase.bit(0) && counter) length--;
if(bit1(apu.phase,0) && counter) length--;
}
}
}

View File

@ -1,14 +1,14 @@
auto Cartridge::HuC1::read(uint16 address) -> uint8 {
if((address & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom.read(address.bits(0,13));
return cartridge.rom.read(bits(address,0-13));
}
if((address & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13));
return cartridge.rom.read(io.rom.bank << 14 | bits(address,0-13));
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12));
return cartridge.ram.read(io.ram.bank << 13 | bits(address,0-12));
}
return 0xff;
@ -16,7 +16,7 @@ auto Cartridge::HuC1::read(uint16 address) -> uint8 {
auto Cartridge::HuC1::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0x0000) { //$0000-1fff
io.ram.writable = data.bits(0,3) == 0x0a;
io.ram.writable = bits(data,0-3) == 0x0a;
return;
}
@ -32,13 +32,13 @@ auto Cartridge::HuC1::write(uint16 address, uint8 data) -> void {
}
if((address & 0xe000) == 0x6000) { //$6000-7fff
io.model = data.bit(0);
io.model = data & 1;
return;
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
if(!io.ram.writable) return;
return cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data);
return cartridge.ram.write(io.ram.bank << 13 | bits(address,0-12), data);
}
}

View File

@ -1,15 +1,15 @@
auto Cartridge::HuC3::read(uint16 address) -> uint8 {
if((address & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom.read(address.bits(0,13));
return cartridge.rom.read(bits(address,0-13));
}
if((address & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13));
return cartridge.rom.read(io.rom.bank << 14 | bits(address,0-13));
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
if(!io.ram.enable) return 0x01; //does not return open collection
return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12));
return cartridge.ram.read(io.ram.bank << 13 | bits(address,0-12));
}
return 0xff;
@ -17,7 +17,7 @@ auto Cartridge::HuC3::read(uint16 address) -> uint8 {
auto Cartridge::HuC3::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0x0000) { //$0000-1fff
io.ram.enable = data.bits(0,3) == 0x0a;
io.ram.enable = bits(data,0-3) == 0x0a;
return;
}
@ -33,7 +33,7 @@ auto Cartridge::HuC3::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0xa000) { //$a000-bfff
if(!io.ram.enable) return;
return cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data);
return cartridge.ram.write(io.ram.bank << 13 | bits(address,0-12), data);
}
}

View File

@ -1,10 +1,10 @@
auto Cartridge::MBC0::read(uint16 address) -> uint8 {
if((address & 0x8000) == 0x0000) { //$0000-7fff
return cartridge.rom.read(address.bits(0,14));
return cartridge.rom.read(bits(address,0-14));
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
return cartridge.ram.read(address.bits(0,12));
return cartridge.ram.read(bits(address,0-12));
}
return 0xff;
@ -12,7 +12,7 @@ auto Cartridge::MBC0::read(uint16 address) -> uint8 {
auto Cartridge::MBC0::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0xa000) { //$a000-bfff
cartridge.ram.write(address.bits(0,12), data);
cartridge.ram.write(bits(address,0-12), data);
return;
}
}

View File

@ -1,22 +1,22 @@
auto Cartridge::MBC1::read(uint16 address) -> uint8 {
if((address & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom.read(address.bits(0,13));
return cartridge.rom.read(bits(address,0-13));
}
if((address & 0xc000) == 0x4000) { //$4000-7fff
if(io.mode == 0) {
return cartridge.rom.read(io.ram.bank << 19 | io.rom.bank << 14 | address.bits(0,13));
return cartridge.rom.read(io.ram.bank << 19 | io.rom.bank << 14 | bits(address,0-13));
} else {
return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13));
return cartridge.rom.read(io.rom.bank << 14 | bits(address,0-13));
}
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
if(!io.ram.enable) return 0xff;
if(io.mode == 0) {
return cartridge.ram.read(address.bits(0,12));
return cartridge.ram.read(bits(address,0-12));
} else {
return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12));
return cartridge.ram.read(io.ram.bank << 13 | bits(address,0-12));
}
}
@ -25,32 +25,32 @@ auto Cartridge::MBC1::read(uint16 address) -> uint8 {
auto Cartridge::MBC1::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0x0000) { //$0000-1fff
io.ram.enable = data.bits(0,3) == 0x0a;
io.ram.enable = bits(data,0-3) == 0x0a;
return;
}
if((address & 0xe000) == 0x2000) { //$2000-3fff
io.rom.bank = data.bits(0,4);
io.rom.bank = bits(data,0-4);
if(!io.rom.bank) io.rom.bank = 0x01;
return;
}
if((address & 0xe000) == 0x4000) { //$4000-5fff
io.ram.bank = data.bits(0,1);
io.ram.bank = bits(data,0-1);
return;
}
if((address & 0xe000) == 0x6000) { //$6000-7fff
io.mode = data.bit(0);
io.mode = bit1(data,0);
return;
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
if(!io.ram.enable) return;
if(io.mode == 0) {
return cartridge.ram.write(address.bits(0,12), data);
return cartridge.ram.write(bits(address,0-12), data);
} else {
return cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data);
return cartridge.ram.write(io.ram.bank << 13 | bits(address,0-12), data);
}
}
}

View File

@ -1,15 +1,15 @@
auto Cartridge::MBC1M::read(uint16 address) -> uint8 {
if((address & 0xc000) == 0x0000) { //$0000-3fff
if(io.mode == 0) return cartridge.rom.read(address.bits(0,13));
return cartridge.rom.read(io.rom.bank.bits(4,5) << 18 | address.bits(0,13));
if(io.mode == 0) return cartridge.rom.read(bits(address,0-13));
return cartridge.rom.read(bits(io.rom.bank,4-5) << 18 | bits(address,0-13));
}
if((address & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13));
return cartridge.rom.read(io.rom.bank << 14 | bits(address,0-13));
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
return cartridge.ram.read(address.bits(0,12));
return cartridge.ram.read(bits(address,0-12));
}
return 0xff;
@ -17,19 +17,19 @@ auto Cartridge::MBC1M::read(uint16 address) -> uint8 {
auto Cartridge::MBC1M::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0x2000) { //$2000-3fff
io.rom.bank.bits(0,3) = data.bits(0,3);
bits(io.rom.bank,0-3) = bits(data,0-3);
}
if((address & 0xe000) == 0x4000) { //$4000-5fff
io.rom.bank.bits(4,5) = data.bits(0,1);
bits(io.rom.bank,4-5) = bits(data,0-1);
}
if((address & 0xe000) == 0x6000) { //$6000-7fff
io.mode = data.bit(0);
io.mode = bit1(data,0);
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
cartridge.ram.write(address.bits(0,13), data);
cartridge.ram.write(bits(address,0-13), data);
}
}

View File

@ -1,22 +1,22 @@
auto Cartridge::MBC2::read(uint16 address) -> uint8 {
if((address & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom.read(address.bits(0,13));
return cartridge.rom.read(bits(address,0-13));
}
if((address & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13));
return cartridge.rom.read(io.rom.bank << 14 | bits(address,0-13));
}
if((address & 0xee01) == 0xa000) { //$a000-a1ff (even)
if(!io.ram.enable) return 0xff;
auto ram = cartridge.ram.read(address.bits(1,8));
return 0xf0 | ram.bits(0,3);
auto ram = cartridge.ram.read(bits(address,1-8));
return 0xf0 | bits(ram,0-3);
}
if((address & 0xee01) == 0xa001) { //$a000-a1ff (odd)
if(!io.ram.enable) return 0xff;
auto ram = cartridge.ram.read(address.bits(1,8));
return 0xf0 | ram.bits(4,7);
auto ram = cartridge.ram.read(bits(address,1-8));
return 0xf0 | bits(ram,4-7);
}
return 0xff;
@ -24,29 +24,29 @@ auto Cartridge::MBC2::read(uint16 address) -> uint8 {
auto Cartridge::MBC2::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0x0000) { //$0000-1fff
if(!address.bit(8)) io.ram.enable = data.bits(0,3) == 0x0a;
if(!bit1(address,8)) io.ram.enable = bits(data,0-3) == 0x0a;
return;
}
if((address & 0xe000) == 0x2000) { //$2000-3fff
if(address.bit(8)) io.rom.bank = data.bits(0,3);
if(bit1(address,8)) io.rom.bank = bits(data,0-3);
if(!io.rom.bank) io.rom.bank = 0x01;
return;
}
if((address & 0xee01) == 0xa000) { //$a000-a1ff (even)
if(!io.ram.enable) return;
auto ram = cartridge.ram.read(address.bits(1,8));
ram.bits(0,3) = data.bits(0,3);
cartridge.ram.write(address.bits(1,8), ram);
auto ram = cartridge.ram.read(bits(address,1-8));
bits(ram,0-3) = (uint)bits(data,0-3);
cartridge.ram.write(bits(address,1-8), ram);
return;
}
if((address & 0xee01) == 0xa001) { //$a000-a1ff (odd)
if(!io.ram.enable) return;
auto ram = cartridge.ram.read(address.bits(1,8));
ram.bits(4,7) = data.bits(0,3);
cartridge.ram.write(address.bits(1,8), ram);
auto ram = cartridge.ram.read(bits(address,1-8));
bits(ram,4-7) = (uint)bits(data,0-3);
cartridge.ram.write(bits(address,1-8), ram);
return;
}
}

View File

@ -16,16 +16,16 @@ auto Cartridge::MBC3::second() -> void {
auto Cartridge::MBC3::read(uint16 address) -> uint8 {
if((address & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom.read(address.bits(0,13));
return cartridge.rom.read(bits(address,0-13));
}
if((address & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13));
return cartridge.rom.read(io.rom.bank << 14 | bits(address,0-13));
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
if(!io.ram.enable) return 0xff;
if(io.ram.bank <= 0x03) return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12));
if(io.ram.bank <= 0x03) return cartridge.ram.read(io.ram.bank << 13 | bits(address,0-12));
if(io.ram.bank == 0x08) return io.rtc.latchSecond;
if(io.ram.bank == 0x09) return io.rtc.latchMinute;
if(io.ram.bank == 0x0a) return io.rtc.latchHour;
@ -39,12 +39,12 @@ auto Cartridge::MBC3::read(uint16 address) -> uint8 {
auto Cartridge::MBC3::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0x0000) { //$0000-1fff
io.ram.enable = data.bits(0,3) == 0x0a;
io.ram.enable = bits(data,0-3) == 0x0a;
return;
}
if((address & 0xe000) == 0x2000) { //$2000-3fff
io.rom.bank = data.bits(0,6);
io.rom.bank = bits(data,0-6);
if(!io.rom.bank) io.rom.bank = 0x01;
return;
}
@ -69,7 +69,7 @@ auto Cartridge::MBC3::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0xa000) { //$a000-bfff
if(!io.ram.enable) return;
if(io.ram.bank <= 0x03) {
cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data);
cartridge.ram.write(io.ram.bank << 13 | bits(address,0-12), data);
} else if(io.ram.bank == 0x08) {
if(data >= 60) data = 0;
io.rtc.second = data;
@ -80,11 +80,11 @@ auto Cartridge::MBC3::write(uint16 address, uint8 data) -> void {
if(data >= 24) data = 0;
io.rtc.hour = data;
} else if(io.ram.bank == 0x0b) {
io.rtc.day.bits(0,7) = data.bits(0,7);
bits(io.rtc.day,0-7) = bits(data,0-7);
} else if(io.ram.bank == 0x0c) {
io.rtc.day.bit(8) = data.bit(0);
io.rtc.halt = data.bit(6);
io.rtc.dayCarry = data.bit(7);
bit1(io.rtc.day,8) = bit1(data,0);
io.rtc.halt = bit1(data,6);
io.rtc.dayCarry = bit1(data,7);
}
return;
}

View File

@ -1,15 +1,15 @@
auto Cartridge::MBC5::read(uint16 address) -> uint8 {
if((address & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom.read(address.bits(0,13));
return cartridge.rom.read(bits(address,0-13));
}
if((address & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13));
return cartridge.rom.read(io.rom.bank << 14 | bits(address,0-13));
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
if(!io.ram.enable) return 0xff;
return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12));
return cartridge.ram.read(io.ram.bank << 13 | bits(address,0-12));
}
return 0xff;
@ -17,29 +17,29 @@ auto Cartridge::MBC5::read(uint16 address) -> uint8 {
auto Cartridge::MBC5::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0x0000) { //$0000-1fff
io.ram.enable = data.bits(0,3) == 0x0a;
io.ram.enable = bits(data,0-3) == 0x0a;
return;
}
if((address & 0xf000) == 0x2000) { //$2000-2fff
io.rom.bank.bits(0,7) = data.bits(0,7);
bits(io.rom.bank,0-7) = bits(data,0-7);
return;
}
if((address & 0xf000) == 0x3000) { //$3000-3fff
io.rom.bank.bit(8) = data.bit(0);
bit1(io.rom.bank,8) = bit1(data,0);
return;
}
if((address & 0xe000) == 0x4000) { //$4000-5fff
if(cartridge.rumble) platform->inputRumble(ID::Port::Cartridge, ID::Device::MBC5, 0, data.bit(3));
io.ram.bank = data.bits(0,3);
if(cartridge.rumble) platform->inputRumble(ID::Port::Cartridge, ID::Device::MBC5, 0, bit1(data,3));
io.ram.bank = bits(data,0-3);
return;
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
if(!io.ram.enable) return;
return cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data);
return cartridge.ram.write(io.ram.bank << 13 | bits(address,0-12), data);
}
}

View File

@ -1,24 +1,24 @@
auto Cartridge::MBC6::read(uint16 address) -> uint8 {
if((address & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom.read(address.bits(0,13));
return cartridge.rom.read(bits(address,0-13));
}
if((address & 0xe000) == 0x4000) { //$4000-5fff
return cartridge.rom.read(io.rom.bank[0] << 13 | address.bits(0,12));
return cartridge.rom.read(io.rom.bank[0] << 13 | bits(address,0-12));
}
if((address & 0xe000) == 0x6000) { //$6000-7fff
return cartridge.rom.read(io.rom.bank[1] << 13 | address.bits(0,12));
return cartridge.rom.read(io.rom.bank[1] << 13 | bits(address,0-12));
}
if((address & 0xf000) == 0xa000) { //$a000-afff
if(!io.ram.enable) return 0xff;
return cartridge.ram.read(io.ram.bank[0] << 12 | address.bits(0,11));
return cartridge.ram.read(io.ram.bank[0] << 12 | bits(address,0-11));
}
if((address & 0xf000) == 0xb000) { //$b000-bfff
if(!io.ram.enable) return 0xff;
return cartridge.ram.read(io.ram.bank[1] << 12 | address.bits(0,11));
return cartridge.ram.read(io.ram.bank[1] << 12 | bits(address,0-11));
}
return 0xff;
@ -26,7 +26,7 @@ auto Cartridge::MBC6::read(uint16 address) -> uint8 {
auto Cartridge::MBC6::write(uint16 address, uint8 data) -> void {
if((address & 0xfc00) == 0x0000) {
io.ram.enable = data.bits(0,3) == 0xa;
io.ram.enable = bits(data,0-3) == 0xa;
return;
}
@ -52,12 +52,12 @@ auto Cartridge::MBC6::write(uint16 address, uint8 data) -> void {
if((address & 0xf000) == 0xa000) { //$a000-afff
if(!io.ram.enable) return;
return cartridge.ram.write(io.ram.bank[0] << 12 | address.bits(0,11), data);
return cartridge.ram.write(io.ram.bank[0] << 12 | bits(address,0-11), data);
}
if((address & 0xf000) == 0xb000) { //$b000-bfff
if(!io.ram.enable) return;
return cartridge.ram.write(io.ram.bank[1] << 12 | address.bits(0,11), data);
return cartridge.ram.write(io.ram.bank[1] << 12 | bits(address,0-11), data);
}
}

View File

@ -53,33 +53,33 @@ auto Cartridge::MBC7::EEPROM::power() -> void {
auto Cartridge::MBC7::EEPROM::readIO() -> uint8 {
uint8 data = 0b00'1111'00;
data.bit(7) = select;
data.bit(6) = clock;
data.bit(1) = input.edge();
bit1(data,7) = select;
bit1(data,6) = clock;
bit1(data,1) = input.edge();
if(!select) {
data.bit(0) = 1; //high-z when the chip is idle (not selected)
bit1(data,0) = 1; //high-z when the chip is idle (not selected)
} else if(busy) {
data.bit(0) = 0; //low when a programming command is in progress
bit1(data,0) = 0; //low when a programming command is in progress
} else if(output.count) {
data.bit(0) = output.edge(); //shift register data during read commands
bit1(data,0) = output.edge(); //shift register data during read commands
} else {
data.bit(0) = 1; //high-z during all other commands
bit1(data,0) = 1; //high-z during all other commands
}
return data;
}
auto Cartridge::MBC7::EEPROM::writeIO(uint8 data) -> void {
//chip enters idle state on falling CS edge
if(select && !data.bit(7)) return power();
if(select && !bit1(data,7)) return power();
//chip leaves idle state on rising CS edge
if(!(select = data.bit(7))) return;
if(!(select = bit1(data,7))) return;
//input shift register clocks on rising edge
if(!clock.raise(data.bit(6))) return;
if(!clock.raise(bit1(data,6))) return;
//read mode
if(output.count && !data.bit(1)) {
if(output.count && !bit1(data,1)) {
if(input.start() && *input.start() == 1) {
if(input.opcode() && *input.opcode() == 0b10) {
output.read();
@ -94,7 +94,7 @@ auto Cartridge::MBC7::EEPROM::writeIO(uint8 data) -> void {
}
output.flush();
input.write(data.bit(1));
input.write(bit1(data,1));
//wait for start
if(!input.start()) return;
@ -128,7 +128,7 @@ auto Cartridge::MBC7::EEPROM::read() -> void {
uint address = *input.address() << (width == 16) & size - 1;
output.flush();
for(uint4 index : range(width)) {
output.write(data[address + !index.bit(3)].bit(index.bits(0,2)));
output.write(bit1(data[address + !bit1(index,3)],bits(index,0-2)));
}
output.write(0); //reads have an extra dummy data bit
}
@ -138,7 +138,7 @@ auto Cartridge::MBC7::EEPROM::write() -> void {
if(!writable) return input.flush();
uint address = *input.address() << (width == 16) & size - 1;
for(uint4 index : range(width)) {
data[address + !index.bit(3)].bit(index.bits(0,2)) = input.read();
bit1(data[address + !bit1(index,3)],bits(index,0-2)) = input.read();
}
busy = 4; //milliseconds
return input.flush();
@ -148,7 +148,7 @@ auto Cartridge::MBC7::EEPROM::erase() -> void {
if(!writable) return input.flush();
uint address = *input.address() << (width == 16) & size - 1;
for(uint index : range(width)) {
data[address + index / 8].bit(index % 8) = 1;
bit1(data[address + index / 8],index % 8) = 1;
}
busy = 4; //milliseconds
return input.flush();
@ -159,8 +159,8 @@ auto Cartridge::MBC7::EEPROM::writeAll() -> void {
if(!writable) return input.flush();
auto word = *input.data();
for(uint address = 0; address < 512;) {
data[address++] = word.byte(width == 16);
data[address++] = word.byte(0);
data[address++] = bit8(word,width == 16);
data[address++] = bit8(word,0);
}
busy = 16; //milliseconds
return input.flush();
@ -191,11 +191,11 @@ auto Cartridge::MBC7::EEPROM::ShiftRegister::flush() -> void {
}
auto Cartridge::MBC7::EEPROM::ShiftRegister::edge() -> uint1 {
return value.bit(0);
return value & 1;
}
auto Cartridge::MBC7::EEPROM::ShiftRegister::read() -> uint1 {
uint1 bit = value.bit(0);
uint1 bit = value & 1;
value >>= 1;
count--;
return bit;
@ -203,7 +203,7 @@ auto Cartridge::MBC7::EEPROM::ShiftRegister::read() -> uint1 {
auto Cartridge::MBC7::EEPROM::ShiftRegister::write(uint1 bit) -> void {
value <<= 1;
value.bit(0) = bit;
bit1(value,0) = bit;
count++;
}
@ -231,9 +231,11 @@ auto Cartridge::MBC7::EEPROM::InputShiftRegister::address() -> maybe<uint9> {
auto Cartridge::MBC7::EEPROM::InputShiftRegister::data() -> maybe<uint16> {
if(count < 1 + 2 + addressLength + dataLength) return {};
return {value >> count - (3 + addressLength + dataLength) & (1 << dataLength) - 1};
uint16 data = value >> count - (3 + addressLength + dataLength) & (1 << dataLength) - 1;
return data;
}
auto Cartridge::MBC7::EEPROM::InputShiftRegister::increment() -> void {
value.bits(0, addressLength - 1)++;
uint mask = (1 << addressLength) - 1;
value = value & ~mask | (value + 1 & mask);
}

View File

@ -15,21 +15,21 @@ auto Cartridge::MBC7::main() -> void {
auto Cartridge::MBC7::read(uint16 address) -> uint8 {
if((address & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom.read(address.bits(0,13));
return cartridge.rom.read(bits(address,0-13));
}
if((address & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13));
return cartridge.rom.read(io.rom.bank << 14 | bits(address,0-13));
}
if((address & 0xf000) == 0xa000) { //$a000-afff
if(!io.ram.enable[0] || !io.ram.enable[1]) return 0xff;
switch(address.bits(4,7)) {
case 2: return io.accelerometer.x.bits(0, 7);
case 3: return io.accelerometer.x.bits(8,15);
case 4: return io.accelerometer.y.bits(0, 7);
case 5: return io.accelerometer.y.bits(8,15);
switch(bits(address,4-7)) {
case 2: return bit8(io.accelerometer.x,0);
case 3: return bit8(io.accelerometer.x,1);
case 4: return bit8(io.accelerometer.y,0);
case 5: return bit8(io.accelerometer.y,1);
case 6: return 0x00; //z?
case 7: return 0xff; //z?
case 8: return eeprom.readIO();
@ -43,7 +43,7 @@ auto Cartridge::MBC7::read(uint16 address) -> uint8 {
auto Cartridge::MBC7::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0x0000) { //$0000-1fff
io.ram.enable[0] = data.bits(0,3) == 0xa;
io.ram.enable[0] = bits(data,0-3) == 0xa;
if(!io.ram.enable[0]) io.ram.enable[1] = false;
return;
}
@ -62,7 +62,7 @@ auto Cartridge::MBC7::write(uint16 address, uint8 data) -> void {
if((address & 0xf000) == 0xa000) { //$a000-afff
if(!io.ram.enable[0] || !io.ram.enable[1]) return;
switch(address.bits(4,7)) {
switch(bits(address,4-7)) {
case 0: {
if(data != 0x55) break;
io.accelerometer.x = Center;

View File

@ -1,22 +1,22 @@
auto Cartridge::MMM01::read(uint16 address) -> uint8 {
if(io.mode == 0) {
if((address & 0x8000) == 0x0000) { //$0000-7fff
return cartridge.rom.read(cartridge.rom.size - 0x8000 + address.bits(0,14));
return cartridge.rom.read(cartridge.rom.size - 0x8000 + bits(address,0-14));
}
return 0xff;
} else {
if((address & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom.read((io.rom.base << 14) + address.bits(0,13));
return cartridge.rom.read((io.rom.base << 14) + bits(address,0-13));
}
if((address & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom.read((io.rom.base << 14) + (io.rom.bank << 14) + address.bits(0,13));
return cartridge.rom.read((io.rom.base << 14) + (io.rom.bank << 14) + bits(address,0-13));
}
if((address & 0xe000) == 0xa000) { //$a000-bfff
if(!io.ram.enable) return 0xff;
return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12));
return cartridge.ram.read(io.ram.bank << 13 | bits(address,0-12));
}
return 0xff;
@ -30,11 +30,11 @@ auto Cartridge::MMM01::write(uint16 address, uint8 data) -> void {
}
if((address & 0xe000) == 0x2000) { //$2000-3fff
io.rom.base = data.bits(0,5);
io.rom.base = bits(data,0-5);
}
} else {
if((address & 0xe000) == 0x0000) { //$0000-1fff
io.ram.enable = data.bits(0,3) == 0x0a;
io.ram.enable = bits(data,0-3) == 0x0a;
}
if((address & 0xe000) == 0x2000) { //$2000-3fff
@ -47,7 +47,7 @@ auto Cartridge::MMM01::write(uint16 address, uint8 data) -> void {
if((address & 0xe000) == 0xa000) { //$a000-bfff
if(!io.ram.enable) return;
cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data);
cartridge.ram.write(io.ram.bank << 13 | bits(address,0-12), data);
}
}
}

View File

@ -48,11 +48,11 @@ auto Cartridge::TAMA::second() -> void {
auto Cartridge::TAMA::read(uint16 address) -> uint8 {
if((address & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom.read(address.bits(0,13));
return cartridge.rom.read(bits(address,0-13));
}
if((address & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13));
return cartridge.rom.read(io.rom.bank << 14 | bits(address,0-13));
}
if((address & 0xe001) == 0xa000) { //$a000-bfff (even)
@ -62,11 +62,11 @@ auto Cartridge::TAMA::read(uint16 address) -> uint8 {
if(io.mode == 0 || io.mode == 1) {
if(io.select == 0x0c) {
return 0xf0 | io.output.bits(0,3);
return 0xf0 | bits(io.output,0-3);
}
if(io.select == 0x0d) {
return 0xf0 | io.output.bits(4,7);
return 0xf0 | bits(io.output,4-7);
}
}
@ -102,28 +102,28 @@ auto Cartridge::TAMA::write(uint16 address, uint8 data) -> void {
if((address & 0xe001) == 0xa000) { //$a000-bfff (even)
if(io.select == 0x00) {
io.rom.bank.bits(0,3) = data.bits(0,3);
bits(io.rom.bank,0-3) = (uint)bits(data,0-3);
}
if(io.select == 0x01) {
io.rom.bank.bit(4) = data.bit(0);
bit1(io.rom.bank,4) = (uint)bit1(data,0);
}
if(io.select == 0x04) {
io.input.bits(0,3) = data.bits(0,3);
bits(io.input,0-3) = (uint)bits(data,0-3);
}
if(io.select == 0x05) {
io.input.bits(4,7) = data.bits(0,3);
bits(io.input,4-7) = (uint)bits(data,0-3);
}
if(io.select == 0x06) {
io.index.bit(4) = data.bit(0);
io.mode = data.bits(1,3);
bit1(io.index,4) = (uint)bit1(data,0);
io.mode = bits(data,1-3);
}
if(io.select == 0x07) {
io.index.bits(0,3) = data.bits(0,3);
bits(io.index,0-3) = (uint)bits(data,0-3);
if(io.mode == 0) {
cartridge.ram.write(io.index, io.input);
@ -142,53 +142,53 @@ auto Cartridge::TAMA::write(uint16 address, uint8 data) -> void {
rtc.meridian = rtc.hour >= 12;
}
if(io.mode == 4 && io.index == 0x00 && io.input.bits(0,3) == 0x7) {
if(io.mode == 4 && io.index == 0x00 && bits(io.input,0-3) == 0x7) {
uint8 day = toBCD(rtc.day);
day.bits(0,3) = io.input.bits(4,7);
bits(day,0-3) = (uint)bits(io.input,4-7);
rtc.day = fromBCD(day);
}
if(io.mode == 4 && io.index == 0x00 && io.input.bits(0,3) == 0x8) {
if(io.mode == 4 && io.index == 0x00 && bits(io.input,0-3) == 0x8) {
uint8 day = toBCD(rtc.day);
day.bits(4,7) = io.input.bits(4,7);
bits(day,4-7) = (uint)bits(io.input,4-7);
rtc.day = fromBCD(day);
}
if(io.mode == 4 && io.index == 0x00 && io.input.bits(0,3) == 0x9) {
if(io.mode == 4 && io.index == 0x00 && bits(io.input,0-3) == 0x9) {
uint8 month = toBCD(rtc.month);
month.bits(0,3) = io.input.bits(4,7);
bits(month,0-3) = (uint)bits(io.input,4-7);
rtc.month = fromBCD(month);
}
if(io.mode == 4 && io.index == 0x00 && io.input.bits(0,3) == 0xa) {
if(io.mode == 4 && io.index == 0x00 && bits(io.input,0-3) == 0xa) {
uint8 month = toBCD(rtc.month);
month.bits(4,7) = io.input.bits(4,7);
bits(month,4-7) = (uint)bits(io.input,4-7);
rtc.month = fromBCD(month);
}
if(io.mode == 4 && io.index == 0x00 && io.input.bits(0,3) == 0xb) {
if(io.mode == 4 && io.index == 0x00 && bits(io.input,0-3) == 0xb) {
uint8 year = toBCD(rtc.year);
year.bits(0,3) = io.input.bits(4,7);
bits(year,0-3) = (uint)bits(io.input,4-7);
rtc.year = fromBCD(year);
}
if(io.mode == 4 && io.index == 0x00 && io.input.bits(0,3) == 0xc) {
if(io.mode == 4 && io.index == 0x00 && bits(io.input,0-3) == 0xc) {
uint8 year = toBCD(rtc.year);
year.bits(4,7) = io.input.bits(4,7);
bits(year,4-7) = (uint)bits(io.input,4-7);
rtc.year = fromBCD(year);
}
if(io.mode == 4 && io.index == 0x02 && io.input.bits(0,3) == 0xa) {
rtc.hourMode = io.input.bit(4);
if(io.mode == 4 && io.index == 0x02 && bits(io.input,0-3) == 0xa) {
rtc.hourMode = bit1(io.input,4);
rtc.second = 0; //hack: unclear where this is really being set (if it is at all)
}
if(io.mode == 4 && io.index == 0x02 && io.input.bits(0,3) == 0xb) {
rtc.leapYear = data.bits(4,5);
if(io.mode == 4 && io.index == 0x02 && bits(io.input,0-3) == 0xb) {
rtc.leapYear = bits(data,4-5);
}
if(io.mode == 4 && io.index == 0x02 && io.input.bits(0,3) == 0xe) {
rtc.test = io.input.bits(4,7);
if(io.mode == 4 && io.index == 0x02 && bits(io.input,0-3) == 0xe) {
rtc.test = bits(io.input,4-7);
}
if(io.mode == 2 && io.index == 0x06) {
@ -200,7 +200,7 @@ auto Cartridge::TAMA::write(uint16 address, uint8 data) -> void {
}
if((address & 0xe001) == 0xa001) { //$a000-bfff (odd)
io.select = data.bits(0,3);
io.select = bits(data,0-3);
if(io.select == 0x0a) {
io.ready = true;

View File

@ -7,13 +7,13 @@ auto GameBoyColorInterface::information() -> Information {
}
auto GameBoyColorInterface::color(uint32 color) -> uint64 {
uint r = color.bits( 0, 4);
uint g = color.bits( 5, 9);
uint b = color.bits(10,14);
uint r = bits(color, 0- 4);
uint g = bits(color, 5- 9);
uint b = bits(color,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);
uint64 R = image::normalize(r, 5, 16);
uint64 G = image::normalize(g, 5, 16);
uint64 B = image::normalize(b, 5, 16);
return R << 32 | G << 16 | B << 0;
}

View File

@ -113,7 +113,7 @@ auto PPU::writeIO(uint16 addr, uint8 data) -> void {
}
if(addr == 0xff40) { //LCDC
if(status.displayEnable && !data.bit(7)) {
if(status.displayEnable && !(data & 0x80)) {
status.mode = 0;
status.ly = 0;
status.lx = 0;

View File

@ -3,27 +3,15 @@ processors := $(call unique,$(processors))
objects += $(if $(findstring arm7tdmi,$(processors)),processor-arm7tdmi)
objects += $(if $(findstring gsu,$(processors)),processor-gsu)
objects += $(if $(findstring hg51b,$(processors)),processor-hg51b)
objects += $(if $(findstring huc6280,$(processors)),processor-huc6280)
objects += $(if $(findstring m68k,$(processors)),processor-m68k)
objects += $(if $(findstring mos6502,$(processors)),processor-mos6502)
objects += $(if $(findstring sm83,$(processors)),processor-sm83)
objects += $(if $(findstring spc700,$(processors)),processor-spc700)
objects += $(if $(findstring tlcs900h,$(processors)),processor-tlcs900h)
objects += $(if $(findstring upd96050,$(processors)),processor-upd96050)
objects += $(if $(findstring v30mz,$(processors)),processor-v30mz)
objects += $(if $(findstring wdc65816,$(processors)),processor-wdc65816)
objects += $(if $(findstring z80,$(processors)),processor-z80)
obj/processor-arm7tdmi.o: processor/arm7tdmi/arm7tdmi.cpp
obj/processor-gsu.o: processor/gsu/gsu.cpp
obj/processor-hg51b.o: processor/hg51b/hg51b.cpp
obj/processor-huc6280.o: processor/huc6280/huc6280.cpp
obj/processor-m68k.o: processor/m68k/m68k.cpp
obj/processor-mos6502.o: processor/mos6502/mos6502.cpp
obj/processor-sm83.o: processor/sm83/sm83.cpp
obj/processor-spc700.o: processor/spc700/spc700.cpp
obj/processor-tlcs900h.o: processor/tlcs900h/tlcs900h.cpp
obj/processor-upd96050.o: processor/upd96050/upd96050.cpp
obj/processor-v30mz.o: processor/v30mz/v30mz.cpp
obj/processor-wdc65816.o: processor/wdc65816/wdc65816.cpp
obj/processor-z80.o: processor/z80/z80.cpp

View File

@ -1,11 +1,11 @@
auto ARM7TDMI::ADD(uint32 source, uint32 modify, bool carry) -> uint32 {
uint32 result = source + modify + carry;
if(cpsr().t || opcode.bit(20)) {
if(cpsr().t || bit1(opcode,20)) {
uint32 overflow = ~(source ^ modify) & (source ^ result);
cpsr().v = 1 << 31 & (overflow);
cpsr().c = 1 << 31 & (overflow ^ source ^ modify ^ result);
cpsr().z = result == 0;
cpsr().n = result.bit(31);
cpsr().n = bit1(result,31);
}
return result;
}
@ -19,10 +19,10 @@ auto ARM7TDMI::ASR(uint32 source, uint8 shift) -> uint32 {
}
auto ARM7TDMI::BIT(uint32 result) -> uint32 {
if(cpsr().t || opcode.bit(20)) {
if(cpsr().t || bit1(opcode,20)) {
cpsr().c = carry;
cpsr().z = result == 0;
cpsr().n = result.bit(31);
cpsr().n = bit1(result,31);
}
return result;
}
@ -49,9 +49,9 @@ auto ARM7TDMI::MUL(uint32 product, uint32 multiplicand, uint32 multiplier) -> ui
if(multiplier >> 16 && multiplier >> 16 != 0xffff) idle();
if(multiplier >> 24 && multiplier >> 24 != 0xff) idle();
product += multiplicand * multiplier;
if(cpsr().t || opcode.bit(20)) {
if(cpsr().t || bit1(opcode,20)) {
cpsr().z = product == 0;
cpsr().n = product.bit(31);
cpsr().n = bit1(product,31);
}
return product;
}
@ -65,7 +65,7 @@ auto ARM7TDMI::ROR(uint32 source, uint8 shift) -> uint32 {
}
auto ARM7TDMI::RRX(uint32 source) -> uint32 {
carry = source.bit(0);
carry = source & 1;
return cpsr().c << 31 | source >> 1;
}

View File

@ -148,14 +148,14 @@ struct ARM7TDMI {
}
inline auto operator=(uint32 data) -> PSR& {
m = data.bits(0,4);
t = data.bit(5);
f = data.bit(6);
i = data.bit(7);
v = data.bit(28);
c = data.bit(29);
z = data.bit(30);
n = data.bit(31);
m = bits(data,0-4);
t = bit1(data,5);
f = bit1(data,6);
i = bit1(data,7);
v = bit1(data,28);
c = bit1(data,29);
z = bit1(data,30);
n = bit1(data,31);
return *this;
}

View File

@ -186,7 +186,7 @@ auto ARM7TDMI::armDisassembleMoveMultiple
(uint16 list, uint4 n, uint1 mode, uint1 writeback, uint1 type, uint1 up, uint1 pre) -> string {
string registers;
for(auto index : range(16)) {
if(list.bit(index)) registers.append(_r[index], ",");
if(bit1(list,index)) registers.append(_r[index], ",");
}
registers.trimRight(",", 1L);
return {mode ? "ldm" : "stm", _c,
@ -358,7 +358,7 @@ auto ARM7TDMI::thumbDisassembleMoveMultiple
(uint8 list, uint3 n, uint1 mode) -> string {
string registers;
for(uint m : range(8)) {
if(list.bit(m)) registers.append(_r[m], ",");
if(bit1(list,m)) registers.append(_r[m], ",");
}
registers.trimRight(",", 1L);
return {mode ? "ldmia" : "stmia", " ", _r[n], "!,{", registers, "}"};
@ -395,7 +395,7 @@ auto ARM7TDMI::thumbDisassembleStackMultiple
(uint8 list, uint1 lrpc, uint1 mode) -> string {
string registers;
for(uint m : range(8)) {
if(list.bit(m)) registers.append(_r[m], ",");
if(bit1(list,m)) registers.append(_r[m], ",");
}
if(lrpc) registers.append(!mode ? "lr," : "pc,");
registers.trimRight(",", 1L);

View File

@ -38,7 +38,7 @@ auto ARM7TDMI::instruction() -> void {
opcode = pipeline.execute.instruction;
if(!pipeline.execute.thumb) {
if(!TST(opcode.bits(28,31))) return;
if(!TST(opcode >> 28)) return;
uint12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4;
armInstruction[index](opcode);
} else {
@ -69,8 +69,8 @@ auto ARM7TDMI::armInitialize() -> void {
std::integral_constant<uint32_t, bit::test(s)>::value
#define arguments \
opcode.bits( 0,23), /* displacement */ \
opcode.bit (24) /* link */
bits(opcode, 0-23), /* displacement */ \
bit1(opcode,24) /* link */
for(uint4 displacementLo : range(16))
for(uint4 displacementHi : range(16))
for(uint1 link : range(2)) {
@ -81,7 +81,7 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3) /* m */
bits(opcode, 0- 3) /* m */
{
auto opcode = pattern(".... 0001 0010 ---- ---- ---- 0001 ????");
bind(opcode, BranchExchangeRegister);
@ -89,12 +89,12 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 7), /* immediate */ \
opcode.bits( 8,11), /* shift */ \
opcode.bits(12,15), /* d */ \
opcode.bits(16,19), /* n */ \
opcode.bit (20), /* save */ \
opcode.bits(21,24) /* mode */
bits(opcode, 0- 7), /* immediate */ \
bits(opcode, 8-11), /* shift */ \
bits(opcode,12-15), /* d */ \
bits(opcode,16-19), /* n */ \
bit1(opcode,20), /* save */ \
bits(opcode,21-24) /* mode */
for(uint4 shiftHi : range(16))
for(uint1 save : range(2))
for(uint4 mode : range(16)) {
@ -105,13 +105,13 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3), /* m */ \
opcode.bits( 5, 6), /* type */ \
opcode.bits( 7,11), /* shift */ \
opcode.bits(12,15), /* d */ \
opcode.bits(16,19), /* n */ \
opcode.bit (20), /* save */ \
opcode.bits(21,24) /* mode */
bits(opcode, 0- 3), /* m */ \
bits(opcode, 5- 6), /* type */ \
bits(opcode, 7-11), /* shift */ \
bits(opcode,12-15), /* d */ \
bits(opcode,16-19), /* n */ \
bit1(opcode,20), /* save */ \
bits(opcode,21-24) /* mode */
for(uint2 type : range(4))
for(uint1 shiftLo : range(2))
for(uint1 save : range(2))
@ -123,13 +123,13 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3), /* m */ \
opcode.bits( 5, 6), /* type */ \
opcode.bits( 8,11), /* s */ \
opcode.bits(12,15), /* d */ \
opcode.bits(16,19), /* n */ \
opcode.bit (20), /* save */ \
opcode.bits(21,24) /* mode */
bits(opcode, 0- 3), /* m */ \
bits(opcode, 5- 6), /* type */ \
bits(opcode, 8-11), /* s */ \
bits(opcode,12-15), /* d */ \
bits(opcode,16-19), /* n */ \
bit1(opcode,20), /* save */ \
bits(opcode,21-24) /* mode */
for(uint2 type : range(4))
for(uint1 save : range(2))
for(uint4 mode : range(16)) {
@ -140,13 +140,13 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3) << 0 | opcode.bits( 8,11) << 4, /* immediate */ \
opcode.bit ( 5), /* half */ \
opcode.bits(12,15), /* d */ \
opcode.bits(16,19), /* n */ \
opcode.bit (21), /* writeback */ \
opcode.bit (23), /* up */ \
opcode.bit (24) /* pre */
bits(opcode, 0- 3) << 0 | bits(opcode, 8-11) << 4, /* immediate */ \
bit1(opcode, 5), /* half */ \
bits(opcode,12-15), /* d */ \
bits(opcode,16-19), /* n */ \
bit1(opcode,21), /* writeback */ \
bit1(opcode,23), /* up */ \
bit1(opcode,24) /* pre */
for(uint1 half : range(2))
for(uint1 writeback : range(2))
for(uint1 up : range(2))
@ -157,13 +157,13 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3), /* m */ \
opcode.bit ( 5), /* half */ \
opcode.bits(12,15), /* d */ \
opcode.bits(16,19), /* n */ \
opcode.bit (21), /* writeback */ \
opcode.bit (23), /* up */ \
opcode.bit (24) /* pre */
bits(opcode, 0- 3), /* m */ \
bit1(opcode, 5), /* half */ \
bits(opcode,12-15), /* d */ \
bits(opcode,16-19), /* n */ \
bit1(opcode,21), /* writeback */ \
bit1(opcode,23), /* up */ \
bit1(opcode,24) /* pre */
for(uint1 half : range(2))
for(uint1 writeback : range(2))
for(uint1 up : range(2))
@ -174,10 +174,10 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3), /* m */ \
opcode.bits(12,15), /* d */ \
opcode.bits(16,19), /* n */ \
opcode.bit (22) /* byte */
bits(opcode, 0- 3), /* m */ \
bits(opcode,12-15), /* d */ \
bits(opcode,16-19), /* n */ \
bit1(opcode,22) /* byte */
for(uint1 byte : range(2)) {
auto opcode = pattern(".... 0001 0?00 ???? ???? ---- 1001 ????") | byte << 22;
bind(opcode, MemorySwap);
@ -185,13 +185,13 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3) << 0 | opcode.bits( 8,11) << 4, /* immediate */ \
opcode.bits(12,15), /* d */ \
opcode.bits(16,19), /* n */ \
opcode.bit (20), /* mode */ \
opcode.bit (21), /* writeback */ \
opcode.bit (23), /* up */ \
opcode.bit (24) /* pre */
bits(opcode, 0- 3) << 0 | bits(opcode, 8-11) << 4, /* immediate */ \
bits(opcode,12-15), /* d */ \
bits(opcode,16-19), /* n */ \
bit1(opcode,20), /* mode */ \
bit1(opcode,21), /* writeback */ \
bit1(opcode,23), /* up */ \
bit1(opcode,24) /* pre */
for(uint1 mode : range(2))
for(uint1 writeback : range(2))
for(uint1 up : range(2))
@ -202,13 +202,13 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3), /* m */ \
opcode.bits(12,15), /* d */ \
opcode.bits(16,19), /* n */ \
opcode.bit (20), /* mode */ \
opcode.bit (21), /* writeback */ \
opcode.bit (23), /* up */ \
opcode.bit (24) /* pre */
bits(opcode, 0- 3), /* m */ \
bits(opcode,12-15), /* d */ \
bits(opcode,16-19), /* n */ \
bit1(opcode,20), /* mode */ \
bit1(opcode,21), /* writeback */ \
bit1(opcode,23), /* up */ \
bit1(opcode,24) /* pre */
for(uint1 mode : range(2))
for(uint1 writeback : range(2))
for(uint1 up : range(2))
@ -219,14 +219,14 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0,11), /* immediate */ \
opcode.bits(12,15), /* d */ \
opcode.bits(16,19), /* n */ \
opcode.bit (20), /* mode */ \
opcode.bit (21), /* writeback */ \
opcode.bit (22), /* byte */ \
opcode.bit (23), /* up */ \
opcode.bit (24) /* pre */
bits(opcode, 0-11), /* immediate */ \
bits(opcode,12-15), /* d */ \
bits(opcode,16-19), /* n */ \
bit1(opcode,20), /* mode */ \
bit1(opcode,21), /* writeback */ \
bit1(opcode,22), /* byte */ \
bit1(opcode,23), /* up */ \
bit1(opcode,24) /* pre */
for(uint4 immediatePart : range(16))
for(uint1 mode : range(2))
for(uint1 writeback : range(2))
@ -240,13 +240,13 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0,15), /* list */ \
opcode.bits(16,19), /* n */ \
opcode.bit (20), /* mode */ \
opcode.bit (21), /* writeback */ \
opcode.bit (22), /* type */ \
opcode.bit (23), /* up */ \
opcode.bit (24) /* pre */
bits(opcode, 0-15), /* list */ \
bits(opcode,16-19), /* n */ \
bit1(opcode,20), /* mode */ \
bit1(opcode,21), /* writeback */ \
bit1(opcode,22), /* type */ \
bit1(opcode,23), /* up */ \
bit1(opcode,24) /* pre */
for(uint4 listPart : range(16))
for(uint1 mode : range(2))
for(uint1 writeback : range(2))
@ -260,16 +260,16 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3), /* m */ \
opcode.bits( 5, 6), /* type */ \
opcode.bits( 7,11), /* shift */ \
opcode.bits(12,15), /* d */ \
opcode.bits(16,19), /* n */ \
opcode.bit (20), /* mode */ \
opcode.bit (21), /* writeback */ \
opcode.bit (22), /* byte */ \
opcode.bit (23), /* up */ \
opcode.bit (24) /* pre */
bits(opcode, 0- 3), /* m */ \
bits(opcode, 5- 6), /* type */ \
bits(opcode, 7-11), /* shift */ \
bits(opcode,12-15), /* d */ \
bits(opcode,16-19), /* n */ \
bit1(opcode,20), /* mode */ \
bit1(opcode,21), /* writeback */ \
bit1(opcode,22), /* byte */ \
bit1(opcode,23), /* up */ \
bit1(opcode,24) /* pre */
for(uint2 type : range(4))
for(uint1 shiftLo : range(2))
for(uint1 mode : range(2))
@ -284,8 +284,8 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits(12,15), /* d */ \
opcode.bit (22) /* mode */
bits(opcode,12-15), /* d */ \
bit1(opcode,22) /* mode */
for(uint1 mode : range(2)) {
auto opcode = pattern(".... 0001 0?00 ---- ???? ---- 0000 ----") | mode << 22;
bind(opcode, MoveToRegisterFromStatus);
@ -293,10 +293,10 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 7), /* immediate */ \
opcode.bits( 8,11), /* rotate */ \
opcode.bits(16,19), /* field */ \
opcode.bit (22) /* mode */
bits(opcode, 0- 7), /* immediate */ \
bits(opcode, 8-11), /* rotate */ \
bits(opcode,16-19), /* field */ \
bit1(opcode,22) /* mode */
for(uint4 immediateHi : range(16))
for(uint1 mode : range(2)) {
auto opcode = pattern(".... 0011 0?10 ???? ---- ???? ???? ????") | immediateHi << 4 | mode << 22;
@ -305,9 +305,9 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3), /* m */ \
opcode.bits(16,19), /* field */ \
opcode.bit (22) /* mode */
bits(opcode, 0- 3), /* m */ \
bits(opcode,16-19), /* field */ \
bit1(opcode,22) /* mode */
for(uint1 mode : range(2)) {
auto opcode = pattern(".... 0001 0?10 ???? ---- ---- 0000 ????") | mode << 22;
bind(opcode, MoveToStatusFromRegister);
@ -315,12 +315,12 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3), /* m */ \
opcode.bits( 8,11), /* s */ \
opcode.bits(12,15), /* n */ \
opcode.bits(16,19), /* d */ \
opcode.bit (20), /* save */ \
opcode.bit (21) /* accumulate */
bits(opcode, 0- 3), /* m */ \
bits(opcode, 8-11), /* s */ \
bits(opcode,12-15), /* n */ \
bits(opcode,16-19), /* d */ \
bit1(opcode,20), /* save */ \
bit1(opcode,21) /* accumulate */
for(uint1 save : range(2))
for(uint1 accumulate : range(2)) {
auto opcode = pattern(".... 0000 00?? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21;
@ -329,13 +329,13 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3), /* m */ \
opcode.bits( 8,11), /* s */ \
opcode.bits(12,15), /* l */ \
opcode.bits(16,19), /* h */ \
opcode.bit (20), /* save */ \
opcode.bit (21), /* accumulate */ \
opcode.bit (22) /* sign */
bits(opcode, 0- 3), /* m */ \
bits(opcode, 8-11), /* s */ \
bits(opcode,12-15), /* l */ \
bits(opcode,16-19), /* h */ \
bit1(opcode,20), /* save */ \
bit1(opcode,21), /* accumulate */ \
bit1(opcode,22) /* sign */
for(uint1 save : range(2))
for(uint1 accumulate : range(2))
for(uint1 sign : range(2)) {
@ -345,7 +345,7 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0,23) /* immediate */
bits(opcode, 0-23) /* immediate */
for(uint4 immediateLo : range(16))
for(uint4 immediateHi : range(16)) {
auto opcode = pattern(".... 1111 ???? ???? ???? ???? ???? ????") | immediateLo << 4 | immediateHi << 20;
@ -356,7 +356,7 @@ auto ARM7TDMI::armInitialize() -> void {
#define arguments
for(uint12 id : range(4096)) {
if(armInstruction[id]) continue;
auto opcode = pattern(".... ???? ???? ---- ---- ---- ???? ----") | id.bits(0,3) << 4 | id.bits(4,11) << 20;
auto opcode = pattern(".... ???? ???? ---- ---- ---- ???? ----") | bits(id,0-3) << 4 | bits(id,4-11) << 20;
bind(opcode, Undefined);
}
#undef arguments
@ -386,7 +386,7 @@ auto ARM7TDMI::thumbInitialize() -> void {
for(uint4 m : range(16))
for(uint2 mode : range(4)) {
if(mode == 3) continue;
auto opcode = pattern("0100 01?? ???? ????") | d.bits(0,2) << 0 | m << 3 | d.bit(3) << 7 | mode << 8;
auto opcode = pattern("0100 01?? ???? ????") | bits(d,0-2) << 0 | m << 3 | bit1(d,3) << 7 | mode << 8;
bind(opcode, ALUExtended, d, m, mode);
}

View File

@ -20,7 +20,7 @@ auto ARM7TDMI::armALU(uint4 mode, uint4 d, uint4 n, uint32 rm) -> void {
case 15: r(d) = BIT(~rm); break; //MVN
}
if(exception() && d == 15 && opcode.bit(20)) {
if(exception() && d == 15 && bit1(opcode,20)) {
cpsr() = spsr();
}
}
@ -31,19 +31,19 @@ auto ARM7TDMI::armMoveToStatus(uint4 field, uint1 mode, uint32 data) -> void {
if(field.bit(0)) {
if(mode || privileged()) {
psr.m = data.bits(0,4);
psr.t = data.bit (5);
psr.f = data.bit (6);
psr.i = data.bit (7);
psr.m = bits(data,0-4);
psr.t = bit1(data,5);
psr.f = bit1(data,6);
psr.i = bit1(data,7);
if(!mode && psr.t) r(15).data += 2;
}
}
if(field.bit(3)) {
psr.v = data.bit(28);
psr.c = data.bit(29);
psr.z = data.bit(30);
psr.n = data.bit(31);
psr.v = bit1(data,28);
psr.c = bit1(data,29);
psr.z = bit1(data,30);
psr.n = bit1(data,31);
}
}
@ -58,7 +58,7 @@ auto ARM7TDMI::armInstructionBranch
auto ARM7TDMI::armInstructionBranchExchangeRegister
(uint4 m) -> void {
uint32 address = r(m);
cpsr().t = address.bit(0);
cpsr().t = address & 1;
r(15) = address;
}
@ -193,13 +193,13 @@ auto ARM7TDMI::armInstructionMoveMultiple
auto cpsrMode = cpsr().m;
bool usr = false;
if(type && mode == 1 && !list.bit(15)) usr = true;
if(type && mode == 1 && !bit1(list,15)) usr = true;
if(type && mode == 0) usr = true;
if(usr) cpsr().m = PSR::USR;
uint sequential = Nonsequential;
for(uint m : range(16)) {
if(!list.bit(m)) continue;
if(!bit1(list,m)) continue;
if(mode == 1) r(m) = read(Word | sequential, rn);
if(mode == 0) write(Word | sequential, rn, r(m));
rn += 4;
@ -210,7 +210,7 @@ auto ARM7TDMI::armInstructionMoveMultiple
if(mode) {
idle();
if(type && list.bit(15) && cpsr().m != PSR::USR && cpsr().m != PSR::SYS) {
if(type && bit1(list,15) && cpsr().m != PSR::USR && cpsr().m != PSR::SYS) {
cpsr() = spsr();
}
} else {
@ -299,7 +299,7 @@ auto ARM7TDMI::armInstructionMultiplyLong
if(save) {
cpsr().z = rd == 0;
cpsr().n = rd.bit(63);
cpsr().n = bit1(rd,63);
}
}

View File

@ -64,7 +64,7 @@ auto ARM7TDMI::thumbInstructionAdjustStack
auto ARM7TDMI::thumbInstructionBranchExchange
(uint4 m) -> void {
uint32 address = r(m);
cpsr().t = address.bit(0);
cpsr().t = address & 1;
r(15) = address;
}
@ -127,7 +127,7 @@ auto ARM7TDMI::thumbInstructionMoveMultiple
uint32 rn = r(n);
for(uint m : range(8)) {
if(!list.bit(m)) continue;
if(!bit1(list,m)) continue;
switch(mode) {
case 0: write(Word | Nonsequential, rn, r(m)); break; //STMIA
case 1: r(m) = read(Word | Nonsequential, rn); break; //LDMIA
@ -135,7 +135,7 @@ auto ARM7TDMI::thumbInstructionMoveMultiple
rn += 4;
}
if(mode == 0 || !list.bit(n)) r(n) = rn;
if(mode == 0 || !bit1(list,n)) r(n) = rn;
if(mode == 1) idle();
}
@ -193,7 +193,7 @@ auto ARM7TDMI::thumbInstructionStackMultiple
uint sequential = Nonsequential;
for(uint m : range(8)) {
if(!list.bit(m)) continue;
if(!bit1(list,m)) continue;
switch(mode) {
case 0: write(Word | sequential, sp, r(m)); break; //PUSH
case 1: r(m) = read(Word | sequential, sp); break; //POP

View File

@ -19,9 +19,9 @@ auto ARM7TDMI::load(uint mode, uint32 address) -> uint32 {
word = mode & Signed ? (uint32)(int8)word : (uint32)(uint8)word;
}
if(mode & Signed) {
word = ASR(word, address.bits(0,1) << 3);
word = ASR(word, (address & 3) << 3);
} else {
word = ROR(word, address.bits(0,1) << 3);
word = ROR(word, (address & 3) << 3);
}
idle();
return word;

View File

@ -20,8 +20,8 @@ struct GSU {
virtual auto writeRAMBuffer(uint16 addr, uint8 data) -> void = 0;
virtual auto flushCache() -> void = 0;
virtual auto read(uint24 addr, uint8 data = 0x00) -> uint8 = 0;
virtual auto write(uint24 addr, uint8 data) -> void = 0;
virtual auto read(uint addr, uint8 data = 0x00) -> uint8 = 0;
virtual auto write(uint addr, uint8 data) -> void = 0;
//gsu.cpp
auto power() -> void;

View File

@ -84,8 +84,8 @@ auto HG51B::cache() -> bool {
io.cache.address[io.cache.page] = address;
for(uint offset : range(256)) {
step(wait(address)); programRAM[io.cache.page][offset].byte(0) = read(address++);
step(wait(address)); programRAM[io.cache.page][offset].byte(1) = read(address++);
step(wait(address)); bit8(programRAM[io.cache.page][offset],0) = read(address++);
step(wait(address)); bit8(programRAM[io.cache.page][offset],1) = read(address++);
}
return io.cache.enable = 0, true;
}

View File

@ -10,10 +10,10 @@ struct HG51B {
//hg51b.cpp
virtual auto step(uint clocks) -> void;
virtual auto isROM(uint24 address) -> bool = 0;
virtual auto isRAM(uint24 address) -> bool = 0;
virtual auto read(uint24 address) -> uint8 = 0;
virtual auto write(uint24 address, uint8 data) -> void = 0;
virtual auto isROM(uint address) -> bool = 0;
virtual auto isRAM(uint address) -> bool = 0;
virtual auto read(uint address) -> uint8 = 0;
virtual auto write(uint address, uint8 data) -> void = 0;
virtual auto lock() -> void;
virtual auto halt() -> void;
auto wait(uint24 address) -> uint;

View File

@ -203,11 +203,11 @@ auto HG51B::instructionLD(uint15& out, uint8 imm) -> void {
}
auto HG51B::instructionLDL(uint15& out, uint8 imm) -> void {
out.bits(0,7) = imm;
bits(out,0-7) = imm;
}
auto HG51B::instructionLDH(uint15& out, uint7 imm) -> void {
out.bits(8,14) = imm;
bits(out,8-14) = imm;
}
auto HG51B::instructionMUL(uint7 reg) -> void {

View File

@ -1,7 +1,7 @@
auto HG51B::readRegister(uint7 address) -> uint24 {
switch(address) {
case 0x01: return r.mul.bits(24,47);
case 0x02: return r.mul.bits( 0,23);
case 0x01: return bits(r.mul,24-47);
case 0x02: return bits(r.mul, 0-23);
case 0x03: return r.mdr;
case 0x08: return r.rom;
case 0x0c: return r.ram;
@ -64,8 +64,8 @@ auto HG51B::readRegister(uint7 address) -> uint24 {
auto HG51B::writeRegister(uint7 address, uint24 data) -> void {
switch(address) {
case 0x01: r.mul.bits(24,47) = data; return;
case 0x02: r.mul.bits( 0,23) = data; return;
case 0x01: bits(r.mul,24-47) = data; return;
case 0x02: bits(r.mul, 0-23) = data; return;
case 0x03: r.mdr = data; return;
case 0x08: r.rom = data; return;
case 0x0c: r.ram = data; return;

View File

@ -1,184 +0,0 @@
auto HuC6280::algorithmADC(uint8 i) -> uint8 {
int16 o;
if(!D) {
o = A + i + C;
V = ~(A ^ i) & (A ^ o) & 0x80;
} else {
io();
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o > 0x09) o += 0x06;
C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
if(o > 0x9f) o += 0x60;
}
C = o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return o;
}
auto HuC6280::algorithmAND(uint8 i) -> uint8 {
uint8 o = A & i;
Z = o == 0;
N = o.bit(7);
return o;
}
auto HuC6280::algorithmASL(uint8 i) -> uint8 {
C = i.bit(7);
i <<= 1;
Z = i == 0;
N = i.bit(7);
return i;
}
auto HuC6280::algorithmBIT(uint8 i) -> uint8 {
Z = (A & i) == 0;
V = i.bit(6);
N = i.bit(7);
return A;
}
auto HuC6280::algorithmCMP(uint8 i) -> uint8 {
uint9 o = A - i;
C = !o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return A;
}
auto HuC6280::algorithmCPX(uint8 i) -> uint8 {
uint9 o = X - i;
C = !o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return X;
}
auto HuC6280::algorithmCPY(uint8 i) -> uint8 {
uint9 o = Y - i;
C = !o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return Y;
}
auto HuC6280::algorithmDEC(uint8 i) -> uint8 {
i--;
Z = i == 0;
N = i.bit(7);
return i;
}
auto HuC6280::algorithmEOR(uint8 i) -> uint8 {
uint8 o = A ^ i;
Z = o == 0;
N = o.bit(7);
return o;
}
auto HuC6280::algorithmINC(uint8 i) -> uint8 {
i++;
Z = i == 0;
N = i.bit(7);
return i;
}
auto HuC6280::algorithmLD(uint8 i) -> uint8 {
Z = i == 0;
N = i.bit(7);
return i;
}
auto HuC6280::algorithmLSR(uint8 i) -> uint8 {
C = i.bit(0);
i >>= 1;
Z = i == 0;
N = i.bit(7);
return i;
}
auto HuC6280::algorithmORA(uint8 i) -> uint8 {
uint8 o = A | i;
Z = o == 0;
N = o.bit(7);
return o;
}
auto HuC6280::algorithmROL(uint8 i) -> uint8 {
bool c = C;
C = i.bit(7);
i = i << 1 | c;
Z = i == 0;
N = i.bit(7);
return i;
}
auto HuC6280::algorithmROR(uint8 i) -> uint8 {
bool c = C;
C = i.bit(0);
i = c << 7 | i >> 1;
Z = i == 0;
N = i.bit(7);
return i;
}
auto HuC6280::algorithmSBC(uint8 i) -> uint8 {
i ^= 0xff;
int16 o;
if(!D) {
o = A + i + C;
V = ~(A ^ i) & (A ^ o) & 0x80;
} else {
io();
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o <= 0x0f) o -= 0x06;
C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
if(o <= 0xff) o -= 0x60;
}
C = o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return o;
}
auto HuC6280::algorithmTRB(uint8 i) -> uint8 {
Z = (A & i) == 0;
V = i.bit(6);
N = i.bit(7);
return ~A & i;
}
auto HuC6280::algorithmTSB(uint8 i) -> uint8 {
Z = (A & i) == 0;
V = i.bit(6);
N = i.bit(7);
return A | i;
}
//
auto HuC6280::algorithmTAI(uint16& source, uint16& target, bool alternate) -> void {
!alternate ? source++ : source--;
target++;
}
auto HuC6280::algorithmTDD(uint16& source, uint16& target, bool) -> void {
source--;
target--;
}
auto HuC6280::algorithmTIA(uint16& source, uint16& target, bool alternate) -> void {
source++;
!alternate ? target++ : target--;
}
auto HuC6280::algorithmTII(uint16& source, uint16& target, bool) -> void {
source++;
target++;
}
auto HuC6280::algorithmTIN(uint16& source, uint16& target, bool) -> void {
source++;
}

View File

@ -1,356 +0,0 @@
auto HuC6280::disassemble(uint16 pc) -> string {
uint8 bank = r.mpr[pc.bits(13,15)];
uint13 addr = pc.bits(0,12);
string s{hex(bank, 2L), ":", hex(addr, 4L), " "};
auto readByte = [&]() -> uint8 {
return read(bank, addr++);
};
auto readWord = [&]() -> uint16 {
uint16 data = read(bank, addr++) << 0;
return data | read(bank, addr++) << 8;
};
auto absolute = [&]() -> string { return {"$", hex(readWord(), 4L)}; };
auto absoluteX = [&]() -> string { return {"$", hex(readWord(), 4L), ",x"}; };
auto absoluteY = [&]() -> string { return {"$", hex(readWord(), 4L), ",y"}; };
auto immediate = [&]() -> string { return {"#$", hex(readByte(), 2L)}; };
auto indirect = [&]() -> string { return {"($", hex(readByte(), 2L), ")"}; };
auto indirectX = [&]() -> string { return {"($", hex(readByte(), 2L), ",x)"}; };
auto indirectY = [&]() -> string { return {"($", hex(readByte(), 2L), "),y"}; };
auto indirectLong = [&]() -> string { return {"($", hex(readWord(), 4L), ")"}; };
auto indirectLongX = [&]() -> string { return {"($", hex(readWord(), 4L), ",x)"}; };
auto memory = [&]() -> string { return {"(x),#$", hex(readByte(), 2L)}; };
auto relative = [&]() -> string { auto displacement = readByte(); return {"$", hex(pc + (int8)displacement, 4L)}; };
auto zeropage = [&]() -> string { return {"$", hex(readByte(), 2L)}; };
auto zeropageX = [&]() -> string { return {"$", hex(readByte(), 2L), ",x"}; };
auto zeropageY = [&]() -> string { return {"$", hex(readByte(), 2L), ",y"}; };
auto immediateAbsolute = [&](string index = "") -> string {
auto immediate = readByte();
auto absolute = readWord();
if(index) index.prepend(",");
return {"#$", hex(immediate, 2L), ",$", hex(absolute, 4L), index};
};
auto immediateZeropage = [&](string index = "") -> string {
auto immediate = readByte();
auto zeropage = readByte();
if(index) index.prepend(",");
return {"#$", hex(immediate, 2L), ",$", hex(zeropage, 2L), index};
};
auto zeropageBit = [&](uint3 bit) -> string {
auto zeropage = readByte();
return {"$", hex(zeropage, 2L), ":", bit};
};
auto zeropageBitRelative = [&](uint3 bit) -> string {
auto zeropage = readByte();
auto displacement = readByte();
return {"$", hex(zeropage, 2L), ":", bit, ",$", hex(pc + (int8)displacement, 4L)};
};
auto blockMove = [&]() -> string {
auto source = readWord();
auto target = readWord();
auto length = readWord();
return {"$", hex(source, 4L), ",$", hex(target, 4L), ",$", hex(length, 4L)};
};
uint8 opcode = readByte();
#define op(id, name, ...) case id: o = {name, " ", vector<string>{__VA_ARGS__}.merge(",")}; break;
string o;
if(T == 1) switch(opcode) {
op(0x09, "ora", memory())
op(0x29, "and", memory())
op(0x49, "eor", memory())
op(0x69, "adc", memory())
}
#define U
if(T == 0) switch(opcode) {
op(0x00, "brk")
op(0x01, "ora", indirectX())
op(0x02, "sxy")
op(0x03, "st0", immediate())
op(0x04, "tsb", zeropage())
op(0x05, "ora", zeropage())
op(0x06, "asl", zeropage())
op(0x07, "rmb", zeropageBit(0))
op(0x08, "php")
op(0x09, "ora", immediate())
op(0x0a, "asl")
U op(0x0b, "nop", "$0b")
op(0x0c, "tsb", absolute())
op(0x0d, "ora", absolute())
op(0x0e, "asl", absolute())
op(0x0f, "bbr", zeropageBitRelative(0))
op(0x10, "bpl", relative())
op(0x11, "ora", indirectY())
op(0x12, "ora", indirect())
op(0x13, "st1", immediate())
op(0x14, "trb", zeropage())
op(0x15, "ora", zeropageX())
op(0x16, "asl", zeropageX())
op(0x17, "rmb", zeropageBit(1))
op(0x18, "clc")
op(0x19, "ora", absoluteY())
op(0x1a, "inc")
U op(0x1b, "nop", "$1b")
op(0x1c, "trb", absolute())
op(0x1d, "ora", absoluteX())
op(0x1e, "asl", absoluteX())
op(0x1f, "bbr", zeropageBitRelative(1))
op(0x20, "jsr", absolute())
op(0x21, "and", indirectX())
op(0x22, "sax")
op(0x23, "st2", immediate())
op(0x24, "bit", zeropage())
op(0x25, "and", zeropage())
op(0x26, "rol", zeropage())
op(0x27, "rmb", zeropageBit(2))
op(0x28, "plp")
op(0x29, "and", immediate())
op(0x2a, "rol")
U op(0x2b, "nop", "$2b")
op(0x2c, "bit", absolute())
op(0x2d, "and", absolute())
op(0x2e, "rol", absolute())
op(0x2f, "bbr", zeropageBitRelative(2))
op(0x30, "bmi", relative())
op(0x31, "and", indirectY())
op(0x32, "and", indirect())
op(0x34, "bit", zeropageX())
op(0x35, "and", zeropageX())
op(0x36, "rol", zeropageX())
op(0x37, "rmb", zeropageBit(3))
op(0x38, "sec")
op(0x39, "and", absoluteY())
op(0x3a, "dec")
U op(0x3b, "nop", "$3b")
op(0x3c, "bit", absoluteX())
op(0x3d, "and", absoluteX())
op(0x3e, "rol", absoluteX())
op(0x3f, "bbr", zeropageBitRelative(3))
op(0x40, "rti")
op(0x41, "eor", indirectX())
op(0x42, "say")
op(0x43, "tma", immediate())
op(0x44, "bsr", relative())
op(0x45, "eor", zeropage())
op(0x46, "lsr", zeropage())
op(0x47, "rmb", zeropageBit(4))
op(0x48, "pha")
op(0x49, "eor", immediate())
op(0x4a, "lsr")
U op(0x4b, "nop", "$4b")
op(0x4c, "jmp", absolute())
op(0x4d, "eor", absolute())
op(0x4e, "lsr", absolute())
op(0x4f, "bbr", zeropageBitRelative(4))
op(0x50, "bvc", relative())
op(0x51, "eor", indirectY())
op(0x52, "eor", indirect())
op(0x53, "tam", immediate())
op(0x54, "csl")
op(0x55, "eor", zeropageX())
op(0x56, "lsr", zeropageX())
op(0x57, "rmb", zeropageBit(5))
op(0x58, "cli")
op(0x59, "eor", absoluteY())
op(0x5a, "phy")
U op(0x5b, "nop", "$5b")
U op(0x5c, "nop", "$5c")
op(0x5d, "eor", absoluteX())
op(0x5e, "lsr", absoluteX())
op(0x5f, "bbr", zeropageBitRelative(5))
op(0x60, "rts")
op(0x61, "adc", indirectX())
op(0x62, "cla")
U op(0x63, "nop", "$63")
op(0x64, "stz", zeropage())
op(0x65, "adc", zeropage())
op(0x66, "ror", zeropage())
op(0x67, "rmb", zeropageBit(6))
op(0x68, "pla")
op(0x69, "adc", immediate())
op(0x6a, "ror")
U op(0x6b, "nop", "$6b")
op(0x6c, "jmp", indirectLong())
op(0x6d, "adc", absolute())
op(0x6e, "ror", absolute())
op(0x6f, "bbr", zeropageBitRelative(6))
op(0x70, "bvs", relative())
op(0x71, "adc", indirectY())
op(0x72, "adc", indirect())
op(0x73, "tii", blockMove())
op(0x74, "stz", zeropageX())
op(0x75, "adc", zeropageX())
op(0x76, "ror", zeropageX())
op(0x77, "rmb", zeropageBit(7))
op(0x78, "sei")
op(0x79, "adc", absoluteY())
op(0x7a, "ply")
U op(0x7b, "nop", "$7b")
op(0x7c, "jmp", indirectLongX())
op(0x7d, "adc", absoluteX())
op(0x7e, "ror", absoluteX())
op(0x7f, "bbr", zeropageBitRelative(7))
op(0x80, "bra", relative())
op(0x81, "sta", indirectX())
op(0x82, "clx")
op(0x83, "tst", immediateZeropage())
op(0x84, "sty", zeropage())
op(0x85, "sta", zeropage())
op(0x86, "stx", zeropage())
op(0x87, "smb", zeropageBit(0))
op(0x88, "dey")
op(0x89, "bit", immediate())
op(0x8a, "txa")
U op(0x8b, "nop", "$8b")
op(0x8c, "sty", absolute())
op(0x8d, "sta", absolute())
op(0x8e, "stx", absolute())
op(0x8f, "bbs", zeropageBitRelative(0))
op(0x90, "bcc", relative())
op(0x91, "sta", indirectY())
op(0x92, "sta", indirect())
op(0x93, "tst", immediateAbsolute())
op(0x94, "sty", zeropageX())
op(0x95, "sta", zeropageX())
op(0x96, "stx", zeropageY())
op(0x97, "smb", zeropageBit(1))
op(0x98, "tya")
op(0x99, "sta", absoluteY())
op(0x9a, "txs")
U op(0x9b, "nop", "$9b")
op(0x9c, "stz", absolute())
op(0x9d, "sta", absoluteX())
op(0x9e, "stz", absoluteX())
op(0x9f, "bbs", zeropageBitRelative(1))
op(0xa0, "ldy", immediate())
op(0xa1, "lda", indirectX())
op(0xa2, "ldx", immediate())
op(0xa3, "tst", immediateZeropage("x"))
op(0xa4, "ldy", zeropage())
op(0xa5, "lda", zeropage())
op(0xa6, "ldx", zeropage())
op(0xa7, "smb", zeropageBit(2))
op(0xa8, "tay")
op(0xa9, "lda", immediate())
op(0xaa, "tax")
U op(0xab, "nop", "$ab")
op(0xac, "ldy", absolute())
op(0xad, "lda", absolute())
op(0xae, "ldx", absolute())
op(0xaf, "bbs", zeropageBitRelative(2))
op(0xb0, "bcs", relative())
op(0xb1, "lda", indirectY())
op(0xb2, "lda", indirect())
op(0xb3, "tst", immediateAbsolute("x"))
op(0xb4, "ldy", zeropageX())
op(0xb5, "lda", zeropageX())
op(0xb6, "ldx", zeropageY())
op(0xb7, "smb", zeropageBit(3))
op(0xb8, "clv")
op(0xb9, "lda", absoluteY())
op(0xba, "tsx")
U op(0xbb, "nop", "$bb")
op(0xbc, "ldy", absoluteX())
op(0xbd, "lda", absoluteX())
op(0xbe, "ldx", absoluteY())
op(0xbf, "bbs", zeropageBitRelative(3))
op(0xc0, "cpy", immediate())
op(0xc1, "cmp", indirectX())
op(0xc2, "cly")
op(0xc3, "tdd", blockMove())
op(0xc4, "cpy", zeropage())
op(0xc5, "cmp", zeropage())
op(0xc6, "dec", zeropage())
op(0xc7, "smb", zeropageBit(4))
op(0xc8, "iny")
op(0xc9, "cmp", immediate())
op(0xca, "dex")
U op(0xcb, "nop", "$cb")
op(0xcc, "cpy", absolute())
op(0xcd, "cmp", absolute())
op(0xce, "dec", absolute())
op(0xcf, "bbs", zeropageBitRelative(4))
op(0xd0, "bne", relative())
op(0xd1, "cmp", indirectY())
op(0xd2, "cmp", indirect())
op(0xd3, "tin", blockMove())
op(0xd4, "csh")
op(0xd5, "cmp", zeropageX())
op(0xd6, "dec", zeropageX())
op(0xd7, "smb", zeropageBit(5))
op(0xd8, "cld")
op(0xd9, "cmp", absoluteY())
op(0xda, "phx")
U op(0xdb, "nop", "$db")
U op(0xdc, "nop", "$dc")
op(0xdd, "cmp", absoluteX())
op(0xde, "dec", absoluteX())
op(0xdf, "bbs", zeropageBitRelative(5))
op(0xe0, "cpx", immediate())
op(0xe1, "sbc", indirectX())
U op(0xe2, "nop", "$e2")
op(0xe3, "tia", blockMove())
op(0xe4, "cpx", zeropage())
op(0xe5, "sbc", zeropage())
op(0xe6, "inc", zeropage())
op(0xe7, "smb", zeropageBit(6))
op(0xe8, "inx")
op(0xe9, "sbc", immediate())
op(0xea, "nop")
U op(0xeb, "nop", "$eb")
op(0xec, "cpx", absolute())
op(0xed, "sbc", absolute())
op(0xee, "inc", absolute())
op(0xef, "bbs", zeropageBitRelative(6))
op(0xf0, "beq", relative())
op(0xf1, "sbc", indirectY())
op(0xf2, "sbc", indirect())
op(0xf3, "tai", blockMove())
op(0xf4, "set")
op(0xf5, "sbc", zeropageX())
op(0xf6, "inc", zeropageX())
op(0xf7, "smb", zeropageBit(7))
op(0xf8, "sed")
op(0xf9, "sbc", absoluteY())
op(0xfa, "plx")
U op(0xfb, "nop", "$fb")
U op(0xfc, "nop", "$fc")
op(0xfd, "sbc", absoluteX())
op(0xfe, "inc", absoluteX())
op(0xff, "bbs", zeropageBitRelative(7))
}
#undef U
if(!o) o = {"??? (", hex(opcode, 2L), ")"};
s.append(pad(o, -22L, ' '));
#undef op
s.append(" A:", hex(r.a, 2L));
s.append(" X:", hex(r.x, 2L));
s.append(" Y:", hex(r.y, 2L));
s.append(" S:", hex(r.s, 2L));
s.append(" PC:", hex(pc, 4L));
s.append(" ");
s.append(r.p.n ? "N" : "n");
s.append(r.p.v ? "V" : "v");
s.append(r.p.t ? "T" : "t");
s.append(r.p.b ? "B" : "b");
s.append(r.p.d ? "D" : "d");
s.append(r.p.i ? "I" : "i");
s.append(r.p.z ? "Z" : "z");
s.append(r.p.c ? "C" : "c");
s.append(r.cs == 3 ? "+" : "-");
return s;
}

View File

@ -1,72 +0,0 @@
#include <processor/processor.hpp>
#include "huc6280.hpp"
namespace Processor {
#define A r.a
#define X r.x
#define Y r.y
#define S r.s
#define PC r.pc
#define PCH r.pc.byte(1)
#define PCL r.pc.byte(0)
#define P r.p
#define C r.p.c
#define Z r.p.z
#define I r.p.i
#define D r.p.d
#define B r.p.b
#define T r.p.t
#define V r.p.v
#define N r.p.n
#define EA r.ea
#define L lastCycle();
#define ALU (this->*alu)
#include "memory.cpp"
#include "algorithms.cpp"
#include "instruction.cpp"
#include "instructions.cpp"
#include "disassembler.cpp"
#include "serialization.cpp"
#undef A
#undef X
#undef Y
#undef S
#undef PC
#undef PCH
#undef PCL
#undef P
#undef C
#undef Z
#undef I
#undef D
#undef B
#undef T
#undef V
#undef N
#undef EA
#undef L
#undef ALU
auto HuC6280::power() -> void {
r.a = 0x00;
r.x = 0x00;
r.y = 0x00;
r.s = 0xff;
r.pc = 0x0000;
r.mpr[0] = 0xff;
r.mpr[1] = 0xf8;
r.mpr[2] = 0x00;
r.mpr[3] = 0x00;
r.mpr[4] = 0x00;
r.mpr[5] = 0x00;
r.mpr[6] = 0x00;
r.mpr[7] = 0x00;
r.mdr = 0x00;
r.p = 0x04;
r.cs = 1;
}
}

View File

@ -1,153 +0,0 @@
//Hudson Soft HuC6280
#pragma once
namespace Processor {
struct HuC6280 {
virtual auto step(uint clocks) -> void = 0;
virtual auto read(uint8 bank, uint13 addr) -> uint8 = 0;
virtual auto write(uint8 bank, uint13 addr, uint8 data) -> void = 0;
virtual auto store(uint2 addr, uint8 data) -> void = 0;
virtual auto lastCycle() -> void = 0;
//huc6280.cpp
auto power() -> void;
//memory.cpp
inline auto load8(uint8) -> uint8;
inline auto load16(uint16) -> uint8;
inline auto store8(uint8, uint8) -> void;
inline auto store16(uint16, uint8) -> void;
auto io() -> void;
auto opcode() -> uint8;
auto operand() -> uint8;
auto push(uint8) -> void;
auto pull() -> uint8;
//instructions.cpp
using fp = auto (HuC6280::*)(uint8) -> uint8;
auto algorithmADC(uint8) -> uint8;
auto algorithmAND(uint8) -> uint8;
auto algorithmASL(uint8) -> uint8;
auto algorithmBIT(uint8) -> uint8;
auto algorithmCMP(uint8) -> uint8;
auto algorithmCPX(uint8) -> uint8;
auto algorithmCPY(uint8) -> uint8;
auto algorithmDEC(uint8) -> uint8;
auto algorithmEOR(uint8) -> uint8;
auto algorithmINC(uint8) -> uint8;
auto algorithmLD (uint8) -> uint8;
auto algorithmLSR(uint8) -> uint8;
auto algorithmORA(uint8) -> uint8;
auto algorithmROL(uint8) -> uint8;
auto algorithmROR(uint8) -> uint8;
auto algorithmSBC(uint8) -> uint8;
auto algorithmTRB(uint8) -> uint8;
auto algorithmTSB(uint8) -> uint8;
using bp = auto (HuC6280::*)(uint16&, uint16&, bool) -> void;
auto algorithmTAI(uint16&, uint16&, bool) -> void;
auto algorithmTDD(uint16&, uint16&, bool) -> void;
auto algorithmTIA(uint16&, uint16&, bool) -> void;
auto algorithmTII(uint16&, uint16&, bool) -> void;
auto algorithmTIN(uint16&, uint16&, bool) -> void;
//instruction.cpp
auto interrupt(uint16 vector) -> void;
auto instruction() -> void;
//instructions.cpp
auto instructionAbsoluteModify(fp, uint8 = 0) -> void;
auto instructionAbsoluteRead(fp, uint8&, uint8 = 0) -> void;
auto instructionAbsoluteWrite(uint8, uint8 = 0) -> void;
auto instructionBlockMove(bp) -> void;
auto instructionBranch(bool) -> void;
auto instructionBranchIfBitReset(uint3) -> void;
auto instructionBranchIfBitSet(uint3) -> void;
auto instructionBranchSubroutine() -> void;
auto instructionBreak() -> void;
auto instructionCallAbsolute() -> void;
auto instructionChangeSpeedLow() -> void;
auto instructionChangeSpeedHigh() -> void;
auto instructionClear(uint8&) -> void;
auto instructionClear(bool&) -> void;
auto instructionImmediate(fp, uint8&) -> void;
auto instructionImplied(fp, uint8&) -> void;
auto instructionIndirectRead(fp, uint8&, uint8 = 0) -> void;
auto instructionIndirectWrite(uint8, uint8 = 0) -> void;
auto instructionIndirectYRead(fp, uint8&) -> void;
auto instructionIndirectYWrite(uint8) -> void;
auto instructionJumpAbsolute() -> void;
auto instructionJumpIndirect(uint8 = 0) -> void;
auto instructionMemory(fp) -> void;
auto instructionNoOperation() -> void;
auto instructionPull(uint8&) -> void;
auto instructionPullP() -> void;
auto instructionPush(uint8) -> void;
auto instructionResetMemoryBit(uint3) -> void;
auto instructionReturnInterrupt() -> void;
auto instructionReturnSubroutine() -> void;
auto instructionSet(bool&) -> void;
auto instructionSetMemoryBit(uint3) -> void;
auto instructionStoreImplied(uint2) -> void;
auto instructionSwap(uint8&, uint8&) -> void;
auto instructionTestAbsolute(uint8 = 0) -> void;
auto instructionTestZeroPage(uint8 = 0) -> void;
auto instructionTransfer(uint8&, uint8&) -> void;
auto instructionTransferAccumulatorToMPR() -> void;
auto instructionTransferMPRToAccumulator() -> void;
auto instructionTransferXS() -> void;
auto instructionZeroPageModify(fp, uint8 = 0) -> void;
auto instructionZeroPageRead(fp, uint8&, uint8 = 0) -> void;
auto instructionZeroPageWrite(uint8, uint8 = 0) -> void;
//disassembler.cpp
auto disassemble(uint16 pc) -> string;
//serialization.cpp
auto serialize(serializer&) -> void;
struct Flags {
bool c; //carry
bool z; //zero
bool i; //interrupt disable
bool d; //decimal mode
bool b; //break
bool t; //memory operation
bool v; //overflow
bool n; //negative
inline operator uint8() const {
return c << 0 | z << 1 | i << 2 | d << 3 | b << 4 | t << 5 | v << 6 | n << 7;
}
inline auto& operator=(uint8 data) {
c = data.bit(0);
z = data.bit(1);
i = data.bit(2);
d = data.bit(3);
b = data.bit(4);
t = data.bit(5);
v = data.bit(6);
n = data.bit(7);
return *this;
}
};
struct Registers {
uint8 a;
uint8 x;
uint8 y;
uint8 s;
uint16 pc;
uint8 mpr[8];
uint8 mdr;
Flags p;
uint8 cs; //code speed (3 = fast, 12 = slow)
} r;
};
}

View File

@ -1,292 +0,0 @@
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
#define fp(name) &HuC6280::algorithm##name
auto HuC6280::interrupt(uint16 vector) -> void {
io();
io();
push(PC >> 8);
push(PC >> 0);
push(P);
D = 0;
I = 1;
PC.byte(0) = load16(vector + 0);
L PC.byte(1) = load16(vector + 1);
}
auto HuC6280::instruction() -> void {
auto code = opcode();
if(T) {
T = 0;
switch(code) {
op(0x09, Memory, fp(ORA))
op(0x29, Memory, fp(AND))
op(0x49, Memory, fp(EOR))
op(0x69, Memory, fp(ADC))
}
}
#define U
switch(code) {
op(0x00, Break)
op(0x01, IndirectRead, fp(ORA), A, X)
op(0x02, Swap, X, Y)
op(0x03, StoreImplied, 0)
op(0x04, ZeroPageModify, fp(TSB))
op(0x05, ZeroPageRead, fp(ORA), A)
op(0x06, ZeroPageModify, fp(ASL))
op(0x07, ResetMemoryBit, 0)
op(0x08, Push, P)
op(0x09, Immediate, fp(ORA), A)
op(0x0a, Implied, fp(ASL), A)
U op(0x0b, NoOperation)
op(0x0c, AbsoluteModify, fp(TSB))
op(0x0d, AbsoluteRead, fp(ORA), A)
op(0x0e, AbsoluteModify, fp(ASL))
op(0x0f, BranchIfBitReset, 0)
op(0x10, Branch, N == 0)
op(0x11, IndirectYRead, fp(ORA), A)
op(0x12, IndirectRead, fp(ORA), A)
op(0x13, StoreImplied, 1)
op(0x14, ZeroPageModify, fp(TRB))
op(0x15, ZeroPageRead, fp(ORA), A, X)
op(0x16, ZeroPageModify, fp(ASL), X)
op(0x17, ResetMemoryBit, 1)
op(0x18, Clear, C)
op(0x19, AbsoluteRead, fp(ORA), A, Y)
op(0x1a, Implied, fp(INC), A)
U op(0x1b, NoOperation)
op(0x1c, AbsoluteModify, fp(TRB))
op(0x1d, AbsoluteRead, fp(ORA), A, X)
op(0x1e, AbsoluteModify, fp(ASL), X)
op(0x1f, BranchIfBitReset, 1)
op(0x20, CallAbsolute)
op(0x21, IndirectRead, fp(AND), A, X)
op(0x22, Swap, A, X)
op(0x23, StoreImplied, 2)
op(0x24, ZeroPageRead, fp(BIT), A)
op(0x25, ZeroPageRead, fp(AND), A)
op(0x26, ZeroPageModify, fp(ROL))
op(0x27, ResetMemoryBit, 2)
op(0x28, PullP)
op(0x29, Immediate, fp(AND), A)
op(0x2a, Implied, fp(ROL), A)
U op(0x2b, NoOperation)
op(0x2c, AbsoluteRead, fp(BIT), A)
op(0x2d, AbsoluteRead, fp(AND), A)
op(0x2e, AbsoluteModify, fp(ROL))
op(0x2f, BranchIfBitReset, 2)
op(0x30, Branch, N == 1)
op(0x31, IndirectYRead, fp(AND), A)
op(0x32, IndirectRead, fp(AND), A)
U op(0x33, NoOperation)
op(0x34, ZeroPageRead, fp(BIT), A, X)
op(0x35, ZeroPageRead, fp(AND), A, X)
op(0x36, ZeroPageModify, fp(ROL), X)
op(0x37, ResetMemoryBit, 3)
op(0x38, Set, C)
op(0x39, AbsoluteRead, fp(AND), A, Y)
op(0x3a, Implied, fp(DEC), A)
U op(0x3b, NoOperation)
op(0x3c, AbsoluteRead, fp(BIT), A, X)
op(0x3d, AbsoluteRead, fp(AND), A, X)
op(0x3e, AbsoluteModify, fp(ROL), X)
op(0x3f, BranchIfBitReset, 3)
op(0x40, ReturnInterrupt)
op(0x41, IndirectRead, fp(EOR), A, X)
op(0x42, Swap, A, Y)
op(0x43, TransferMPRToAccumulator)
op(0x44, BranchSubroutine)
op(0x45, ZeroPageRead, fp(EOR), A)
op(0x46, ZeroPageModify, fp(LSR))
op(0x47, ResetMemoryBit, 4)
op(0x48, Push, A)
op(0x49, Immediate, fp(EOR), A)
op(0x4a, Implied, fp(LSR), A)
U op(0x4b, NoOperation)
op(0x4c, JumpAbsolute)
op(0x4d, AbsoluteRead, fp(EOR), A)
op(0x4e, AbsoluteModify, fp(LSR))
op(0x4f, BranchIfBitReset, 4)
op(0x50, Branch, V == 0)
op(0x51, IndirectYRead, fp(EOR), A)
op(0x52, IndirectRead, fp(EOR), A)
op(0x53, TransferAccumulatorToMPR)
op(0x54, ChangeSpeedLow)
op(0x55, ZeroPageRead, fp(EOR), A, X)
op(0x56, ZeroPageModify, fp(LSR), X)
op(0x57, ResetMemoryBit, 5)
op(0x58, Clear, I)
op(0x59, AbsoluteRead, fp(EOR), A, Y)
op(0x5a, Push, Y)
U op(0x5b, NoOperation)
U op(0x5c, NoOperation)
op(0x5d, AbsoluteRead, fp(EOR), A, X)
op(0x5e, AbsoluteModify, fp(LSR), X)
op(0x5f, BranchIfBitReset, 5)
op(0x60, ReturnSubroutine)
op(0x61, IndirectRead, fp(ADC), A, X)
op(0x62, Clear, A)
U op(0x63, NoOperation)
op(0x64, ZeroPageWrite, 0)
op(0x65, ZeroPageRead, fp(ADC), A)
op(0x66, ZeroPageModify, fp(ROR))
op(0x67, ResetMemoryBit, 6)
op(0x68, Pull, A)
op(0x69, Immediate, fp(ADC), A)
op(0x6a, Implied, fp(ROR), A)
U op(0x6b, NoOperation)
op(0x6c, JumpIndirect)
op(0x6d, AbsoluteRead, fp(ADC), A)
op(0x6e, AbsoluteModify, fp(ROR))
op(0x6f, BranchIfBitReset, 6)
op(0x70, Branch, V == 1)
op(0x71, IndirectYRead, fp(ADC), A)
op(0x72, IndirectRead, fp(ADC), A)
op(0x73, BlockMove, fp(TII))
op(0x74, ZeroPageWrite, 0, X)
op(0x75, ZeroPageRead, fp(ADC), A, X)
op(0x76, ZeroPageModify, fp(ROR), X)
op(0x77, ResetMemoryBit, 7)
op(0x78, Set, I)
op(0x79, AbsoluteRead, fp(ADC), A, Y)
op(0x7a, Pull, Y)
U op(0x7b, NoOperation)
op(0x7c, JumpIndirect, X)
op(0x7d, AbsoluteRead, fp(ADC), A, X)
op(0x7e, AbsoluteModify, fp(ROR), X)
op(0x7f, BranchIfBitReset, 7)
op(0x80, Branch, 1)
op(0x81, IndirectWrite, A, X)
op(0x82, Clear, X)
op(0x83, TestZeroPage)
op(0x84, ZeroPageWrite, Y)
op(0x85, ZeroPageWrite, A)
op(0x86, ZeroPageWrite, X)
op(0x87, SetMemoryBit, 0)
op(0x88, Implied, fp(DEC), Y)
op(0x89, Immediate, fp(BIT), A)
op(0x8a, Transfer, X, A)
U op(0x8b, NoOperation)
op(0x8c, AbsoluteWrite, Y)
op(0x8d, AbsoluteWrite, A)
op(0x8e, AbsoluteWrite, X)
op(0x8f, BranchIfBitSet, 0)
op(0x90, Branch, C == 0)
op(0x91, IndirectYWrite, A)
op(0x92, IndirectWrite, A)
op(0x93, TestAbsolute)
op(0x94, ZeroPageWrite, Y, X)
op(0x95, ZeroPageWrite, A, X)
op(0x96, ZeroPageWrite, X, Y)
op(0x97, SetMemoryBit, 1)
op(0x98, Transfer, Y, A)
op(0x99, AbsoluteWrite, A, Y)
op(0x9a, TransferXS)
U op(0x9b, NoOperation)
op(0x9c, AbsoluteWrite, 0)
op(0x9d, AbsoluteWrite, A, X)
op(0x9e, AbsoluteWrite, 0, X)
op(0x9f, BranchIfBitSet, 1)
op(0xa0, Immediate, fp(LD), Y)
op(0xa1, IndirectRead, fp(LD), A, X)
op(0xa2, Immediate, fp(LD), X)
op(0xa3, TestZeroPage, X)
op(0xa4, ZeroPageRead, fp(LD), Y)
op(0xa5, ZeroPageRead, fp(LD), A)
op(0xa6, ZeroPageRead, fp(LD), X)
op(0xa7, SetMemoryBit, 2)
op(0xa8, Transfer, A, Y)
op(0xa9, Immediate, fp(LD), A)
op(0xaa, Transfer, A, X)
U op(0xab, NoOperation)
op(0xac, AbsoluteRead, fp(LD), Y)
op(0xad, AbsoluteRead, fp(LD), A)
op(0xae, AbsoluteRead, fp(LD), X)
op(0xaf, BranchIfBitSet, 2)
op(0xb0, Branch, C == 1)
op(0xb1, IndirectYRead, fp(LD), A)
op(0xb2, IndirectRead, fp(LD), A)
op(0xb3, TestAbsolute, X)
op(0xb4, ZeroPageRead, fp(LD), Y, X)
op(0xb5, ZeroPageRead, fp(LD), A, X)
op(0xb6, ZeroPageRead, fp(LD), X, Y)
op(0xb7, SetMemoryBit, 3)
op(0xb8, Clear, V)
op(0xb9, AbsoluteRead, fp(LD), A, Y)
op(0xba, Transfer, S, X)
U op(0xbb, NoOperation)
op(0xbc, AbsoluteRead, fp(LD), Y, X)
op(0xbd, AbsoluteRead, fp(LD), A, X)
op(0xbe, AbsoluteRead, fp(LD), X, Y)
op(0xbf, BranchIfBitSet, 3)
op(0xc0, Immediate, fp(CPY), Y)
op(0xc1, IndirectRead, fp(CMP), A, X)
op(0xc2, Clear, Y)
op(0xc3, BlockMove, fp(TDD))
op(0xc4, ZeroPageRead, fp(CPY), Y)
op(0xc5, ZeroPageRead, fp(CMP), A)
op(0xc6, ZeroPageModify, fp(DEC))
op(0xc7, SetMemoryBit, 4)
op(0xc8, Implied, fp(INC), Y)
op(0xc9, Immediate, fp(CMP), A)
op(0xca, Implied, fp(DEC), X)
U op(0xcb, NoOperation)
op(0xcc, AbsoluteRead, fp(CPY), Y)
op(0xcd, AbsoluteRead, fp(CMP), A)
op(0xce, AbsoluteModify, fp(DEC))
op(0xcf, BranchIfBitSet, 4)
op(0xd0, Branch, Z == 0)
op(0xd1, IndirectYRead, fp(CMP), A)
op(0xd2, IndirectRead, fp(CMP), A)
op(0xd3, BlockMove, fp(TIN))
op(0xd4, ChangeSpeedHigh)
op(0xd5, ZeroPageRead, fp(CMP), A, X)
op(0xd6, ZeroPageModify, fp(DEC), X)
op(0xd7, SetMemoryBit, 5)
op(0xd8, Clear, D)
op(0xd9, AbsoluteRead, fp(CMP), A, Y)
op(0xda, Push, X)
U op(0xdb, NoOperation)
U op(0xdc, NoOperation)
op(0xdd, AbsoluteRead, fp(CMP), A, X)
op(0xde, AbsoluteModify, fp(DEC), X)
op(0xdf, BranchIfBitSet, 5)
op(0xe0, Immediate, fp(CPX), X)
op(0xe1, IndirectRead, fp(SBC), A, X)
U op(0xe2, NoOperation)
op(0xe3, BlockMove, fp(TIA))
op(0xe4, ZeroPageRead, fp(CPX), X)
op(0xe5, ZeroPageRead, fp(SBC), A)
op(0xe6, ZeroPageModify, fp(INC))
op(0xe7, SetMemoryBit, 6)
op(0xe8, Implied, fp(INC), X)
op(0xe9, Immediate, fp(SBC), A)
op(0xea, NoOperation)
U op(0xeb, NoOperation)
op(0xec, AbsoluteRead, fp(CPX), X)
op(0xed, AbsoluteRead, fp(SBC), A)
op(0xee, AbsoluteModify, fp(INC))
op(0xef, BranchIfBitSet, 6)
op(0xf0, Branch, Z == 1)
op(0xf1, IndirectYRead, fp(SBC), A)
op(0xf2, IndirectRead, fp(SBC), A)
op(0xf3, BlockMove, fp(TAI))
op(0xf4, Set, T)
op(0xf5, ZeroPageRead, fp(SBC), A, X)
op(0xf6, ZeroPageModify, fp(INC), X)
op(0xf7, SetMemoryBit, 7)
op(0xf8, Set, D)
op(0xf9, AbsoluteRead, fp(SBC), A, Y)
op(0xfa, Pull, X)
U op(0xfb, NoOperation)
U op(0xfc, NoOperation)
op(0xfd, AbsoluteRead, fp(SBC), A, X)
op(0xfe, AbsoluteModify, fp(INC), X)
op(0xff, BranchIfBitSet, 7)
}
#undef U
}
#undef op
#undef fp

View File

@ -1,362 +0,0 @@
auto HuC6280::instructionAbsoluteModify(fp alu, uint8 index) -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
io();
io();
auto data = ALU(load16(absolute + index));
L store16(absolute + index, data);
}
auto HuC6280::instructionAbsoluteRead(fp alu, uint8& data, uint8 index) -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
io();
L data = ALU(load16(absolute + index));
}
auto HuC6280::instructionAbsoluteWrite(uint8 data, uint8 index) -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
io();
L store16(absolute + index, data);
}
auto HuC6280::instructionBlockMove(bp alu) -> void {
uint16 source = operand();
source |= operand() << 8;
uint16 target = operand();
target |= operand() << 8;
uint16 length = operand();
length |= operand() << 8;
push(Y);
push(A);
push(X);
io();
io();
io();
io();
bool alternate = 0;
do {
auto data = load16(source);
store16(target, data);
ALU(source, target, alternate);
alternate ^= 1;
io();
io();
io();
io();
} while(--length);
X = pull();
A = pull();
L Y = pull();
}
auto HuC6280::instructionBranch(bool take) -> void {
if(!take) {
L operand();
} else {
auto displacement = operand();
io();
L io();
PC += (int8)displacement;
}
}
auto HuC6280::instructionBranchIfBitReset(uint3 index) -> void {
auto zeropage = operand();
auto displacement = operand();
io();
io();
L auto data = load8(zeropage);
if(data.bit(index) == 0) {
PC += (int8)displacement;
}
}
auto HuC6280::instructionBranchIfBitSet(uint3 index) -> void {
auto zeropage = operand();
auto displacement = operand();
io();
io();
L auto data = load8(zeropage);
if(data.bit(index) == 1) {
PC += (int8)displacement;
}
}
auto HuC6280::instructionBranchSubroutine() -> void {
auto displacement = operand();
io();
io();
io();
io();
push((PC - 1) >> 8);
L push((PC - 1) >> 0);
PC += (int8)displacement;
}
auto HuC6280::instructionBreak() -> void {
operand();
io();
push(PC >> 8);
push(PC >> 0);
uint8 p = P;
push(p | 0x10); //B flag set on push
D = 0;
I = 1;
PC.byte(0) = load16(0xfff6);
L PC.byte(1) = load16(0xfff7);
}
auto HuC6280::instructionCallAbsolute() -> void {
uint16 address = operand();
address |= operand() << 8;
io();
io();
push((PC - 1) >> 8);
L push((PC - 1) >> 0);
PC = address;
}
auto HuC6280::instructionChangeSpeedLow() -> void {
L io();
r.cs = 4;
}
auto HuC6280::instructionChangeSpeedHigh() -> void {
L io();
r.cs = 1;
}
auto HuC6280::instructionClear(uint8& data) -> void {
L io();
data = 0;
}
auto HuC6280::instructionClear(bool& flag) -> void {
L io();
flag = 0;
}
auto HuC6280::instructionImmediate(fp alu, uint8& data) -> void {
L io();
data = ALU(operand());
}
auto HuC6280::instructionImplied(fp alu, uint8& data) -> void {
L io();
data = ALU(data);
}
auto HuC6280::instructionIndirectRead(fp alu, uint8& data, uint8 index) -> void {
auto zeropage = operand();
io();
uint16 absolute = load8(zeropage + index + 0);
absolute |= load8(zeropage + index + 1) << 8;
io();
L data = ALU(load16(absolute));
}
auto HuC6280::instructionIndirectWrite(uint8 data, uint8 index) -> void {
auto zeropage = operand();
io();
uint16 absolute = load8(zeropage + index + 0);
absolute |= load8(zeropage + index + 1) << 8;
L store16(absolute, data);
}
auto HuC6280::instructionIndirectYRead(fp alu, uint8& data) -> void {
auto zeropage = operand();
io();
uint16 absolute = load8(zeropage + 0);
absolute |= load8(zeropage + 1) << 8;
io();
L data = ALU(load16(absolute + Y));
}
auto HuC6280::instructionIndirectYWrite(uint8 data) -> void {
auto zeropage = operand();
io();
uint16 absolute = load8(zeropage + 0);
absolute |= load8(zeropage + 1) << 8;
L store16(absolute + Y, data);
}
auto HuC6280::instructionJumpAbsolute() -> void {
uint16 address = operand();
address |= operand() << 8;
L io();
PC = address;
}
auto HuC6280::instructionJumpIndirect(uint8 index) -> void {
uint16 address = operand();
address |= operand() << 8;
io();
io();
PC.byte(0) = load16(address + index + 0);
L PC.byte(1) = load16(address + index + 1);
}
auto HuC6280::instructionMemory(fp alu) -> void {
auto a = A;
A = ALU(load8(X));
L store8(X, A);
A = a;
}
auto HuC6280::instructionNoOperation() -> void {
L io();
}
auto HuC6280::instructionPull(uint8& data) -> void {
io();
io();
L data = pull();
Z = data == 0;
N = data.bit(7);
}
auto HuC6280::instructionPullP() -> void {
io();
io();
L P = pull();
}
auto HuC6280::instructionPush(uint8 data) -> void {
io();
L push(data);
}
auto HuC6280::instructionResetMemoryBit(uint3 index) -> void {
auto zeropage = operand();
io();
io();
io();
auto data = load8(zeropage);
data.bit(index) = 0;
L store8(zeropage, data);
}
auto HuC6280::instructionReturnInterrupt() -> void {
io();
io();
io();
P = pull();
PC.byte(0) = pull();
L PC.byte(1) = pull();
}
auto HuC6280::instructionReturnSubroutine() -> void {
io();
io();
io();
PC.byte(0) = pull();
PC.byte(1) = pull();
L io();
PC++;
}
auto HuC6280::instructionSet(bool& flag) -> void {
L io();
flag = 1;
}
auto HuC6280::instructionSetMemoryBit(uint3 index) -> void {
auto zeropage = operand();
io();
io();
io();
auto data = load8(zeropage);
data.bit(index) = 1;
L store8(zeropage, data);
}
auto HuC6280::instructionStoreImplied(uint2 index) -> void {
auto data = operand();
io();
io();
L store(index, data);
}
auto HuC6280::instructionSwap(uint8& lhs, uint8& rhs) -> void {
io();
L io();
swap(lhs, rhs);
}
auto HuC6280::instructionTestAbsolute(uint8 index) -> void {
auto mask = operand();
uint16 absolute = operand();
absolute |= operand() << 8;
io();
io();
io();
L uint8 data = load16(absolute + index);
Z = (data & mask) == 0;
V = data.bit(6);
N = data.bit(7);
}
auto HuC6280::instructionTestZeroPage(uint8 index) -> void {
auto mask = operand();
auto zeropage = operand();
io();
io();
io();
L uint8 data = load8(zeropage + index);
Z = (data & mask) == 0;
V = data.bit(6);
N = data.bit(7);
}
auto HuC6280::instructionTransfer(uint8& source, uint8& target) -> void {
L io();
target = source;
Z = target == 0;
N = target.bit(7);
}
auto HuC6280::instructionTransferAccumulatorToMPR() -> void {
auto mask = operand();
io();
io();
L io();
for(uint index : range(8)) {
if(mask.bit(index)) r.mpr[index] = A;
}
}
auto HuC6280::instructionTransferMPRToAccumulator() -> void {
auto mask = operand();
io();
L io();
for(uint index : range(8)) {
if(mask.bit(index)) { A = r.mpr[index]; break; }
}
}
auto HuC6280::instructionTransferXS() -> void {
L io();
S = X;
}
auto HuC6280::instructionZeroPageModify(fp alu, uint8 index) -> void {
auto zeropage = operand();
io();
io();
auto data = ALU(load8(zeropage + index));
L store8(zeropage + index, data);
}
auto HuC6280::instructionZeroPageRead(fp alu, uint8& data, uint8 index) -> void {
auto zeropage = operand();
io();
L data = ALU(load8(zeropage + index));
}
auto HuC6280::instructionZeroPageWrite(uint8 data, uint8 index) -> void {
auto zeropage = operand();
io();
L store8(zeropage + index, data);
}

View File

@ -1,47 +0,0 @@
auto HuC6280::load8(uint8 addr) -> uint8 {
step(r.cs);
return read(r.mpr[1], addr);
}
auto HuC6280::load16(uint16 addr) -> uint8 {
step(r.cs);
return read(r.mpr[addr.bits(13,15)], addr.bits(0,12));
}
auto HuC6280::store8(uint8 addr, uint8 data) -> void {
step(r.cs);
return write(r.mpr[1], addr, data);
}
auto HuC6280::store16(uint16 addr, uint8 data) -> void {
step(r.cs);
return write(r.mpr[addr.bits(13,15)], addr.bits(0,12), data);
}
//
auto HuC6280::io() -> void {
step(r.cs);
}
auto HuC6280::opcode() -> uint8 {
return load16(PC++);
}
auto HuC6280::operand() -> uint8 {
return load16(PC++);
}
//
auto HuC6280::push(uint8 data) -> void {
step(r.cs);
write(r.mpr[1], 0x0100 | S, data);
S--;
}
auto HuC6280::pull() -> uint8 {
step(r.cs);
S++;
return read(r.mpr[1], 0x0100 | S);
}

View File

@ -1,18 +0,0 @@
auto HuC6280::serialize(serializer& s) -> void {
s.integer(r.a);
s.integer(r.x);
s.integer(r.y);
s.integer(r.s);
s.integer(r.pc);
s.array(r.mpr);
s.integer(r.mdr);
s.integer(r.p.c);
s.integer(r.p.z);
s.integer(r.p.i);
s.integer(r.p.d);
s.integer(r.p.b);
s.integer(r.p.t);
s.integer(r.p.v);
s.integer(r.p.n);
s.integer(r.cs);
}

View File

@ -1,588 +0,0 @@
template<> auto M68K::_read<Byte>(uint32 addr) -> uint32 {
return bus->readByte(addr);
}
template<> auto M68K::_read<Word>(uint32 addr) -> uint32 {
return bus->readWord(addr);
}
template<> auto M68K::_read<Long>(uint32 addr) -> uint32 {
uint32 data = _read<Word>(addr + 0) << 16;
return data | _read<Word>(addr + 2) << 0;
}
template<uint Size> auto M68K::_readPC() -> uint32 {
auto data = _read<Size == Byte ? Word : Size>(_pc);
_pc += Size == Long ? 4 : 2;
return clip<Size>(data);
}
auto M68K::_readDisplacement(uint32 base) -> uint32 {
return base + (int16)_readPC<Word>();
}
auto M68K::_readIndex(uint32 base) -> uint32 {
auto extension = _readPC<Word>();
auto index = extension & 0x8000
? read(AddressRegister{extension >> 12})
: read(DataRegister{extension >> 12});
if(extension & 0x800) index = (int16)index;
return base + index + (int8)extension;
}
auto M68K::_dataRegister(DataRegister dr) -> string {
return {"d", dr.number};
}
auto M68K::_addressRegister(AddressRegister ar) -> string {
return {"a", ar.number};
}
template<uint Size> auto M68K::_immediate() -> string {
return {"#$", hex(_readPC<Size>(), 2 << Size)};
}
template<uint Size> auto M68K::_address(EffectiveAddress& ea) -> string {
if(ea.mode == 7) return {"$", hex((int16)_readPC<Word>(), 6L)};
if(ea.mode == 8) return {"$", hex(_readPC<Long>(), 6L)};
if(ea.mode == 9) return {"$", hex(_pc + (int16)_readPC(), 6L)};
return "???";
}
template<uint Size> auto M68K::_effectiveAddress(EffectiveAddress& ea) -> string {
if(ea.mode == 0) return {_dataRegister(DataRegister{ea.reg})};
if(ea.mode == 1) return {_addressRegister(AddressRegister{ea.reg})};
if(ea.mode == 2) return {"(", _addressRegister(AddressRegister{ea.reg}), ")"};
if(ea.mode == 3) return {"(", _addressRegister(AddressRegister{ea.reg}), ")+"};
if(ea.mode == 4) return {"-(", _addressRegister(AddressRegister{ea.reg}), ")"};
if(ea.mode == 5) return {"($", hex(_readDisplacement(read(AddressRegister{ea.reg})), 6L), ")"};
if(ea.mode == 6) return {"($", hex(_readIndex(read(AddressRegister{ea.reg})), 6L), ")"};
if(ea.mode == 7) return {"($", hex((int16)_readPC<Word>(), 6L), ")"};
if(ea.mode == 8) return {"($", hex(_readPC<Long>(), 6L), ")"};
if(ea.mode == 9) return {"($", hex(_readDisplacement(_pc), 6L), ")"};
if(ea.mode == 10) return {"($", hex(_readIndex(_pc), 6L), ")"};
if(ea.mode == 11) return {"#$", hex(_readPC<Size>(), 2 << Size)};
return "???"; //should never occur
}
auto M68K::_branch(uint8 displacement) -> string {
uint16 extension = _readPC();
_pc -= 2;
int32 offset = displacement ? sign<Byte>(displacement) : sign<Word>(extension);
return {"$", hex(_pc + offset, 6L)};
}
template<uint Size> auto M68K::_suffix() -> string {
return Size == Byte ? ".b" : Size == Word ? ".w" : ".l";
}
auto M68K::_condition(uint4 condition) -> string {
static const string conditions[16] = {
"t ", "f ", "hi", "ls", "cc", "cs", "ne", "eq",
"vc", "vs", "pl", "mi", "ge", "lt", "gt", "le",
};
return conditions[condition];
}
auto M68K::disassemble(uint32 pc) -> string {
uint16 opcode;
return {hex(_pc = pc, 6L), " ", hex(opcode = _readPC(), 4L), " ", disassembleTable[opcode]()};
}
auto M68K::disassembleRegisters() -> string {
return {
hex(r.d[0], 8L), " ", hex(r.d[1], 8L), " ", hex(r.d[2], 8L), " ", hex(r.d[3], 8L), " ",
hex(r.d[4], 8L), " ", hex(r.d[5], 8L), " ", hex(r.d[6], 8L), " ", hex(r.d[7], 8L), " ",
r.t ? "T" : "t",
r.s ? "S" : "s",
(uint)r.i,
r.c ? "C" : "c",
r.v ? "V" : "v",
r.z ? "Z" : "z",
r.n ? "N" : "n",
r.x ? "X" : "x", "\n",
hex(r.a[0], 8L), " ", hex(r.a[1], 8L), " ", hex(r.a[2], 8L), " ", hex(r.a[3], 8L), " ",
hex(r.a[4], 8L), " ", hex(r.a[5], 8L), " ", hex(r.a[6], 8L), " ", hex(r.a[7], 8L), " ", hex(r.sp, 8L)
};
}
//
auto M68K::disassembleABCD(EffectiveAddress with, EffectiveAddress from) -> string {
return {"abcd ", _effectiveAddress<Byte>(from), ",", _effectiveAddress<Byte>(with)};
}
template<uint Size> auto M68K::disassembleADD(EffectiveAddress from, DataRegister with) -> string {
return {"add", _suffix<Size>(), " ", _effectiveAddress<Size>(from), ",", _dataRegister(with)};
}
template<uint Size> auto M68K::disassembleADD(DataRegister from, EffectiveAddress with) -> string {
return {"add", _suffix<Size>(), " ", _dataRegister(from), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleADDA(AddressRegister ar, EffectiveAddress ea) -> string {
return {"adda", _suffix<Size>(), " ", _effectiveAddress<Size>(ea), ",", _addressRegister(ar)};
}
template<uint Size> auto M68K::disassembleADDI(EffectiveAddress ea) -> string {
return {"addi", _suffix<Size>(), " ", _immediate<Size>(), ",", _effectiveAddress<Size>(ea)};
}
template<uint Size> auto M68K::disassembleADDQ(uint4 immediate, EffectiveAddress with) -> string {
return {"addq", _suffix<Size>(), " #", immediate, ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleADDQ(uint4 immediate, AddressRegister with) -> string {
return {"addq", _suffix<Size>(), " #", immediate, ",", _addressRegister(with)};
}
template<uint Size> auto M68K::disassembleADDX(EffectiveAddress with, EffectiveAddress from) -> string {
return {"addx", _suffix<Size>(), " ", _effectiveAddress<Size>(from), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleAND(EffectiveAddress from, DataRegister with) -> string {
return {"and", _suffix<Size>(), " ", _effectiveAddress<Size>(from), ",", _dataRegister(with)};
}
template<uint Size> auto M68K::disassembleAND(DataRegister from, EffectiveAddress with) -> string {
return {"and", _suffix<Size>(), " ", _dataRegister(from), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleANDI(EffectiveAddress ea) -> string {
return {"andi", _suffix<Size>(), " ", _immediate<Size>(), ",", _effectiveAddress<Size>(ea)};
}
auto M68K::disassembleANDI_TO_CCR() -> string {
return {"andi ", _immediate<Byte>(), ",ccr"};
}
auto M68K::disassembleANDI_TO_SR() -> string {
return {"andi ", _immediate<Word>(), ",sr"};
}
template<uint Size> auto M68K::disassembleASL(uint4 shift, DataRegister modify) -> string {
return {"asl", _suffix<Size>(), " #", shift, ",", _dataRegister(modify)};
}
template<uint Size> auto M68K::disassembleASL(DataRegister shift, DataRegister modify) -> string {
return {"asl", _suffix<Size>(), " ", _dataRegister(shift), ",", _dataRegister(modify)};
}
auto M68K::disassembleASL(EffectiveAddress modify) -> string {
return {"asl", _suffix<Word>(), " ", _effectiveAddress<Word>(modify)};
}
template<uint Size> auto M68K::disassembleASR(uint4 shift, DataRegister modify) -> string {
return {"asr", _suffix<Size>(), " #", shift, ",", _dataRegister(modify)};
}
template<uint Size> auto M68K::disassembleASR(DataRegister shift, DataRegister modify) -> string {
return {"asr", _suffix<Size>(), " ", _dataRegister(shift), ",", _dataRegister(modify)};
}
auto M68K::disassembleASR(EffectiveAddress modify) -> string {
return {"asr", _suffix<Word>(), " ", _effectiveAddress<Word>(modify)};
}
auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string {
auto cc = _condition(condition);
if(condition == 0) cc = "ra";
if(condition == 1) cc = "sr";
return {"b", cc, " ", _branch(displacement)};
}
template<uint Size> auto M68K::disassembleBCHG(DataRegister bit, EffectiveAddress with) -> string {
return {"bchg", _suffix<Size>(), " ", _dataRegister(bit), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleBCHG(EffectiveAddress with) -> string {
return {"bchg", _suffix<Size>(), " ", _immediate<Byte>(), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleBCLR(DataRegister bit, EffectiveAddress with) -> string {
return {"bclr", _suffix<Size>(), " ", _dataRegister(bit), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleBCLR(EffectiveAddress with) -> string {
return {"bclr", _suffix<Size>(), " ", _immediate<Byte>(), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleBSET(DataRegister bit, EffectiveAddress with) -> string {
return {"bset", _suffix<Size>(), " ", _dataRegister(bit), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleBSET(EffectiveAddress with) -> string {
return {"bset", _suffix<Size>(), " ", _immediate<Byte>(), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleBTST(DataRegister bit, EffectiveAddress with) -> string {
return {"btst", _suffix<Size>(), " ", _dataRegister(bit), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleBTST(EffectiveAddress with) -> string {
return {"btst", _suffix<Size>(), " ", _immediate<Byte>(), ",", _effectiveAddress<Size>(with)};
}
auto M68K::disassembleCHK(DataRegister compare, EffectiveAddress maximum) -> string {
return {"chk", _suffix<Word>(), " ", _effectiveAddress<Word>(maximum), ",", _dataRegister(compare)};
}
template<uint Size> auto M68K::disassembleCLR(EffectiveAddress ea) -> string {
return {"clr", _suffix<Size>(), " ", _effectiveAddress<Size>(ea)};
}
template<uint Size> auto M68K::disassembleCMP(DataRegister dr, EffectiveAddress ea) -> string {
return {"cmp", _suffix<Size>(), " ", _effectiveAddress<Size>(ea), ",", _dataRegister(dr)};
}
template<uint Size> auto M68K::disassembleCMPA(AddressRegister ar, EffectiveAddress ea) -> string {
return {"cmpa", _suffix<Size>(), " ", _effectiveAddress<Size>(ea), ",", _addressRegister(ar)};
}
template<uint Size> auto M68K::disassembleCMPI(EffectiveAddress ea) -> string {
return {"cmpi", _suffix<Size>(), " ", _immediate<Size>(), ",", _effectiveAddress<Size>(ea)};
}
template<uint Size> auto M68K::disassembleCMPM(EffectiveAddress ax, EffectiveAddress ay) -> string {
return {"cmpm", _suffix<Size>(), " ", _effectiveAddress<Size>(ay), ",", _effectiveAddress<Size>(ax)};
}
auto M68K::disassembleDBCC(uint4 condition, DataRegister dr) -> string {
auto base = _pc;
auto displacement = (int16)_readPC();
return {"db", _condition(condition), " ", _dataRegister(dr), ",$", hex(base + displacement, 6L)};
}
auto M68K::disassembleDIVS(DataRegister with, EffectiveAddress from) -> string {
return {"divs", _suffix<Word>(), " ", _effectiveAddress<Word>(from), ",", _dataRegister(with)};
}
auto M68K::disassembleDIVU(DataRegister with, EffectiveAddress from) -> string {
return {"divu", _suffix<Word>(), " ", _effectiveAddress<Word>(from), ",", _dataRegister(with)};
}
template<uint Size> auto M68K::disassembleEOR(DataRegister from, EffectiveAddress with) -> string {
return {"eor", _suffix<Size>(), " ", _dataRegister(from), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleEORI(EffectiveAddress with) -> string {
return {"eori", _suffix<Size>(), " ", _immediate<Size>(), ",", _effectiveAddress<Size>(with)};
}
auto M68K::disassembleEORI_TO_CCR() -> string {
return {"eori ", _immediate<Byte>(), ",ccr"};
}
auto M68K::disassembleEORI_TO_SR() -> string {
return {"eori ", _immediate<Word>(), ",sr"};
}
auto M68K::disassembleEXG(DataRegister x, DataRegister y) -> string {
return {"exg ", _dataRegister(x), ",", _dataRegister(y)};
}
auto M68K::disassembleEXG(AddressRegister x, AddressRegister y) -> string {
return {"exg ", _addressRegister(x), ",", _addressRegister(y)};
}
auto M68K::disassembleEXG(DataRegister x, AddressRegister y) -> string {
return {"exg ", _dataRegister(x), ",", _addressRegister(y)};
}
template<uint Size> auto M68K::disassembleEXT(DataRegister with) -> string {
return {"ext", _suffix<Size>(), " ", _dataRegister(with)};
}
auto M68K::disassembleILLEGAL(uint16 code) -> string {
if(code.bits(12,15) == 0xa) return {"linea $", hex(code.bits(0,11), 3L)};
if(code.bits(12,15) == 0xf) return {"linef $", hex(code.bits(0,11), 3L)};
return {"illegal "};
}
auto M68K::disassembleJMP(EffectiveAddress target) -> string {
return {"jmp ", _effectiveAddress<Long>(target)};
}
auto M68K::disassembleJSR(EffectiveAddress target) -> string {
return {"jsr ", _effectiveAddress<Long>(target)};
}
auto M68K::disassembleLEA(AddressRegister ar, EffectiveAddress ea) -> string {
return {"lea ", _address<Long>(ea), ",", _addressRegister(ar)};
}
auto M68K::disassembleLINK(AddressRegister with) -> string {
return {"link ", _addressRegister(with), ",", _immediate<Word>()};
}
template<uint Size> auto M68K::disassembleLSL(uint4 immediate, DataRegister dr) -> string {
return {"lsl", _suffix<Size>(), " #", immediate, ",", _dataRegister(dr)};
}
template<uint Size> auto M68K::disassembleLSL(DataRegister sr, DataRegister dr) -> string {
return {"lsl", _suffix<Size>(), " ", _dataRegister(sr), ",", _dataRegister(dr)};
}
auto M68K::disassembleLSL(EffectiveAddress ea) -> string {
return {"lsl", _suffix<Word>(), " ", _effectiveAddress<Word>(ea)};
}
template<uint Size> auto M68K::disassembleLSR(uint4 immediate, DataRegister dr) -> string {
return {"lsr", _suffix<Size>(), " #", immediate, ",", _dataRegister(dr)};
}
template<uint Size> auto M68K::disassembleLSR(DataRegister shift, DataRegister dr) -> string {
return {"lsr", _suffix<Size>(), " ", _dataRegister(shift), ",", _dataRegister(dr)};
}
auto M68K::disassembleLSR(EffectiveAddress ea) -> string {
return {"lsr", _suffix<Word>(), " ", _effectiveAddress<Word>(ea)};
}
template<uint Size> auto M68K::disassembleMOVE(EffectiveAddress to, EffectiveAddress from) -> string {
return {"move", _suffix<Size>(), " ", _effectiveAddress<Size>(from), ",", _effectiveAddress<Size>(to)};
}
template<uint Size> auto M68K::disassembleMOVEA(AddressRegister ar, EffectiveAddress ea) -> string {
return {"movea ", _effectiveAddress<Size>(ea), ",", _addressRegister(ar)};
}
template<uint Size> auto M68K::disassembleMOVEM_TO_MEM(EffectiveAddress to) -> string {
string op{"movem", _suffix<Size>(), " "};
uint16 list = _readPC();
string regs;
for(uint n : range(8)) if(list.bit(0 + n)) regs.append(_dataRegister(DataRegister{n}), ",");
regs.trimRight(",");
if(regs && list >> 8) regs.append("/");
for(uint n : range(8)) if(list.bit(8 + n)) regs.append(_addressRegister(AddressRegister{n}), ",");
regs.trimRight(",");
return {op, regs, ",", _effectiveAddress<Size>(to)};
}
template<uint Size> auto M68K::disassembleMOVEM_TO_REG(EffectiveAddress from) -> string {
string op{"movem", _suffix<Size>(), " "};
uint16 list = _readPC();
string regs;
for(uint n : range(8)) if(list.bit(0 + n)) regs.append(_dataRegister(DataRegister{n}), ",");
regs.trimRight(",");
if(regs && list >> 8) regs.append("/");
for(uint n : range(8)) if(list.bit(8 + n)) regs.append(_addressRegister(AddressRegister{n}), ",");
regs.trimRight(",");
return {op, _effectiveAddress<Size>(from), ",", regs};
}
template<uint Size> auto M68K::disassembleMOVEP(DataRegister from, EffectiveAddress to) -> string {
return {"movep", _suffix<Size>(), " ", _dataRegister(from), ",", _effectiveAddress<Size>(to)};
}
template<uint Size> auto M68K::disassembleMOVEP(EffectiveAddress from, DataRegister to) -> string {
return {"movep", _suffix<Size>(), " ", _effectiveAddress<Size>(from), ",", _dataRegister(to)};
}
auto M68K::disassembleMOVEQ(DataRegister dr, uint8 immediate) -> string {
return {"moveq #$", hex(immediate, 2L), ",", _dataRegister(dr)};
}
auto M68K::disassembleMOVE_FROM_SR(EffectiveAddress ea) -> string {
return {"move sr,", _effectiveAddress<Word>(ea)};
}
auto M68K::disassembleMOVE_TO_CCR(EffectiveAddress ea) -> string {
return {"move ", _effectiveAddress<Byte>(ea), ",ccr"};
}
auto M68K::disassembleMOVE_TO_SR(EffectiveAddress ea) -> string {
return {"move ", _effectiveAddress<Word>(ea), ",sr"};
}
auto M68K::disassembleMOVE_FROM_USP(AddressRegister to) -> string {
return {"move usp,", _addressRegister(to)};
}
auto M68K::disassembleMOVE_TO_USP(AddressRegister from) -> string {
return {"move ", _addressRegister(from), ",usp"};
}
auto M68K::disassembleMULS(DataRegister with, EffectiveAddress from) -> string {
return {"muls", _suffix<Word>(), " ", _effectiveAddress<Word>(from), ",", _dataRegister(with)};
}
auto M68K::disassembleMULU(DataRegister with, EffectiveAddress from) -> string {
return {"mulu", _suffix<Word>(), " ", _effectiveAddress<Word>(from), ",", _dataRegister(with)};
}
auto M68K::disassembleNBCD(EffectiveAddress with) -> string {
return {"nbcd ", _effectiveAddress<Byte>(with)};
}
template<uint Size> auto M68K::disassembleNEG(EffectiveAddress with) -> string {
return {"neg", _suffix<Size>(), " ", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleNEGX(EffectiveAddress with) -> string {
return {"negx", _suffix<Size>(), " ", _effectiveAddress<Size>(with)};
}
auto M68K::disassembleNOP() -> string {
return {"nop "};
}
template<uint Size> auto M68K::disassembleNOT(EffectiveAddress with) -> string {
return {"not", _suffix<Size>(), " ", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleOR(EffectiveAddress from, DataRegister with) -> string {
return {"or", _suffix<Size>(), " ", _effectiveAddress<Size>(from), ",", _dataRegister(with)};
}
template<uint Size> auto M68K::disassembleOR(DataRegister from, EffectiveAddress with) -> string {
return {"or", _suffix<Size>(), " ", _dataRegister(from), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleORI(EffectiveAddress with) -> string {
return {"ori", _suffix<Size>(), " ", _immediate<Size>(), ",", _effectiveAddress<Size>(with)};
}
auto M68K::disassembleORI_TO_CCR() -> string {
return {"ori ", _immediate<Byte>(), ",ccr"};
}
auto M68K::disassembleORI_TO_SR() -> string {
return {"ori ", _immediate<Word>(), ",sr"};
}
auto M68K::disassemblePEA(EffectiveAddress from) -> string {
return {"pea ", _effectiveAddress<Long>(from)};
}
auto M68K::disassembleRESET() -> string {
return {"reset "};
}
template<uint Size> auto M68K::disassembleROL(uint4 shift, DataRegister modify) -> string {
return {"rol", _suffix<Size>(), " #", shift, ",", _dataRegister(modify)};
}
template<uint Size> auto M68K::disassembleROL(DataRegister shift, DataRegister modify) -> string {
return {"rol", _suffix<Size>(), " ", _dataRegister(shift), ",", _dataRegister(modify)};
}
auto M68K::disassembleROL(EffectiveAddress modify) -> string {
return {"rol", _suffix<Word>(), " ", _effectiveAddress<Word>(modify)};
}
template<uint Size> auto M68K::disassembleROR(uint4 shift, DataRegister modify) -> string {
return {"ror", _suffix<Size>(), " #", shift, ",", _dataRegister(modify)};
}
template<uint Size> auto M68K::disassembleROR(DataRegister shift, DataRegister modify) -> string {
return {"ror", _suffix<Size>(), " ", _dataRegister(shift) ,",", _dataRegister(modify)};
}
auto M68K::disassembleROR(EffectiveAddress modify) -> string {
return {"ror", _suffix<Word>(), " ", _effectiveAddress<Word>(modify)};
}
template<uint Size> auto M68K::disassembleROXL(uint4 shift, DataRegister modify) -> string {
return {"roxl", _suffix<Size>(), " #", shift, ",", _dataRegister(modify)};
}
template<uint Size> auto M68K::disassembleROXL(DataRegister shift, DataRegister modify) -> string {
return {"roxl", _suffix<Size>(), " ", _dataRegister(shift), ",", _dataRegister(modify)};
}
auto M68K::disassembleROXL(EffectiveAddress modify) -> string {
return {"roxl", _suffix<Word>(), " ", _effectiveAddress<Word>(modify)};
}
template<uint Size> auto M68K::disassembleROXR(uint4 shift, DataRegister modify) -> string {
return {"roxr", _suffix<Size>(), " #", shift, ",", _dataRegister(modify)};
}
template<uint Size> auto M68K::disassembleROXR(DataRegister shift, DataRegister modify) -> string {
return {"roxr", _suffix<Size>(), " ", _dataRegister(shift), ",", _dataRegister(modify)};
}
auto M68K::disassembleROXR(EffectiveAddress modify) -> string {
return {"roxr", _suffix<Word>(), " ", _effectiveAddress<Word>(modify)};
}
auto M68K::disassembleRTE() -> string {
return {"rte "};
}
auto M68K::disassembleRTR() -> string {
return {"rtr "};
}
auto M68K::disassembleRTS() -> string {
return {"rts "};
}
auto M68K::disassembleSBCD(EffectiveAddress with, EffectiveAddress from) -> string {
return {"sbcd ", _effectiveAddress<Byte>(from), ",", _effectiveAddress<Byte>(with)};
}
auto M68K::disassembleSCC(uint4 condition, EffectiveAddress to) -> string {
return {"s", _condition(condition), " ", _effectiveAddress<Byte>(to)};
}
auto M68K::disassembleSTOP() -> string {
return {"stop ", _immediate<Word>()};
}
template<uint Size> auto M68K::disassembleSUB(EffectiveAddress source, DataRegister target) -> string {
return {"sub", _suffix<Size>(), " ", _effectiveAddress<Size>(source), ",", _dataRegister(target)};
}
template<uint Size> auto M68K::disassembleSUB(DataRegister source, EffectiveAddress target) -> string {
return {"sub", _suffix<Size>(), " ", _dataRegister(source), ",", _effectiveAddress<Size>(target)};
}
template<uint Size> auto M68K::disassembleSUBA(AddressRegister to, EffectiveAddress from) -> string {
return {"suba", _suffix<Size>(), " ", _addressRegister(to), ",", _effectiveAddress<Size>(from)};
}
template<uint Size> auto M68K::disassembleSUBI(EffectiveAddress with) -> string {
return {"subi", _suffix<Size>(), " ", _immediate<Size>(), ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleSUBQ(uint4 immediate, EffectiveAddress with) -> string {
return {"subq", _suffix<Size>(), " #", immediate, ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleSUBQ(uint4 immediate, AddressRegister with) -> string {
return {"subq", _suffix<Size>(), " #", immediate, ",", _addressRegister(with)};
}
template<uint Size> auto M68K::disassembleSUBX(EffectiveAddress with, EffectiveAddress from) -> string {
return {"subx", _suffix<Size>(), " ", _effectiveAddress<Size>(from), ",", _effectiveAddress<Size>(with)};
}
auto M68K::disassembleSWAP(DataRegister with) -> string {
return {"swap ", _dataRegister(with)};
}
auto M68K::disassembleTAS(EffectiveAddress with) -> string {
return {"tas ", _effectiveAddress<Byte>(with)};
}
auto M68K::disassembleTRAP(uint4 vector) -> string {
return {"trap #", vector};
}
auto M68K::disassembleTRAPV() -> string {
return {"trapv "};
}
template<uint Size> auto M68K::disassembleTST(EffectiveAddress ea) -> string {
return {"tst", _suffix<Size>(), " ", _effectiveAddress<Size>(ea)};
}
auto M68K::disassembleUNLK(AddressRegister with) -> string {
return {"unlk ", _addressRegister(with)};
}

View File

@ -1,195 +0,0 @@
template<uint Size> auto M68K::fetch(EffectiveAddress& ea) -> uint32 {
if(!ea.valid.raise()) return ea.address;
switch(ea.mode) {
case DataRegisterDirect: {
return read(DataRegister{ea.reg});
}
case AddressRegisterDirect: {
return read(AddressRegister{ea.reg});
}
case AddressRegisterIndirect: {
return read(AddressRegister{ea.reg});
}
case AddressRegisterIndirectWithPostIncrement: {
return read(AddressRegister{ea.reg});
}
case AddressRegisterIndirectWithPreDecrement: {
return read(AddressRegister{ea.reg});
}
case AddressRegisterIndirectWithDisplacement: {
return read(AddressRegister{ea.reg}) + (int16)readPC();
}
case AddressRegisterIndirectWithIndex: {
auto extension = readPC();
auto index = extension & 0x8000
? read(AddressRegister{extension >> 12})
: read(DataRegister{extension >> 12});
if(!(extension & 0x800)) index = (int16)index;
return read(AddressRegister{ea.reg}) + index + (int8)extension;
}
case AbsoluteShortIndirect: {
return (int16)readPC();
}
case AbsoluteLongIndirect: {
return readPC<Long>();
}
case ProgramCounterIndirectWithDisplacement: {
auto base = r.pc;
return base + (int16)readPC();
}
case ProgramCounterIndirectWithIndex: {
auto base = r.pc;
auto extension = readPC();
auto index = extension & 0x8000
? read(AddressRegister{extension >> 12})
: read(DataRegister{extension >> 12});
if(!(extension & 0x800)) index = (int16)index;
return base + index + (int8)extension;
}
case Immediate: {
return readPC<Size>();
}
}
return 0;
}
template<uint Size, bool hold> auto M68K::read(EffectiveAddress& ea) -> uint32 {
ea.address = fetch<Size>(ea);
switch(ea.mode) {
case DataRegisterDirect: {
return clip<Size>(ea.address);
}
case AddressRegisterDirect: {
return sign<Size>(ea.address);
}
case AddressRegisterIndirect: {
return read<Size>(ea.address);
}
case AddressRegisterIndirectWithPostIncrement: {
auto address = ea.address + (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
auto data = read<Size>(ea.address);
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
return data;
}
case AddressRegisterIndirectWithPreDecrement: {
auto address = ea.address - (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
auto data = read<Size>(address);
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
return data;
}
case AddressRegisterIndirectWithDisplacement: {
return read<Size>(ea.address);
}
case AddressRegisterIndirectWithIndex: {
return read<Size>(ea.address);
}
case AbsoluteShortIndirect: {
return read<Size>(ea.address);
}
case AbsoluteLongIndirect: {
return read<Size>(ea.address);
}
case ProgramCounterIndirectWithDisplacement: {
return read<Size>(ea.address);
}
case ProgramCounterIndirectWithIndex: {
return read<Size>(ea.address);
}
case Immediate: {
return clip<Size>(ea.address);
}
}
return 0;
}
template<uint Size, bool hold> auto M68K::write(EffectiveAddress& ea, uint32 data) -> void {
ea.address = fetch<Size>(ea);
switch(ea.mode) {
case DataRegisterDirect: {
return write<Size>(DataRegister{ea.reg}, data);
}
case AddressRegisterDirect: {
return write<Size>(AddressRegister{ea.reg}, data);
}
case AddressRegisterIndirect: {
return write<Size>(ea.address, data);
}
case AddressRegisterIndirectWithPostIncrement: {
auto address = ea.address + (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
write<Size>(ea.address, data);
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
return;
}
case AddressRegisterIndirectWithPreDecrement: {
auto address = ea.address - (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
write<Size, Reverse>(address, data);
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
return;
}
case AddressRegisterIndirectWithDisplacement: {
return write<Size>(ea.address, data);
}
case AddressRegisterIndirectWithIndex: {
return write<Size>(ea.address, data);
}
case AbsoluteShortIndirect: {
return write<Size>(ea.address, data);
}
case AbsoluteLongIndirect: {
return write<Size>(ea.address, data);
}
case ProgramCounterIndirectWithDisplacement: {
return write<Size>(ea.address, data);
}
case ProgramCounterIndirectWithIndex: {
return write<Size>(ea.address, data);
}
case Immediate: {
return;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,61 +0,0 @@
#include <processor/processor.hpp>
#include "m68k.hpp"
namespace Processor {
enum : uint { Byte, Word, Long };
enum : bool { Reverse = 1 };
#include "registers.cpp"
#include "memory.cpp"
#include "effective-address.cpp"
#include "instructions.cpp"
#include "disassembler.cpp"
#include "instruction.cpp"
#include "serialization.cpp"
auto M68K::power() -> void {
for(auto& dr : r.d) dr = 0;
for(auto& ar : r.a) ar = 0;
r.sp = 0;
r.pc = 0;
r.c = 0;
r.v = 0;
r.z = 0;
r.n = 0;
r.x = 0;
r.i = 7;
r.s = 1;
r.t = 0;
r.stop = false;
r.reset = false;
}
auto M68K::supervisor() -> bool {
if(r.s) return true;
r.pc -= 2;
exception(Exception::Unprivileged, Vector::Unprivileged);
return false;
}
auto M68K::exception(uint exception, uint vector, uint priority) -> void {
auto pc = r.pc;
auto sr = readSR();
if(exception != Exception::Illegal) {
if(!r.s) swap(r.a[7], r.sp);
r.i = priority;
r.s = 1;
r.t = 0;
}
push<Long>(pc);
push<Word>(sr);
r.pc = read<Long>(vector << 2);
}
}

View File

@ -1,415 +0,0 @@
#pragma once
//Motorola M68000
namespace Processor {
struct M68K {
struct Bus {
virtual auto readByte(uint24 addr) -> uint16 = 0;
virtual auto readWord(uint24 addr) -> uint16 = 0;
virtual auto writeByte(uint24 addr, uint16 data) -> void = 0;
virtual auto writeWord(uint24 addr, uint16 data) -> void = 0;
};
virtual auto step(uint clocks) -> void = 0;
enum : bool { User, Supervisor };
enum : uint { Byte, Word, Long };
enum : bool { Reverse = 1, Extend = 1, Hold = 1 };
enum : uint {
DataRegisterDirect,
AddressRegisterDirect,
AddressRegisterIndirect,
AddressRegisterIndirectWithPostIncrement,
AddressRegisterIndirectWithPreDecrement,
AddressRegisterIndirectWithDisplacement,
AddressRegisterIndirectWithIndex,
AbsoluteShortIndirect,
AbsoluteLongIndirect,
ProgramCounterIndirectWithDisplacement,
ProgramCounterIndirectWithIndex,
Immediate,
};
struct Exception { enum : uint {
Illegal,
DivisionByZero,
BoundsCheck,
Overflow,
Unprivileged,
Trap,
Interrupt,
};};
struct Vector { enum : uint {
Illegal = 4,
DivisionByZero = 5,
BoundsCheck = 6,
Overflow = 7,
Unprivileged = 8,
IllegalLineA = 10,
IllegalLineF = 11,
HorizontalBlank = 28,
VerticalBlank = 30,
};};
M68K();
auto power() -> void;
auto supervisor() -> bool;
auto exception(uint exception, uint vector, uint priority = 7) -> void;
//registers.cpp
struct DataRegister {
explicit DataRegister(uint64 number_) : number(number_) {}
uint3 number;
};
template<uint Size = Long> auto read(DataRegister reg) -> uint32;
template<uint Size = Long> auto write(DataRegister reg, uint32 data) -> void;
struct AddressRegister {
explicit AddressRegister(uint64 number_) : number(number_) {}
uint3 number;
};
template<uint Size = Long> auto read(AddressRegister reg) -> uint32;
template<uint Size = Long> auto write(AddressRegister reg, uint32 data) -> void;
auto readCCR() -> uint8;
auto readSR() -> uint16;
auto writeCCR(uint8 ccr) -> void;
auto writeSR(uint16 sr) -> void;
//memory.cpp
template<uint Size> auto read(uint32 addr) -> uint32;
template<uint Size, bool Order = 0> auto write(uint32 addr, uint32 data) -> void;
template<uint Size = Word> auto readPC() -> uint32;
template<uint Size> auto pop() -> uint32;
template<uint Size> auto push(uint32 data) -> void;
//effective-address.cpp
struct EffectiveAddress {
explicit EffectiveAddress(uint4 mode_, uint3 reg_) : mode(mode_), reg(reg_) {
if(mode == 7) mode += reg; //optimization: convert modes {7; 0-4} to {8-11}
}
uint4 mode;
uint3 reg;
boolean valid;
uint32 address;
};
template<uint Size> auto fetch(EffectiveAddress& ea) -> uint32;
template<uint Size, bool hold = 0> auto read(EffectiveAddress& ea) -> uint32;
template<uint Size, bool hold = 0> auto write(EffectiveAddress& ea, uint32 data) -> void;
//instruction.cpp
auto instruction() -> void;
//instructions.cpp
auto testCondition(uint4 condition) -> bool;
template<uint Size> auto bytes() -> uint;
template<uint Size> auto bits() -> uint;
template<uint Size> auto lsb() -> uint32;
template<uint Size> auto msb() -> uint32;
template<uint Size> auto mask() -> uint32;
template<uint Size> auto clip(uint32 data) -> uint32;
template<uint Size> auto sign(uint32 data) -> int32;
auto instructionABCD(EffectiveAddress with, EffectiveAddress from) -> void;
template<uint Size, bool extend = false> auto ADD(uint32 source, uint32 target) -> uint32;
template<uint Size> auto instructionADD(EffectiveAddress from, DataRegister with) -> void;
template<uint Size> auto instructionADD(DataRegister from, EffectiveAddress with) -> void;
template<uint Size> auto instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void;
template<uint Size> auto instructionADDI(EffectiveAddress modify) -> void;
template<uint Size> auto instructionADDQ(uint4 immediate, EffectiveAddress with) -> void;
template<uint Size> auto instructionADDQ(uint4 immediate, AddressRegister with) -> void;
template<uint Size> auto instructionADDX(EffectiveAddress with, EffectiveAddress from) -> void;
template<uint Size> auto AND(uint32 source, uint32 target) -> uint32;
template<uint Size> auto instructionAND(EffectiveAddress from, DataRegister with) -> void;
template<uint Size> auto instructionAND(DataRegister from, EffectiveAddress with) -> void;
template<uint Size> auto instructionANDI(EffectiveAddress with) -> void;
auto instructionANDI_TO_CCR() -> void;
auto instructionANDI_TO_SR() -> void;
template<uint Size> auto ASL(uint32 result, uint shift) -> uint32;
template<uint Size> auto instructionASL(uint4 shift, DataRegister modify) -> void;
template<uint Size> auto instructionASL(DataRegister shift, DataRegister modify) -> void;
auto instructionASL(EffectiveAddress modify) -> void;
template<uint Size> auto ASR(uint32 result, uint shift) -> uint32;
template<uint Size> auto instructionASR(uint4 shift, DataRegister modify) -> void;
template<uint Size> auto instructionASR(DataRegister shift, DataRegister modify) -> void;
auto instructionASR(EffectiveAddress modify) -> void;
auto instructionBCC(uint4 condition, uint8 displacement) -> void;
template<uint Size> auto instructionBCHG(DataRegister bit, EffectiveAddress with) -> void;
template<uint Size> auto instructionBCHG(EffectiveAddress with) -> void;
template<uint Size> auto instructionBCLR(DataRegister bit, EffectiveAddress with) -> void;
template<uint Size> auto instructionBCLR(EffectiveAddress with) -> void;
template<uint Size> auto instructionBSET(DataRegister bit, EffectiveAddress with) -> void;
template<uint Size> auto instructionBSET(EffectiveAddress with) -> void;
template<uint Size> auto instructionBTST(DataRegister bit, EffectiveAddress with) -> void;
template<uint Size> auto instructionBTST(EffectiveAddress with) -> void;
auto instructionCHK(DataRegister compare, EffectiveAddress maximum) -> void;
template<uint Size> auto instructionCLR(EffectiveAddress ea) -> void;
template<uint Size> auto CMP(uint32 source, uint32 target) -> uint32;
template<uint Size> auto instructionCMP(DataRegister dr, EffectiveAddress ea) -> void;
template<uint Size> auto instructionCMPA(AddressRegister ar, EffectiveAddress ea) -> void;
template<uint Size> auto instructionCMPI(EffectiveAddress ea) -> void;
template<uint Size> auto instructionCMPM(EffectiveAddress ax, EffectiveAddress ay) -> void;
auto instructionDBCC(uint4 condition, DataRegister dr) -> void;
template<bool Sign> auto DIV(uint16 divisor, DataRegister with) -> void;
auto instructionDIVS(DataRegister with, EffectiveAddress from) -> void;
auto instructionDIVU(DataRegister with, EffectiveAddress from) -> void;
template<uint Size> auto EOR(uint32 source, uint32 target) -> uint32;
template<uint Size> auto instructionEOR(DataRegister from, EffectiveAddress with) -> void;
template<uint Size> auto instructionEORI(EffectiveAddress with) -> void;
auto instructionEORI_TO_CCR() -> void;
auto instructionEORI_TO_SR() -> void;
auto instructionEXG(DataRegister x, DataRegister y) -> void;
auto instructionEXG(AddressRegister x, AddressRegister y) -> void;
auto instructionEXG(DataRegister x, AddressRegister y) -> void;
template<uint Size> auto instructionEXT(DataRegister with) -> void;
auto instructionILLEGAL(uint16 code) -> void;
auto instructionJMP(EffectiveAddress target) -> void;
auto instructionJSR(EffectiveAddress target) -> void;
auto instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void;
auto instructionLINK(AddressRegister with) -> void;
template<uint Size> auto LSL(uint32 result, uint shift) -> uint32;
template<uint Size> auto instructionLSL(uint4 immediate, DataRegister dr) -> void;
template<uint Size> auto instructionLSL(DataRegister sr, DataRegister dr) -> void;
auto instructionLSL(EffectiveAddress ea) -> void;
template<uint Size> auto LSR(uint32 result, uint shift) -> uint32;
template<uint Size> auto instructionLSR(uint4 immediate, DataRegister dr) -> void;
template<uint Size> auto instructionLSR(DataRegister shift, DataRegister dr) -> void;
auto instructionLSR(EffectiveAddress ea) -> void;
template<uint Size> auto instructionMOVE(EffectiveAddress to, EffectiveAddress from) -> void;
template<uint Size> auto instructionMOVEA(AddressRegister ar, EffectiveAddress ea) -> void;
template<uint Size> auto instructionMOVEM_TO_MEM(EffectiveAddress to) -> void;
template<uint Size> auto instructionMOVEM_TO_REG(EffectiveAddress from) -> void;
template<uint Size> auto instructionMOVEP(DataRegister from, EffectiveAddress to) -> void;
template<uint Size> auto instructionMOVEP(EffectiveAddress from, DataRegister to) -> void;
auto instructionMOVEQ(DataRegister dr, uint8 immediate) -> void;
auto instructionMOVE_FROM_SR(EffectiveAddress ea) -> void;
auto instructionMOVE_TO_CCR(EffectiveAddress ea) -> void;
auto instructionMOVE_TO_SR(EffectiveAddress ea) -> void;
auto instructionMOVE_FROM_USP(AddressRegister to) -> void;
auto instructionMOVE_TO_USP(AddressRegister from) -> void;
auto instructionMULS(DataRegister with, EffectiveAddress from) -> void;
auto instructionMULU(DataRegister with, EffectiveAddress from) -> void;
auto instructionNBCD(EffectiveAddress with) -> void;
template<uint Size> auto instructionNEG(EffectiveAddress with) -> void;
template<uint Size> auto instructionNEGX(EffectiveAddress with) -> void;
auto instructionNOP() -> void;
template<uint Size> auto instructionNOT(EffectiveAddress with) -> void;
template<uint Size> auto OR(uint32 source, uint32 target) -> uint32;
template<uint Size> auto instructionOR(EffectiveAddress from, DataRegister with) -> void;
template<uint Size> auto instructionOR(DataRegister from, EffectiveAddress with) -> void;
template<uint Size> auto instructionORI(EffectiveAddress with) -> void;
auto instructionORI_TO_CCR() -> void;
auto instructionORI_TO_SR() -> void;
auto instructionPEA(EffectiveAddress from) -> void;
auto instructionRESET() -> void;
template<uint Size> auto ROL(uint32 result, uint shift) -> uint32;
template<uint Size> auto instructionROL(uint4 shift, DataRegister modify) -> void;
template<uint Size> auto instructionROL(DataRegister shift, DataRegister modify) -> void;
auto instructionROL(EffectiveAddress modify) -> void;
template<uint Size> auto ROR(uint32 result, uint shift) -> uint32;
template<uint Size> auto instructionROR(uint4 shift, DataRegister modify) -> void;
template<uint Size> auto instructionROR(DataRegister shift, DataRegister modify) -> void;
auto instructionROR(EffectiveAddress modify) -> void;
template<uint Size> auto ROXL(uint32 result, uint shift) -> uint32;
template<uint Size> auto instructionROXL(uint4 shift, DataRegister modify) -> void;
template<uint Size> auto instructionROXL(DataRegister shift, DataRegister modify) -> void;
auto instructionROXL(EffectiveAddress modify) -> void;
template<uint Size> auto ROXR(uint32 result, uint shift) -> uint32;
template<uint Size> auto instructionROXR(uint4 shift, DataRegister modify) -> void;
template<uint Size> auto instructionROXR(DataRegister shift, DataRegister modify) -> void;
auto instructionROXR(EffectiveAddress modify) -> void;
auto instructionRTE() -> void;
auto instructionRTR() -> void;
auto instructionRTS() -> void;
auto instructionSBCD(EffectiveAddress with, EffectiveAddress from) -> void;
auto instructionSCC(uint4 condition, EffectiveAddress to) -> void;
auto instructionSTOP() -> void;
template<uint Size, bool extend = false> auto SUB(uint32 source, uint32 target) -> uint32;
template<uint Size> auto instructionSUB(EffectiveAddress source, DataRegister target) -> void;
template<uint Size> auto instructionSUB(DataRegister source, EffectiveAddress target) -> void;
template<uint Size> auto instructionSUBA(AddressRegister to, EffectiveAddress from) -> void;
template<uint Size> auto instructionSUBI(EffectiveAddress with) -> void;
template<uint Size> auto instructionSUBQ(uint4 immediate, EffectiveAddress with) -> void;
template<uint Size> auto instructionSUBQ(uint4 immediate, AddressRegister with) -> void;
template<uint Size> auto instructionSUBX(EffectiveAddress with, EffectiveAddress from) -> void;
auto instructionSWAP(DataRegister with) -> void;
auto instructionTAS(EffectiveAddress with) -> void;
auto instructionTRAP(uint4 vector) -> void;
auto instructionTRAPV() -> void;
template<uint Size> auto instructionTST(EffectiveAddress ea) -> void;
auto instructionUNLK(AddressRegister with) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
//disassembler.cpp
auto disassemble(uint32 pc) -> string;
auto disassembleRegisters() -> string;
struct Registers {
uint32 d[8]; //data registers
uint32 a[8]; //address registers (a7 = s ? ssp : usp)
uint32 sp; //inactive stack pointer (s ? usp : ssp)
uint32 pc; //program counter
bool c; //carry
bool v; //overflow
bool z; //zero
bool n; //negative
bool x; //extend
uint3 i; //interrupt mask
bool s; //supervisor mode
bool t; //trace mode
bool stop;
bool reset;
} r;
uint16 opcode = 0;
function<void ()> instructionTable[65536];
Bus* bus = nullptr;
private:
//disassembler.cpp
auto disassembleABCD(EffectiveAddress with, EffectiveAddress from) -> string;
template<uint Size> auto disassembleADD(EffectiveAddress from, DataRegister with) -> string;
template<uint Size> auto disassembleADD(DataRegister from, EffectiveAddress with) -> string;
template<uint Size> auto disassembleADDA(AddressRegister ar, EffectiveAddress ea) -> string;
template<uint Size> auto disassembleADDI(EffectiveAddress modify) -> string;
template<uint Size> auto disassembleADDQ(uint4 immediate, EffectiveAddress with) -> string;
template<uint Size> auto disassembleADDQ(uint4 immediate, AddressRegister with) -> string;
template<uint Size> auto disassembleADDX(EffectiveAddress with, EffectiveAddress from) -> string;
template<uint Size> auto disassembleAND(EffectiveAddress from, DataRegister with) -> string;
template<uint Size> auto disassembleAND(DataRegister from, EffectiveAddress with) -> string;
template<uint Size> auto disassembleANDI(EffectiveAddress with) -> string;
auto disassembleANDI_TO_CCR() -> string;
auto disassembleANDI_TO_SR() -> string;
template<uint Size> auto disassembleASL(uint4 shift, DataRegister modify) -> string;
template<uint Size> auto disassembleASL(DataRegister shift, DataRegister modify) -> string;
auto disassembleASL(EffectiveAddress modify) -> string;
template<uint Size> auto disassembleASR(uint4 shift, DataRegister modify) -> string;
template<uint Size> auto disassembleASR(DataRegister shift, DataRegister modify) -> string;
auto disassembleASR(EffectiveAddress modify) -> string;
auto disassembleBCC(uint4 condition, uint8 displacement) -> string;
template<uint Size> auto disassembleBCHG(DataRegister bit, EffectiveAddress with) -> string;
template<uint Size> auto disassembleBCHG(EffectiveAddress with) -> string;
template<uint Size> auto disassembleBCLR(DataRegister bit, EffectiveAddress with) -> string;
template<uint Size> auto disassembleBCLR(EffectiveAddress with) -> string;
template<uint Size> auto disassembleBSET(DataRegister bit, EffectiveAddress with) -> string;
template<uint Size> auto disassembleBSET(EffectiveAddress with) -> string;
template<uint Size> auto disassembleBTST(DataRegister bit, EffectiveAddress with) -> string;
template<uint Size> auto disassembleBTST(EffectiveAddress with) -> string;
auto disassembleCHK(DataRegister compare, EffectiveAddress maximum) -> string;
template<uint Size> auto disassembleCLR(EffectiveAddress ea) -> string;
template<uint Size> auto disassembleCMP(DataRegister dr, EffectiveAddress ea) -> string;
template<uint Size> auto disassembleCMPA(AddressRegister ar, EffectiveAddress ea) -> string;
template<uint Size> auto disassembleCMPI(EffectiveAddress ea) -> string;
template<uint Size> auto disassembleCMPM(EffectiveAddress ax, EffectiveAddress ay) -> string;
auto disassembleDBCC(uint4 condition, DataRegister dr) -> string;
auto disassembleDIVS(DataRegister with, EffectiveAddress from) -> string;
auto disassembleDIVU(DataRegister with, EffectiveAddress from) -> string;
template<uint Size> auto disassembleEOR(DataRegister from, EffectiveAddress with) -> string;
template<uint Size> auto disassembleEORI(EffectiveAddress with) -> string;
auto disassembleEORI_TO_CCR() -> string;
auto disassembleEORI_TO_SR() -> string;
auto disassembleEXG(DataRegister x, DataRegister y) -> string;
auto disassembleEXG(AddressRegister x, AddressRegister y) -> string;
auto disassembleEXG(DataRegister x, AddressRegister y) -> string;
template<uint Size> auto disassembleEXT(DataRegister with) -> string;
auto disassembleILLEGAL(uint16 code) -> string;
auto disassembleJMP(EffectiveAddress target) -> string;
auto disassembleJSR(EffectiveAddress target) -> string;
auto disassembleLEA(AddressRegister ar, EffectiveAddress ea) -> string;
auto disassembleLINK(AddressRegister with) -> string;
template<uint Size> auto disassembleLSL(uint4 immediate, DataRegister dr) -> string;
template<uint Size> auto disassembleLSL(DataRegister sr, DataRegister dr) -> string;
auto disassembleLSL(EffectiveAddress ea) -> string;
template<uint Size> auto disassembleLSR(uint4 immediate, DataRegister dr) -> string;
template<uint Size> auto disassembleLSR(DataRegister shift, DataRegister dr) -> string;
auto disassembleLSR(EffectiveAddress ea) -> string;
template<uint Size> auto disassembleMOVE(EffectiveAddress to, EffectiveAddress from) -> string;
template<uint Size> auto disassembleMOVEA(AddressRegister ar, EffectiveAddress ea) -> string;
template<uint Size> auto disassembleMOVEM_TO_MEM(EffectiveAddress to) -> string;
template<uint Size> auto disassembleMOVEM_TO_REG(EffectiveAddress from) -> string;
template<uint Size> auto disassembleMOVEP(DataRegister from, EffectiveAddress to) -> string;
template<uint Size> auto disassembleMOVEP(EffectiveAddress from, DataRegister to) -> string;
auto disassembleMOVEQ(DataRegister dr, uint8 immediate) -> string;
auto disassembleMOVE_FROM_SR(EffectiveAddress ea) -> string;
auto disassembleMOVE_TO_CCR(EffectiveAddress ea) -> string;
auto disassembleMOVE_TO_SR(EffectiveAddress ea) -> string;
auto disassembleMOVE_FROM_USP(AddressRegister to) -> string;
auto disassembleMOVE_TO_USP(AddressRegister from) -> string;
auto disassembleMULS(DataRegister with, EffectiveAddress from) -> string;
auto disassembleMULU(DataRegister with, EffectiveAddress from) -> string;
auto disassembleNBCD(EffectiveAddress with) -> string;
template<uint Size> auto disassembleNEG(EffectiveAddress with) -> string;
template<uint Size> auto disassembleNEGX(EffectiveAddress with) -> string;
auto disassembleNOP() -> string;
template<uint Size> auto disassembleNOT(EffectiveAddress with) -> string;
template<uint Size> auto disassembleOR(EffectiveAddress from, DataRegister with) -> string;
template<uint Size> auto disassembleOR(DataRegister from, EffectiveAddress with) -> string;
template<uint Size> auto disassembleORI(EffectiveAddress with) -> string;
auto disassembleORI_TO_CCR() -> string;
auto disassembleORI_TO_SR() -> string;
auto disassemblePEA(EffectiveAddress from) -> string;
auto disassembleRESET() -> string;
template<uint Size> auto disassembleROL(uint4 shift, DataRegister modify) -> string;
template<uint Size> auto disassembleROL(DataRegister shift, DataRegister modify) -> string;
auto disassembleROL(EffectiveAddress modify) -> string;
template<uint Size> auto disassembleROR(uint4 shift, DataRegister modify) -> string;
template<uint Size> auto disassembleROR(DataRegister shift, DataRegister modify) -> string;
auto disassembleROR(EffectiveAddress modify) -> string;
template<uint Size> auto disassembleROXL(uint4 shift, DataRegister modify) -> string;
template<uint Size> auto disassembleROXL(DataRegister shift, DataRegister modify) -> string;
auto disassembleROXL(EffectiveAddress modify) -> string;
template<uint Size> auto disassembleROXR(uint4 shift, DataRegister modify) -> string;
template<uint Size> auto disassembleROXR(DataRegister shift, DataRegister modify) -> string;
auto disassembleROXR(EffectiveAddress modify) -> string;
auto disassembleRTE() -> string;
auto disassembleRTR() -> string;
auto disassembleRTS() -> string;
auto disassembleSBCD(EffectiveAddress with, EffectiveAddress from) -> string;
auto disassembleSCC(uint4 condition, EffectiveAddress to) -> string;
auto disassembleSTOP() -> string;
template<uint Size> auto disassembleSUB(EffectiveAddress source, DataRegister target) -> string;
template<uint Size> auto disassembleSUB(DataRegister source, EffectiveAddress target) -> string;
template<uint Size> auto disassembleSUBA(AddressRegister to, EffectiveAddress from) -> string;
template<uint Size> auto disassembleSUBI(EffectiveAddress with) -> string;
template<uint Size> auto disassembleSUBQ(uint4 immediate, EffectiveAddress with) -> string;
template<uint Size> auto disassembleSUBQ(uint4 immediate, AddressRegister with) -> string;
template<uint Size> auto disassembleSUBX(EffectiveAddress with, EffectiveAddress from) -> string;
auto disassembleSWAP(DataRegister with) -> string;
auto disassembleTAS(EffectiveAddress with) -> string;
auto disassembleTRAP(uint4 vector) -> string;
auto disassembleTRAPV() -> string;
template<uint Size> auto disassembleTST(EffectiveAddress ea) -> string;
auto disassembleUNLK(AddressRegister with) -> string;
template<uint Size> auto _read(uint32 addr) -> uint32;
template<uint Size = Word> auto _readPC() -> uint32;
auto _readDisplacement(uint32 base) -> uint32;
auto _readIndex(uint32 base) -> uint32;
auto _dataRegister(DataRegister dr) -> string;
auto _addressRegister(AddressRegister ar) -> string;
template<uint Size> auto _immediate() -> string;
template<uint Size> auto _address(EffectiveAddress& ea) -> string;
template<uint Size> auto _effectiveAddress(EffectiveAddress& ea) -> string;
auto _branch(uint8 displacement) -> string;
template<uint Size> auto _suffix() -> string;
auto _condition(uint4 condition) -> string;
uint32 _pc;
function<string ()> disassembleTable[65536];
};
}

View File

@ -1,91 +0,0 @@
template<> auto M68K::read<Byte>(uint32 addr) -> uint32 {
step(4);
return bus->readByte(addr);
}
template<> auto M68K::read<Word>(uint32 addr) -> uint32 {
step(4);
return bus->readWord(addr);
}
template<> auto M68K::read<Long>(uint32 addr) -> uint32 {
step(4);
uint32 data = bus->readWord(addr + 0) << 16;
step(4);
return data | bus->readWord(addr + 2) << 0;
}
//
template<> auto M68K::write<Byte>(uint32 addr, uint32 data) -> void {
step(4);
return bus->writeByte(addr, data);
}
template<> auto M68K::write<Word>(uint32 addr, uint32 data) -> void {
step(4);
return bus->writeWord(addr, data);
}
template<> auto M68K::write<Long>(uint32 addr, uint32 data) -> void {
step(4);
bus->writeWord(addr + 0, data >> 16);
step(4);
bus->writeWord(addr + 2, data >> 0);
}
template<> auto M68K::write<Byte, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
return bus->writeByte(addr, data);
}
template<> auto M68K::write<Word, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
return bus->writeWord(addr, data);
}
template<> auto M68K::write<Long, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
bus->writeWord(addr + 2, data >> 0);
step(4);
bus->writeWord(addr + 0, data >> 16);
}
//
template<> auto M68K::readPC<Byte>() -> uint32 {
step(4);
auto data = bus->readWord(r.pc);
r.pc += 2;
return (uint8)data;
}
template<> auto M68K::readPC<Word>() -> uint32 {
step(4);
auto data = bus->readWord(r.pc);
r.pc += 2;
return data;
}
template<> auto M68K::readPC<Long>() -> uint32 {
step(4);
auto hi = bus->readWord(r.pc);
r.pc += 2;
step(4);
auto lo = bus->readWord(r.pc);
r.pc += 2;
return hi << 16 | lo << 0;
}
//
template<uint Size> auto M68K::pop() -> uint32 {
auto data = read<Size>((uint32)r.a[7]);
r.a[7] += bytes<Size>();
return data;
}
template<uint Size> auto M68K::push(uint32 data) -> void {
r.a[7] -= bytes<Size>();
return write<Size, Reverse>((uint32)r.a[7], data);
}

View File

@ -1,48 +0,0 @@
template<uint Size> auto M68K::read(DataRegister reg) -> uint32 {
return clip<Size>(r.d[reg.number]);
}
template<uint Size> auto M68K::write(DataRegister reg, uint32 data) -> void {
r.d[reg.number] = (r.d[reg.number] & ~mask<Size>()) | (data & mask<Size>());
}
//
template<uint Size> auto M68K::read(AddressRegister reg) -> uint32 {
return sign<Size>(r.a[reg.number]);
}
template<uint Size> auto M68K::write(AddressRegister reg, uint32 data) -> void {
r.a[reg.number] = sign<Size>(data);
}
//
//CCR,SR unused bits cannot be set; always read out as 0
auto M68K::readCCR() -> uint8 {
return r.c << 0 | r.v << 1 | r.z << 2 | r.n << 3 | r.x << 4;
}
auto M68K::readSR() -> uint16 {
return readCCR() << 0 | r.i << 8 | r.s << 13 | r.t << 15;
}
auto M68K::writeCCR(uint8 ccr) -> void {
r.c = ccr.bit(0);
r.v = ccr.bit(1);
r.z = ccr.bit(2);
r.n = ccr.bit(3);
r.x = ccr.bit(4);
}
auto M68K::writeSR(uint16 sr) -> void {
writeCCR(sr);
//when entering or exiting supervisor mode; swap SSP and USP into A7
if(r.s != sr.bit(13)) swap(r.a[7], r.sp);
r.i = sr.bits(8,10);
r.s = sr.bit(13);
r.t = sr.bit(15);
}

View File

@ -1,20 +0,0 @@
auto M68K::serialize(serializer& s) -> void {
s.array(r.d);
s.array(r.a);
s.integer(r.sp);
s.integer(r.pc);
s.integer(r.c);
s.integer(r.v);
s.integer(r.z);
s.integer(r.n);
s.integer(r.x);
s.integer(r.i);
s.integer(r.s);
s.integer(r.t);
s.integer(r.stop);
s.integer(r.reset);
s.integer(opcode);
}

View File

@ -1,144 +0,0 @@
auto MOS6502::algorithmADC(uint8 i) -> uint8 {
int16 o;
if(!BCD || !D) {
o = A + i + C;
V = ~(A ^ i) & (A ^ o) & 0x80;
} else {
idle();
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o > 0x09) o += 0x06;
C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
if(o > 0x9f) o += 0x60;
}
C = o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return o;
}
auto MOS6502::algorithmAND(uint8 i) -> uint8 {
uint8 o = A & i;
Z = o == 0;
N = o.bit(7);
return o;
}
auto MOS6502::algorithmASL(uint8 i) -> uint8 {
C = i.bit(7);
i <<= 1;
Z = i == 0;
N = i.bit(7);
return i;
}
auto MOS6502::algorithmBIT(uint8 i) -> uint8 {
Z = (A & i) == 0;
V = i.bit(6);
N = i.bit(7);
return A;
}
auto MOS6502::algorithmCMP(uint8 i) -> uint8 {
uint9 o = A - i;
C = !o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return A;
}
auto MOS6502::algorithmCPX(uint8 i) -> uint8 {
uint9 o = X - i;
C = !o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return X;
}
auto MOS6502::algorithmCPY(uint8 i) -> uint8 {
uint9 o = Y - i;
C = !o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return Y;
}
auto MOS6502::algorithmDEC(uint8 i) -> uint8 {
i--;
Z = i == 0;
N = i.bit(7);
return i;
}
auto MOS6502::algorithmEOR(uint8 i) -> uint8 {
uint8 o = A ^ i;
Z = o == 0;
N = o.bit(7);
return o;
}
auto MOS6502::algorithmINC(uint8 i) -> uint8 {
i++;
Z = i == 0;
N = i.bit(7);
return i;
}
auto MOS6502::algorithmLD(uint8 i) -> uint8 {
Z = i == 0;
N = i.bit(7);
return i;
}
auto MOS6502::algorithmLSR(uint8 i) -> uint8 {
C = i.bit(0);
i >>= 1;
Z = i == 0;
N = i.bit(7);
return i;
}
auto MOS6502::algorithmORA(uint8 i) -> uint8 {
uint8 o = A | i;
Z = o == 0;
N = o.bit(7);
return o;
}
auto MOS6502::algorithmROL(uint8 i) -> uint8 {
bool c = C;
C = i.bit(7);
i = i << 1 | c;
Z = i == 0;
N = i.bit(7);
return i;
}
auto MOS6502::algorithmROR(uint8 i) -> uint8 {
bool c = C;
C = i.bit(0);
i = c << 7 | i >> 1;
Z = i == 0;
N = i.bit(7);
return i;
}
auto MOS6502::algorithmSBC(uint8 i) -> uint8 {
i = ~i;
int16 o;
if(!BCD || !D) {
o = A + i + C;
V = ~(A ^ i) & (A ^ o) & 0x80;
} else {
idle();
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o <= 0x0f) o -= 0x06;
C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
if(o <= 0xff) o -= 0x60;
}
C = o.bit(8);
Z = uint8(o) == 0;
N = o.bit(7);
return o;
}

View File

@ -1,234 +0,0 @@
auto MOS6502::disassemble(uint16 pc) -> string {
string s{hex(pc, 4L), " "};
auto absolute = [&]() -> string {
return {"$", hex(readDebugger(pc + 2), 2L), hex(readDebugger(pc + 1), 2L)};
};
auto absoluteX = [&]() -> string {
return {"$", hex(readDebugger(pc + 2), 2L), hex(readDebugger(pc + 1), 2L), ",x"};
};
auto absoluteY = [&]() -> string {
return {"$", hex(readDebugger(pc + 2), 2L), hex(readDebugger(pc + 1), 2L), ",y"};
};
auto branch = [&]() -> string {
return {"$", hex((pc + 2) + (int8)readDebugger(pc + 1), 4L)};
};
auto immediate = [&]() -> string {
return {"#$", hex(readDebugger(pc + 1), 2L)};
};
auto implied = [&]() -> string {
return {""};
};
auto indirect = [&]() -> string {
return {"($", hex(readDebugger(pc + 2), 2L), hex(readDebugger(pc + 1), 2L), ")"};
};
auto indirectX = [&]() -> string {
return {"($", hex(readDebugger(pc + 1), 2L), ",x)"};
};
auto indirectY = [&]() -> string {
return {"($", hex(readDebugger(pc + 1), 2L), "),y"};
};
auto zeroPage = [&]() -> string {
return {"$", hex(readDebugger(pc + 1), 2L)};
};
auto zeroPageX = [&]() -> string {
return {"$", hex(readDebugger(pc + 1), 2L), ",x"};
};
auto zeroPageY = [&]() -> string {
return {"$", hex(readDebugger(pc + 1), 2L), ",y"};
};
#define op(id, prefix, mode) \
case id: s.append(prefix, " ", mode()); \
break;
switch(auto opcode = readDebugger(pc)) {
op(0x00, "brk", immediate)
op(0x01, "ora", indirectX)
op(0x05, "ora", zeroPage)
op(0x06, "asl", zeroPage)
op(0x08, "php", implied)
op(0x09, "ora", immediate)
op(0x0a, "asl", implied)
op(0x0d, "ora", absolute)
op(0x0e, "asl", absolute)
op(0x10, "bpl", branch)
op(0x11, "ora", indirectY)
op(0x15, "ora", zeroPageX)
op(0x16, "asl", zeroPageX)
op(0x18, "clc", implied)
op(0x19, "ora", absoluteY)
op(0x1d, "ora", absoluteX)
op(0x1e, "asl", absoluteX)
op(0x20, "jsr", absolute)
op(0x21, "and", indirectX)
op(0x24, "bit", zeroPage)
op(0x25, "and", zeroPage)
op(0x26, "rol", zeroPage)
op(0x28, "plp", implied)
op(0x29, "and", immediate)
op(0x2a, "rol", implied)
op(0x2c, "bit", absolute)
op(0x2d, "and", absolute)
op(0x2e, "rol", absolute)
op(0x30, "bmi", branch)
op(0x31, "and", indirectY)
op(0x35, "and", zeroPageX)
op(0x36, "rol", zeroPageX)
op(0x38, "sec", implied)
op(0x39, "and", absoluteY)
op(0x3d, "and", absoluteX)
op(0x3e, "rol", absoluteX)
op(0x40, "rti", implied)
op(0x41, "eor", indirectX)
op(0x45, "eor", zeroPage)
op(0x46, "lsr", zeroPage)
op(0x48, "pha", implied)
op(0x49, "eor", immediate)
op(0x4a, "lsr", implied)
op(0x4c, "jmp", absolute)
op(0x4d, "eor", absolute)
op(0x4e, "lsr", absolute)
op(0x50, "bvc", branch)
op(0x51, "eor", indirectY)
op(0x55, "eor", zeroPageX)
op(0x56, "lsr", zeroPageX)
op(0x58, "cli", implied)
op(0x59, "eor", absoluteY)
op(0x5d, "eor", absoluteX)
op(0x5e, "lsr", absoluteX)
op(0x60, "rts", implied)
op(0x61, "adc", indirectX)
op(0x65, "adc", zeroPage)
op(0x66, "ror", zeroPage)
op(0x68, "pla", implied)
op(0x69, "adc", immediate)
op(0x6a, "ror", implied)
op(0x6c, "jmp", indirect)
op(0x6d, "adc", absolute)
op(0x6e, "ror", absolute)
op(0x70, "bvs", branch)
op(0x71, "adc", indirectY)
op(0x75, "adc", zeroPageX)
op(0x76, "ror", zeroPageX)
op(0x78, "sei", implied)
op(0x79, "adc", absoluteY)
op(0x7d, "adc", absoluteX)
op(0x7e, "ror", absoluteX)
op(0x81, "sta", indirectX)
op(0x84, "sty", zeroPage)
op(0x85, "sta", zeroPage)
op(0x86, "stx", zeroPage)
op(0x88, "dey", implied)
op(0x8a, "txa", implied)
op(0x8c, "sty", absolute)
op(0x8d, "sta", absolute)
op(0x8e, "stx", absolute)
op(0x90, "bcc", branch)
op(0x91, "sta", indirectY)
op(0x94, "sty", zeroPageX)
op(0x95, "sta", zeroPageX)
op(0x96, "stx", zeroPageY)
op(0x98, "tya", implied)
op(0x99, "sta", absoluteY)
op(0x9a, "txs", implied)
op(0x9d, "sta", absoluteX)
op(0xa0, "ldy", immediate)
op(0xa1, "lda", indirectX)
op(0xa2, "ldx", immediate)
op(0xa4, "ldy", zeroPage)
op(0xa5, "lda", zeroPage)
op(0xa6, "ldx", zeroPage)
op(0xa8, "tay", implied)
op(0xa9, "lda", immediate)
op(0xaa, "tax", implied)
op(0xac, "ldy", absolute)
op(0xad, "lda", absolute)
op(0xae, "ldx", absolute)
op(0xb0, "bcs", branch)
op(0xb1, "lda", indirectY)
op(0xb4, "ldy", zeroPageX)
op(0xb5, "lda", zeroPageX)
op(0xb6, "ldx", zeroPageY)
op(0xb8, "clv", implied)
op(0xb9, "lda", absoluteY)
op(0xba, "tsx", implied)
op(0xbc, "ldy", absoluteX)
op(0xbd, "lda", absoluteX)
op(0xbe, "ldx", absoluteY)
op(0xc0, "cpy", immediate)
op(0xc1, "cmp", indirectX)
op(0xc4, "cpy", zeroPage)
op(0xc5, "cmp", zeroPage)
op(0xc6, "dec", zeroPage)
op(0xc8, "iny", implied)
op(0xc9, "cmp", immediate)
op(0xca, "dex", implied)
op(0xcc, "cpy", absolute)
op(0xcd, "cmp", absolute)
op(0xce, "dec", absolute)
op(0xd0, "bne", branch)
op(0xd1, "cmp", indirectY)
op(0xd5, "cmp", zeroPageX)
op(0xd6, "dec", zeroPageX)
op(0xd8, "cld", implied)
op(0xd9, "cmp", absoluteY)
op(0xdd, "cmp", absoluteX)
op(0xde, "dec", absoluteX)
op(0xe0, "cpx", immediate)
op(0xe1, "sbc", indirectX)
op(0xe4, "cpx", zeroPage)
op(0xe5, "sbc", zeroPage)
op(0xe6, "inc", zeroPage)
op(0xe8, "inx", implied)
op(0xe9, "sbc", immediate)
op(0xea, "nop", implied)
op(0xec, "cpx", absolute)
op(0xed, "sbc", absolute)
op(0xee, "inc", absolute)
op(0xf0, "beq", branch)
op(0xf1, "sbc", indirectY)
op(0xf5, "sbc", zeroPageX)
op(0xf6, "inc", zeroPageX)
op(0xf8, "sed", implied)
op(0xf9, "sbc", absoluteY)
op(0xfd, "sbc", absoluteX)
op(0xfe, "inc", absoluteX)
default:
s.append("$", hex(opcode, 2L));
break;
}
#undef op
s.append(" ");
s.resize(20);
s.append(" A:", hex(A, 2L));
s.append(" X:", hex(X, 2L));
s.append(" Y:", hex(Y, 2L));
s.append(" S:", hex(S, 2L));
s.append(" ");
s.append(N ? "N" : "n");
s.append(V ? "V" : "v");
s.append("-");
s.append("-");
s.append(D ? "D" : "d");
s.append(I ? "I" : "i");
s.append(Z ? "Z" : "z");
s.append(C ? "C" : "c");
return s;
}

View File

@ -1,179 +0,0 @@
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
#define fp(name) &MOS6502::algorithm##name
auto MOS6502::interrupt() -> void {
idle();
idle();
push(PCH);
push(PCL);
uint16 vector = 0xfffe;
nmi(vector);
push(P | 0x20);
I = 1;
PCL = read(vector++);
L PCH = read(vector++);
}
auto MOS6502::instruction() -> void {
auto code = opcode();
switch(code) {
op(0x00, Break)
op(0x01, IndirectXRead, fp(ORA), A)
op(0x05, ZeroPageRead, fp(ORA), A)
op(0x06, ZeroPageModify, fp(ASL))
op(0x08, PushP)
op(0x09, Immediate, fp(ORA), A)
op(0x0a, Implied, fp(ASL), A)
op(0x0d, AbsoluteRead, fp(ORA), A)
op(0x0e, AbsoluteModify, fp(ASL))
op(0x10, Branch, N == 0)
op(0x11, IndirectYRead, fp(ORA), A)
op(0x15, ZeroPageRead, fp(ORA), A, X)
op(0x16, ZeroPageModify, fp(ASL), X)
op(0x18, Clear, C)
op(0x19, AbsoluteRead, fp(ORA), A, Y)
op(0x1d, AbsoluteRead, fp(ORA), A, X)
op(0x1e, AbsoluteModify, fp(ASL), X)
op(0x20, CallAbsolute)
op(0x21, IndirectXRead, fp(AND), A)
op(0x24, ZeroPageRead, fp(BIT), A)
op(0x25, ZeroPageRead, fp(AND), A)
op(0x26, ZeroPageModify, fp(ROL))
op(0x28, PullP)
op(0x29, Immediate, fp(AND), A)
op(0x2a, Implied, fp(ROL), A)
op(0x2c, AbsoluteRead, fp(BIT), A)
op(0x2d, AbsoluteRead, fp(AND), A)
op(0x2e, AbsoluteModify, fp(ROL))
op(0x30, Branch, N == 1)
op(0x31, IndirectYRead, fp(AND), A)
op(0x35, ZeroPageRead, fp(AND), A, X)
op(0x36, ZeroPageModify, fp(ROL), X)
op(0x38, Set, C)
op(0x39, AbsoluteRead, fp(AND), A, Y)
op(0x3d, AbsoluteRead, fp(AND), A, X)
op(0x3e, AbsoluteModify, fp(ROL), X)
op(0x40, ReturnInterrupt)
op(0x41, IndirectXRead, fp(EOR), A)
op(0x45, ZeroPageRead, fp(EOR), A)
op(0x46, ZeroPageModify, fp(LSR))
op(0x48, Push, A)
op(0x49, Immediate, fp(EOR), A)
op(0x4a, Implied, fp(LSR), A)
op(0x4c, JumpAbsolute)
op(0x4d, AbsoluteRead, fp(EOR), A)
op(0x4e, AbsoluteModify, fp(LSR))
op(0x50, Branch, V == 0)
op(0x51, IndirectYRead, fp(EOR), A)
op(0x55, ZeroPageRead, fp(EOR), A, X)
op(0x56, ZeroPageModify, fp(LSR), X)
op(0x58, Clear, I)
op(0x59, AbsoluteRead, fp(EOR), A, Y)
op(0x5d, AbsoluteRead, fp(EOR), A, X)
op(0x5e, AbsoluteModify, fp(LSR), X)
op(0x60, ReturnSubroutine)
op(0x61, IndirectXRead, fp(ADC), A)
op(0x65, ZeroPageRead, fp(ADC), A)
op(0x66, ZeroPageModify, fp(ROR))
op(0x68, Pull, A)
op(0x69, Immediate, fp(ADC), A)
op(0x6a, Implied, fp(ROR), A)
op(0x6c, JumpIndirect)
op(0x6d, AbsoluteRead, fp(ADC), A)
op(0x6e, AbsoluteModify, fp(ROR))
op(0x70, Branch, V == 1)
op(0x71, IndirectYRead, fp(ADC), A)
op(0x75, ZeroPageRead, fp(ADC), A, X)
op(0x76, ZeroPageModify, fp(ROR), X)
op(0x78, Set, I)
op(0x79, AbsoluteRead, fp(ADC), A, Y)
op(0x7d, AbsoluteRead, fp(ADC), A, X)
op(0x7e, AbsoluteModify, fp(ROR), X)
op(0x81, IndirectXWrite, A)
op(0x84, ZeroPageWrite, Y)
op(0x85, ZeroPageWrite, A)
op(0x86, ZeroPageWrite, X)
op(0x88, Implied, fp(DEC), Y)
op(0x8a, Transfer, X, A, 1)
op(0x8c, AbsoluteWrite, Y)
op(0x8d, AbsoluteWrite, A)
op(0x8e, AbsoluteWrite, X)
op(0x90, Branch, C == 0)
op(0x91, IndirectYWrite, A)
op(0x94, ZeroPageWrite, Y, X)
op(0x95, ZeroPageWrite, A, X)
op(0x96, ZeroPageWrite, X, Y)
op(0x98, Transfer, Y, A, 1)
op(0x99, AbsoluteWrite, A, Y)
op(0x9a, Transfer, X, S, 0)
op(0x9d, AbsoluteWrite, A, X)
op(0xa0, Immediate, fp(LD), Y)
op(0xa1, IndirectXRead, fp(LD), A)
op(0xa2, Immediate, fp(LD), X)
op(0xa4, ZeroPageRead, fp(LD), Y)
op(0xa5, ZeroPageRead, fp(LD), A)
op(0xa6, ZeroPageRead, fp(LD), X)
op(0xa8, Transfer, A, Y, 1)
op(0xa9, Immediate, fp(LD), A)
op(0xaa, Transfer, A, X, 1)
op(0xac, AbsoluteRead, fp(LD), Y)
op(0xad, AbsoluteRead, fp(LD), A)
op(0xae, AbsoluteRead, fp(LD), X)
op(0xb0, Branch, C == 1)
op(0xb1, IndirectYRead, fp(LD), A)
op(0xb4, ZeroPageRead, fp(LD), Y, X)
op(0xb5, ZeroPageRead, fp(LD), A, X)
op(0xb6, ZeroPageRead, fp(LD), X, Y)
op(0xb8, Clear, V)
op(0xb9, AbsoluteRead, fp(LD), A, Y)
op(0xba, Transfer, S, X, 1)
op(0xbc, AbsoluteRead, fp(LD), Y, X)
op(0xbd, AbsoluteRead, fp(LD), A, X)
op(0xbe, AbsoluteRead, fp(LD), X, Y)
op(0xc0, Immediate, fp(CPY), Y)
op(0xc1, IndirectXRead, fp(CMP), A)
op(0xc4, ZeroPageRead, fp(CPY), Y)
op(0xc5, ZeroPageRead, fp(CMP), A)
op(0xc6, ZeroPageModify, fp(DEC))
op(0xc8, Implied, fp(INC), Y)
op(0xc9, Immediate, fp(CMP), A)
op(0xca, Implied, fp(DEC), X)
op(0xcc, AbsoluteRead, fp(CPY), Y)
op(0xcd, AbsoluteRead, fp(CMP), A)
op(0xce, AbsoluteModify, fp(DEC))
op(0xd0, Branch, Z == 0)
op(0xd1, IndirectYRead, fp(CMP), A)
op(0xd5, ZeroPageRead, fp(CMP), A, X)
op(0xd6, ZeroPageModify, fp(DEC), X)
op(0xd8, Clear, D)
op(0xd9, AbsoluteRead, fp(CMP), A, Y)
op(0xdd, AbsoluteRead, fp(CMP), A, X)
op(0xde, AbsoluteModify, fp(DEC), X)
op(0xe0, Immediate, fp(CPX), X)
op(0xe1, IndirectXRead, fp(SBC), A)
op(0xe4, ZeroPageRead, fp(CPX), X)
op(0xe5, ZeroPageRead, fp(SBC), A)
op(0xe6, ZeroPageModify, fp(INC))
op(0xe8, Implied, fp(INC), X)
op(0xe9, Immediate, fp(SBC), A)
op(0xea, NoOperation)
op(0xec, AbsoluteRead, fp(CPX), X)
op(0xed, AbsoluteRead, fp(SBC), A)
op(0xee, AbsoluteModify, fp(INC))
op(0xf0, Branch, Z == 1)
op(0xf1, IndirectYRead, fp(SBC), A)
op(0xf5, ZeroPageRead, fp(SBC), A, X)
op(0xf6, ZeroPageModify, fp(INC), X)
op(0xf8, Set, D)
op(0xf9, AbsoluteRead, fp(SBC), A, Y)
op(0xfd, AbsoluteRead, fp(SBC), A, X)
op(0xfe, AbsoluteModify, fp(INC), X)
}
//unimplemented instruction
return instructionNoOperation();
}
#undef op
#undef fp

View File

@ -1,231 +0,0 @@
auto MOS6502::instructionAbsoluteModify(fp alu) -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
auto data = read(absolute);
write(absolute, data);
L write(absolute, ALU(data));
}
auto MOS6502::instructionAbsoluteModify(fp alu, uint8 index) -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
idlePageAlways(absolute, absolute + index);
auto data = read(absolute + index);
write(absolute + index, data);
L write(absolute + index, ALU(data));
}
auto MOS6502::instructionAbsoluteRead(fp alu, uint8& data) -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
L data = ALU(read(absolute));
}
auto MOS6502::instructionAbsoluteRead(fp alu, uint8& data, uint8 index) -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
idlePageCrossed(absolute, absolute + index);
L data = ALU(read(absolute + index));
}
auto MOS6502::instructionAbsoluteWrite(uint8& data) -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
L write(absolute, data);
}
auto MOS6502::instructionAbsoluteWrite(uint8& data, uint8 index) -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
idlePageAlways(absolute, absolute + index);
L write(absolute + index, data);
}
auto MOS6502::instructionBranch(bool take) -> void {
if(!take) {
L operand();
} else {
int8 displacement = operand();
idlePageCrossed(PC, PC + displacement);
L idle();
PC = PC + displacement;
}
}
auto MOS6502::instructionBreak() -> void {
operand();
push(PCH);
push(PCL);
uint16 vector = 0xfffe;
nmi(vector);
push(P | 0x30);
I = 1;
PCL = read(vector++);
L PCH = read(vector++);
}
auto MOS6502::instructionCallAbsolute() -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
idle();
PC--;
push(PCH);
L push(PCL);
PC = absolute;
}
auto MOS6502::instructionClear(bool& flag) -> void {
L idle();
flag = 0;
}
auto MOS6502::instructionImmediate(fp alu, uint8& data) -> void {
L data = ALU(operand());
}
auto MOS6502::instructionImplied(fp alu, uint8& data) -> void {
L idle();
data = ALU(data);
}
auto MOS6502::instructionIndirectXRead(fp alu, uint8& data) -> void {
auto zeroPage = operand();
load(zeroPage);
uint16 absolute = load(zeroPage + X + 0);
absolute |= load(zeroPage + X + 1) << 8;
L data = ALU(read(absolute));
}
auto MOS6502::instructionIndirectXWrite(uint8& data) -> void {
auto zeroPage = operand();
load(zeroPage);
uint16 absolute = load(zeroPage + X + 0);
absolute |= load(zeroPage + X + 1) << 8;
L write(absolute, data);
}
auto MOS6502::instructionIndirectYRead(fp alu, uint8& data) -> void {
auto zeroPage = operand();
uint16 absolute = load(zeroPage + 0);
absolute |= load(zeroPage + 1) << 8;
idlePageCrossed(absolute, absolute + Y);
L data = ALU(read(absolute + Y));
}
auto MOS6502::instructionIndirectYWrite(uint8& data) -> void {
auto zeroPage = operand();
uint16 absolute = load(zeroPage + 0);
absolute |= load(zeroPage + 1) << 8;
idlePageAlways(absolute, absolute + Y);
L write(absolute + Y, data);
}
auto MOS6502::instructionJumpAbsolute() -> void {
uint16 absolute = operand();
L absolute |= operand() << 8;
PC = absolute;
}
auto MOS6502::instructionJumpIndirect() -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
uint16 pc = read(absolute);
absolute.byte(0)++; //MOS6502: $00ff wraps here to $0000; not $0100
L pc |= read(absolute) << 8;
PC = pc;
}
auto MOS6502::instructionNoOperation() -> void {
L idle();
}
auto MOS6502::instructionPull(uint8& data) -> void {
idle();
idle();
L data = pull();
Z = data == 0;
N = data.bit(7);
}
auto MOS6502::instructionPullP() -> void {
idle();
idle();
L P = pull();
}
auto MOS6502::instructionPush(uint8& data) -> void {
idle();
L push(data);
}
auto MOS6502::instructionPushP() -> void {
idle();
L push(P | 0x30);
}
auto MOS6502::instructionReturnInterrupt() -> void {
idle();
idle();
P = pull();
PCL = pull();
L PCH = pull();
}
auto MOS6502::instructionReturnSubroutine() -> void {
idle();
idle();
PCL = pull();
PCH = pull();
L idle();
PC++;
}
auto MOS6502::instructionSet(bool& flag) -> void {
L idle();
flag = 1;
}
auto MOS6502::instructionTransfer(uint8& source, uint8& target, bool flag) -> void {
L idle();
target = source;
if(!flag) return;
Z = target == 0;
N = target.bit(7);
}
auto MOS6502::instructionZeroPageModify(fp alu) -> void {
auto zeroPage = operand();
auto data = load(zeroPage);
store(zeroPage, data);
L store(zeroPage, ALU(data));
}
auto MOS6502::instructionZeroPageModify(fp alu, uint8 index) -> void {
auto zeroPage = operand();
load(zeroPage);
auto data = load(zeroPage + index);
store(zeroPage + index, data);
L store(zeroPage + index, ALU(data));
}
auto MOS6502::instructionZeroPageRead(fp alu, uint8& data) -> void {
auto zeroPage = operand();
L data = ALU(load(zeroPage));
}
auto MOS6502::instructionZeroPageRead(fp alu, uint8& data, uint8 index) -> void {
auto zeroPage = operand();
load(zeroPage);
L data = ALU(load(zeroPage + index));
}
auto MOS6502::instructionZeroPageWrite(uint8& data) -> void {
auto zeroPage = operand();
L store(zeroPage, data);
}
auto MOS6502::instructionZeroPageWrite(uint8& data, uint8 index) -> void {
auto zeroPage = operand();
read(zeroPage);
L store(zeroPage + index, data);
}

View File

@ -1,36 +0,0 @@
auto MOS6502::idle() -> void {
read(PC);
}
auto MOS6502::idlePageCrossed(uint16 x, uint16 y) -> void {
if(x >> 8 == y >> 8) return;
read((x & 0xff00) | (y & 0x00ff));
}
auto MOS6502::idlePageAlways(uint16 x, uint16 y) -> void {
read((x & 0xff00) | (y & 0x00ff));
}
auto MOS6502::opcode() -> uint8 {
return read(PC++);
}
auto MOS6502::operand() -> uint8 {
return read(PC++);
}
auto MOS6502::load(uint8 addr) -> uint8 {
return read(addr);
}
auto MOS6502::store(uint8 addr, uint8 data) -> void {
write(addr, data);
}
auto MOS6502::push(uint8 data) -> void {
write(0x0100 | S--, data);
}
auto MOS6502::pull() -> uint8 {
return read(0x0100 | ++S);
}

View File

@ -1,60 +0,0 @@
#include <processor/processor.hpp>
#include "mos6502.hpp"
namespace Processor {
#define A r.a
#define X r.x
#define Y r.y
#define S r.s
#define P r.p
#define PC r.pc
#define PCH r.pc.byte(1)
#define PCL r.pc.byte(0)
#define ALU (this->*alu)
#define C r.p.c
#define Z r.p.z
#define I r.p.i
#define D r.p.d
#define V r.p.v
#define N r.p.n
#define L lastCycle();
#include "memory.cpp"
#include "algorithms.cpp"
#include "instruction.cpp"
#include "instructions.cpp"
#include "disassembler.cpp"
#include "serialization.cpp"
#undef A
#undef X
#undef Y
#undef S
#undef P
#undef PC
#undef PCH
#undef PCL
#undef ALU
#undef C
#undef Z
#undef I
#undef D
#undef V
#undef N
#undef L
auto MOS6502::mdr() const -> uint8 {
return r.mdr;
}
auto MOS6502::power() -> void {
r.a = 0x00;
r.x = 0x00;
r.y = 0x00;
r.s = 0xff;
r.p = 0x04;
r.mdr = 0x00;
}
}

View File

@ -1,130 +0,0 @@
//MOS Technologies MOS6502
#pragma once
namespace Processor {
struct MOS6502 {
virtual auto read(uint16 addr) -> uint8 = 0;
virtual auto write(uint16 addr, uint8 data) -> void = 0;
virtual auto lastCycle() -> void = 0;
virtual auto nmi(uint16& vector) -> void = 0;
virtual auto readDebugger(uint16 addr) -> uint8 { return 0; }
//mos6502.cpp
auto mdr() const -> uint8;
auto power() -> void;
//memory.cpp
auto idle() -> void;
auto idlePageCrossed(uint16, uint16) -> void;
auto idlePageAlways(uint16, uint16) -> void;
auto opcode() -> uint8;
auto operand() -> uint8;
auto load(uint8 addr) -> uint8;
auto store(uint8 addr, uint8 data) -> void;
auto push(uint8 data) -> void;
auto pull() -> uint8;
//algorithms.cpp
using fp = auto (MOS6502::*)(uint8) -> uint8;
auto algorithmADC(uint8) -> uint8;
auto algorithmAND(uint8) -> uint8;
auto algorithmASL(uint8) -> uint8;
auto algorithmBIT(uint8) -> uint8;
auto algorithmCMP(uint8) -> uint8;
auto algorithmCPX(uint8) -> uint8;
auto algorithmCPY(uint8) -> uint8;
auto algorithmDEC(uint8) -> uint8;
auto algorithmEOR(uint8) -> uint8;
auto algorithmINC(uint8) -> uint8;
auto algorithmLD (uint8) -> uint8;
auto algorithmLSR(uint8) -> uint8;
auto algorithmORA(uint8) -> uint8;
auto algorithmROL(uint8) -> uint8;
auto algorithmROR(uint8) -> uint8;
auto algorithmSBC(uint8) -> uint8;
//instruction.cpp
auto interrupt() -> void;
auto instruction() -> void;
//instructions.cpp
auto instructionAbsoluteModify(fp alu) -> void;
auto instructionAbsoluteModify(fp alu, uint8 index) -> void;
auto instructionAbsoluteRead(fp alu, uint8& data) -> void;
auto instructionAbsoluteRead(fp alu, uint8& data, uint8 index) -> void;
auto instructionAbsoluteWrite(uint8& data) -> void;
auto instructionAbsoluteWrite(uint8& data, uint8 index) -> void;
auto instructionBranch(bool take) -> void;
auto instructionBreak() -> void;
auto instructionCallAbsolute() -> void;
auto instructionClear(bool& flag) -> void;
auto instructionImmediate(fp alu, uint8& data) -> void;
auto instructionImplied(fp alu, uint8& data) -> void;
auto instructionIndirectXRead(fp alu, uint8& data) -> void;
auto instructionIndirectXWrite(uint8& data) -> void;
auto instructionIndirectYRead(fp alu, uint8& data) -> void;
auto instructionIndirectYWrite(uint8& data) -> void;
auto instructionJumpAbsolute() -> void;
auto instructionJumpIndirect() -> void;
auto instructionNoOperation() -> void;
auto instructionPull(uint8& data) -> void;
auto instructionPullP() -> void;
auto instructionPush(uint8& data) -> void;
auto instructionPushP() -> void;
auto instructionReturnInterrupt() -> void;
auto instructionReturnSubroutine() -> void;
auto instructionSet(bool& flag) -> void;
auto instructionTransfer(uint8& source, uint8& target, bool flag) -> void;
auto instructionZeroPageModify(fp alu) -> void;
auto instructionZeroPageModify(fp alu, uint8 index) -> void;
auto instructionZeroPageRead(fp alu, uint8& data) -> void;
auto instructionZeroPageRead(fp alu, uint8& data, uint8 index) -> void;
auto instructionZeroPageWrite(uint8& data) -> void;
auto instructionZeroPageWrite(uint8& data, uint8 index) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
//disassembler.cpp
auto disassemble(uint16 pc) -> string;
//set to false to disable BCD mode in ADC, SBC instructions
bool BCD = true;
struct Flags {
bool c; //carry
bool z; //zero
bool i; //interrupt disable
bool d; //decimal mode
bool v; //overflow
bool n; //negative
inline operator uint() const {
return c << 0 | z << 1 | i << 2 | d << 3 | v << 6 | n << 7;
}
inline auto& operator=(uint8 data) {
c = data.bit(0);
z = data.bit(1);
i = data.bit(2);
d = data.bit(3);
v = data.bit(6);
n = data.bit(7);
return *this;
}
};
struct Registers {
uint8 a;
uint8 x;
uint8 y;
uint8 s;
uint16 pc;
Flags p;
uint8 mdr;
} r;
};
}

View File

@ -1,15 +0,0 @@
auto MOS6502::serialize(serializer& s) -> void {
s.integer(BCD);
s.integer(r.a);
s.integer(r.x);
s.integer(r.y);
s.integer(r.s);
s.integer(r.pc);
s.integer(r.p.c);
s.integer(r.p.z);
s.integer(r.p.i);
s.integer(r.p.d);
s.integer(r.p.v);
s.integer(r.p.n);
s.integer(r.mdr);
}

View File

@ -20,7 +20,7 @@ auto SM83::AND(uint8 target, uint8 source) -> uint8 {
auto SM83::BIT(uint3 index, uint8 target) -> void {
HF = 1;
NF = 0;
ZF = target.bit(index) == 0;
ZF = bit1(target,index) == 0;
}
auto SM83::CP(uint8 target, uint8 source) -> void {
@ -50,68 +50,77 @@ auto SM83::INC(uint8 target) -> uint8 {
auto SM83::OR(uint8 target, uint8 source) -> uint8 {
target |= source;
CF = HF = NF = 0;
CF = 0;
HF = 0;
NF = 0;
ZF = target == 0;
return target;
}
auto SM83::RL(uint8 target) -> uint8 {
bool carry = target.bit(7);
bool carry = target >> 7;
target = target << 1 | CF;
CF = carry;
HF = NF = 0;
HF = 0;
NF = 0;
ZF = target == 0;
return target;
}
auto SM83::RLC(uint8 target) -> uint8 {
target = target << 1 | target >> 7;
CF = target.bit(0);
HF = NF = 0;
CF = target & 1;
HF = 0;
NF = 0;
ZF = target == 0;
return target;
}
auto SM83::RR(uint8 target) -> uint8 {
bool carry = target.bit(0);
bool carry = target & 1;
target = CF << 7 | target >> 1;
CF = carry;
HF = NF = 0;
HF = 0;
NF = 0;
ZF = target == 0;
return target;
}
auto SM83::RRC(uint8 target) -> uint8 {
target = target << 7 | target >> 1;
CF = target.bit(7);
HF = NF = 0;
CF = target >> 7;
HF = 0;
NF = 0;
ZF = target == 0;
return target;
}
auto SM83::SLA(uint8 target) -> uint8 {
bool carry = target.bit(7);
bool carry = target >> 7;
target <<= 1;
CF = carry;
HF = NF = 0;
HF = 0;
NF = 0;
ZF = target == 0;
return target;
}
auto SM83::SRA(uint8 target) -> uint8 {
bool carry = target.bit(0);
bool carry = target & 1;
target = (int8)target >> 1;
CF = carry;
HF = NF = 0;
HF = 0;
NF = 0;
ZF = target == 0;
return target;
}
auto SM83::SRL(uint8 target) -> uint8 {
bool carry = target.bit(0);
bool carry = target & 1;
target >>= 1;
CF = carry;
HF = NF = 0;
HF = 0;
NF = 0;
ZF = target == 0;
return target;
}
@ -128,14 +137,18 @@ auto SM83::SUB(uint8 target, uint8 source, bool carry) -> uint8 {
auto SM83::SWAP(uint8 target) -> uint8 {
target = target << 4 | target >> 4;
CF = HF = NF = 0;
CF = 0;
HF = 0;
NF = 0;
ZF = target == 0;
return target;
}
auto SM83::XOR(uint8 target, uint8 source) -> uint8 {
target ^= source;
CF = HF = NF = 0;
CF = 0;
HF = 0;
NF = 0;
ZF = target == 0;
return target;
}

View File

@ -332,8 +332,8 @@ auto SM83::instructionCB() -> void {
}
//opcodes 0x40-0xff [op(0x00 - 0x07) declared above]
uint3 bit = opcode.bits(3,5);
switch(opcode.bits(6,7) << 3 | opcode.bits(0,2)) {
uint3 bit = bits(opcode,3-5);
switch(bits(opcode,6-7) << 3 | bits(opcode,0-2)) {
op(0x08, BIT_Index_Direct, bit, B)
op(0x09, BIT_Index_Direct, bit, C)
op(0x0a, BIT_Index_Direct, bit, D)

View File

@ -38,7 +38,8 @@ auto SM83::instructionADD_Direct_Relative(uint16& target) -> void {
idle();
CF = (uint8)target + (uint8)data > 0xff;
HF = (uint4)target + (uint4)data > 0x0f;
NF = ZF = 0;
NF = 0;
ZF = 0;
target += (int8)data;
}
@ -73,7 +74,8 @@ auto SM83::instructionCALL_Condition_Address(bool take) -> void {
auto SM83::instructionCCF() -> void {
CF = !CF;
HF = NF = 0;
HF = 0;
NF = 0;
}
auto SM83::instructionCP_Direct_Data(uint8& target) -> void {
@ -90,7 +92,8 @@ auto SM83::instructionCP_Direct_Indirect(uint8& target, uint16& source) -> void
auto SM83::instructionCPL() -> void {
A = ~A;
HF = NF = 1;
HF = 1;
NF = 1;
}
auto SM83::instructionDAA() -> void {
@ -106,7 +109,7 @@ auto SM83::instructionDAA() -> void {
if(CF) a -= 0x60;
}
A = a;
CF |= a.bit(8);
CF |= bit1(a,8);
HF = 0;
ZF = A == 0;
}
@ -204,7 +207,8 @@ auto SM83::instructionLD_Direct_DirectRelative(uint16& target, uint16& source) -
idle();
CF = (uint8)source + (uint8)data > 0xff;
HF = (uint4)source + (uint4)data > 0x0f;
NF = ZF = 0;
NF = 0;
ZF = 0;
target = source + (int8)data;
}
@ -277,12 +281,12 @@ auto SM83::instructionPUSH_Direct(uint16& data) -> void {
}
auto SM83::instructionRES_Index_Direct(uint3 index, uint8& data) -> void {
data.bit(index) = 0;
bit1(data,index) = 0;
}
auto SM83::instructionRES_Index_Indirect(uint3 index, uint16& address) -> void {
auto data = read(address);
data.bit(index) = 0;
bit1(data,index) = 0;
write(address, data);
}
@ -382,16 +386,17 @@ auto SM83::instructionSBC_Direct_Indirect(uint8& target, uint16& source) -> void
auto SM83::instructionSCF() -> void {
CF = 1;
HF = NF = 0;
HF = 0;
NF = 0;
}
auto SM83::instructionSET_Index_Direct(uint3 index, uint8& data) -> void {
data.bit(index) = 1;
bit1(data,index) = 1;
}
auto SM83::instructionSET_Index_Indirect(uint3 index, uint16& address) -> void {
auto data = read(address);
data.bit(index) = 1;
bit1(data,index) = 1;
write(address, data);
}

View File

@ -14,7 +14,7 @@
#define H r.hl.byte.hi
#define L r.hl.byte.lo
#define CF r.af.byte.lo.bit(4)
#define HF r.af.byte.lo.bit(5)
#define NF r.af.byte.lo.bit(6)
#define ZF r.af.byte.lo.bit(7)
#define CF bit1(r.af.byte.lo,4)
#define HF bit1(r.af.byte.lo,5)
#define NF bit1(r.af.byte.lo,6)
#define ZF bit1(r.af.byte.lo,7)

View File

@ -7,32 +7,32 @@ auto SPC700::instructionAbsoluteBitModify(uint3 mode) -> void {
switch(mode) {
case 0: //or addr:bit
idle();
CF |= data.bit(bit);
CF |= bit1(data,bit);
break;
case 1: //or !addr:bit
idle();
CF |= !data.bit(bit);
CF |= !bit1(data,bit);
break;
case 2: //and addr:bit
CF &= data.bit(bit);
CF &= bit1(data,bit);
break;
case 3: //and !addr:bit
CF &= !data.bit(bit);
CF &= !bit1(data,bit);
break;
case 4: //eor addr:bit
idle();
CF ^= data.bit(bit);
CF ^= bit1(data,bit);
break;
case 5: //ld addr:bit
CF = data.bit(bit);
CF = bit1(data,bit);
break;
case 6: //st addr:bit
idle();
data.bit(bit) = CF;
bit1(data,bit) = CF;
write(address, data);
break;
case 7: //not addr:bit
data.bit(bit) ^= 1;
bit1(data,bit) ^= 1;
write(address, data);
break;
}
@ -41,7 +41,7 @@ auto SPC700::instructionAbsoluteBitModify(uint3 mode) -> void {
auto SPC700::instructionAbsoluteBitSet(uint3 bit, bool value) -> void {
uint8 address = fetch();
uint8 data = load(address);
data.bit(bit) = value;
bit1(data,bit) = value;
store(address, data);
}
@ -95,7 +95,7 @@ auto SPC700::instructionBranchBit(uint3 bit, bool match) -> void {
uint8 data = load(address);
idle();
uint8 displacement = fetch();
if(data.bit(bit) != match) return;
if(bit1(data,bit) != match) return;
idle();
idle();
PC += (int8)displacement;

View File

@ -120,28 +120,28 @@ struct SPC700 {
auto disassemble(uint16 address, bool p) -> string;
struct Flags {
bool c; //carry
bool z; //zero
bool i; //interrupt disable
bool h; //half-carry
bool b; //break
bool p; //page
bool v; //overflow
bool n; //negative
bool c = 0; //carry
bool z = 0; //zero
bool i = 0; //interrupt disable
bool h = 0; //half-carry
bool b = 0; //break
bool p = 0; //page
bool v = 0; //overflow
bool n = 0; //negative
inline operator uint() const {
return c << 0 | z << 1 | i << 2 | h << 3 | b << 4 | p << 5 | v << 6 | n << 7;
}
inline auto& operator=(uint8 data) {
c = data.bit(0);
z = data.bit(1);
i = data.bit(2);
h = data.bit(3);
b = data.bit(4);
p = data.bit(5);
v = data.bit(6);
n = data.bit(7);
c = bit1(data,0);
z = bit1(data,1);
i = bit1(data,2);
h = bit1(data,3);
b = bit1(data,4);
p = bit1(data,5);
v = bit1(data,6);
n = bit1(data,7);
return *this;
}
};
@ -152,11 +152,12 @@ struct SPC700 {
uint16 w;
struct Byte { uint8 order_lsb2(l, h); } byte;
} pc, ya;
uint8 x, s;
uint8 x = 0;
uint8 s = 0;
Flags p;
bool wait = false;
bool stop = false;
bool wait = 0;
bool stop = 0;
} r;
};

View File

@ -1,123 +0,0 @@
template<> auto TLCS900H::parity< uint8>( uint8 data) const -> bool {
data ^= data >> 4;
data ^= data >> 2;
data ^= data >> 1;
return !(data & 1);
}
template<> auto TLCS900H::parity<uint16>(uint16 data) const -> bool {
data ^= data >> 8;
data ^= data >> 4;
data ^= data >> 2;
data ^= data >> 1;
return !(data & 1);
}
template<> auto TLCS900H::parity<uint32>(uint32 data) const -> bool {
return Undefined;
}
//
template<typename T> auto TLCS900H::algorithmAdd(T target, T source, uint1 carry) -> T {
T result = target + source + carry;
T carries = target ^ source ^ result;
T overflow = (target ^ result) & (source ^ result);
CF = T(carries ^ overflow).bit(-1);
NF = 0;
VF = overflow.bit(-1);
HF = carries.bit(4);
if constexpr(T::bits() == 32) HF = Undefined;
ZF = result == 0;
SF = result.bit(-1);
return result;
}
template<typename T> auto TLCS900H::algorithmAnd(T target, T source) -> T {
T result = target & source;
CF = 0;
NF = 0;
PF = parity(result);
HF = 1;
ZF = result == 0;
SF = result.bit(-1);
return result;
}
template<typename T> auto TLCS900H::algorithmDecrement(T target, T source) -> T {
T result = target - source;
if constexpr(T::bits() == 8) {
NF = 1;
VF = T((target ^ source) & (target ^ result)).bit(-1);
HF = T(target ^ source ^ result).bit(4);
ZF = result == 0;
SF = result.bit(-1);
}
return result;
}
template<typename T> auto TLCS900H::algorithmIncrement(T target, T source) -> T {
T result = target + source;
if constexpr(T::bits() == 8) {
NF = 0;
VF = T((target ^ result) & (source ^ result)).bit(-1);
HF = T(target ^ source ^ result).bit(4);
ZF = result == 0;
SF = result.bit(-1);
}
return result;
}
template<typename T> auto TLCS900H::algorithmOr(T target, T source) -> T {
T result = target | source;
CF = 0;
NF = 0;
PF = parity(result);
HF = 0;
ZF = result == 0;
SF = result.bit(-1);
return result;
}
template<typename T> auto TLCS900H::algorithmRotated(T result) -> T {
NF = 0;
PF = parity(result);
HF = 0;
ZF = result == 0;
SF = result.bit(-1);
return result;
}
template<typename T> auto TLCS900H::algorithmShifted(T result) -> T {
NF = 0;
PF = parity(result);
HF = 0;
ZF = result == 0;
SF = result.bit(-1);
return result;
}
template<typename T> auto TLCS900H::algorithmSubtract(T target, T source, uint1 carry) -> T {
T result = target - source - carry;
T carries = target ^ source ^ result;
T overflow = (target ^ result) & (source ^ target);
CF = T(carries ^ overflow).bit(-1);
NF = 1;
VF = overflow.bit(-1);
HF = carries.bit(4);
if constexpr(T::bits() == 32) HF = Undefined;
ZF = result == 0;
SF = result.bit(-1);
return result;
}
template<typename T> auto TLCS900H::algorithmXor(T target, T source) -> T {
T result = target ^ source;
CF = 0;
NF = 0;
PF = parity(result);
HF = 0;
ZF = result == 0;
SF = result.bit(-1);
return result;
}

View File

@ -1,20 +0,0 @@
auto TLCS900H::condition(uint4 code) -> bool {
switch(code) {
case 0: return 0 == 1; //F (false)
case 1: return (SF ^ VF) == 1; //LT (signed less than)
case 2: return (ZF | SF ^ VF) == 1; //LE (signed less than or equal)
case 3: return (CF | ZF) == 1; //ULE (unsigned less than or equal)
case 4: return VF == 1; //OV (overflow)
case 5: return SF == 1; //MI (minus)
case 6: return ZF == 1; //EQ (equal)
case 7: return CF == 1; //ULT (unsigned less than)
case 8: return 0 == 0; //T (true)
case 9: return (SF ^ VF) == 0; //GE (signed greater than or equal)
case 10: return (ZF | SF ^ VF) == 0; //GT (signed greater than)
case 11: return (CF | ZF) == 0; //UGT (unsigned greater than)
case 12: return VF == 0; //NOV (no overflow)
case 13: return SF == 0; //PL (plus)
case 14: return ZF == 0; //NE (not equal)
case 15: return CF == 0; //UGE (unsigned greater than or equal)
} unreachable;
}

View File

@ -1,80 +0,0 @@
template<> auto TLCS900H::map(ControlRegister<uint8> register) const -> maybe<uint8&> {
switch(register.id) {
#define r(id, name) case id: return r.name;
r(0x00, dmas[0].b.b0) r(0x01, dmas[0].b.b1) r(0x02, dmas[0].b.b2) r(0x03, dmas[0].b.b3)
r(0x04, dmas[1].b.b0) r(0x05, dmas[1].b.b1) r(0x06, dmas[1].b.b2) r(0x07, dmas[1].b.b3)
r(0x08, dmas[2].b.b0) r(0x09, dmas[2].b.b1) r(0x0a, dmas[2].b.b2) r(0x0b, dmas[2].b.b3)
r(0x0c, dmas[3].b.b0) r(0x0d, dmas[3].b.b1) r(0x0e, dmas[3].b.b2) r(0x0f, dmas[3].b.b3)
r(0x10, dmad[0].b.b0) r(0x11, dmad[0].b.b1) r(0x12, dmad[0].b.b2) r(0x13, dmad[0].b.b3)
r(0x14, dmad[1].b.b0) r(0x15, dmad[1].b.b1) r(0x16, dmad[1].b.b2) r(0x17, dmad[1].b.b3)
r(0x18, dmad[2].b.b0) r(0x19, dmad[2].b.b1) r(0x1a, dmad[2].b.b2) r(0x1b, dmad[2].b.b3)
r(0x1c, dmad[3].b.b0) r(0x1d, dmad[3].b.b1) r(0x1e, dmad[3].b.b2) r(0x1f, dmad[3].b.b3)
r(0x20, dmam[0].b.b0) r(0x21, dmam[0].b.b1) r(0x22, dmam[0].b.b2) r(0x23, dmam[0].b.b3)
r(0x24, dmam[1].b.b0) r(0x25, dmam[1].b.b1) r(0x26, dmam[1].b.b2) r(0x27, dmam[1].b.b3)
r(0x28, dmam[2].b.b0) r(0x29, dmam[2].b.b1) r(0x2a, dmam[2].b.b2) r(0x2b, dmam[2].b.b3)
r(0x2c, dmam[3].b.b0) r(0x2d, dmam[3].b.b1) r(0x2e, dmam[3].b.b3) r(0x2f, dmam[3].b.b3)
r(0x3c, intnest.b.b0) r(0x3d, intnest.b.b1)
#undef r
}
return nothing;
}
template<> auto TLCS900H::map(ControlRegister<uint16> register) const -> maybe<uint16&> {
switch(register.id & ~1) {
#define r(id, name) case id: return r.name;
r(0x00, dmas[0].w.w0) r(0x02, dmas[0].w.w1)
r(0x04, dmas[1].w.w0) r(0x06, dmas[1].w.w1)
r(0x08, dmas[2].w.w0) r(0x0a, dmas[2].w.w1)
r(0x0c, dmas[3].w.w0) r(0x0e, dmas[3].w.w1)
r(0x10, dmad[0].w.w0) r(0x12, dmad[0].w.w1)
r(0x14, dmad[1].w.w0) r(0x16, dmad[1].w.w1)
r(0x18, dmad[2].w.w0) r(0x1a, dmad[2].w.w1)
r(0x1c, dmad[3].w.w0) r(0x1e, dmad[3].w.w1)
r(0x20, dmam[0].w.w0) r(0x22, dmam[0].w.w1)
r(0x24, dmam[1].w.w0) r(0x26, dmam[1].w.w1)
r(0x28, dmam[2].w.w0) r(0x2a, dmam[2].w.w1)
r(0x2c, dmam[3].w.w0) r(0x2e, dmam[3].w.w1)
r(0x3c, intnest.w.w0)
#undef r
}
return nothing;
}
template<> auto TLCS900H::map(ControlRegister<uint32> register) const -> maybe<uint32&> {
switch(register.id & ~1) {
#define r(id, name) case id: return r.name;
r(0x00, dmas[0].l.l0)
r(0x04, dmas[1].l.l0)
r(0x08, dmas[2].l.l0)
r(0x0c, dmas[3].l.l0)
r(0x10, dmad[0].l.l0)
r(0x14, dmad[1].l.l0)
r(0x18, dmad[2].l.l0)
r(0x1c, dmad[3].l.l0)
r(0x20, dmam[0].l.l0)
r(0x24, dmam[1].l.l0)
r(0x28, dmam[2].l.l0)
r(0x2c, dmam[3].l.l0)
r(0x3c, intnest.l.l0)
#undef r
}
return nothing;
}
template<> auto TLCS900H::load< uint8>(ControlRegister< uint8> register) const -> uint8 { return map(register)(Undefined); }
template<> auto TLCS900H::load<uint16>(ControlRegister<uint16> register) const -> uint16 { return map(register)(Undefined); }
template<> auto TLCS900H::load<uint32>(ControlRegister<uint32> register) const -> uint32 { return map(register)(Undefined); }
template<> auto TLCS900H::store<uint8>(ControlRegister<uint8> register, uint32 data) -> void {
if(auto r = map(register)) r() = data;
}
template<> auto TLCS900H::store<uint16>(ControlRegister<uint16> register, uint32 data) -> void {
if(auto r = map(register)) r() = data;
}
template<> auto TLCS900H::store<uint32>(ControlRegister<uint32> register, uint32 data) -> void {
//INTNEST is 16-bit: this isn't the nicest way to handle this, but ...
if((register.id & ~3) == 0x3c) data = (uint16)data;
if(auto r = map(register)) r() = data;
}

View File

@ -1,716 +0,0 @@
auto TLCS900H::disassemble() -> string {
string output;
auto pc = r.pc.l.l0;
output.append(hex(pc, 6L), " ");
uint8 op[8] = {}, ops = 0;
auto read8 = [&]() -> uint8 { return op[ops++] = disassembleRead(pc++); };
auto read16 = [&]() -> uint16 { uint16 data = read8(); return data | read8() << 8; };
auto read24 = [&]() -> uint24 { uint24 data = read8(); data |= read8() << 8; return data | read8() << 16; };
auto read32 = [&]() -> uint32 { uint32 data = read8(); data |= read8() << 8; data |= read8() << 16; return data | read8() << 24; };
enum : uint {
Null,
Text, //text
Condition, //condition
Register, //register.size
Control, //register.size
Immediate, //immediate.size
Displacement, //displacement.size
DisplacementPC, //pc+displacement.size
IndirectRegister, //op.size (r32)
IndirectRegisterDecrement, //op.size (-r32)
IndirectRegisterIncrement, //op.size (r32+)
IndirectRegisterRegister8, //op.size (r32+r8)
IndirectRegisterRegister16, //op.size (r32+r16)
IndirectRegisterDisplacement8, //op.size (r32+d8)
IndirectRegisterDisplacement16, //op.size (r32+d16)
IndirectImmediate8, //(i8)
IndirectImmediate16, //(i16)
IndirectImmediate24, //(i24)
};
//name [lhs[,rhs]]
string name;
struct Operand {
explicit operator bool() const { return _mode != Null; }
auto mode() const { return _mode; }
auto size() const { return _size; }
auto text() const { return _text; }
auto condition() const { return _condition; }
auto register() const { return _register; }
auto registerAdd() const { return _registerAdd; }
auto immediate() const { return _immediate; }
auto displacement() const { return _displacement; }
auto mode(natural mode_) -> void { _mode = mode_; }
auto size(natural size_) -> void { _size = size_; }
auto null() -> void { mode(Null); }
auto text(string text_) -> void { mode(Text); _text = text_; }
auto condition(uint4 condition_) -> void { mode(Condition); _condition = condition_; }
auto register(natural size_, uint8 register_) -> void { mode(Register); size(size_); _register = register_; }
auto register3(natural size_, uint3 register_) -> void { mode(Register); size(size_); _register = lookup(size_, register_); }
auto control(natural size_, uint8 register_) -> void { mode(Control); size(size_); _register = register_; }
auto immediate(natural size_, natural immediate_) -> void { mode(Immediate); size(size_); _immediate = immediate_; }
auto displacement(natural size_, natural displacement_) -> void { mode(Displacement); size(size_); _displacement = displacement_; }
auto displacementPC(natural size_, natural displacement_) -> void { mode(DisplacementPC); size(size_); _displacement = displacement_; }
auto indirectRegister(natural size_, uint8 register_) -> void { mode(IndirectRegister); size(size_); _register = register_; }
auto indirectRegister3(natural size_, uint3 register_) -> void { mode(IndirectRegister); size(size_); _register = lookup(32, register_); }
auto indirectRegisterDecrement(natural size_, uint8 register_) -> void { mode(IndirectRegisterDecrement); size(size_); _register = register_; }
auto indirectRegisterIncrement(natural size_, uint8 register_) -> void { mode(IndirectRegisterIncrement); size(size_); _register = register_; }
auto indirectRegister3Increment(natural size_, uint3 register_) -> void { mode(IndirectRegisterIncrement); size(size_); _register = lookup(32, register_); }
auto indirectRegisterRegister8(natural size_, uint8 register32, uint8 register8) -> void { mode(IndirectRegisterRegister8); size(size_); _register = register32; _registerAdd = register8; }
auto indirectRegisterRegister16(natural size_, uint8 register32, uint8 register16) -> void { mode(IndirectRegisterRegister16); size(size_); _register = register32; _registerAdd = register16; }
auto indirectRegister3Displacement8(natural size_, uint3 register_, uint8 displacement_) -> void { mode(IndirectRegisterDisplacement8); size(size_); _register = lookup(32, register_); _displacement = displacement_; }
auto indirectRegisterDisplacement16(natural size_, uint8 register_, uint16 displacement_) -> void { mode(IndirectRegisterDisplacement16); size(size_); _register = register_; _displacement = displacement_; }
auto indirectImmediate8(natural size_, uint8 immediate_) -> void { mode(IndirectImmediate8); size(size_); _immediate = immediate_; }
auto indirectImmediate16(natural size_, uint16 immediate_) -> void { mode(IndirectImmediate16); size(size_); _immediate = immediate_; }
auto indirectImmediate24(natural size_, uint24 immediate_) -> void { mode(IndirectImmediate24); size(size_); _immediate = immediate_; }
private:
natural _mode = Null;
natural _size;
string _text;
natural _condition;
natural _register;
natural _registerAdd;
natural _immediate;
natural _displacement;
static auto lookup(natural size, uint3 register) -> uint8 {
if(size == 8) return from_array<0xe1, 0xe0, 0xe5, 0xe4, 0xe9, 0xe8, 0xed, 0xec>(register);
if(size == 16) return from_array<0xe0, 0xe4, 0xe8, 0xec, 0xf0, 0xf4, 0xf8, 0xfc>(register);
if(size == 32) return from_array<0xe0, 0xe4, 0xe8, 0xec, 0xf0, 0xf4, 0xf8, 0xfc>(register);
return 0;
}
} lhs, rhs;
boolean opRegister;
boolean opSourceMemory;
boolean opTargetMemory;
static const natural opSizes[] = {8, 16, 32, 0}; //0xc0 - 0xf5 use combined logic switch cases:
#define opSize opSizes[fetch.bits(4,5)] //extract the size from the opcode fetch
switch(auto fetch = read8()) {
case 0x00: name = "nop"; break;
case 0x01: break; //"normal" (not present on 900/H)
case 0x02: name = "push"; lhs.text("sr"); break;
case 0x03: name = "pop"; lhs.text("sr"); break;
case 0x04: break; //"max" or "min" (not present on 900/H)
case 0x05: name = "halt"; break;
case 0x06: name = "ei"; lhs.immediate(3, (uint3)read8()); if(lhs.immediate() == 7) name = "di", lhs.null(); break;
case 0x07: name = "reti"; break;
case 0x08: name = "ld"; lhs.indirectImmediate8(8, read8()); rhs.immediate(8, read8()); break;
case 0x09: name = "push"; lhs.immediate(8, read8()); break;
case 0x0a: name = "ldw"; lhs.indirectImmediate8(8, read8()); rhs.immediate(16, read16()); break;
case 0x0b: name = "pushw"; lhs.immediate(16, read16()); break;
case 0x0c: name = "incf"; break;
case 0x0d: name = "decf"; break;
case 0x0e: name = "ret"; break;
case 0x0f: name = "retd"; lhs.displacement(16, read16()); break;
case 0x10: name = "rcf"; break;
case 0x11: name = "scf"; break;
case 0x12: name = "ccf"; break;
case 0x13: name = "zcf"; break;
case 0x14: name = "push"; lhs.register3(8, A.id); break;
case 0x15: name = "pop"; lhs.register3(8, A.id); break;
case 0x16: name = "ex"; lhs.text("f"); rhs.text("f'"); break;
case 0x17: name = "ldf"; lhs.immediate(2, (uint2)read8()); break;
case 0x18: name = "push"; lhs.text("f"); break;
case 0x19: name = "pop"; lhs.text("f"); break;
case 0x1a: name = "jp"; lhs.immediate(16, read16()); break;
case 0x1b: name = "jp"; lhs.immediate(24, read24()); break;
case 0x1c: name = "call"; lhs.immediate(16, read16()); break;
case 0x1d: name = "call"; lhs.immediate(24, read24()); break;
case 0x1e: name = "calr"; lhs.displacementPC(16, read16()); break;
case 0x1f: break;
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
name = "ld"; lhs.register3(8, fetch); rhs.immediate(8, read8()); break;
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
name = "push"; lhs.register3(16, fetch); break;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
name = "ld"; lhs.register3(16, fetch); rhs.immediate(16, read16()); break;
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
name = "push"; lhs.register3(32, fetch); break;
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
name = "ld"; lhs.register3(32, fetch); rhs.immediate(32, read32()); break;
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
name = "pop"; lhs.register3(16, fetch); break;
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: break;
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
name = "pop"; lhs.register3(32, fetch); break;
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
name = "jr"; lhs.condition(fetch); rhs.displacementPC(8, read8()); break;
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
name = "jrl"; lhs.condition(fetch); rhs.displacementPC(16, read16()); break;
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
opSourceMemory = true; lhs.indirectRegister3(8, fetch); break;
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
opSourceMemory = true; lhs.indirectRegister3Displacement8(8, fetch, read8()); break;
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
opSourceMemory = true; lhs.indirectRegister3(16, fetch); break;
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
opSourceMemory = true; lhs.indirectRegister3Displacement8(16, fetch, read8()); break;
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
opSourceMemory = true; lhs.indirectRegister3(32, fetch); break;
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
opSourceMemory = true; lhs.indirectRegister3Displacement8(32, fetch, read8()); break;
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
opTargetMemory = true; lhs.indirectRegister3(0, fetch); break;
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
opTargetMemory = true; lhs.indirectRegister3Displacement8(0, fetch, read8()); break;
case 0xc0: case 0xd0: case 0xe0: case 0xf0:
opSourceMemory = fetch < 0xf0; opTargetMemory = !opSourceMemory;
lhs.indirectImmediate8(opSize, read8()); break;
case 0xc1: case 0xd1: case 0xe1: case 0xf1:
opSourceMemory = fetch < 0xf0; opTargetMemory = !opSourceMemory;
lhs.indirectImmediate16(opSize, read16()); break;
case 0xc2: case 0xd2: case 0xe2: case 0xf2:
opSourceMemory = fetch < 0xf0; opTargetMemory = !opSourceMemory;
lhs.indirectImmediate24(opSize, read24()); break;
case 0xc3: case 0xd3: case 0xe3: case 0xf3: {
opSourceMemory = fetch < 0xf0; opTargetMemory = !opSourceMemory;
auto data = read8();
if((uint2)data == 0) lhs.indirectRegister(opSize, data);
if((uint2)data == 1) lhs.indirectRegisterDisplacement16(opSize, data, read16());
if(data == 0x03) { auto r32 = read8(); lhs.indirectRegisterRegister8(opSize, r32, read8()); }
if(data == 0x07) { auto r32 = read8(); lhs.indirectRegisterRegister16(opSize, r32, read16()); }
} break;
case 0xc4: case 0xd4: case 0xe4: case 0xf4:
opSourceMemory = fetch < 0xf0; opTargetMemory = !opSourceMemory;
lhs.indirectRegisterDecrement(opSize, read8()); break;
case 0xc5: case 0xd5: case 0xe5: case 0xf5:
opSourceMemory = fetch < 0xf0; opTargetMemory = !opSourceMemory;
lhs.indirectRegisterIncrement(opSize, read8()); break;
case 0xc6: case 0xd6: case 0xe6: case 0xf6: break;
case 0xc7: case 0xd7: case 0xe7:
opRegister = true;
lhs.indirectRegister(opSize, read8()); break;
case 0xf7:
name = "ldx";
read8(); lhs.indirectImmediate8(8, read8());
read8(); rhs.immediate(8, read8());
read8(); break;
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
opRegister = true; lhs.register3(8, fetch); break;
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
opRegister = true; lhs.register3(16, fetch); break;
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
opRegister = true; lhs.register3(32, fetch); break;
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
name = "swi"; lhs.immediate(3, (uint3)fetch); break;
}
#undef opSize
auto reads = [&](uint size) -> uint32 {
if(size == 8) return read8();
if(size == 16) return read16();
if(size == 24) return read24();
if(size == 32) return read32();
return 0;
};
//size defined
if(opRegister)
switch(auto fetch = read8()) {
case 0x00: case 0x01: case 0x02: break;
case 0x03: name = "ld"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x04: name = "push"; break;
case 0x05: name = "pop"; break;
case 0x06: name = "cpl"; break;
case 0x07: name = "neg"; break;
case 0x08: name = "mul"; rhs.immediate(lhs.size(), reads(lhs.size())); lhs.register3(16, op[0]); break;
case 0x09: name = "muls"; rhs.immediate(lhs.size(), reads(lhs.size())); lhs.register3(16, op[0]); break;
case 0x0a: name = "div"; rhs.immediate(lhs.size(), reads(lhs.size())); lhs.register3(16, op[0]); break;
case 0x0b: name = "divs"; rhs.immediate(lhs.size(), reads(lhs.size())); lhs.register3(16, op[0]); break;
case 0x0c: name = "link"; rhs.displacement(16, read16()); break;
case 0x0d: name = "unlk"; break;
case 0x0e: name = "bs1f"; rhs = lhs; lhs.register(8, A.id); break;
case 0x0f: name = "bs1b"; rhs = lhs; lhs.register(8, A.id); break;
case 0x10: name = "daa"; break;
case 0x11: break;
case 0x12: name = "extz"; break;
case 0x13: name = "exts"; break;
case 0x14: name = "paa"; break;
case 0x15: break;
case 0x16: name = "mirr"; break;
case 0x17: case 0x18: break;
case 0x19: name = "mula"; break;
case 0x1a: case 0x1b: break;
case 0x1c: name = "djnz"; rhs.displacement(8, read8()); break;
case 0x1d: case 0x1e: case 0x1f: break;
case 0x20: name = "andcf"; rhs.immediate(4, (uint4)read8()); break;
case 0x21: name = "orcf"; rhs.immediate(4, (uint4)read8()); break;
case 0x22: name = "xorcf"; rhs.immediate(4, (uint4)read8()); break;
case 0x23: name = "ldcf"; rhs.immediate(4, (uint4)read8()); break;
case 0x24: name = "stcf"; rhs.immediate(4, (uint4)read8()); break;
case 0x25: case 0x26: case 0x27: break;
case 0x28: name = "andcf"; rhs.register(8, A.id); break;
case 0x29: name = "orcf"; rhs.register(8, A.id); break;
case 0x2a: name = "xorcf"; rhs.register(8, A.id); break;
case 0x2b: name = "ldcf"; rhs.register(8, A.id); break;
case 0x2c: name = "stcf"; rhs.register(8, A.id); break;
case 0x2d: break;
case 0x2e: name = "ldc"; rhs = lhs; lhs.control(rhs.size(), read8()); break;
case 0x2f: name = "ldc"; rhs.control(lhs.size(), read8()); break;
case 0x30: name = "res"; rhs.immediate(4, (uint4)read8()); break;
case 0x31: name = "set"; rhs.immediate(4, (uint4)read8()); break;
case 0x32: name = "chg"; rhs.immediate(4, (uint4)read8()); break;
case 0x33: name = "bit"; rhs.immediate(4, (uint4)read8()); break;
case 0x34: name = "tset"; rhs.immediate(4, (uint4)read8()); break;
case 0x35: case 0x36: case 0x37: break;
case 0x38: name = "minc1"; rhs.immediate(16, read16()); break;
case 0x39: name = "minc2"; rhs.immediate(16, read16()); break;
case 0x3a: name = "minc4"; rhs.immediate(16, read16()); break;
case 0x3b: break;
case 0x3c: name = "mdec1"; rhs.immediate(16, read16()); break;
case 0x3d: name = "mdec2"; rhs.immediate(16, read16()); break;
case 0x3e: name = "mdec4"; rhs.immediate(16, read16()); break;
case 0x3f: break;
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
name = "mul"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
name = "muls"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
name = "div"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
name = "divs"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
name = "inc"; rhs.immediate(4, fetch ? natural((uint3)fetch) : 8_n); break;
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
name = "dec"; rhs.immediate(4, fetch ? natural((uint3)fetch) : 8_n); break;
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
name = "scc"; rhs = lhs; lhs.condition(fetch); break;
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
name = "add"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
name = "ld"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
name = "adc"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
name = "ld"; rhs.register3(lhs.size(), fetch); break;
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
name = "sub"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
name = "ld"; rhs.immediate(3, (uint3)fetch); break;
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
name = "sbb"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
name = "ex"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
name = "and"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xc8: name = "add"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xc9: name = "adc"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xca: name = "sub"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xcb: name = "sbb"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xcc: name = "and"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xcd: name = "xor"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xce: name = "or"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xcf: name = "cp"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
name = "xor"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
name = "cp"; rhs.immediate(3, (uint3)fetch); break;
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
name = "or"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xe8: name = "rlc"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xe9: name = "rrc"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xea: name = "rl"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xeb: name = "rr"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xec: name = "sla"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xed: name = "sra"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xee: name = "sll"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xef: name = "srl"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
name = "cp"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xf8: name = "rlc"; rhs.register(8, A.id); break;
case 0xf9: name = "rrc"; rhs.register(8, A.id); break;
case 0xfa: name = "rl"; rhs.register(8, A.id); break;
case 0xfb: name = "rr"; rhs.register(8, A.id); break;
case 0xfc: name = "sla"; rhs.register(8, A.id); break;
case 0xfd: name = "sra"; rhs.register(8, A.id); break;
case 0xfe: name = "sll"; rhs.register(8, A.id); break;
case 0xff: name = "srl"; rhs.register(8, A.id); break;
}
//size defined
if(opSourceMemory)
switch(auto fetch = read8()) {
case 0x00: case 0x01: case 0x02: case 0x03: break;
case 0x04: name = lhs.size() == 8 ? "push" : "pushw"; break;
case 0x05: break;
case 0x06: name = "rld"; rhs = lhs; lhs.register(8, A.id); break;
case 0x07: name = "rrd"; rhs = lhs; lhs.register(8, A.id); break;
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: break;
case 0x10:
name = lhs.size() == 8 ? "ldi" : "ldiw";
lhs.indirectRegisterIncrement(32, (uint3)op[0] != 5 ? XDE.id : XIX.id);
rhs.indirectRegisterIncrement(32, (uint3)op[0] != 5 ? XHL.id : XIY.id);
break;
case 0x11:
name = lhs.size() == 8 ? "ldir" : "ldirw";
lhs.indirectRegisterIncrement(32, (uint3)op[0] != 5 ? XDE.id : XIX.id);
rhs.indirectRegisterIncrement(32, (uint3)op[0] != 5 ? XHL.id : XIY.id);
break;
case 0x12:
name = lhs.size() == 8 ? "ldd" : "lddw";
lhs.indirectRegisterIncrement(32, (uint3)op[0] != 5 ? XDE.id : XIX.id);
rhs.indirectRegisterIncrement(32, (uint3)op[0] != 5 ? XHL.id : XIY.id);
break;
case 0x13:
name = lhs.size() == 8 ? "lddr" : "lddrw";
lhs.indirectRegisterIncrement(32, (uint3)op[0] != 5 ? XDE.id : XIX.id);
rhs.indirectRegisterIncrement(32, (uint3)op[0] != 5 ? XHL.id : XIY.id);
break;
case 0x14:
name = lhs.size() == 8 ? "cpi" : "cpiw";
lhs.indirectRegister3Increment(32, op[0]);
rhs.register(lhs.size(), lhs.size() == 8 ? A.id : WA.id);
break;
case 0x15:
name = lhs.size() == 8 ? "cpir" : "cpirw";
lhs.indirectRegister3Increment(32, op[0]);
rhs.register(lhs.size(), lhs.size() == 8 ? A.id : WA.id);
break;
case 0x16:
name = lhs.size() == 8 ? "cpd" : "cpdw";
lhs.indirectRegister3Increment(32, op[0]);
rhs.register(lhs.size(), lhs.size() == 8 ? A.id : WA.id);
break;
case 0x17:
name = lhs.size() == 8 ? "cpdr" : "cpdrw";
lhs.indirectRegister3Increment(32, op[0]);
rhs.register(lhs.size(), lhs.size() == 8 ? A.id : WA.id);
break;
case 0x18: break;
case 0x19: name = "ld"; rhs = lhs; lhs.indirectImmediate16(16, read16()); break;
case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: break;
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
name = "ld"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: break;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
name = "ex"; rhs.register3(lhs.size(), fetch); break;
case 0x38: name = "add"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x39: name = "adc"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x3a: name = "sub"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x3b: name = "sbb"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x3c: name = "and"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x3d: name = "xor"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x3e: name = "or"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x3f: name = "cp"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
name = "mul"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
name = "muls"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
name = "div"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
name = "divs"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
name = "inc"; rhs.immediate(4, (uint3)fetch ? natural((uint3)fetch) : 8_n); break;
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
name = "dec"; rhs.immediate(4, (uint3)fetch ? natural((uint3)fetch) : 8_n); break;
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: break;
case 0x78: name = "rlc"; break;
case 0x79: name = "rrc"; break;
case 0x7a: name = "rl"; break;
case 0x7b: name = "rr"; break;
case 0x7c: name = "sla"; break;
case 0x7d: name = "sra"; break;
case 0x7e: name = "sll"; break;
case 0x7f: name = "srl"; break;
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
name = "add"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
name = "add"; rhs.register3(lhs.size(), fetch); break;
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
name = "adc"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
name = "adc"; rhs.register3(lhs.size(), fetch); break;
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
name = "sub"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
name = "sub"; rhs.register3(lhs.size(), fetch); break;
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
name = "sbb"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
name = "sbb"; rhs.register3(lhs.size(), fetch); break;
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
name = "and"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
name = "and"; rhs.register3(lhs.size(), fetch); break;
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
name = "xor"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
name = "xor"; rhs.register3(lhs.size(), fetch); break;
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
name = "or"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
name = "or"; rhs.register3(lhs.size(), fetch); break;
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
name = "cp"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
name = "cp"; rhs.register3(lhs.size(), fetch); break;
}
//size undefined
if(opTargetMemory)
switch(auto fetch = read8()) {
case 0x00: name = "ld"; lhs.size(8); rhs.immediate(8, read8()); break;
case 0x01: break;
case 0x02: name = "ld"; lhs.size(16); rhs.immediate(16, read16()); break;
case 0x03: break;
case 0x04: name = "pop"; lhs.size(8); break;
case 0x05: break;
case 0x06: name = "pop"; lhs.size(16); break;
case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: break;
case 0x10: case 0x11: case 0x12: case 0x13: break;
case 0x14: name = "ld"; lhs.size(8); rhs.indirectImmediate16(16, read16()); break;
case 0x15: break;
case 0x16: name = "ld"; lhs.size(16); rhs.indirectImmediate16(16, read16()); break;
case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: break;
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
name = "lda"; lhs.size(16); rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x28: name = "andcf"; rhs.register3(8, A.id); break;
case 0x29: name = "orcf"; rhs.register3(8, A.id); break;
case 0x2a: name = "xorcf"; rhs.register3(8, A.id); break;
case 0x2b: name = "ldcf"; rhs.register3(8, A.id); break;
case 0x2c: name = "stcf"; rhs.register3(8, A.id); break;
case 0x2d: case 0x2e: case 0x2f: break;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
name = "lda"; lhs.size(32); rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: break;
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
name = "ld"; lhs.size(8); rhs.register3(lhs.size(), fetch); break;
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: break;
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
name = "ld"; lhs.size(16); rhs.register3(lhs.size(), fetch); break;
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: break;
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
name = "ld"; lhs.size(32); rhs.register3(lhs.size(), fetch); break;
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: break;
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: break;
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: break;
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
name = "andcf"; lhs.size(8); rhs.immediate(3, (uint3)fetch); break;
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
name = "orcf"; lhs.size(8); rhs.immediate(3, (uint3)fetch); break;
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
name = "xorcf"; lhs.size(8); rhs.immediate(3, (uint3)fetch); break;
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
name = "ldcf"; lhs.size(8); rhs.immediate(3, (uint3)fetch); break;
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
name = "stcf"; lhs.size(8); rhs.immediate(3, (uint3)fetch); break;
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
name = "tset"; lhs.size(8); rhs.immediate(3, (uint3)fetch); break;
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
name = "res"; lhs.size(8); rhs.immediate(3, (uint3)fetch); break;
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
name = "set"; lhs.size(8); rhs.immediate(3, (uint3)fetch); break;
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
name = "chg"; lhs.size(8); rhs.immediate(3, (uint3)fetch); break;
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
name = "bit"; lhs.size(8); rhs.immediate(3, (uint3)fetch); break;
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
name = "jp"; rhs = lhs; lhs.condition(fetch); break;
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
name = "call"; rhs = lhs; lhs.condition(fetch); break;
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
name = "ret"; lhs.condition(fetch); break;
}
auto operand = [&](Operand& operand) -> string {
static const string registers8[] = {
"ra0", "rw0", "qa0", "qw0", "rc0", "rb0", "qc0", "qb0", "re0", "rd0", "qe0", "qd0", "rl0", "rh0", "ql0", "qh0", //00-1f
"ra1", "rw1", "qa1", "qw1", "rc1", "rb1", "qc1", "qb1", "re1", "rd1", "qe1", "qd1", "rl1", "rh1", "ql1", "qh1", //10-1f
"ra2", "rw2", "qa2", "qw2", "rc2", "rb2", "qc2", "qb2", "re2", "rd2", "qe2", "qd2", "rl2", "rh2", "ql2", "qh2", //20-2f
"ra3", "rw3", "qa3", "qw3", "rc3", "rb3", "qc3", "qb3", "re3", "rd3", "qe3", "qd3", "rl3", "rh3", "ql3", "qh3", //30-3f
"a'", "w'", "qa'", "qw'", "c'", "b'", "qc'", "qb'", "e'", "d'", "qe'", "qd'", "l'", "h'", "ql'", "qh'", //d0-df
"a", "w", "qa", "qw", "c", "b", "qc", "qb", "e", "d", "eq", "qd", "l", "h", "ql", "qh", //e0-ef
"ixl", "ixh", "qixl","qixh","iyl", "iyh", "qiyl","qiyh","izl", "izh", "qizl","qizh","spl", "sph", "qspl","qsph", //f0-ff
};
auto register8 = [](uint8 register) -> string {
if(register < 0x40) return registers8[register];
if(register >= 0xd0) return registers8[(register - 0xd0 >> 0) + 0x40];
return "rb?";
};
static const string registers16[] = {
"rwa0", "qwa0", "rbc0", "qbc0", "rde0", "qde0", "rhl0", "qhl0", //00-0f
"rwa1", "qwa1", "rbc1", "qbc1", "rde1", "qde1", "rhl1", "qhl1", //10-1f
"rwa2", "qwa2", "rbc2", "qbc2", "rde2", "qde2", "rhl2", "qhl2", //20-2f
"rwa3", "qwa3", "rbc3", "qbc3", "rde3", "qde3", "rhl3", "qhl3", //30-3f
"rwa'", "qwa'", "rbc'", "qbc'", "rde'", "qde'", "rhl'", "qhl'", //d0-df
"rwa", "qwa", "rbc", "qbc", "rde", "qde", "rhl", "qhl", //e0-ef
"ix", "qix", "iy", "qiy", "iz", "qiz", "sp", "qsp", //f0-ff
};
auto register16 = [](uint8 register) -> string {
if(register < 0x40) return registers16[register >> 1];
if(register >= 0xd0) return registers16[(register - 0xd0 >> 1) + 0x20];
return "rw?";
};
static const string registers32[] = {
"xwa0", "xbc0", "xde0", "xhl0", //00-0f
"xwa1", "xbc1", "xde1", "xhl1", //10-1f
"xwa2", "xbc2", "xde2", "xhl2", //20-2f
"xwa3", "xbc3", "xde3", "xhl3", //30-3f
"xwa'", "xbc'", "xde'", "xhl'", //d0-df
"xwa", "xbc", "xde", "xhl", //e0-ef
"xix", "xiy", "xiz", "xsp", //f0-ff
};
auto register32 = [&](uint8 register) -> string {
if(register < 0x40) return registers32[register >> 2];
if(register >= 0xd0) return registers32[(register - 0xd0 >> 2) + 0x10];
return "rl?";
};
//there are no names for byte-accesses to control registers
auto control8 = [](uint8 register) -> string {
return {"c", hex(register, 2L)};
};
static string controls16[] = {
"dmas0l", "dmas0h", "dmas1l", "dmas1h", "dmas2l", "dmas2h", "dmas3l", "dmas3h", //00-0f
"dmad0l", "dmad0h", "dmad1l", "dmad1h", "dmad2l", "dmad2h", "dmad3l", "dmad3h", //10-1f
"dmac0", "dmac0h", "dmac1", "dmac1h", "dmac2", "dmac2h", "dmac3", "dmac3h", //20-2f
};
auto control16 = [](uint8 register) -> string {
if(register < 0x30) return controls16[register >> 1];
if(register >= 0x3c || register <= 0x3d) return "intnest";
return "cw?";
};
static string controls32[] = {
"dmas0", "dmas1", "dmas2", "dmas3", //00-0f
"dmad0", "dmad1", "dmad2", "dmad3", //10-1f
"dmam0", "dmam1", "dmam2", "dmam3", //20-2f
};
auto control32 = [](uint8 register) -> string {
if(register < 0x30) return controls32[register >> 2];
if(register >= 0x3c && register <= 0x3f) return "intnest";
return "cl?";
};
if(operand.mode() == Text) return operand.text();
if(operand.mode() == Condition) {
static const string conditions[] = {
"f", "lt", "le", "ule", "ov", "mi", "eq", "ult",
"t", "ge", "gt", "ugt", "nov", "pl", "ne", "uge",
};
return conditions[operand.condition()];
}
if(operand.mode() == Register) {
if(operand.size() == 8) return register8(operand.register());
if(operand.size() == 16) return register16(operand.register());
if(operand.size() == 32) return register32(operand.register());
}
if(operand.mode() == Control) {
if(operand.size() == 8) return control8(operand.register());
if(operand.size() == 16) return control16(operand.register());
if(operand.size() == 32) return control32(operand.register());
}
if(operand.mode() == Immediate) {
if(operand.size() <= 7) return {operand.immediate()};
if(operand.size() == 8) return {"0x", hex(operand.immediate(), 2L)};
if(operand.size() == 16) return {"0x", hex(operand.immediate(), 4L)};
if(operand.size() == 24) return {"0x", hex(operand.immediate(), 6L)};
if(operand.size() == 32) return {"0x", hex(operand.immediate(), 8L)};
}
if(operand.mode() == Displacement) {
if(operand.size() == 8) {
integer displacement = (int8)operand.displacement();
if(displacement < 0) return {"-0x", hex(-displacement, 2L)};
if(displacement >= 0) return {"+0x", hex(+displacement, 2L)};
}
if(operand.size() == 16) {
integer displacement = (int8)operand.displacement();
if(displacement < 0) return {"-0x", hex(-displacement, 4L)};
if(displacement >= 0) return {"+0x", hex(+displacement, 4L)};
}
}
if(operand.mode() == DisplacementPC) {
if(operand.size() == 8) {
natural displacement = pc + (int8)operand.displacement();
return {"0x", hex(displacement, 6L)};
}
if(operand.size() == 16) {
natural displacement = pc + (int16)operand.displacement();
return {"0x", hex(displacement, 6L)};
}
}
if(operand.mode() == IndirectRegister) return {"(", register32(operand.register()), ")"};
if(operand.mode() == IndirectRegisterDecrement) return {"(-", register32(operand.register()), ")"};
if(operand.mode() == IndirectRegisterIncrement) return {"(", register32(operand.register()), "+)"};
if(operand.mode() == IndirectRegisterRegister8) return {"(", register32(operand.register()), "+", register8(operand.registerAdd()), ")"};
if(operand.mode() == IndirectRegisterRegister16) return {"(", register32(operand.register()), "+", register16(operand.registerAdd()), ")"};
if(operand.mode() == IndirectRegisterDisplacement8) {
integer displacement = (int8)operand.displacement();
if(displacement == 0) return {"(", register32(operand.register()), ")"};
if(displacement < 0) return {"(", register32(operand.register()), "-0x", hex(-displacement, 2L), ")"};
if(displacement > 0) return {"(", register32(operand.register()), "+0x", hex(+displacement, 2L), ")"};
}
if(operand.mode() == IndirectRegisterDisplacement16) {
integer displacement = (int16)operand.displacement();
if(displacement == 0) return {"(", register32(operand.register()), ")"};
if(displacement < 0) return {"(", register32(operand.register()), "-0x", hex(-displacement, 4L), ")"};
if(displacement > 0) return {"(", register32(operand.register()), "+0x", hex(+displacement, 4L), ")"};
}
if(operand.mode() == IndirectImmediate8) return {"(0x", hex(operand.immediate(), 2L), ")"};
if(operand.mode() == IndirectImmediate16) return {"(0x", hex(operand.immediate(), 4L), ")"};
if(operand.mode() == IndirectImmediate24) return {"(0x", hex(operand.immediate(), 6L), ")"};
return {};
};
//omit true condition operand
if(lhs.mode() == Condition && lhs.condition() == 8) {
lhs = rhs;
rhs.null();
}
if(name) {
output.append(pad(name, -6));
if(lhs) {
output.append(operand(lhs));
if(rhs) {
output.append(",", operand(rhs));
}
}
} else {
output.append(pad("???", -6));
for(auto byte : range(ops)) output.append("0x", hex(op[byte], 2L), ",");
output.trimRight(",", 1L);
}
//for(auto byte : range(ops)) print("0x", hex(op[byte], 2L), " "); print("\n");
output.size(-48);
output.append("XWA:", hex(r.xwa[r.rfp].l.l0, 8L), " ");
output.append("XBC:", hex(r.xbc[r.rfp].l.l0, 8L), " ");
output.append("XDE:", hex(r.xde[r.rfp].l.l0, 8L), " ");
output.append("XHL:", hex(r.xhl[r.rfp].l.l0, 8L), " ");
output.append("XIX:", hex(r.xix.l.l0, 8L), " ");
output.append("XIY:", hex(r.xiy.l.l0, 8L), " ");
output.append("XIZ:", hex(r.xiz.l.l0, 8L), " ");
output.append("XSP:", hex(r.xsp.l.l0, 8L), " ");
output.append("I", r.iff);
output.append("R", r.rfp);
output.append(r.s ? "S" : "s");
output.append(r.z ? "Z" : "z");
output.append(r.h ? "H" : "h");
output.append(r.v ? "V" : "v");
output.append(r.n ? "N" : "n");
output.append(r.c ? "C" : "c");
return output;
}

View File

@ -1,711 +0,0 @@
template<> auto TLCS900H::toRegister3<uint8>(uint3 code) const -> Register<uint8> {
static const Register< uint8> lookup[] = {W, A, B, C, D, E, H, L};
return lookup[code];
}
template<> auto TLCS900H::toRegister3<uint16>(uint3 code) const -> Register<uint16> {
static const Register<uint16> lookup[] = {WA, BC, DE, HL, IX, IY, IZ, SP};
return lookup[code];
}
template<> auto TLCS900H::toRegister3<uint32>(uint3 code) const -> Register<uint32> {
static const Register<uint32> lookup[] = {XWA, XBC, XDE, XHL, XIX, XIY, XIZ, XSP};
return lookup[code];
}
template<typename T> auto TLCS900H::toRegister8(uint8 code) const -> Register<T> { return {code}; }
template<typename T> auto TLCS900H::toControlRegister(uint8 code) const -> ControlRegister<T> { return {code}; }
template<typename T> auto TLCS900H::toMemory(uint32 address) const -> Memory<T> { return {address}; }
template<typename T> auto TLCS900H::toImmediate(uint32 constant) const -> Immediate<T> { return {constant}; }
template<typename T> auto TLCS900H::toImmediate3(natural constant) const -> Immediate<T> { return {constant.clip(3) ? constant.clip(3) : 8}; }
//note: much of this code is split to multiple statements due to C++ not guaranteeing
//the order of evaluations of function arguments. fetch() ordering is critical.
auto TLCS900H::instruction() -> void {
auto data = fetch();
switch(r.prefix = data) {
case 0x00: return instructionNoOperation();
case 0x01: return (void)Undefined; //NORMAL (not present on 900/H)
case 0x02: return instructionPush(SR);
case 0x03: return instructionPop(SR);
case 0x04: return (void)Undefined; //MAX or MIN (not present on 900/H)
case 0x05: return instructionHalt();
case 0x06: return instructionSetInterruptFlipFlop((uint3)fetch());
case 0x07: return instructionReturnInterrupt();
case 0x08: {
auto memory = fetchMemory<uint8, uint8>();
return instructionLoad(memory, fetchImmediate<uint8>()); }
case 0x09: return instructionPush(fetchImmediate<uint8>());
case 0x0a: {
auto memory = fetchMemory<uint16, uint8>();
return instructionLoad(memory, fetchImmediate<uint16>()); }
case 0x0b: return instructionPush(fetchImmediate<uint16>());
case 0x0c: return instructionSetRegisterFilePointer(RFP + 1);
case 0x0d: return instructionSetRegisterFilePointer(RFP - 1);
case 0x0e: return instructionReturn(True);
case 0x0f: return instructionReturnDeallocate(fetchImmediate<int16>());
case 0x10: return instructionSetFlag(CF, 0);
case 0x11: return instructionSetFlag(CF, 1);
case 0x12: return instructionSetFlag(CF, !CF);
case 0x13: return instructionSetFlag(CF, ZF);
case 0x14: return instructionPush(A);
case 0x15: return instructionPop(A);
case 0x16: return instructionExchange(F, FP);
case 0x17: return instructionSetRegisterFilePointer((uint2)fetch());
case 0x18: return instructionPush(F);
case 0x19: return instructionPop(F);
case 0x1a: return instructionJump(True, fetchImmediate<uint16>());
case 0x1b: return instructionJump(True, fetchImmediate<uint24>());
case 0x1c: return instructionCall(True, fetchImmediate<uint16>());
case 0x1d: return instructionCall(True, fetchImmediate<uint24>());
case 0x1e: return instructionCallRelative(fetchImmediate<int16>());
case 0x1f: return (void)Undefined;
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
return instructionLoad(toRegister3<uint8>(data), fetchImmediate<uint8>());
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
return instructionPush(toRegister3<uint16>(data));
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
return instructionLoad(toRegister3<uint16>(data), fetchImmediate<uint16>());
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
return instructionPush(toRegister3<uint32>(data));
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
return instructionLoad(toRegister3<uint32>(data), fetchImmediate<uint32>());
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
return instructionPop(toRegister3<uint16>(data));
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: return (void)Undefined;
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
return instructionPop(toRegister3<uint32>(data));
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
return instructionJumpRelative((uint4)data, fetchImmediate<int8>());
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
return instructionJumpRelative((uint4)data, fetchImmediate<int16>());
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
return instructionSourceMemory(toMemory<uint8>(load(toRegister3<uint32>(data))));
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
return instructionSourceMemory(toMemory<uint8>(load(toRegister3<uint32>(data)) + fetch<int8>()));
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
return instructionSourceMemory(toMemory<uint16>(load(toRegister3<uint32>(data))));
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
return instructionSourceMemory(toMemory<uint16>(load(toRegister3<uint32>(data)) + fetch<int8>()));
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
return instructionSourceMemory(toMemory<uint32>(load(toRegister3<uint32>(data))));
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
return instructionSourceMemory(toMemory<uint32>(load(toRegister3<uint32>(data)) + fetch<int8>()));
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
return instructionTargetMemory(load(toRegister3<uint32>(data)));
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
return instructionTargetMemory(load(toRegister3<uint32>(data)) + fetch<int8>());
case 0xc0: return instructionSourceMemory(fetchMemory<uint8, uint8>());
case 0xc1: return instructionSourceMemory(fetchMemory<uint8, uint16>());
case 0xc2: return instructionSourceMemory(fetchMemory<uint8, uint24>());
case 0xc3: {
data = fetch();
if((data & 3) == 0) return instructionSourceMemory(toMemory<uint8>(load(toRegister8<uint32>(data))));
if((data & 3) == 1) return instructionSourceMemory(toMemory<uint8>(load(toRegister8<uint32>(data)) + fetch<int16>()));
if(data == 0x03) {
auto r32 = load(fetchRegister<uint32>());
auto r8 = load(fetchRegister< uint8>());
return instructionSourceMemory(Memory<uint8>{r32 + (int8)r8});
}
if(data == 0x07) {
auto r32 = load(fetchRegister<uint32>());
auto r16 = load(fetchRegister<uint16>());
return instructionSourceMemory(Memory<uint8>{r32 + (int16)r16});
}
return (void)Undefined; }
case 0xc4: {
data = fetch();
auto register = toRegister8<uint32>(data);
if((data & 3) == 0) store(register, load(register) - 1);
if((data & 3) == 1) store(register, load(register) - 2);
if((data & 3) == 2) store(register, load(register) - 4);
if((data & 3) == 3) Undefined;
return instructionSourceMemory(toMemory<uint8>(load(register))); }
case 0xc5: {
data = fetch();
auto register = toRegister8<uint32>(data);
instructionSourceMemory(toMemory<uint8>(load(register)));
if((data & 3) == 0) store(register, load(register) + 1);
if((data & 3) == 1) store(register, load(register) + 2);
if((data & 3) == 2) store(register, load(register) + 4);
if((data & 3) == 3) Undefined;
return; }
case 0xc6: return (void)Undefined;
case 0xc7: return instructionRegister(fetchRegister<uint8>());
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
return instructionRegister(toRegister3<uint8>(data));
case 0xd0: return instructionSourceMemory(fetchMemory<uint16, uint8>());
case 0xd1: return instructionSourceMemory(fetchMemory<uint16, uint16>());
case 0xd2: return instructionSourceMemory(fetchMemory<uint16, uint24>());
case 0xd3: {
data = fetch();
if((data & 3) == 0) return instructionSourceMemory(toMemory<uint16>(load(toRegister8<uint32>(data))));
if((data & 3) == 1) return instructionSourceMemory(toMemory<uint16>(load(toRegister8<uint32>(data)) + fetch<int16>()));
if(data == 0x03) {
auto r32 = load(fetchRegister<uint32>());
auto r8 = load(fetchRegister< uint8>());
return instructionSourceMemory(toMemory<uint16>(r32 + (int8)r8));
}
if(data == 0x07) {
auto r32 = load(fetchRegister<uint32>());
auto r16 = load(fetchRegister<uint16>());
return instructionSourceMemory(toMemory<uint16>(r32 + (int16)r16));
}
return (void)Undefined; }
case 0xd4: {
data = fetch();
auto register = toRegister8<uint32>(data);
if((data & 3) == 0) store(register, load(register) - 1);
if((data & 3) == 1) store(register, load(register) - 2);
if((data & 3) == 2) store(register, load(register) - 4);
if((data & 3) == 3) Undefined;
return instructionSourceMemory(toMemory<uint16>(load(register))); }
case 0xd5: {
data = fetch();
auto register = toRegister8<uint32>(data);
instructionSourceMemory(toMemory<uint16>(load(register)));
if((data & 3) == 0) store(register, load(register) + 1);
if((data & 3) == 1) store(register, load(register) + 2);
if((data & 3) == 2) store(register, load(register) + 4);
if((data & 3) == 3) Undefined;
return; }
case 0xd6: return (void)Undefined;
case 0xd7: return instructionRegister(fetchRegister<uint16>());
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
return instructionRegister(toRegister3<uint16>(data));
case 0xe0: return instructionSourceMemory(fetchMemory<uint32, uint8>());
case 0xe1: return instructionSourceMemory(fetchMemory<uint32, uint16>());
case 0xe2: return instructionSourceMemory(fetchMemory<uint32, uint24>());
case 0xe3: {
data = fetch();
if((data & 3) == 0) return instructionSourceMemory(toMemory<uint32>(load(toRegister8<uint32>(data))));
if((data & 3) == 1) return instructionSourceMemory(toMemory<uint32>(load(toRegister8<uint32>(data)) + fetch<int16>()));
if(data == 0x03) {
auto r32 = load(fetchRegister<uint32>());
auto r8 = load(fetchRegister< uint8>());
return instructionSourceMemory(toMemory<uint32>(r32 + (int8)r8));
}
if(data == 0x07) {
auto r32 = load(fetchRegister<uint32>());
auto r16 = load(fetchRegister<uint16>());
return instructionSourceMemory(toMemory<uint32>(r32 + (int16)r16));
}
return (void)Undefined; }
case 0xe4: {
data = fetch();
auto register = toRegister8<uint32>(data);
if((data & 3) == 0) store(register, load(register) - 1);
if((data & 3) == 1) store(register, load(register) - 2);
if((data & 3) == 2) store(register, load(register) - 4);
if((data & 3) == 3) Undefined;
return instructionSourceMemory(toMemory<uint32>(load(register))); }
case 0xe5: {
data = fetch();
auto register = toRegister8<uint32>(data);
instructionSourceMemory(toMemory<uint32>(load(register)));
if((data & 3) == 0) store(register, load(register) + 1);
if((data & 3) == 1) store(register, load(register) + 2);
if((data & 3) == 2) store(register, load(register) + 4);
if((data & 3) == 3) Undefined;
return; }
case 0xe6: return (void)Undefined;
case 0xe7: return instructionRegister(fetchRegister<uint32>());
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
return instructionRegister(toRegister3<uint32>(data));
case 0xf0: return instructionTargetMemory(fetch< uint8>());
case 0xf1: return instructionTargetMemory(fetch<uint16>());
case 0xf2: return instructionTargetMemory(fetch<uint24>());
case 0xf3: {
data = fetch();
if((data & 3) == 0) return instructionTargetMemory(load(toRegister8<uint32>(data)));
if((data & 3) == 1) return instructionTargetMemory(load(toRegister8<uint32>(data)) + fetch<int16>());
if(data == 0x03) {
auto r32 = load(fetchRegister<uint32>());
auto r8 = load(fetchRegister< uint8>());
return instructionTargetMemory(r32 + (int8)r8);
}
if(data == 0x07) {
auto r32 = load(fetchRegister<uint32>());
auto r16 = load(fetchRegister<uint16>());
return instructionTargetMemory(r32 + (int16)r16);
}
return (void)Undefined; }
case 0xf4: {
data = fetch();
auto register = toRegister8<uint32>(data);
if((data & 3) == 0) store(register, load(register) - 1);
if((data & 3) == 1) store(register, load(register) - 2);
if((data & 3) == 2) store(register, load(register) - 4);
if((data & 3) == 3) Undefined;
return instructionTargetMemory(load(register)); }
case 0xf5: {
data = fetch();
auto register = toRegister8<uint32>(data);
instructionTargetMemory(load(register));
if((data & 3) == 0) store(register, load(register) + 1);
if((data & 3) == 1) store(register, load(register) + 2);
if((data & 3) == 2) store(register, load(register) + 4);
if((data & 3) == 3) Undefined;
return; }
case 0xf6: return (void)Undefined;
case 0xf7: {
if(fetch()) Undefined;
auto memory = fetchMemory<uint8, uint8>();
if(fetch()) Undefined;
auto immediate = fetchImmediate<uint8>();
if(fetch()) Undefined;
return instructionLoad(memory, immediate); }
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
return instructionSoftwareInterrupt((uint3)data);
}
}
template<typename R>
auto TLCS900H::instructionRegister(R register) -> void {
using T = typename R::type;
enum : uint { bits = R::bits };
auto data = fetch();
switch(data) {
case 0x00: case 0x01: case 0x02: return (void)Undefined;
case 0x03: return instructionLoad(register, fetchImmediate<T>());
case 0x04: return instructionPush(register);
case 0x05: return instructionPop(register);
case 0x06:
if constexpr(bits == 32) return (void)Undefined;
return instructionComplement(register);
case 0x07:
if constexpr(bits == 32) return (void)Undefined;
return instructionNegate(register);
case 0x08:
if constexpr(bits != 32) return instructionMultiply(register, fetchImmediate<T>());
return (void)Undefined;
case 0x09:
if constexpr(bits != 32) return instructionMultiplySigned(register, fetchImmediate<T>());
return (void)Undefined;
case 0x0a:
if constexpr(bits != 32) return instructionDivide(register, fetchImmediate<T>());
return (void)Undefined;
case 0x0b:
if constexpr(bits != 32) return instructionDivideSigned(register, fetchImmediate<T>());
return (void)Undefined;
case 0x0c:
if constexpr(bits == 32) return instructionLink(register, fetchImmediate<int16>());
return (void)Undefined;
case 0x0d:
if constexpr(bits == 32) return instructionUnlink(register);
return (void)Undefined;
case 0x0e:
if constexpr(bits == 16) return instructionBitSearch1Forward(register);
return (void)Undefined;
case 0x0f:
if constexpr(bits == 16) return instructionBitSearch1Backward(register);
return (void)Undefined;
case 0x10:
if constexpr(bits == 8) return instructionDecimalAdjustAccumulator(register);
return (void)Undefined;
case 0x11: return (void)Undefined;
case 0x12:
if constexpr(bits != 8) return instructionExtendZero(register);
return (void)Undefined;
case 0x13:
if constexpr(bits != 8) return instructionExtendSign(register);
return (void)Undefined;
case 0x14:
if constexpr(bits != 8) return instructionPointerAdjustAccumulator(register);
return (void)Undefined;
case 0x15: return (void)Undefined;
case 0x16:
if constexpr(bits == 16) return instructionMirror(register);
return (void)Undefined;
case 0x17: case 0x18: return (void)Undefined;
case 0x19:
if constexpr(bits == 16) return instructionMultiplyAdd(register);
return (void)Undefined;
case 0x1a: case 0x1b: return (void)Undefined;
case 0x1c:
if constexpr(bits != 32) return instructionDecrementJumpNotZero(register, fetchImmediate<int8>());
return (void)Undefined;
case 0x1d: case 0x1e: case 0x1f: return (void)Undefined;
case 0x20:
if constexpr(bits != 32) return instructionAndCarry(register, fetchImmediate<uint8>());
return (void)Undefined;
case 0x21:
if constexpr(bits != 32) return instructionOrCarry(register, fetchImmediate<uint8>());
return (void)Undefined;
case 0x22:
if constexpr(bits != 32) return instructionXorCarry(register, fetchImmediate<uint8>());
return (void)Undefined;
case 0x23:
if constexpr(bits != 32) return instructionLoadCarry(register, fetchImmediate<uint8>());
return (void)Undefined;
case 0x24:
if constexpr(bits != 32) return instructionStoreCarry(register, fetchImmediate<uint8>());
return (void)Undefined;
case 0x25: case 0x26: case 0x27: return (void)Undefined;
case 0x28:
if constexpr(bits != 32) return instructionAndCarry(register, A);
return (void)Undefined;
case 0x29:
if constexpr(bits != 32) return instructionOrCarry(register, A);
return (void)Undefined;
case 0x2a:
if constexpr(bits != 32) return instructionXorCarry(register, A);
return (void)Undefined;
case 0x2b:
if constexpr(bits != 32) return instructionLoadCarry(register, A);
return (void)Undefined;
case 0x2c:
if constexpr(bits != 32) return instructionStoreCarry(register, A);
return (void)Undefined;
case 0x2d: return (void)Undefined;
case 0x2e: return instructionLoad(toControlRegister<T>(data), register);
case 0x2f: return instructionLoad(register, toControlRegister<T>(data));
case 0x30:
if constexpr(bits != 32) return instructionReset(register, fetchImmediate<uint8>());
return (void)Undefined;
case 0x31:
if constexpr(bits != 32) return instructionSet(register, fetchImmediate<uint8>());
return (void)Undefined;
case 0x32:
if constexpr(bits != 32) return instructionChange(register, fetchImmediate<uint8>());
return (void)Undefined;
case 0x33:
if constexpr(bits != 32) return instructionBit(register, fetchImmediate<uint8>());
return (void)Undefined;
case 0x34:
if constexpr(bits != 32) return instructionTestSet(register, fetchImmediate<uint8>());
return (void)Undefined;
case 0x35: case 0x36: case 0x37: return (void)Undefined;
case 0x38:
if constexpr(bits == 16) return instructionModuloIncrement<1>(register, fetchImmediate<uint16>());
return (void)Undefined;
case 0x39:
if constexpr(bits == 16) return instructionModuloIncrement<2>(register, fetchImmediate<uint16>());
return (void)Undefined;
case 0x3a:
if constexpr(bits == 16) return instructionModuloIncrement<4>(register, fetchImmediate<uint16>());
return (void)Undefined;
case 0x3b: return (void)Undefined;
case 0x3c:
if constexpr(bits == 16) return instructionModuloDecrement<1>(register, fetchImmediate<uint16>());
return (void)Undefined;
case 0x3d:
if constexpr(bits == 16) return instructionModuloDecrement<2>(register, fetchImmediate<uint16>());
return (void)Undefined;
case 0x3e:
if constexpr(bits == 16) return instructionModuloDecrement<4>(register, fetchImmediate<uint16>());
return (void)Undefined;
case 0x3f: return (void)Undefined;
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
if constexpr(bits != 32) return instructionMultiply(toRegister3<T>(data), register);
return (void)Undefined;
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
if constexpr(bits != 32) return instructionMultiplySigned(toRegister3<T>(data), register);
return (void)Undefined;
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
if constexpr(bits != 32) return instructionDivide(toRegister3<T>(data), register);
return (void)Undefined;
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
if constexpr(bits != 32) return instructionDivideSigned(toRegister3<T>(data), register);
return (void)Undefined;
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
return instructionIncrement(register, toImmediate<T>((uint3)data));
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
return instructionDecrement(register, toImmediate<T>((uint3)data));
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
if constexpr(bits == 32) return (void)Undefined;
return instructionSetConditionCode((uint4)data, register);
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
return instructionAdd(toRegister3<T>(data), register);
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
return instructionLoad(toRegister3<T>(data), register);
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
return instructionAddCarry(toRegister3<T>(data), register);
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
return instructionLoad(register, toRegister3<T>(data));
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
return instructionSubtract(toRegister3<T>(data), register);
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
return instructionLoad(register, toImmediate<T>((uint3)data));
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
return instructionSubtractBorrow(toRegister3<T>(data), register);
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
if constexpr(bits == 32) return (void)Undefined;
return instructionExchange(toRegister3<T>(data), register);
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
return instructionAnd(toRegister3<T>(data), register);
case 0xc8: return instructionAdd(register, fetchImmediate<T>());
case 0xc9: return instructionAddCarry(register, fetchImmediate<T>());
case 0xca: return instructionSubtract(register, fetchImmediate<T>());
case 0xcb: return instructionSubtractBorrow(register, fetchImmediate<T>());
case 0xcc: return instructionAnd(register, fetchImmediate<T>());
case 0xcd: return instructionXor(register, fetchImmediate<T>());
case 0xce: return instructionOr(register, fetchImmediate<T>());
case 0xcf: return instructionCompare(register, fetchImmediate<T>());
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
return instructionXor(toRegister3<T>(data), register);
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
return instructionCompare(register, toImmediate<T>((uint3)data));
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
return instructionOr(toRegister3<T>(data), register);
case 0xe8: return instructionRotateLeftWithoutCarry(register, fetchImmediate<uint8>());
case 0xe9: return instructionRotateRightWithoutCarry(register, fetchImmediate<uint8>());
case 0xea: return instructionRotateLeft(register, fetchImmediate<uint8>());
case 0xeb: return instructionRotateRight(register, fetchImmediate<uint8>());
case 0xec: return instructionShiftLeftArithmetic(register, fetchImmediate<uint8>());
case 0xed: return instructionShiftRightArithmetic(register, fetchImmediate<uint8>());
case 0xee: return instructionShiftLeftLogical(register, fetchImmediate<uint8>());
case 0xef: return instructionShiftRightLogical(register, fetchImmediate<uint8>());
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
return instructionCompare(toRegister3<T>(data), register);
case 0xf8: return instructionRotateLeftWithoutCarry(register, A);
case 0xf9: return instructionRotateRightWithoutCarry(register, A);
case 0xfa: return instructionRotateLeft(register, A);
case 0xfb: return instructionRotateRight(register, A);
case 0xfc: return instructionShiftLeftArithmetic(register, A);
case 0xfd: return instructionShiftRightArithmetic(register, A);
case 0xfe: return instructionShiftLeftLogical(register, A);
case 0xff: return instructionShiftRightLogical(register, A);
}
}
template<typename M>
auto TLCS900H::instructionSourceMemory(M memory) -> void {
using T = typename M::type;
enum : uint { bits = M::bits };
auto data = fetch();
switch(data) {
case 0x00: case 0x01: case 0x02: case 0x03: return (void)Undefined;
case 0x04:
if constexpr(bits == 32) return (void)Undefined;
return instructionPush(memory);
case 0x05: return (void)Undefined;
case 0x06:
if constexpr(bits == 8) return instructionRotateLeftDigit(A, memory);
return (void)Undefined;
case 0x07:
if constexpr(bits == 8) return instructionRotateRightDigit(A, memory);
return (void)Undefined;
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: return (void)Undefined;
case 0x10:
if constexpr(bits == 8) return instructionLoad<T, +1>();
if constexpr(bits == 16) return instructionLoad<T, +2>();
return (void)Undefined;
case 0x11:
if constexpr(bits == 8) return instructionLoadRepeat<T, +1>();
if constexpr(bits == 16) return instructionLoadRepeat<T, +2>();
return (void)Undefined;
case 0x12:
if constexpr(bits == 8) return instructionLoad<T, -1>();
if constexpr(bits == 16) return instructionLoad<T, -2>();
return (void)Undefined;
case 0x13:
if constexpr(bits == 8) return instructionLoadRepeat<T, -1>();
if constexpr(bits == 16) return instructionLoadRepeat<T, -2>();
return (void)Undefined;
case 0x14:
if constexpr(bits == 8) return instructionCompare<T, +1>(A);
if constexpr(bits == 16) return instructionCompare<T, +2>(WA);
return (void)Undefined;
case 0x15:
if constexpr(bits == 8) return instructionCompareRepeat<T, +1>(A);
if constexpr(bits == 16) return instructionCompareRepeat<T, +2>(WA);
return (void)Undefined;
case 0x16:
if constexpr(bits == 8) return instructionCompare<T, -1>(A);
if constexpr(bits == 16) return instructionCompare<T, -2>(WA);
return (void)Undefined;
case 0x17:
if constexpr(bits == 8) return instructionCompareRepeat<T, -1>(A);
if constexpr(bits == 16) return instructionCompareRepeat<T, -2>(WA);
return (void)Undefined;
case 0x18: return (void)Undefined;
case 0x19:
if constexpr(bits == 32) return (void)Undefined;
return instructionLoad(fetchMemory<T, uint16>(), memory);
case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: return (void)Undefined;
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
return instructionLoad(toRegister3<T>(data), memory);
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: return (void)Undefined;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
if constexpr(bits == 32) return (void)Undefined;
return instructionExchange(memory, toRegister3<T>(data));
case 0x38:
if constexpr(bits == 32) return (void)Undefined;
return instructionAdd(memory, fetchImmediate<T>());
case 0x39:
if constexpr(bits == 32) return (void)Undefined;
return instructionAddCarry(memory, fetchImmediate<T>());
case 0x3a:
if constexpr(bits == 32) return (void)Undefined;
return instructionSubtract(memory, fetchImmediate<T>());
case 0x3b:
if constexpr(bits == 32) return (void)Undefined;
return instructionSubtractBorrow(memory, fetchImmediate<T>());
case 0x3c:
if constexpr(bits == 32) return (void)Undefined;
return instructionAnd(memory, fetchImmediate<T>());
case 0x3d:
if constexpr(bits == 32) return (void)Undefined;
return instructionXor(memory, fetchImmediate<T>());
case 0x3e:
if constexpr(bits == 32) return (void)Undefined;
return instructionOr(memory, fetchImmediate<T>());
case 0x3f:
if constexpr(bits == 32) return (void)Undefined;
return instructionCompare(memory, fetchImmediate<T>());
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
if constexpr(bits != 32) return instructionMultiply(toRegister3<T>(data), memory);
return (void)Undefined;
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
if constexpr(bits != 32) return instructionMultiplySigned(toRegister3<T>(data), memory);
return (void)Undefined;
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
if constexpr(bits != 32) return instructionDivide(toRegister3<T>(data), memory);
return (void)Undefined;
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
if constexpr(bits != 32) return instructionDivideSigned(toRegister3<T>(data), memory);
return (void)Undefined;
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
return instructionIncrement(memory, toImmediate<T>((uint3)data));
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
return instructionDecrement(memory, toImmediate<T>((uint3)data));
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: return (void)Undefined;
case 0x78:
if constexpr(bits != 32) return instructionRotateLeftWithoutCarry(memory, toImmediate<uint4>(1));
return (void)Undefined;
case 0x79:
if constexpr(bits != 32) return instructionRotateRightWithoutCarry(memory, toImmediate<uint4>(1));
return (void)Undefined;
case 0x7a:
if constexpr(bits != 32) return instructionRotateLeft(memory, toImmediate<uint4>(1));
return (void)Undefined;
case 0x7b:
if constexpr(bits != 32) return instructionRotateRight(memory, toImmediate<uint4>(1));
return (void)Undefined;
case 0x7c:
if constexpr(bits != 32) return instructionShiftLeftArithmetic(memory, toImmediate<uint4>(1));
return (void)Undefined;
case 0x7d:
if constexpr(bits != 32) return instructionShiftRightArithmetic(memory, toImmediate<uint4>(1));
return (void)Undefined;
case 0x7e:
if constexpr(bits != 32) return instructionShiftLeftLogical(memory, toImmediate<uint4>(1));
return (void)Undefined;
case 0x7f:
if constexpr(bits != 32) return instructionShiftRightLogical(memory, toImmediate<uint4>(1));
return (void)Undefined;
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
return instructionAdd(toRegister3<T>(data), memory);
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
return instructionAdd(memory, toRegister3<T>(data));
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
return instructionAddCarry(toRegister3<T>(data), memory);
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
return instructionAddCarry(memory, toRegister3<T>(data));
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
return instructionSubtract(toRegister3<T>(data), memory);
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
return instructionSubtract(memory, toRegister3<T>(data));
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
return instructionSubtractBorrow(toRegister3<T>(data), memory);
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
return instructionSubtractBorrow(memory, toRegister3<T>(data));
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
return instructionAnd(toRegister3<T>(data), memory);
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
return instructionAnd(memory, toRegister3<T>(data));
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
return instructionXor(toRegister3<T>(data), memory);
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
return instructionXor(memory, toRegister3<T>(data));
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
return instructionOr(toRegister3<T>(data), memory);
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
return instructionOr(memory, toRegister3<T>(data));
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
return instructionCompare(toRegister3<T>(data), memory);
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
return instructionCompare(memory, toRegister3<T>(data));
}
}
auto TLCS900H::instructionTargetMemory(uint32 address) -> void {
auto data = fetch();
switch(data) {
case 0x00: return instructionLoad(toMemory<uint8>(address), fetchImmediate<uint8>());
case 0x01: return (void)Undefined;
case 0x02: return instructionLoad(toMemory<uint16>(address), fetchImmediate<uint16>());
case 0x03: return (void)Undefined;
case 0x04: return instructionPop(toMemory<uint8>(address));
case 0x05: return (void)Undefined;
case 0x06: return instructionPop(toMemory<uint16>(address));
case 0x07: return (void)Undefined;
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: return (void)Undefined;
case 0x10: case 0x11: case 0x12: case 0x13: return (void)Undefined;
case 0x14: return instructionLoad(toMemory<uint8>(address), fetchMemory<uint8, uint16>());
case 0x15: return (void)Undefined;
case 0x16: return instructionLoad(toMemory<uint16>(address), fetchMemory<uint16, uint16>());
case 0x17: return (void)Undefined;
case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: return (void)Undefined;
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
return instructionLoad(toRegister3<uint16>(data), toImmediate<uint16>(address));
case 0x28: return instructionAndCarry(toMemory<uint8>(address), A);
case 0x29: return instructionOrCarry(toMemory<uint8>(address), A);
case 0x2a: return instructionXorCarry(toMemory<uint8>(address), A);
case 0x2b: return instructionLoadCarry(toMemory<uint8>(address), A);
case 0x2c: return instructionStoreCarry(toMemory<uint8>(address), A);
case 0x2d: case 0x2e: case 0x2f: return (void)Undefined;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
return instructionLoad(toRegister3<uint32>(data), toImmediate<uint32>(address));
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: return (void)Undefined;
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
return instructionLoad(toMemory<uint8>(address), toRegister3<uint8>(data));
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: return (void)Undefined;
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
return instructionLoad(toMemory<uint16>(address), toRegister3<uint16>(data));
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: return (void)Undefined;
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
return instructionLoad(toMemory<uint32>(address), toRegister3<uint32>(data));
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: return (void)Undefined;
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: return (void)Undefined;
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: return (void)Undefined;
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
return instructionAndCarry(toMemory<uint8>(address), toImmediate<uint3>(data));
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
return instructionOrCarry(toMemory<uint8>(address), toImmediate<uint3>(data));
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
return instructionXorCarry(toMemory<uint8>(address), toImmediate<uint3>(data));
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
return instructionLoadCarry(toMemory<uint8>(address), toImmediate<uint3>(data));
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
return instructionStoreCarry(toMemory<uint8>(address), toImmediate<uint3>(data));
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
return instructionTestSet(toMemory<uint8>(address), toImmediate<uint3>(data));
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
return instructionReset(toMemory<uint8>(address), toImmediate<uint3>(data));
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
return instructionSet(toMemory<uint8>(address), toImmediate<uint3>(data));
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
return instructionChange(toMemory<uint8>(address), toImmediate<uint3>(data));
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
return instructionBit(toMemory<uint8>(address), toImmediate<uint3>(data));
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
return instructionJump((uint4)data, toImmediate<uint32>(address));
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
return instructionCall((uint4)data, toImmediate<uint32>(address));
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
return instructionReturn((uint4)data);
}
}

View File

@ -1,536 +0,0 @@
template<typename Target, typename Source>
auto TLCS900H::instructionAdd(Target target, Source source) -> void {
store(target, algorithmAdd(load(target), load(source)));
}
template<typename Target, typename Source>
auto TLCS900H::instructionAddCarry(Target target, Source source) -> void {
store(target, algorithmAdd(load(target), load(source), CF));
}
template<typename Target, typename Source>
auto TLCS900H::instructionAnd(Target target, Source source) -> void {
store(target, algorithmAnd(load(target), load(source)));
}
template<typename Source, typename Offset>
auto TLCS900H::instructionAndCarry(Source source, Offset offset) -> void {
if constexpr(Source::bits == 8 && is_same_v<Offset, Register<uint8>>) { if(load(offset).bit(3)) return (void)Undefined; }
CF &= load(source).bit(load(offset) & Source::bits - 1);
}
template<typename Source, typename Offset>
auto TLCS900H::instructionBit(Source source, Offset offset) -> void {
NF = 0;
VF = Undefined;
HF = 1;
ZF = !load(source).bit(load(offset) & Source::bits - 1);
SF = Undefined;
}
auto TLCS900H::instructionBitSearch1Backward(Register<uint16> register) -> void {
auto value = load(register);
for(uint index : reverse(range(16))) {
if(value.bit(index)) return VF = 1, store(A, index);
}
VF = 0;
}
auto TLCS900H::instructionBitSearch1Forward(Register<uint16> register) -> void {
auto value = load(register);
for(uint index : range(16)) {
if(value.bit(index)) return VF = 1, store(A, index);
}
VF = 0;
}
template<typename Source>
auto TLCS900H::instructionCall(uint4 code, Source source) -> void {
auto address = load(source);
if(condition(code)) push(PC), store(PC, address);
}
template<typename Source>
auto TLCS900H::instructionCallRelative(Source displacement) -> void {
push(PC);
store(PC, load(PC) + load(displacement));
}
template<typename Target, typename Offset>
auto TLCS900H::instructionChange(Target target, Offset offset) -> void {
auto result = load(target);
result.bit(load(offset) & Target::bits - 1) ^= 1;
store(target, result);
}
template<typename Size, int Adjust, typename Target>
auto TLCS900H::instructionCompare(Target target) -> void {
auto source = toRegister3<uint32>(r.prefix);
auto cf = CF; //CF is not modified; but algorithmSubtract will modify it
algorithmSubtract(load(target), load(toMemory<Size>(load(source))));
store(source, load(source) + Adjust);
store(BC, load(BC) - 1);
CF = cf;
VF = load(BC) == 0;
}
template<typename Size, int Adjust, typename Target>
auto TLCS900H::instructionCompareRepeat(Target target) -> void {
do { instructionCompare<Size, Adjust>(target); } while(VF && !ZF);
}
template<typename Target, typename Source>
auto TLCS900H::instructionCompare(Target target, Source source) -> void {
algorithmSubtract(load(target), load(source));
}
template<typename Target>
auto TLCS900H::instructionComplement(Target target) -> void {
store(target, ~load(target));
NF = 1;
HF = 1;
}
auto TLCS900H::instructionDecimalAdjustAccumulator(Register<uint8> register) -> void {
auto value = load(register);
if(CF || (uint8)value > 0x99) value += NF ? -0x60 : 0x60, CF = 1;
if(HF || (uint4)value > 0x09) value += NF ? -0x06 : 0x06;
PF = parity(value);
HF = uint8(value ^ load(register)).bit(4);
ZF = value == 0;
SF = value.bit(-1);
store(register, value);
}
template<typename Target, typename Source>
auto TLCS900H::instructionDecrement(Target target, Source source) -> void {
auto immediate = load(source);
if(!immediate) immediate = 8;
store(target, algorithmDecrement(load(target), immediate));
}
template<typename Target, typename Offset>
auto TLCS900H::instructionDecrementJumpNotZero(Target target, Offset offset) -> void {
auto result = load(target);
store(target, --result);
if(result) store(PC, load(PC) + load(offset));
}
template<typename Target, typename Source>
auto TLCS900H::instructionDivide(Target target, Source source) -> void {
using T = typename Target::type;
using E = Natural<2 * T::bits()>;
auto dividend = load(expand(target));
auto divisor = load(source);
auto quotient = divisor ? E(dividend / divisor) : E(T(~(dividend >> T::bits())));
auto remainder = divisor ? E(dividend % divisor) : E(T(dividend));
store(expand(target), T(remainder) << T::bits() | T(quotient));
VF = !divisor || remainder >> T::bits();
}
template<typename Target, typename Source>
auto TLCS900H::instructionDivideSigned(Target target, Source source) -> void {
using T = typename Target::type;
using E = Natural<2 * T::bits()>;
auto dividend = load(expand(target)).integer();
auto divisor = load(source).integer();
auto quotient = divisor ? E(dividend / divisor) : E(T(~(dividend >> T::bits())));
auto remainder = divisor ? E(dividend % divisor) : E(T(dividend));
store(expand(target), T(remainder) << T::bits() | T(quotient));
VF = !divisor || remainder >> T::bits();
}
template<typename Target, typename Source>
auto TLCS900H::instructionExchange(Target target, Source source) -> void {
auto data = load(target);
store(target, load(source));
store(source, data);
}
template<typename Target>
auto TLCS900H::instructionExtendSign(Target target) -> void {
store(target, load(shrink(target)).integer());
}
template<typename Target>
auto TLCS900H::instructionExtendZero(Target target) -> void {
store(target, load(shrink(target)));
}
auto TLCS900H::instructionHalt() -> void {
r.halted = true;
}
template<typename Target, typename Source>
auto TLCS900H::instructionIncrement(Target target, Source source) -> void {
auto immediate = load(source);
if(!immediate) immediate = 8;
store(target, algorithmIncrement(load(target), immediate));
}
template<typename Source>
auto TLCS900H::instructionJump(uint4 code, Source source) -> void {
auto address = load(source);
if(condition(code)) store(PC, address);
}
template<typename Source>
auto TLCS900H::instructionJumpRelative(uint4 code, Source displacement) -> void {
if(condition(code)) store(PC, load(PC) + load(displacement));
}
template<typename Target, typename Offset>
auto TLCS900H::instructionLink(Target target, Offset offset) -> void {
push(target);
store(target, load(XSP));
store(XSP, load(XSP) + load(offset));
}
template<typename Target, typename Source>
auto TLCS900H::instructionLoad(Target target, Source source) -> void {
store(target, load(source));
}
template<typename Source, typename Offset>
auto TLCS900H::instructionLoadCarry(Source source, Offset offset) -> void {
if constexpr(Source::bits == 8 && is_same_v<Offset, Register<uint8>>) { if(load(offset).bit(3)) return (void)Undefined; }
CF = load(source).bit(load(offset) & Source::bits - 1);
}
template<typename Size, int Adjust> auto TLCS900H::instructionLoad() -> void {
auto target = (uint3)r.prefix == 5 ? XIX : XDE;
auto source = (uint3)r.prefix == 5 ? XIY : XHL;
store(toMemory<Size>(load(target)), load(toMemory<Size>(load(source))));
store(target, load(target) + Adjust);
store(source, load(source) + Adjust);
store(BC, load(BC) - 1);
NF = 0;
VF = load(BC) == 0;
HF = 0;
}
template<typename Size, int Adjust> auto TLCS900H::instructionLoadRepeat() -> void {
do { instructionLoad<Size, Adjust>(); } while(VF);
}
//reverse all bits in a 16-bit register
//note: an 8-bit lookup table is faster (when in L1/L2 cache), but much more code
auto TLCS900H::instructionMirror(Register<uint16> register) -> void {
auto data = load(register);
data = data << 1 & 0xaaaa | data >> 1 & 0x5555;
data = data << 2 & 0xcccc | data >> 2 & 0x3333;
data = data << 4 & 0xf0f0 | data >> 4 & 0x0f0f;
store(register, data << 8 | data >> 8);
}
template<uint Modulo, typename Target, typename Source>
auto TLCS900H::instructionModuloDecrement(Target target, Source source) -> void {
auto result = load(target);
auto number = load(source);
if(bit::count(number) != 1) return (void)Undefined; //must be power of two (what about number==1?)
if(result % number == 0) {
store(target, result + (number - Modulo));
} else {
store(target, result - Modulo);
}
}
template<uint Modulo, typename Target, typename Source>
auto TLCS900H::instructionModuloIncrement(Target target, Source source) -> void {
auto result = load(target);
auto number = load(source);
if(bit::count(number) != 1) return (void)Undefined; //must be power of two (what about number==1?)
if(result % number == number - Modulo) {
store(target, result - (number - Modulo));
} else {
store(target, result + Modulo);
}
}
template<typename Target, typename Source>
auto TLCS900H::instructionMultiply(Target target, Source source) -> void {
store(expand(target), load(target) * load(source));
}
auto TLCS900H::instructionMultiplyAdd(Register<uint16> register) -> void {
auto xde = toMemory<int16>(load(XDE));
auto xhl = toMemory<int16>(load(XHL));
auto source = load(expand(register));
auto target = load(xde) * load(xhl);
store(expand(register), source + target);
store(XHL, load(XHL) - 2);
auto result = load(expand(register));
VF = uint32((target ^ result) & (source ^ result)).bit(-1);
ZF = result == 0;
SF = result.bit(-1);
}
template<typename Target, typename Source>
auto TLCS900H::instructionMultiplySigned(Target target, Source source) -> void {
store(expand(target), load(target).integer() * load(source).integer());
}
template<typename Target>
auto TLCS900H::instructionNegate(Target target) -> void {
store(target, algorithmSubtract(typename Target::type{0}, load(target)));
}
auto TLCS900H::instructionNoOperation() -> void {
}
template<typename Target, typename Source>
auto TLCS900H::instructionOr(Target target, Source source) -> void {
store(target, algorithmOr(load(target), load(source)));
}
template<typename Source, typename Offset>
auto TLCS900H::instructionOrCarry(Source source, Offset offset) -> void {
if constexpr(Source::bits == 8 && is_same_v<Offset, Register<uint8>>) { if(load(offset).bit(3)) return (void)Undefined; }
CF |= load(source).bit(load(offset) & Source::bits - 1);
}
//increments odd addresses only to ensure they are even (16-bit aligned)
template<typename Target>
auto TLCS900H::instructionPointerAdjustAccumulator(Target target) -> void {
auto result = load(target);
store(target, result + result.bit(0));
}
template<typename Target>
auto TLCS900H::instructionPop(Target target) -> void {
pop(target);
}
template<typename Source>
auto TLCS900H::instructionPush(Source source) -> void {
push(source);
}
template<typename Target, typename Offset>
auto TLCS900H::instructionReset(Target target, Offset offset) -> void {
auto result = load(target);
result.bit(load(offset) & Target::bits - 1) = 0;
store(target, result);
}
auto TLCS900H::instructionReturn(uint4 code) -> void {
if(condition(code)) pop(PC);
}
template<typename Source>
auto TLCS900H::instructionReturnDeallocate(Source displacement) -> void {
pop(PC);
store(XSP, load(XSP) + load(displacement));
}
auto TLCS900H::instructionReturnInterrupt() -> void {
pop(SR);
pop(PC);
store(INTNEST, load(INTNEST) - 1);
}
template<typename LHS, typename RHS>
auto TLCS900H::instructionRotateLeftDigit(LHS lhs, RHS rhs) -> void {
auto lvalue = load(lhs);
auto rvalue = load(rhs);
auto Lvalue = lvalue;
lvalue.bits(0,3) = rvalue.bits(4,7);
rvalue.bits(4,7) = rvalue.bits(0,3);
rvalue.bits(0,3) = Lvalue.bits(0,3);
store(lhs, lvalue);
store(rhs, rvalue);
NF = 0;
PF = parity(lvalue);
HF = 0;
ZF = lvalue == 0;
SF = lvalue.bit(-1);
}
template<typename Target, typename Amount>
auto TLCS900H::instructionRotateLeft(Target target, Amount amount) -> void {
auto result = load(target);
auto length = load(amount).clip(4);
for(uint n : range(length ? length : 16)) {
uint cf = result.bit(-1);
result = result << 1 | CF;
CF = cf;
}
store(target, algorithmRotated(result));
}
template<typename Target, typename Amount>
auto TLCS900H::instructionRotateLeftWithoutCarry(Target target, Amount amount) -> void {
auto result = load(target);
auto length = load(amount).clip(4);
for(uint n : range(length ? length : 16)) {
CF = result.bit(-1);
result = result << 1 | CF;
}
store(target, algorithmRotated(result));
}
template<typename LHS, typename RHS>
auto TLCS900H::instructionRotateRightDigit(LHS lhs, RHS rhs) -> void {
auto lvalue = load(lhs);
auto rvalue = load(rhs);
auto Rvalue = rvalue;
rvalue.bits(0,3) = rvalue.bits(4,7);
rvalue.bits(4,7) = lvalue.bits(0,3);
lvalue.bits(0,3) = Rvalue.bits(0,3);
store(lhs, lvalue);
store(rhs, rvalue);
NF = 0;
PF = parity(lvalue);
HF = 0;
ZF = lvalue == 0;
SF = lvalue.bit(-1);
}
template<typename Target, typename Amount>
auto TLCS900H::instructionRotateRight(Target target, Amount amount) -> void {
auto result = load(target);
auto length = load(amount).clip(4);
for(uint n : range(length ? length : 16)) {
uint cf = result.bit(0);
result = CF << Target::bits - 1 | result >> 1;
CF = cf;
}
store(target, algorithmRotated(result));
}
template<typename Target, typename Amount>
auto TLCS900H::instructionRotateRightWithoutCarry(Target target, Amount amount) -> void {
auto result = load(target);
auto length = load(amount).clip(4);
for(uint n : range(length ? length : 16)) {
CF = result.bit(0);
result = CF << Target::bits - 1 | result >> 1;
}
store(target, algorithmRotated(result));
}
template<typename Target, typename Offset>
auto TLCS900H::instructionSet(Target target, Offset offset) -> void {
auto result = load(target);
result.bit(load(offset) & Target::bits - 1) = 1;
store(target, result);
}
template<typename Target>
auto TLCS900H::instructionSetConditionCode(uint4 code, Target target) -> void {
store(target, condition(code));
}
auto TLCS900H::instructionSetFlag(uint1& flag, uint1 value) -> void {
flag = value;
}
auto TLCS900H::instructionSetInterruptFlipFlop(uint3 value) -> void {
IFF = value;
}
auto TLCS900H::instructionSetRegisterFilePointer(uint2 value) -> void {
RFP = value;
}
template<typename Target, typename Amount>
auto TLCS900H::instructionShiftLeftArithmetic(Target target, Amount amount) -> void {
auto result = load(target);
auto length = load(amount).clip(4);
for(uint n : range(length ? length : 16)) {
CF = result.bit(-1);
result = result << 1;
}
store(target, algorithmShifted(result));
}
template<typename Target, typename Amount>
auto TLCS900H::instructionShiftLeftLogical(Target target, Amount amount) -> void {
auto result = load(target);
auto length = load(amount).clip(4);
for(uint n : range(length ? length : 16)) {
CF = result.bit(-1);
result = result << 1;
}
store(target, algorithmShifted(result));
}
template<typename Target, typename Amount>
auto TLCS900H::instructionShiftRightArithmetic(Target target, Amount amount) -> void {
auto result = load(target);
auto length = load(amount).clip(4);
for(uint n : range(length ? length : 16)) {
CF = result.bit(0);
result = result >> 1;
result.bit(-1) = result.bit(-2);
}
store(target, algorithmShifted(result));
}
template<typename Target, typename Amount>
auto TLCS900H::instructionShiftRightLogical(Target target, Amount amount) -> void {
auto result = load(target);
auto length = load(amount).clip(4);
for(uint n : range(length ? length : 16)) {
CF = result.bit(0);
result = result >> 1;
}
store(target, algorithmShifted(result));
}
template<typename Target, typename Offset>
auto TLCS900H::instructionStoreCarry(Target target, Offset offset) -> void {
if constexpr(Target::bits == 8) { if(load(offset).bit(3)) return; } //unlike other *CF instructions, STCF behavior is defined
auto result = load(target);
result.bit(load(offset)) = CF;
store(target, result);
}
auto TLCS900H::instructionSoftwareInterrupt(uint3 interrupt) -> void {
push(PC);
push(SR);
store(PC, load(Memory<uint24>{0xffff00 + interrupt * 4}));
store(INTNEST, load(INTNEST) + 1); //note: not confirmed behavior
}
template<typename Target, typename Source>
auto TLCS900H::instructionSubtract(Target target, Source source) -> void {
store(target, algorithmSubtract(load(target), load(source)));
}
//note: the TLCS900/H manual states this is subtract-with-carry, but it isn't
template<typename Target, typename Source>
auto TLCS900H::instructionSubtractBorrow(Target target, Source source) -> void {
store(target, algorithmSubtract(load(target), load(source), CF));
}
template<typename Target, typename Offset>
auto TLCS900H::instructionTestSet(Target target, Offset offset) -> void {
auto result = load(target);
NF = 0;
VF = Undefined;
HF = 1;
ZF = result.bit(load(offset) & Target::bits - 1);
SF = Undefined;
result.bit(load(offset) & Target::bits - 1) = 1;
store(target, result);
}
template<typename Target>
auto TLCS900H::instructionUnlink(Target target) -> void {
store(XSP, load(target));
pop(target);
}
template<typename Target, typename Source>
auto TLCS900H::instructionXor(Target target, Source source) -> void {
store(target, algorithmXor(load(target), load(source)));
}
template<typename Source, typename Offset>
auto TLCS900H::instructionXorCarry(Source source, Offset offset) -> void {
if constexpr(Source::bits == 8 && is_same_v<Offset, Register<uint8>>) { if(load(offset).bit(3)) return (void)Undefined; }
CF ^= load(source).bit(load(offset) & Source::bits - 1);
}

View File

@ -1,104 +0,0 @@
#define PC r.pc.l.l0
template<> auto TLCS900H::fetch< uint8>() -> uint8 {
return read(PC++);
}
template<> auto TLCS900H::fetch<uint16>() -> uint16 {
uint16 data = read(PC++) << 0;
return data | read(PC++) << 8;
}
template<> auto TLCS900H::fetch<uint24>() -> uint24 {
uint24 data = read(PC++) << 0;
data |= read(PC++) << 8;
return data |= read(PC++) << 16;
}
template<> auto TLCS900H::fetch<uint32>() -> uint32 {
uint32 data = read(PC++) << 0;
data |= read(PC++) << 8;
data |= read(PC++) << 16;
return data |= read(PC++) << 24;
}
#undef PC
template<> auto TLCS900H::fetch< int8>() -> int8 { return ( int8)fetch< uint8>(); }
template<> auto TLCS900H::fetch<int16>() -> int16 { return (int16)fetch<uint16>(); }
template<> auto TLCS900H::fetch<int24>() -> int24 { return (int24)fetch<uint24>(); }
template<> auto TLCS900H::fetch<int32>() -> int32 { return (int32)fetch<uint32>(); }
template<typename T> auto TLCS900H::fetchRegister() -> Register<T> { return Register<T>{fetch<uint8>()}; }
template<typename T, typename U> auto TLCS900H::fetchMemory() -> Memory<T> { return Memory<T>{fetch<U>()}; }
template<typename T> auto TLCS900H::fetchImmediate() -> Immediate<T> { return Immediate<T>{fetch<T>()}; }
//
#define XSP r.xsp.l.l0
template<typename T> auto TLCS900H::pop(T data) -> void {
auto value = typename T::type();
if constexpr(T::bits >= 8) value.byte(0) = read(XSP + 0);
if constexpr(T::bits >= 16) value.byte(1) = read(XSP + 1);
if constexpr(T::bits >= 24) value.byte(2) = read(XSP + 2);
if constexpr(T::bits >= 32) value.byte(3) = read(XSP + 3);
store(data, value);
XSP += T::bits >> 3;
}
template<typename T> auto TLCS900H::push(T data) -> void {
XSP -= T::bits >> 3;
auto value = load(data);
if constexpr(T::bits >= 8) write(XSP + 0, value >> 0);
if constexpr(T::bits >= 16) write(XSP + 1, value >> 8);
if constexpr(T::bits >= 24) write(XSP + 2, value >> 16);
if constexpr(T::bits >= 32) write(XSP + 3, value >> 24);
}
#undef XSP
//
template<> auto TLCS900H::load(Memory< uint8> memory) -> uint8 {
return read(memory.address);
}
template<> auto TLCS900H::load(Memory<uint16> memory) -> uint16 {
uint16 data = read(memory.address + 0) << 0;
return data | read(memory.address + 1) << 8;
}
template<> auto TLCS900H::load(Memory<uint24> memory) -> uint24 {
uint24 data = read(memory.address + 0) << 0;
data |= read(memory.address + 1) << 8;
return data |= read(memory.address + 2) << 16;
}
template<> auto TLCS900H::load(Memory<uint32> memory) -> uint32 {
uint32 data = read(memory.address + 0) << 0;
data |= read(memory.address + 1) << 8;
data |= read(memory.address + 2) << 16;
return data |= read(memory.address + 3) << 24;
}
template<> auto TLCS900H::load(Memory< int8> memory) -> int8 { return (int8)load< uint8>(Memory< uint8>{memory.address}); }
template<> auto TLCS900H::load(Memory<int16> memory) -> int16 { return (int16)load<uint16>(Memory<uint16>{memory.address}); }
template<> auto TLCS900H::load(Memory<int24> memory) -> int24 { return (int24)load<uint24>(Memory<uint24>{memory.address}); }
template<> auto TLCS900H::load(Memory<int32> memory) -> int32 { return (int32)load<uint32>(Memory<uint32>{memory.address}); }
template<> auto TLCS900H::store(Memory< uint8> memory, uint32 data) -> void {
write(memory.address, data);
}
template<> auto TLCS900H::store(Memory<uint16> memory, uint32 data) -> void {
write(memory.address + 0, data >> 0);
write(memory.address + 1, data >> 8);
}
template<> auto TLCS900H::store(Memory<uint32> memory, uint32 data) -> void {
write(memory.address + 0, data >> 0);
write(memory.address + 1, data >> 8);
write(memory.address + 2, data >> 16);
write(memory.address + 3, data >> 24);
}

View File

@ -1,120 +0,0 @@
#define a RFP
#define p RFP - 1 & 3
template<> auto TLCS900H::map(Register<uint8> register) const -> maybe<uint8&> {
switch(register.id) {
#define r(id, name) case id: return r.name;
r(0x00, xwa[0].b.b0) r(0x01, xwa[0].b.b1) r(0x02, xwa[0].b.b2) r(0x03, xwa[0].b.b3)
r(0x04, xbc[0].b.b0) r(0x05, xbc[0].b.b1) r(0x06, xbc[0].b.b2) r(0x07, xbc[0].b.b3)
r(0x08, xde[0].b.b0) r(0x09, xde[0].b.b1) r(0x0a, xde[0].b.b2) r(0x0b, xde[0].b.b3)
r(0x0c, xhl[0].b.b0) r(0x0d, xhl[0].b.b1) r(0x0e, xhl[0].b.b2) r(0x0f, xhl[0].b.b3)
r(0x10, xwa[1].b.b0) r(0x11, xwa[1].b.b1) r(0x12, xwa[1].b.b2) r(0x13, xwa[1].b.b3)
r(0x14, xbc[1].b.b0) r(0x15, xbc[1].b.b1) r(0x16, xbc[1].b.b2) r(0x17, xbc[1].b.b3)
r(0x18, xde[1].b.b0) r(0x19, xde[1].b.b1) r(0x1a, xde[1].b.b2) r(0x1b, xde[1].b.b3)
r(0x1c, xhl[1].b.b0) r(0x1d, xhl[1].b.b1) r(0x1e, xhl[1].b.b2) r(0x1f, xhl[1].b.b3)
r(0x20, xwa[2].b.b0) r(0x21, xwa[2].b.b1) r(0x22, xwa[2].b.b2) r(0x23, xwa[2].b.b3)
r(0x24, xbc[2].b.b0) r(0x25, xbc[2].b.b1) r(0x26, xbc[2].b.b2) r(0x27, xbc[2].b.b3)
r(0x28, xde[2].b.b0) r(0x29, xde[2].b.b1) r(0x2a, xde[2].b.b2) r(0x2b, xde[2].b.b3)
r(0x2c, xhl[2].b.b0) r(0x2d, xhl[2].b.b1) r(0x2e, xhl[2].b.b2) r(0x2f, xhl[2].b.b3)
r(0x30, xwa[3].b.b0) r(0x31, xwa[3].b.b1) r(0x32, xwa[3].b.b2) r(0x33, xwa[3].b.b3)
r(0x34, xbc[3].b.b0) r(0x35, xbc[3].b.b1) r(0x36, xbc[3].b.b2) r(0x37, xbc[3].b.b3)
r(0x38, xde[3].b.b0) r(0x39, xde[3].b.b1) r(0x3a, xde[3].b.b2) r(0x3b, xde[3].b.b3)
r(0x3c, xhl[3].b.b0) r(0x3d, xhl[3].b.b1) r(0x3e, xhl[3].b.b2) r(0x3f, xhl[3].b.b3)
r(0xd0, xwa[p].b.b0) r(0xd1, xwa[p].b.b1) r(0xd2, xwa[p].b.b2) r(0xd3, xwa[p].b.b3)
r(0xd4, xbc[p].b.b0) r(0xd5, xbc[p].b.b1) r(0xd6, xbc[p].b.b2) r(0xd7, xbc[p].b.b3)
r(0xd8, xde[p].b.b0) r(0xd9, xde[p].b.b1) r(0xda, xde[p].b.b2) r(0xdb, xde[p].b.b3)
r(0xdc, xhl[p].b.b0) r(0xdd, xhl[p].b.b1) r(0xde, xhl[p].b.b2) r(0xdf, xhl[p].b.b3)
r(0xe0, xwa[a].b.b0) r(0xe1, xwa[a].b.b1) r(0xe2, xwa[a].b.b2) r(0xe3, xwa[a].b.b3)
r(0xe4, xbc[a].b.b0) r(0xe5, xbc[a].b.b1) r(0xe6, xbc[a].b.b2) r(0xe7, xbc[a].b.b3)
r(0xe8, xde[a].b.b0) r(0xe9, xde[a].b.b1) r(0xea, xde[a].b.b2) r(0xeb, xde[a].b.b3)
r(0xec, xhl[a].b.b0) r(0xed, xhl[a].b.b1) r(0xee, xhl[a].b.b2) r(0xef, xhl[a].b.b3)
r(0xf0, xix .b.b0) r(0xf1, xix .b.b1) r(0xf2, xix .b.b2) r(0xf3, xix .b.b3)
r(0xf4, xiy .b.b0) r(0xf5, xiy .b.b1) r(0xf6, xiy .b.b2) r(0xf7, xiy .b.b3)
r(0xf8, xiz .b.b0) r(0xf9, xiz .b.b1) r(0xfa, xiz .b.b2) r(0xfb, xiz .b.b3)
r(0xfc, xsp .b.b0) r(0xfd, xsp .b.b1) r(0xfe, xsp .b.b2) r(0xff, xsp .b.b3)
#undef r
}
return nothing;
}
template<> auto TLCS900H::map(Register<uint16> register) const -> maybe<uint16&> {
switch(register.id & ~1) {
#define r(id, name) case id: return r.name;
r(0x00, xwa[0].w.w0) r(0x02, xwa[0].w.w1) r(0x04, xbc[0].w.w0) r(0x06, xbc[0].w.w1)
r(0x08, xde[0].w.w0) r(0x0a, xde[0].w.w1) r(0x0c, xhl[0].w.w0) r(0x0e, xhl[0].w.w1)
r(0x10, xwa[1].w.w0) r(0x12, xwa[1].w.w1) r(0x14, xbc[1].w.w0) r(0x16, xbc[1].w.w1)
r(0x18, xde[1].w.w0) r(0x1a, xde[1].w.w1) r(0x1c, xhl[1].w.w0) r(0x1e, xhl[1].w.w1)
r(0x20, xwa[2].w.w0) r(0x22, xwa[2].w.w1) r(0x24, xbc[2].w.w0) r(0x26, xbc[2].w.w1)
r(0x28, xde[2].w.w0) r(0x2a, xde[2].w.w1) r(0x2c, xhl[2].w.w0) r(0x2e, xhl[2].w.w1)
r(0x30, xwa[3].w.w0) r(0x32, xwa[3].w.w1) r(0x34, xbc[3].w.w0) r(0x36, xbc[3].w.w1)
r(0x38, xde[3].w.w0) r(0x3a, xde[3].w.w1) r(0x3c, xhl[3].w.w0) r(0x3e, xhl[3].w.w1)
r(0xd0, xwa[p].w.w0) r(0xd2, xwa[p].w.w1) r(0xd4, xbc[p].w.w0) r(0xd6, xbc[p].w.w1)
r(0xd8, xde[p].w.w0) r(0xda, xde[p].w.w1) r(0xdc, xhl[p].w.w0) r(0xde, xhl[p].w.w1)
r(0xe0, xwa[a].w.w0) r(0xe2, xwa[a].w.w1) r(0xe4, xbc[a].w.w0) r(0xe6, xbc[a].w.w1)
r(0xe8, xde[a].w.w0) r(0xea, xde[a].w.w1) r(0xec, xhl[a].w.w0) r(0xee, xhl[a].w.w1)
r(0xf0, xix .w.w0) r(0xf2, xix .w.w1) r(0xf4, xiy .w.w0) r(0xf6, xiy .w.w1)
r(0xf8, xiz .w.w0) r(0xfa, xiz .w.w1) r(0xfc, xsp .w.w0) r(0xfe, xsp .w.w0)
#undef r
}
return nothing;
}
template<> auto TLCS900H::map(Register<uint32> register) const -> maybe<uint32&> {
switch(register.id & ~3) {
#define r(id, name) case id: return r.name;
r(0x00, xwa[0].l.l0) r(0x04, xbc[0].l.l0) r(0x08, xde[0].l.l0) r(0x0c, xhl[0].l.l0)
r(0x10, xwa[1].l.l0) r(0x14, xbc[1].l.l0) r(0x18, xde[1].l.l0) r(0x1c, xhl[1].l.l0)
r(0x20, xwa[2].l.l0) r(0x24, xbc[2].l.l0) r(0x28, xde[2].l.l0) r(0x2c, xhl[2].l.l0)
r(0x30, xwa[3].l.l0) r(0x34, xbc[3].l.l0) r(0x38, xde[3].l.l0) r(0x3c, xhl[3].l.l0)
r(0xd0, xwa[p].l.l0) r(0xd4, xbc[p].l.l0) r(0xd8, xde[p].l.l0) r(0xdc, xhl[p].l.l0)
r(0xe0, xwa[a].l.l0) r(0xe4, xbc[a].l.l0) r(0xe8, xde[a].l.l0) r(0xec, xhl[a].l.l0)
r(0xf0, xix .l.l0) r(0xf4, xiy .l.l0) r(0xf8, xiz .l.l0) r(0xfc, xsp .l.l0)
#undef r
}
return nothing;
}
#undef a
#undef p
template<> auto TLCS900H::load< uint8>(Register< uint8> register) const -> uint8 { return map(register)(Undefined); }
template<> auto TLCS900H::load<uint16>(Register<uint16> register) const -> uint16 { return map(register)(Undefined); }
template<> auto TLCS900H::load<uint32>(Register<uint32> register) const -> uint32 { return map(register)(Undefined); }
template<> auto TLCS900H::store< uint8>(Register< uint8> register, uint32 data) -> void { if(auto r = map(register)) r() = data; }
template<> auto TLCS900H::store<uint16>(Register<uint16> register, uint32 data) -> void { if(auto r = map(register)) r() = data; }
template<> auto TLCS900H::store<uint32>(Register<uint32> register, uint32 data) -> void { if(auto r = map(register)) r() = data; }
auto TLCS900H::expand(Register< uint8> register) const -> Register<uint16> { return {register.id & ~1}; }
auto TLCS900H::expand(Register<uint16> register) const -> Register<uint32> { return {register.id & ~3}; }
auto TLCS900H::shrink(Register<uint32> register) const -> Register<uint16> { return {register.id}; }
auto TLCS900H::shrink(Register<uint16> register) const -> Register< uint8> { return {register.id}; }
auto TLCS900H::load(FlagRegister f) const -> uint8 {
switch(f.id) {
case 0: return r.c << 0 | r.n << 1 | r.v << 2 | r.h << 4 | r.z << 6 | r.s << 7;
case 1: return r.cp << 0 | r.np << 1 | r.vp << 2 | r.hp << 4 | r.zp << 6 | r.sp << 7;
} unreachable;
}
auto TLCS900H::store(FlagRegister f, uint8 data) -> void {
switch(f.id) {
case 0: r.c = data.bit(0); r.n = data.bit(1); r.v = data.bit(2); r.h = data.bit(4); r.z = data.bit(6); r.s = data.bit(7); return;
case 1: r.cp = data.bit(0); r.np = data.bit(1); r.vp = data.bit(2); r.hp = data.bit(4); r.zp = data.bit(6); r.sp = data.bit(7); return;
} unreachable;
}
auto TLCS900H::load(StatusRegister) const -> uint16 {
//900/H: d10 = RFP2 (always 0); d11 = MAX (always 1); d15 = SYSM (always 1)
return load(F) | r.rfp << 8 | 0 << 10 | 1 << 11 | r.iff << 12 | 1 << 15;
}
auto TLCS900H::store(StatusRegister, uint16 data) -> void {
store(F, data.bits(0,7));
r.rfp = data.bits(8,9);
r.iff = data.bits(12,14);
}
auto TLCS900H::load(ProgramCounter) const -> uint32 { return r.pc.l.l0; }
auto TLCS900H::store(ProgramCounter, uint32 data) -> void { r.pc.l.l0 = data; }

View File

@ -1,2 +0,0 @@
auto TLCS900H::serialize(serializer& s) -> void {
}

View File

@ -1,39 +0,0 @@
#include <processor/processor.hpp>
#include "tlcs900h.hpp"
namespace Processor {
#define CF r.c
#define NF r.n
#define VF r.v
#define PF r.v
#define HF r.h
#define ZF r.z
#define SF r.s
#define RFP r.rfp
#define IFF r.iff
#include "registers.cpp"
#include "control-registers.cpp"
#include "memory.cpp"
#include "conditions.cpp"
#include "algorithms.cpp"
#include "instruction.cpp"
#include "instructions.cpp"
#include "serialization.cpp"
#include "disassembler.cpp"
auto TLCS900H::interrupt(uint24 address) -> void {
push(PC);
push(SR);
store(PC, load(Memory<uint24>{address}));
store(INTNEST, load(INTNEST) + 1);
}
auto TLCS900H::power() -> void {
r = {};
r.xsp.l.l0 = 0x100;
}
}

View File

@ -1,269 +0,0 @@
//Toshiba TLCS900/H
/* open questions:
*
* what happens when a prohibited instruction operand size is used? (eg adc.l (memory),#immediate)
* what happens when %11 is used for pre-decrement and post-increment addressing?
* what happens when using 8-bit register indexing and d0 is set (Word) or d1/d0 is set (Long)?
* what happens during an LDX instruction when the three padding bytes aren't all 0x00?
* what value is read back from a non-existent 8-bit register ID? (eg 0x40-0xcf)
* many instructions are undefined, some are marked as dummy instructions ... what do each do?
* what happens when using (AND,OR,XOR,LD)CF (byte)source,A with A.bit(3) set?
* what happens when using MINC#,MDEC# with a non-power of two? what about with a value of 1?
*/
#pragma once
namespace Processor {
struct TLCS900H {
virtual auto step(uint clocks) -> void = 0;
virtual auto read(uint24 address) -> uint8 = 0;
virtual auto write(uint24 address, uint8 data) -> void = 0;
struct FlagRegister { using type = uint8; enum : uint { bits = 8 }; uint1 id; };
struct StatusRegister { using type = uint16; enum : uint { bits = 16 }; };
struct ProgramCounter { using type = uint32; enum : uint { bits = 32 }; };
template<typename T> struct ControlRegister { using type = T; enum : uint { bits = 8 * sizeof(T) }; uint8 id; };
template<typename T> struct Register { using type = T; enum : uint { bits = 8 * sizeof(T) }; uint8 id; };
template<typename T> struct Memory { using type = T; enum : uint { bits = 8 * sizeof(T) }; uint32 address; };
template<typename T> struct Immediate { using type = T; enum : uint { bits = 8 * sizeof(T) }; uint32 constant; };
template<typename T> auto load(Immediate<T> immediate) const -> T { return immediate.constant; }
//tlcs900h.cpp
auto interrupt(uint24 vector) -> void;
auto power() -> void;
//registers.cpp
template<typename T> auto map(Register<T>) const -> maybe<T&>;
template<typename T> auto load(Register<T>) const -> T;
template<typename T> auto store(Register<T>, uint32) -> void;
auto expand(Register< uint8>) const -> Register<uint16>;
auto expand(Register<uint16>) const -> Register<uint32>;
auto shrink(Register<uint32>) const -> Register<uint16>;
auto shrink(Register<uint16>) const -> Register< uint8>;
auto load(FlagRegister) const -> uint8;
auto store(FlagRegister, uint8) -> void;
auto load(StatusRegister) const -> uint16;
auto store(StatusRegister, uint16) -> void;
auto load(ProgramCounter) const -> uint32;
auto store(ProgramCounter, uint32) -> void;
//control-registers.cpp
template<typename T> auto map(ControlRegister<T>) const -> maybe<T&>;
template<typename T> auto load(ControlRegister<T>) const -> T;
template<typename T> auto store(ControlRegister<T>, uint32) -> void;
//memory.cpp
template<typename T = uint8> auto fetch() -> T;
template<typename T> auto fetchRegister() -> Register<T>;
template<typename T, typename U> auto fetchMemory() -> Memory<T>;
template<typename T> auto fetchImmediate() -> Immediate<T>;
template<typename T> auto push(T) -> void;
template<typename T> auto pop(T) -> void;
template<typename T> auto load(Memory<T>) -> T;
template<typename T> auto store(Memory<T>, uint32) -> void;
//conditions.cpp
auto condition(uint4 code) -> bool;
//algorithms.cpp
template<typename T> auto parity(T) const -> bool;
template<typename T> auto algorithmAdd(T target, T source, uint1 carry = 0) -> T;
template<typename T> auto algorithmAnd(T target, T source) -> T;
template<typename T> auto algorithmDecrement(T target, T source) -> T;
template<typename T> auto algorithmIncrement(T target, T source) -> T;
template<typename T> auto algorithmOr(T target, T source) -> T;
template<typename T> auto algorithmRotated(T result) -> T;
template<typename T> auto algorithmShifted(T result) -> T;
template<typename T> auto algorithmSubtract(T target, T source, uint1 carry = 0) -> T;
template<typename T> auto algorithmXor(T target, T source) -> T;
//instruction.cpp
template<typename T> auto toRegister3(uint3) const -> Register<T>;
template<typename T> auto toRegister8(uint8) const -> Register<T>;
template<typename T> auto toControlRegister(uint8) const -> ControlRegister<T>;
template<typename T> auto toMemory(uint32 address) const -> Memory<T>;
template<typename T> auto toImmediate(uint32 constant) const -> Immediate<T>;
template<typename T> auto toImmediate3(natural constant) const -> Immediate<T>;
auto instruction() -> void;
template<typename Register> auto instructionRegister(Register) -> void;
template<typename Memory> auto instructionSourceMemory(Memory) -> void;
auto instructionTargetMemory(uint32 address) -> void;
//instructions.cpp
template<typename Target, typename Source> auto instructionAdd(Target, Source) -> void;
template<typename Target, typename Source> auto instructionAddCarry(Target, Source) -> void;
template<typename Target, typename Source> auto instructionAnd(Target, Source) -> void;
template<typename Source, typename Offset> auto instructionAndCarry(Source, Offset) -> void;
template<typename Source, typename Offset> auto instructionBit(Source, Offset) -> void;
auto instructionBitSearch1Backward(Register<uint16>) -> void;
auto instructionBitSearch1Forward(Register<uint16>) -> void;
template<typename Source> auto instructionCall(uint4 code, Source) -> void;
template<typename Source> auto instructionCallRelative(Source) -> void;
template<typename Target, typename Offset> auto instructionChange(Target, Offset) -> void;
template<typename Size, int Adjust, typename Target> auto instructionCompare(Target) -> void;
template<typename Size, int Adjust, typename Target> auto instructionCompareRepeat(Target) -> void;
template<typename Target, typename Source> auto instructionCompare(Target, Source) -> void;
template<typename Target> auto instructionComplement(Target) -> void;
auto instructionDecimalAdjustAccumulator(Register<uint8>) -> void;
template<typename Target, typename Source> auto instructionDecrement(Target, Source) -> void;
template<typename Target, typename Offset> auto instructionDecrementJumpNotZero(Target, Offset) -> void;
template<typename Target, typename Source> auto instructionDivide(Target, Source) -> void;
template<typename Target, typename Source> auto instructionDivideSigned(Target, Source) -> void;
template<typename Target, typename Source> auto instructionExchange(Target, Source) -> void;
template<typename Target> auto instructionExtendSign(Target) -> void;
template<typename Target> auto instructionExtendZero(Target) -> void;
auto instructionHalt() -> void;
template<typename Target, typename Source> auto instructionIncrement(Target, Source) -> void;
template<typename Source> auto instructionJump(uint4 code, Source) -> void;
template<typename Source> auto instructionJumpRelative(uint4 code, Source) -> void;
template<typename Target, typename Offset> auto instructionLink(Target, Offset) -> void;
template<typename Target, typename Source> auto instructionLoad(Target, Source) -> void;
template<typename Source, typename Offset> auto instructionLoadCarry(Source, Offset) -> void;
template<typename Size, int Adjust> auto instructionLoad() -> void;
template<typename Size, int Adjust> auto instructionLoadRepeat() -> void;
template<uint Modulo, typename Target, typename Source> auto instructionModuloDecrement(Target, Source) -> void;
template<uint Modulo, typename Target, typename Source> auto instructionModuloIncrement(Target, Source) -> void;
auto instructionMirror(Register<uint16>) -> void;
template<typename Target, typename Source> auto instructionMultiply(Target, Source) -> void;
auto instructionMultiplyAdd(Register<uint16>) -> void;
template<typename Target, typename Source> auto instructionMultiplySigned(Target, Source) -> void;
template<typename Target> auto instructionNegate(Target) -> void;
auto instructionNoOperation() -> void;
template<typename Target, typename Source> auto instructionOr(Target, Source) -> void;
template<typename Source, typename Offset> auto instructionOrCarry(Source, Offset) -> void;
template<typename Target> auto instructionPointerAdjustAccumulator(Target) -> void;
template<typename Target> auto instructionPop(Target) -> void;
template<typename Source> auto instructionPush(Source) -> void;
template<typename Target, typename Offset> auto instructionReset(Target, Offset) -> void;
auto instructionReturn(uint4 code) -> void;
template<typename Source> auto instructionReturnDeallocate(Source) -> void;
auto instructionReturnInterrupt() -> void;
template<typename LHS, typename RHS> auto instructionRotateLeftDigit(LHS, RHS) -> void;
template<typename Target, typename Amount> auto instructionRotateLeft(Target, Amount) -> void;
template<typename Target, typename Amount> auto instructionRotateLeftWithoutCarry(Target, Amount) -> void;
template<typename LHS, typename RHS> auto instructionRotateRightDigit(LHS, RHS) -> void;
template<typename Target, typename Amount> auto instructionRotateRight(Target, Amount) -> void;
template<typename Target, typename Amount> auto instructionRotateRightWithoutCarry(Target, Amount) -> void;
template<typename Target, typename Offset> auto instructionSet(Target, Offset) -> void;
template<typename Target> auto instructionSetConditionCode(uint4 code, Target) -> void;
auto instructionSetFlag(uint1& flag, uint1 value) -> void;
auto instructionSetInterruptFlipFlop(uint3 value) -> void;
auto instructionSetRegisterFilePointer(uint2 value) -> void;
template<typename Target, typename Amount> auto instructionShiftLeftArithmetic(Target, Amount) -> void;
template<typename Target, typename Amount> auto instructionShiftLeftLogical(Target, Amount) -> void;
template<typename Target, typename Amount> auto instructionShiftRightArithmetic(Target, Amount) -> void;
template<typename Target, typename Amount> auto instructionShiftRightLogical(Target, Amount) -> void;
template<typename Target, typename Offset> auto instructionStoreCarry(Target, Offset) -> void;
auto instructionSoftwareInterrupt(uint3 interrupt) -> void;
template<typename Target, typename Source> auto instructionSubtract(Target, Source) -> void;
template<typename Target, typename Source> auto instructionSubtractBorrow(Target, Source) -> void;
template<typename Target, typename Offset> auto instructionTestSet(Target, Offset) -> void;
template<typename Target> auto instructionUnlink(Target) -> void;
template<typename Target, typename Source> auto instructionXor(Target, Source) -> void;
template<typename Source, typename Offset> auto instructionXorCarry(Source, Offset) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
union DataRegister {
DataRegister() {}
struct { uint32 order_lsb1(l0); } l;
struct { uint16 order_lsb2(w0, w1); } w;
struct { uint8 order_lsb4(b0, b1, b2, b3); } b;
};
struct Registers {
DataRegister xwa[4];
DataRegister xbc[4];
DataRegister xde[4];
DataRegister xhl[4];
DataRegister xix;
DataRegister xiy;
DataRegister xiz;
DataRegister xsp;
DataRegister pc;
DataRegister dmas[4];
DataRegister dmad[4];
DataRegister dmam[4];
DataRegister intnest; //16-bit
uint1 c, cp; //carry
uint1 n, np; //negative
uint1 v, vp; //overflow or parity
uint1 h, hp; //half carry
uint1 z, zp; //zero
uint1 s, sp; //sign
uint2 rfp; //register file pointer
uint3 iff = 7; //interrupt mask flip-flop
uint1 halted; //set if halt instruction executed; waits for an interrupt to resume
uint8 prefix; //first opcode byte; needed for [CP|LD][ID](R) instructions
} r;
static inline const Register< uint8> A{0xe0};
static inline const Register< uint8> W{0xe1};
static inline const Register< uint8> C{0xe4};
static inline const Register< uint8> B{0xe5};
static inline const Register< uint8> E{0xe8};
static inline const Register< uint8> D{0xe9};
static inline const Register< uint8> L{0xec};
static inline const Register< uint8> H{0xed};
static inline const Register<uint16> WA{0xe0};
static inline const Register<uint16> BC{0xe4};
static inline const Register<uint16> DE{0xe8};
static inline const Register<uint16> HL{0xec};
static inline const Register<uint16> IX{0xf0};
static inline const Register<uint16> IY{0xf4};
static inline const Register<uint16> IZ{0xf8};
static inline const Register<uint16> SP{0xfc};
static inline const Register<uint32> XWA{0xe0};
static inline const Register<uint32> XBC{0xe4};
static inline const Register<uint32> XDE{0xe8};
static inline const Register<uint32> XHL{0xec};
static inline const Register<uint32> XIX{0xf0};
static inline const Register<uint32> XIY{0xf4};
static inline const Register<uint32> XIZ{0xf8};
static inline const Register<uint32> XSP{0xfc};
static inline const FlagRegister F {0};
static inline const FlagRegister FP{1};
static inline const StatusRegister SR{};
static inline const ProgramCounter PC{};
static inline const ControlRegister<uint32> DMAS0{0x00};
static inline const ControlRegister<uint32> DMAS1{0x04};
static inline const ControlRegister<uint32> DMAS2{0x08};
static inline const ControlRegister<uint32> DMAS3{0x0c};
static inline const ControlRegister<uint32> DMAD0{0x10};
static inline const ControlRegister<uint32> DMAD1{0x14};
static inline const ControlRegister<uint32> DMAD2{0x18};
static inline const ControlRegister<uint32> DMAD3{0x1c};
static inline const ControlRegister<uint32> DMAM0{0x20};
static inline const ControlRegister<uint32> DMAM1{0x24};
static inline const ControlRegister<uint32> DMAM2{0x28};
static inline const ControlRegister<uint32> DMAM3{0x2c};
static inline const ControlRegister<uint16> DMAC0{0x20};
static inline const ControlRegister<uint16> DMAC1{0x24};
static inline const ControlRegister<uint16> DMAC2{0x28};
static inline const ControlRegister<uint16> DMAC3{0x2c};
static inline const ControlRegister<uint16> INTNEST{0x3c};
static inline const uint4 False{0x00};
static inline const uint4 True {0x08};
static inline const uint1 Undefined = 0;
//disassembler.cpp
virtual auto disassembleRead(uint24 address) -> uint8 { return read(address); }
auto disassemble() -> string;
};
}

View File

@ -37,12 +37,12 @@ struct uPD96050 {
}
inline auto operator=(uint16 data) -> Flag& {
ov0 = data.bit(0);
ov1 = data.bit(1);
z = data.bit(2);
c = data.bit(3);
s0 = data.bit(4);
s1 = data.bit(5);
ov0 = bit1(data,0);
ov1 = bit1(data,1);
z = bit1(data,2);
c = bit1(data,3);
s0 = bit1(data,4);
s1 = bit1(data,5);
return *this;
}
@ -64,17 +64,17 @@ struct uPD96050 {
}
inline auto operator=(uint16 data) -> Status& {
p0 = data.bit( 0);
p1 = data.bit( 1);
ei = data.bit( 7);
sic = data.bit( 8);
soc = data.bit( 9);
drc = data.bit(10);
dma = data.bit(11);
drs = data.bit(12);
usf0 = data.bit(13);
usf1 = data.bit(14);
rqm = data.bit(15);
p0 = bit1(data, 0);
p1 = bit1(data, 1);
ei = bit1(data, 7);
sic = bit1(data, 8);
soc = bit1(data, 9);
drc = bit1(data,10);
dma = bit1(data,11);
drs = bit1(data,12);
usf0 = bit1(data,13);
usf1 = bit1(data,14);
rqm = bit1(data,15);
return *this;
}

View File

@ -1,226 +0,0 @@
//(0 = odd, 1 = even) number of bits set in value
auto V30MZ::parity(uint8 value) const -> bool {
value ^= value >> 4;
value ^= value >> 2;
value ^= value >> 1;
return !(value & 1);
}
#define bits (size == Byte ? 8 : 16)
#define mask (size == Byte ? 0xff : 0xffff)
#define sign (size == Byte ? 0x80 : 0x8000)
auto V30MZ::ADC(Size size, uint16 x, uint16 y) -> uint16 {
return ADD(size, x, y + r.f.c);
}
auto V30MZ::ADD(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x + y) & mask;
r.f.c = x + y > mask;
r.f.p = parity(result);
r.f.h = (uint4)x + (uint4)y >= 16;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = (result ^ x) & (result ^ y) & sign;
return result;
}
auto V30MZ::AND(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x & y) & mask;
r.f.c = 0;
r.f.p = parity(result);
r.f.h = 0;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = 0;
return result;
}
auto V30MZ::DEC(Size size, uint16 x) -> uint16 {
uint16 result = (x - 1) & mask;
r.f.p = parity(result);
r.f.h = (x & 0x0f) == 0;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = result == sign - 1;
return result;
}
auto V30MZ::DIV(Size size, uint32 x, uint32 y) -> uint32 {
if(y == 0) return interrupt(0), 0;
uint32 quotient = x / y;
uint32 remainder = x % y;
return (remainder & mask) << bits | (quotient & mask);
}
auto V30MZ::DIVI(Size size, int32 x, int32 y) -> uint32 {
if(y == 0) return interrupt(0), 0;
x = size == Byte ? (int8_t)x : (int16_t)x;
y = size == Byte ? (int8_t)y : (int16_t)y;
uint32 quotient = x / y;
uint32 remainder = x % y;
return (remainder & mask) << bits | (quotient & mask);
}
auto V30MZ::INC(Size size, uint16 x) -> uint16 {
uint16 result = (x + 1) & mask;
r.f.p = parity(result);
r.f.h = (x & 0x0f) == 0x0f;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = result == sign;
return result;
}
auto V30MZ::MUL(Size size, uint16 x, uint16 y) -> uint32 {
uint32 result = x * y;
r.f.c = result >> bits;
r.f.v = result >> bits;
return result;
}
auto V30MZ::MULI(Size size, int16 x, int16 y) -> uint32 {
x = size == Byte ? (int8_t)x : (int16_t)x;
y = size == Byte ? (int8_t)y : (int16_t)y;
uint32 result = x * y;
r.f.c = result >> bits;
r.f.v = result >> bits;
return result;
}
auto V30MZ::NEG(Size size, uint16 x) -> uint16 {
uint16 result = (-x) & mask;
r.f.c = x;
r.f.p = parity(result);
r.f.h = x & 0x0f;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = x == sign;
return result;
}
auto V30MZ::NOT(Size size, uint16 x) -> uint16 {
uint16 result = (~x) & mask;
return result;
}
auto V30MZ::OR(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x | y) & mask;
r.f.c = 0;
r.f.p = parity(result);
r.f.h = 0;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = 0;
return result;
}
auto V30MZ::RCL(Size size, uint16 x, uint5 y) -> uint16 {
uint16 result = x;
for(uint n = 0; n < y; n++) {
bool carry = result & sign;
result = (result << 1) | r.f.c;
r.f.c = carry;
}
r.f.v = (x ^ result) & sign;
return result & mask;
}
auto V30MZ::RCR(Size size, uint16 x, uint5 y) -> uint16 {
uint16 result = x;
for(uint n = 0; n < y; n++) {
bool carry = result & 1;
result = (r.f.c ? sign : 0) | (result >> 1);
r.f.c = carry;
}
r.f.v = (x ^ result) & sign;
return result & mask;
}
auto V30MZ::ROL(Size size, uint16 x, uint4 y) -> uint16 {
r.f.c = (x << y) & (1 << bits);
uint16 result = ((x << y) | (x >> (bits - y))) & mask;
r.f.v = (x ^ result) & sign;
return result;
}
auto V30MZ::ROR(Size size, uint16 x, uint4 y) -> uint16 {
r.f.c = (x >> (y - 1)) & 1;
uint16 result = ((x >> y) | (x << (bits - y))) & mask;
r.f.v = (x ^ result) & sign;
return result;
}
auto V30MZ::SAL(Size size, uint16 x, uint5 y) -> uint16 {
r.f.c = (x << y) & (1 << bits);
uint16 result = (x << y) & mask;
r.f.p = parity(result);
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = 0;
return result;
}
auto V30MZ::SAR(Size size, uint16 x, uint5 y) -> uint16 {
if(y & 16) {
r.f.c = x & sign;
return 0 - r.f.c;
}
r.f.c = (x >> (y - 1)) & 1;
uint16 result = (x >> y) & mask;
if(x & sign) result |= mask << (bits - y);
r.f.p = parity(result);
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = 0;
return result;
}
auto V30MZ::SBB(Size size, uint16 x, uint16 y) -> uint16 {
return SUB(size, x, y + r.f.c);
}
auto V30MZ::SHL(Size size, uint16 x, uint5 y) -> uint16 {
r.f.c = (x << y) & (1 << bits);
uint16 result = (x << y) & mask;
r.f.p = parity(result);
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = (x ^ result) & sign;
return result;
}
auto V30MZ::SHR(Size size, uint16 x, uint5 y) -> uint16 {
r.f.c = (x >> (y - 1)) & 1;
uint16 result = (x >> y) & mask;
r.f.p = parity(result);
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = (x ^ result) & sign;
return result;
}
auto V30MZ::SUB(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x - y) & mask;
r.f.c = y > x;
r.f.p = parity(result);
r.f.h = (uint4)y > (uint4)x;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = (x ^ y) & (x ^ result) & sign;
return result;
}
auto V30MZ::XOR(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x ^ y) & mask;
r.f.c = 0;
r.f.p = parity(result);
r.f.h = 0;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = 0;
return result;
}
#undef mask
#undef sign

View File

@ -1,387 +0,0 @@
using format = string_format;
//todo: this is horribly broken in many cases; needs a total rewrite
auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> string {
string s;
uint20 ea = cs * 16 + ip;
vector<uint8> bytesRead;
auto fetch = [&](bool inc = true) -> uint8 {
uint8 data = read(cs * 16 + ip);
if(inc) ip++, bytesRead.append(data);
return data;
};
auto readByte = [&]() -> string {
uint8 byte = fetch();
return {"$", hex(byte, 2L)};
};
auto readWord = [&]() -> string {
uint16 word = fetch(); word |= fetch() << 8;
return {"$", hex(word, 4L)};
};
auto readByteSigned = [&]() -> string {
uint8 byte = fetch();
return {"$", byte & 0x80 ? "-" : "+", hex(byte & 0x80 ? uint8(256 - byte) : byte, 2L)};
};
auto readRelativeByte = [&]() -> string {
uint8 byte = fetch();
return {"$", hex(ip + (int8)byte, 4L)};
};
auto readRelativeWord = [&]() -> string {
uint16 word = fetch(); word |= fetch() << 8;
return {"$", hex(ip + (int16)word, 4L)};
};
auto readIndirectByte = [&]() -> string {
return {"[", readWord(), "]"};
};
auto readIndirectWord = [&]() -> string {
return {"{", readWord(), "}"};
};
auto readRegByte = [&](bool inc = true) -> string {
uint8 modRM = fetch(inc);
static const string reg[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};
return reg[(uint3)(modRM >> 3)];
};
auto readRegWord = [&](bool inc = true) -> string {
uint8 modRM = fetch(inc);
static const string reg[] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
return reg[(uint3)(modRM >> 3)];
};
auto readSeg = [&](bool inc = true) -> string {
uint8 modRM = fetch(inc);
static const string seg[] = {"es", "cs", "ss", "ds"};
return seg[(uint2)(modRM >> 3)];
};
auto readMemByte = [&](bool inc = true) -> string {
uint8 modRM = fetch(inc);
static const string reg[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};
if(modRM >= 0xc0) return reg[(uint3)modRM];
if((modRM & 0xc7) == 0x06) return {"[", readWord(), "]"};
static const string mem[] = {"bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx"};
if((modRM & 0xc0) == 0x40) return {"[", mem[(uint3)modRM], "+", readByte(), "]"};
if((modRM & 0xc0) == 0x80) return {"[", mem[(uint3)modRM], "+", readWord(), "]"};
return {"[", mem[(uint3)modRM], "]"};
};
auto readMemWord = [&](bool inc = true) -> string {
uint8 modRM = fetch(inc);
static const string reg[] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
if(modRM >= 0xc0) return reg[(uint3)modRM];
if((modRM & 0xc7) == 0x06) return {"{", readWord(), "}"};
static const string mem[] = {"bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx"};
if((modRM & 0xc0) == 0x40) return {"{", mem[(uint3)modRM], "+", readByte(), "}"};
if((modRM & 0xc0) == 0x80) return {"{", mem[(uint3)modRM], "+", readWord(), "}"};
return {"{", mem[(uint3)modRM], "}"};
};
auto readGroup = [&](uint group) -> string {
uint8 modRM = fetch(false);
static const string opcode[4][8] = {
{"add ", "or ", "adc ", "sbb ", "and ", "sub ", "xor ", "cmp "},
{"rol ", "ror ", "rcl ", "rcr ", "shl ", "shr ", "sal ", "sar "},
{"test", "test", "not ", "neg ", "mul ", "imul", "div ", "idiv"},
{"inc ", "dec ", "call", "calf", "jmp ", "jmpf", "push", "??? "},
};
return opcode[group - 1][(uint3)(modRM >> 3)];
};
auto opcode = fetch();
switch(opcode) {
case 0x00: s = {"add {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x01: s = {"add {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x02: s = {"add {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x03: s = {"add {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x04: s = {"add al,{0}", format{readByte()}}; break;
case 0x05: s = {"add ax,{0}", format{readWord()}}; break;
case 0x06: s = {"push es"}; break;
case 0x07: s = {"pop es"}; break;
case 0x08: s = {"or {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x09: s = {"or {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x0a: s = {"or {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x0b: s = {"or {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x0c: s = {"or al,{0}", format{readByte()}}; break;
case 0x0d: s = {"or ax,{0}", format{readWord()}}; break;
case 0x0e: s = {"push cs"}; break;
//case 0x0f:
case 0x10: s = {"adc {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x11: s = {"adc {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x12: s = {"adc {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x13: s = {"adc {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x14: s = {"adc al,{0}", format{readByte()}}; break;
case 0x15: s = {"adc ax,{0}", format{readWord()}}; break;
case 0x16: s = {"push ss"}; break;
case 0x17: s = {"pop ss"}; break;
case 0x18: s = {"sbb {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x19: s = {"sbb {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x1a: s = {"sbb {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x1b: s = {"sbb {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x1c: s = {"sbb al,{0}", format{readByte()}}; break;
case 0x1d: s = {"sbb ax,{0}", format{readWord()}}; break;
case 0x1e: s = {"push ds"}; break;
case 0x1f: s = {"pop ds"}; break;
case 0x20: s = {"and {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x21: s = {"and {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x22: s = {"and {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x23: s = {"and {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x24: s = {"and al,{0}", format{readByte()}}; break;
case 0x25: s = {"and ax,{0}", format{readWord()}}; break;
case 0x26: s = {"es: "}; break;
case 0x27: s = {"daa "}; break;
case 0x28: s = {"sub {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x29: s = {"sub {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x2a: s = {"sub {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x2b: s = {"sub {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x2c: s = {"sub al,{0}", format{readByte()}}; break;
case 0x2d: s = {"sub ax,{0}", format{readWord()}}; break;
case 0x2e: s = {"cs: "}; break;
case 0x2f: s = {"das "}; break;
case 0x30: s = {"xor {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x31: s = {"xor {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x32: s = {"xor {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x33: s = {"xor {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x34: s = {"xor al,{0}", format{readByte()}}; break;
case 0x35: s = {"xor ax,{0}", format{readWord()}}; break;
case 0x36: s = {"ss: "}; break;
case 0x37: s = {"aaa "}; break;
case 0x38: s = {"cmp {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x39: s = {"cmp {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x3a: s = {"cmp {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x3b: s = {"cmp {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x3c: s = {"cmp al,{0}", format{readByte()}}; break;
case 0x3d: s = {"cmp ax,{0}", format{readWord()}}; break;
case 0x3e: s = {"ds: "}; break;
case 0x3f: s = {"aas "}; break;
case 0x40: s = {"inc ax"}; break;
case 0x41: s = {"inc cx"}; break;
case 0x42: s = {"inc dx"}; break;
case 0x43: s = {"inc bx"}; break;
case 0x44: s = {"inc sp"}; break;
case 0x45: s = {"inc bp"}; break;
case 0x46: s = {"inc si"}; break;
case 0x47: s = {"inc di"}; break;
case 0x48: s = {"dec ax"}; break;
case 0x49: s = {"dec cx"}; break;
case 0x4a: s = {"dec dx"}; break;
case 0x4b: s = {"dec bx"}; break;
case 0x4c: s = {"dec sp"}; break;
case 0x4d: s = {"dec bp"}; break;
case 0x4e: s = {"dec si"}; break;
case 0x4f: s = {"dec di"}; break;
case 0x50: s = {"push ax"}; break;
case 0x51: s = {"push cx"}; break;
case 0x52: s = {"push dx"}; break;
case 0x53: s = {"push bx"}; break;
case 0x54: s = {"push sp"}; break;
case 0x55: s = {"push bp"}; break;
case 0x56: s = {"push si"}; break;
case 0x57: s = {"push di"}; break;
case 0x58: s = {"pop ax"}; break;
case 0x59: s = {"pop cx"}; break;
case 0x5a: s = {"pop dx"}; break;
case 0x5b: s = {"pop bx"}; break;
case 0x5c: s = {"pop sp"}; break;
case 0x5d: s = {"pop bp"}; break;
case 0x5e: s = {"pop si"}; break;
case 0x5f: s = {"pop di"}; break;
case 0x60: s = {"pusha "}; break;
case 0x61: s = {"popa "}; break;
case 0x62: s = {"bound {0},{1}", format{readRegWord(0), readMemWord()}}; break;
//case 0x63:
//case 0x64:
//case 0x65:
//case 0x66:
//case 0x67:
case 0x68: s = {"push {0}", format{readWord()}}; break;
case 0x69: s = {"imul {0},{1},{2}", format{readRegWord(0), readMemWord(), readWord()}}; break;
case 0x6a: s = {"push {0}", format{readByteSigned()}}; break;
case 0x6b: s = {"imul {0},{1},{2}", format{readRegWord(0), readMemWord(), readByteSigned()}}; break;
case 0x6c: s = {"insb "}; break;
case 0x6d: s = {"insw "}; break;
case 0x6e: s = {"outsb "}; break;
case 0x6f: s = {"outsw "}; break;
case 0x70: s = {"jo {0}", format{readRelativeByte()}}; break;
case 0x71: s = {"jno {0}", format{readRelativeByte()}}; break;
case 0x72: s = {"jc {0}", format{readRelativeByte()}}; break;
case 0x73: s = {"jnc {0}", format{readRelativeByte()}}; break;
case 0x74: s = {"jz {0}", format{readRelativeByte()}}; break;
case 0x75: s = {"jnz {0}", format{readRelativeByte()}}; break;
case 0x76: s = {"jcz {0}", format{readRelativeByte()}}; break;
case 0x77: s = {"jncz {0}", format{readRelativeByte()}}; break;
case 0x78: s = {"js {0}", format{readRelativeByte()}}; break;
case 0x79: s = {"jns {0}", format{readRelativeByte()}}; break;
case 0x7a: s = {"jp {0}", format{readRelativeByte()}}; break;
case 0x7b: s = {"jnp {0}", format{readRelativeByte()}}; break;
case 0x7c: s = {"jl {0}", format{readRelativeByte()}}; break;
case 0x7d: s = {"jnl {0}", format{readRelativeByte()}}; break;
case 0x7e: s = {"jle {0}", format{readRelativeByte()}}; break;
case 0x7f: s = {"jnle {0}", format{readRelativeByte()}}; break;
case 0x80: s = {"{0} {1},{2}", format{readGroup(1), readMemByte(), readByte()}}; break;
case 0x81: s = {"{0} {1},{2}", format{readGroup(1), readMemWord(), readWord()}}; break;
case 0x82: s = {"{0} {1},{2}", format{readGroup(1), readMemByte(), readByteSigned()}}; break;
case 0x83: s = {"{0} {1},{2}", format{readGroup(1), readMemWord(), readByteSigned()}}; break;
case 0x84: s = {"test {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x85: s = {"test {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x86: s = {"xchg {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x87: s = {"xchg {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x88: s = {"mov {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x89: s = {"mov {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x8a: s = {"mov {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x8b: s = {"mov {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x8c: s = {"mov {0},{1}", format{readMemWord(0), readSeg()}}; break;
case 0x8d: s = {"lea {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x8e: s = {"mov {0},{1}", format{readSeg(0), readMemWord()}}; break;
case 0x8f: s = {"pop {0}", format{readMemWord()}}; break;
case 0x90: s = {"nop "}; break;
case 0x91: s = {"xchg ax,cx"}; break;
case 0x92: s = {"xchg ax,dx"}; break;
case 0x93: s = {"xchg ax,bx"}; break;
case 0x94: s = {"xchg ax,sp"}; break;
case 0x95: s = {"xchg ax,bp"}; break;
case 0x96: s = {"xchg ax,si"}; break;
case 0x97: s = {"xchg ax,di"}; break;
case 0x98: s = {"cbw "}; break;
case 0x99: s = {"cwd "}; break;
case 0x9a: s = {"call {1}:{0}", format{readWord(), readWord()}}; break;
case 0x9b: s = {"wait "}; break;
case 0x9c: s = {"pushf "}; break;
case 0x9d: s = {"popf "}; break;
case 0x9e: s = {"sahf "}; break;
case 0x9f: s = {"lahf "}; break;
case 0xa0: s = {"mov al,{0}", format{readIndirectByte()}}; break;
case 0xa1: s = {"mov ax,{0}", format{readIndirectWord()}}; break;
case 0xa2: s = {"mov {0},al", format{readIndirectByte()}}; break;
case 0xa3: s = {"mov {0},ax", format{readIndirectWord()}}; break;
case 0xa4: s = {"movsb "}; break;
case 0xa5: s = {"movsw "}; break;
case 0xa6: s = {"cmpsb "}; break;
case 0xa7: s = {"cmpsw "}; break;
case 0xa8: s = {"test al,{0}", format{readByte()}}; break;
case 0xa9: s = {"test ax,{0}", format{readWord()}}; break;
case 0xaa: s = {"stosb "}; break;
case 0xab: s = {"stosw "}; break;
case 0xac: s = {"lodsb "}; break;
case 0xad: s = {"lodsw "}; break;
case 0xae: s = {"scasb "}; break;
case 0xaf: s = {"scasw "}; break;
case 0xb0: s = {"mov al,{0}", format{readByte()}}; break;
case 0xb1: s = {"mov cl,{0}", format{readByte()}}; break;
case 0xb2: s = {"mov dl,{0}", format{readByte()}}; break;
case 0xb3: s = {"mov bl,{0}", format{readByte()}}; break;
case 0xb4: s = {"mov ah,{0}", format{readByte()}}; break;
case 0xb5: s = {"mov ch,{0}", format{readByte()}}; break;
case 0xb6: s = {"mov dh,{0}", format{readByte()}}; break;
case 0xb7: s = {"mov bh,{0}", format{readByte()}}; break;
case 0xb8: s = {"mov ax,{0}", format{readWord()}}; break;
case 0xb9: s = {"mov cx,{0}", format{readWord()}}; break;
case 0xba: s = {"mov dx,{0}", format{readWord()}}; break;
case 0xbb: s = {"mov bx,{0}", format{readWord()}}; break;
case 0xbc: s = {"mov sp,{0}", format{readWord()}}; break;
case 0xbd: s = {"mov bp,{0}", format{readWord()}}; break;
case 0xbe: s = {"mov si,{0}", format{readWord()}}; break;
case 0xbf: s = {"mov di,{0}", format{readWord()}}; break;
case 0xc0: s = {"{0} {1},{2}", format{readGroup(2), readMemByte(), readByte()}}; break;
case 0xc1: s = {"{0} {1},{2}", format{readGroup(2), readMemWord(), readByte()}}; break;
case 0xc2: s = {"ret {0}", format{readWord()}}; break;
case 0xc3: s = {"ret "}; break;
case 0xc4: s = {"les {0}", format{readMemWord()}}; break;
case 0xc5: s = {"lds {0}", format{readMemWord()}}; break;
case 0xc6: s = {"mov {0},{1}", format{readMemByte(), readByte()}}; break;
case 0xc7: s = {"mov {0},{1}", format{readMemWord(), readWord()}}; break;
case 0xc8: s = {"enter {0},{1}", format{readWord(), readByte()}}; break;
case 0xc9: s = {"leave "}; break;
case 0xca: s = {"retf {0}", format{readWord()}}; break;
case 0xcb: s = {"retf "}; break;
case 0xcc: s = {"int3 "}; break;
case 0xcd: s = {"int ", format{readByte()}}; break;
case 0xce: s = {"into "}; break;
case 0xcf: s = {"iret "}; break;
case 0xd0: s = {"{0} {1},1", format{readGroup(2), readMemByte()}}; break;
case 0xd1: s = {"{0} {1},1", format{readGroup(2), readMemWord()}}; break;
case 0xd2: s = {"{0} {1},cl", format{readGroup(2), readMemByte()}}; break;
case 0xd3: s = {"{0} {1},cl", format{readGroup(2), readMemWord()}}; break;
case 0xd4: s = {"aam {0}", format{readByte()}}; break;
case 0xd5: s = {"aad {0}", format{readByte()}}; break;
//case 0xd6:
case 0xd7: s = {"xlat "}; break;
//case 0xd8:
//case 0xd9:
//case 0xda:
//case 0xdb:
//case 0xdc:
//case 0xdd:
//case 0xde:
//case 0xdf:
case 0xe0: s = {"loopnz "}; break;
case 0xe1: s = {"loopz "}; break;
case 0xe2: s = {"loop "}; break;
case 0xe3: s = {"jcxz {0}", format{readRelativeByte()}}; break;
case 0xe4: s = {"in al,{0}", format{readByte()}}; break;
case 0xe5: s = {"in ax,{0}", format{readByte()}}; break;
case 0xe6: s = {"out {0},al", format{readByte()}}; break;
case 0xe7: s = {"out {0},ax", format{readByte()}}; break;
case 0xe8: s = {"call {0}", format{readRelativeWord()}}; break;
case 0xe9: s = {"jmp {0}", format{readRelativeWord()}}; break;
case 0xea: s = {"jmp {1}:{0}", format{readWord(), readWord()}}; break;
case 0xeb: s = {"jmp {0}", format{readRelativeByte()}}; break;
case 0xec: s = {"in al,dx"}; break;
case 0xed: s = {"in ax,dx"}; break;
case 0xee: s = {"out dx,al"}; break;
case 0xef: s = {"out dx,ax"}; break;
case 0xf0: s = {"lock: "}; break;
//case 0xf1:
case 0xf2: s = {"repnz: "}; break;
case 0xf3: s = {"repz: "}; break;
case 0xf4: s = {"hlt "}; break;
case 0xf5: s = {"cmc "}; break;
case 0xf6: s = {"{0} {1},{2}", format{readGroup(3), readMemByte(), readByte()}}; break;
case 0xf7: s = {"{0} {1},{2}", format{readGroup(3), readMemWord(), readWord()}}; break;
case 0xf8: s = {"clc "}; break;
case 0xf9: s = {"stc "}; break;
case 0xfa: s = {"cli "}; break;
case 0xfb: s = {"sti "}; break;
case 0xfc: s = {"cld "}; break;
case 0xfd: s = {"std "}; break;
case 0xfe: s = {"{0} {1},{2}", format{readGroup(4), readMemByte(), readByte()}}; break;
case 0xff: s = {"{0} {1},{2}", format{readGroup(4), readMemWord(), readWord()}}; break;
default: s = {"??? {0}", format{hex(opcode, 2L)}}; break;
}
while(s.size() < 24) s.append(" ");
string l;
if(registers) {
l = {
" ax:", hex(r.ax, 4L),
" bx:", hex(r.bx, 4L),
" cx:", hex(r.cx, 4L),
" dx:", hex(r.dx, 4L),
" si:", hex(r.si, 4L),
" di:", hex(r.di, 4L),
" bp:", hex(r.bp, 4L),
" sp:", hex(r.sp, 4L),
" ip:", hex(r.ip, 4L),
" cs:", hex(r.cs, 4L),
" ds:", hex(r.ds, 4L),
" es:", hex(r.es, 4L),
" ss:", hex(r.ss, 4L), " ",
r.f.m ? "M" : "m",
r.f.v ? "V" : "v",
r.f.d ? "D" : "d",
r.f.i ? "I" : "i",
r.f.b ? "B" : "b",
r.f.s ? "S" : "s",
r.f.z ? "Z" : "z",
r.f.h ? "H" : "h",
r.f.p ? "P" : "p",
r.f.c ? "C" : "c"
};
}
string b;
if(bytes) {
b = " ";
while(bytesRead) {
b.append(hex(bytesRead.takeLeft(), 2L), " ");
}
b.stripRight();
}
return {hex(ea, 5L), " ", s, l, b};
}

View File

@ -1,455 +0,0 @@
auto V30MZ::disassemble() -> string {
return disassemble(r.cs, r.ip);
}
auto V30MZ::disassemble(uint16 cs, uint16 ip) -> string {
//hack: prefixes execute as separate instructions; combine them instead
static uint32 suppress = 0xffffffff;
if((cs << 16 | ip) == suppress) return {};
string output, repeat, prefix;
output.append(hex(r.cs * 16 + r.ip, 5L), " ");
auto read = [&](uint offset) -> uint8 {
return V30MZ::read(Byte, cs, ip + offset);
};
auto modRM = [&](uint offset = 1) -> uint {
auto modRM = read(offset++);
if((modRM & 0xc0) == 0x40) offset += 1;
if((modRM & 0xc0) == 0x80) offset += 2;
return offset;
};
auto instruction = [&](string_view name) -> string {
if(name.size() >= 7) return name;
return pad(name, -7);
};
auto segment = [&](string_view name) -> string {
if(prefix) return {prefix, ":"};
return {name, ":"};
};
auto repeatable = [&](string_view opcode) -> string {
if(repeat) return {pad(string{repeat, ":"}, -7), opcode};
return {opcode};
};
auto segmentRegister = [&](uint offset = 1) -> string {
auto modRM = read(offset);
static const string seg[] = {"es", "cs", "ss", "ds"};
return {seg[modRM >> 3 & 2]};
};
auto readByte = [&](uint offset) -> string {
return hex(read(offset), 2L);
};
auto immediateByte = [&](uint offset = 1) -> string {
return {"0x", readByte(offset)};
};
auto immediateWord = [&](uint offset = 1) -> string {
return {"0x", readByte(offset + 1), readByte(offset + 0)};
};
auto immediateLong = [&](uint offset = 1) -> string {
return {"0x", readByte(offset + 3), readByte(offset + 2), ":",
"0x", readByte(offset + 1), readByte(offset + 0)};
};
auto indirectByte = [&](uint offset = 1) -> string {
return {"[", immediateByte(), "]"};
};
auto indirectWord = [&](uint offset = 1) -> string {
return {"[", immediateWord(), "]"};
};
auto relativeByte = [&](uint offset = 1) -> string {
int8 displacement = read(offset);
return {"cs:0x", hex(ip + offset + 1 + displacement, 4L)};
};
auto relativeWord = [&](uint offset = 1) -> string {
int16 displacement = read(offset + 1) << 8 | read(offset + 0) << 0;
return {"cs:0x", hex(ip + offset + 2 + displacement, 4L)};
};
auto adjustByte = [&](uint offset = 2) -> string {
int8 displacement = read(offset);
if(displacement >= 0) return {"+0x", hex(displacement, 2L)};
return {"-0x", hex(abs(displacement), 2L)};
};
auto adjustWord = [&](uint offset = 2) -> string {
int16 displacement = read(offset + 1) << 8 | read(offset + 0) << 0;
if(displacement >= 0) return {"+0x", hex(displacement, 4L)};
return {"-0x", hex(abs(displacement), 2L)};
};
auto registerByte = [&](uint offset = 1) -> string {
auto modRM = read(offset);
static const string reg[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};
return reg[modRM >> 3 & 7];
};
auto registerWord = [&](uint offset = 1) -> string {
auto modRM = read(offset);
static const string reg[] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
return reg[modRM >> 3 & 7];
};
auto memoryByte = [&](uint offset = 1) -> string {
auto modRM = read(offset);
if(modRM >= 0xc0) return registerByte(modRM & 7);
if((modRM & 0xc7) == 0x06) return {"byte[", segment("ds"), immediateByte(), "]"};
static const string seg[] = {"ds", "ds", "ss", "ss", "ds", "ds", "ss", "ds"};
static const string mem[] = {"bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx"};
if((modRM & 0xc0) == 0x40) return {"byte[", segment(seg[modRM & 7]), mem[modRM & 7], "+", adjustByte(), "]"};
if((modRM & 0xc0) == 0x80) return {"byte[", segment(seg[modRM & 7]), mem[modRM & 7], "+", adjustWord(), "]"};
return {"byte[", segment(seg[modRM & 7]), mem[modRM & 7], "]"};
};
auto memoryWord = [&](uint offset = 1) -> string {
auto modRM = read(offset);
if(modRM >= 0xc0) return registerWord(modRM & 7);
if((modRM & 0xc7) == 0x06) return {"word[", segment("ds"), immediateWord(), "]"};
static const string seg[] = {"ds", "ds", "ss", "ss", "ds", "ds", "ss", "ds"};
static const string mem[] = {"bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx"};
if((modRM & 0xc0) == 0x40) return {"word[", segment(seg[modRM & 7]), mem[modRM & 7], adjustByte(), "]"};
if((modRM & 0xc0) == 0x80) return {"word[", segment(seg[modRM & 7]), mem[modRM & 7], adjustWord(), "]"};
return {"word[", segment(seg[modRM & 7]), mem[modRM & 7], "]"};
};
auto group1 = [&](uint offset = 1) -> string {
auto modRM = read(offset);
static const string opcode[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"};
return opcode[modRM >> 3 & 7];
};
auto group2 = [&](uint offset = 1) -> string {
auto modRM = read(offset);
static const string opcode[] = {"rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar"};
return opcode[modRM >> 3 & 7];
};
auto group3 = [&](uint offset = 1) -> string {
auto modRM = read(offset);
static const string opcode[] = {"test", "test", "not", "neg", "mul", "imul", "div", "idiv"};
return opcode[modRM >> 3 & 7];
};
auto group4 = [&](uint offset = 1) -> string {
auto modRM = read(offset);
static const string opcode[] = {"inc", "dec", "call", "callf", "jmp", "jmpf", "push", "push"};
return opcode[modRM >> 3 & 7];
};
#define op(id, name, ...) case id: \
output.append(instruction(name), vector<string>{__VA_ARGS__}.merge(",")); \
break
auto opcode = read(0);
for(uint index : range(7)) {
if(opcode == 0x26) { prefix = "es"; ip++; opcode = read(0); suppress = cs << 16 | ip; continue; }
if(opcode == 0x2e) { prefix = "cs"; ip++; opcode = read(0); suppress = cs << 16 | ip; continue; }
if(opcode == 0x36) { prefix = "ss"; ip++; opcode = read(0); suppress = cs << 16 | ip; continue; }
if(opcode == 0x3e) { prefix = "ds"; ip++; opcode = read(0); suppress = cs << 16 | ip; continue; }
if(opcode == 0xf2) { repeat = "repnz"; ip++; opcode = read(0); suppress = cs << 16 | ip; continue; }
if(opcode == 0xf3) { repeat = "repz"; ip++; opcode = read(0); suppress = cs << 16 | ip; continue; }
break;
}
switch(opcode) {
op(0x00, "add", memoryByte(), registerByte());
op(0x01, "add", memoryWord(), registerWord());
op(0x02, "add", registerByte(), memoryByte());
op(0x03, "add", registerWord(), memoryWord());
op(0x04, "add", "al", immediateByte());
op(0x05, "add", "ax", immediateWord());
op(0x06, "push", "es");
op(0x07, "pop", "es");
op(0x08, "or", memoryByte(), registerByte());
op(0x09, "or", memoryWord(), registerWord());
op(0x0a, "or", registerByte(), memoryByte());
op(0x0b, "or", registerWord(), memoryWord());
op(0x0c, "or", "al", immediateByte());
op(0x0d, "or", "ax", immediateWord());
op(0x0e, "push", "cx");
op(0x0f, "pop", "cs");
op(0x10, "adc", memoryByte(), registerByte());
op(0x11, "adc", memoryWord(), registerWord());
op(0x12, "adc", registerByte(), memoryByte());
op(0x13, "adc", registerWord(), memoryWord());
op(0x14, "adc", "al", immediateByte());
op(0x15, "adc", "ax", immediateWord());
op(0x16, "push", "ss");
op(0x17, "pop", "ss");
op(0x18, "sbb", memoryByte(), registerByte());
op(0x19, "sbb", memoryWord(), registerWord());
op(0x1a, "sbb", registerByte(), memoryByte());
op(0x1b, "sbb", registerWord(), memoryWord());
op(0x1c, "sbb", "al", immediateByte());
op(0x1d, "sbb", "ax", immediateWord());
op(0x1e, "push", "ds");
op(0x1f, "pop", "ds");
op(0x20, "and", memoryByte(), registerByte());
op(0x21, "and", memoryWord(), registerWord());
op(0x22, "and", registerByte(), memoryByte());
op(0x23, "and", registerWord(), memoryWord());
op(0x24, "and", "al", immediateByte());
op(0x25, "and", "ax", immediateWord());
op(0x26, "es:");
op(0x27, "daa");
op(0x28, "sub", memoryByte(), registerByte());
op(0x29, "sub", memoryWord(), registerWord());
op(0x2a, "sub", registerByte(), memoryByte());
op(0x2b, "sub", registerWord(), memoryWord());
op(0x2c, "sub", "al", immediateByte());
op(0x2d, "sub", "ax", immediateWord());
op(0x2e, "cs:");
op(0x2f, "das");
op(0x30, "xor", memoryByte(), registerByte());
op(0x31, "xor", memoryWord(), registerWord());
op(0x32, "xor", registerByte(), memoryByte());
op(0x33, "xor", registerWord(), memoryWord());
op(0x34, "xor", "al", immediateByte());
op(0x35, "xor", "ax", immediateWord());
op(0x36, "ss:");
op(0x37, "aaa");
op(0x38, "cmp", memoryByte(), registerByte());
op(0x39, "cmp", memoryWord(), registerWord());
op(0x3a, "cmp", registerByte(), memoryByte());
op(0x3b, "cmp", registerWord(), memoryWord());
op(0x3c, "cmp", "al", immediateByte());
op(0x3d, "cmp", "ax", immediateWord());
op(0x3e, "ds:");
op(0x3f, "aas");
op(0x40, "inc", "ax");
op(0x41, "inc", "cx");
op(0x42, "inc", "dx");
op(0x43, "inc", "bx");
op(0x44, "inc", "sp");
op(0x45, "inc", "bp");
op(0x46, "inc", "si");
op(0x47, "inc", "di");
op(0x48, "dec", "ax");
op(0x49, "dec", "cx");
op(0x4a, "dec", "dx");
op(0x4b, "dec", "bx");
op(0x4c, "dec", "sp");
op(0x4d, "dec", "bp");
op(0x4e, "dec", "si");
op(0x4f, "dec", "di");
op(0x50, "push", "ax");
op(0x51, "push", "cx");
op(0x52, "push", "dx");
op(0x53, "push", "bx");
op(0x54, "push", "sp");
op(0x55, "push", "bp");
op(0x56, "push", "si");
op(0x57, "push", "di");
op(0x58, "pop", "ax");
op(0x59, "pop", "cx");
op(0x5a, "pop", "dx");
op(0x5b, "pop", "bx");
op(0x5c, "pop", "sp");
op(0x5d, "pop", "bp");
op(0x5e, "pop", "si");
op(0x5f, "pop", "di");
op(0x60, "pusha");
op(0x61, "popa");
op(0x62, "bound", registerWord(), memoryWord());
//op(0x63);
//op(0x64);
//op(0x65);
//op(0x66);
//op(0x67);
op(0x68, "push", immediateWord());
op(0x69, "imul", registerWord(), memoryWord(), immediateWord(modRM()));
op(0x6a, "push", adjustByte(1));
op(0x6b, "imul", registerWord(), memoryWord(), adjustByte(modRM()));
op(0x6c, repeatable("insb"));
op(0x6d, repeatable("insw"));
op(0x6e, repeatable("outsb"));
op(0x6f, repeatable("outsw"));
op(0x70, "jo", relativeByte());
op(0x71, "jno", relativeByte());
op(0x72, "jb", relativeByte());
op(0x73, "jnb", relativeByte());
op(0x74, "jz", relativeByte());
op(0x75, "jnz", relativeByte());
op(0x76, "jbe", relativeByte());
op(0x77, "ja", relativeByte());
op(0x78, "js", relativeByte());
op(0x79, "jns", relativeByte());
op(0x7a, "jpe", relativeByte());
op(0x7b, "jpo", relativeByte());
op(0x7c, "jl", relativeByte());
op(0x7d, "jge", relativeByte());
op(0x7e, "jle", relativeByte());
op(0x7f, "jg", relativeByte());
op(0x80, group1(), memoryByte(), immediateByte(modRM()));
op(0x81, group1(), memoryWord(), immediateWord(modRM()));
op(0x82, group1(), memoryByte(), adjustByte(modRM()));
op(0x83, group1(), memoryWord(), adjustByte(modRM()));
op(0x84, "test", memoryByte(), registerByte());
op(0x85, "test", memoryWord(), registerWord());
op(0x86, "xchg", memoryByte(), registerByte());
op(0x87, "xchg", memoryWord(), registerWord());
op(0x88, "mov", memoryByte(), registerByte());
op(0x89, "mov", memoryWord(), registerWord());
op(0x8a, "mov", registerByte(), memoryByte());
op(0x8b, "mov", registerWord(), memoryWord());
op(0x8c, "mov", memoryWord(), segmentRegister());
op(0x8d, "lea", registerWord(), memoryWord());
op(0x8e, "mov", segmentRegister(), memoryWord());
op(0x8f, "pop", memoryWord());
op(0x90, "nop");
op(0x91, "xchg", "ax", "cx");
op(0x92, "xchg", "ax", "dx");
op(0x93, "xchg", "ax", "bx");
op(0x94, "xchg", "ax", "sp");
op(0x95, "xchg", "ax", "bp");
op(0x96, "xchg", "ax", "si");
op(0x97, "xchg", "ax", "di");
op(0x98, "cbw");
op(0x99, "cwd");
op(0x9a, "call", immediateLong());
op(0x9b, "wait");
op(0x9c, "pushf");
op(0x9d, "popf");
op(0x9e, "sahf");
op(0x9f, "lahf");
op(0xa0, "mov", "al", indirectByte());
op(0xa1, "mov", "ax", indirectWord());
op(0xa2, "mov", indirectByte(), "al");
op(0xa3, "mov", indirectWord(), "ax");
op(0xa4, repeatable("movsb"));
op(0xa5, repeatable("movsw"));
op(0xa6, repeatable("cmpsb"));
op(0xa7, repeatable("cmpsw"));
op(0xa8, "test", immediateByte());
op(0xa9, "test", immediateWord());
op(0xaa, repeatable("stosb"));
op(0xab, repeatable("stosw"));
op(0xac, repeatable("lodsb"));
op(0xad, repeatable("lodsw"));
op(0xae, repeatable("scasb"));
op(0xaf, repeatable("scasw"));
op(0xb0, "mov", "al", immediateByte());
op(0xb1, "mov", "cl", immediateByte());
op(0xb2, "mov", "dl", immediateByte());
op(0xb3, "mov", "bl", immediateByte());
op(0xb4, "mov", "ah", immediateByte());
op(0xb5, "mov", "ch", immediateByte());
op(0xb6, "mov", "dh", immediateByte());
op(0xb7, "mov", "bh", immediateByte());
op(0xb8, "mov", "ax", immediateWord());
op(0xb9, "mov", "cx", immediateWord());
op(0xba, "mov", "dx", immediateWord());
op(0xbb, "mov", "bx", immediateWord());
op(0xbc, "mov", "sp", immediateWord());
op(0xbd, "mov", "bp", immediateWord());
op(0xbe, "mov", "si", immediateWord());
op(0xbf, "mov", "di", immediateWord());
op(0xc0, group2(), memoryByte(), immediateByte(modRM()));
op(0xc1, group2(), memoryWord(), immediateByte(modRM()));
op(0xc2, "ret", immediateWord());
op(0xc3, "ret");
op(0xc4, "les", memoryWord());
op(0xc5, "lds", memoryWord());
op(0xc6, "mov", memoryByte(), immediateByte(modRM()));
op(0xc7, "mov", memoryWord(), immediateWord(modRM()));
op(0xc8, "enter", immediateWord(), immediateByte(3));
op(0xc9, "leave");
op(0xca, "retf", immediateWord());
op(0xcb, "retf");
op(0xcc, "int", "0x3");
op(0xcd, "int", immediateByte());
op(0xce, "into");
op(0xcf, "iret");
op(0xd0, group2(), memoryByte(), "1");
op(0xd1, group2(), memoryWord(), "1");
op(0xd2, group2(), memoryByte(), "cl");
op(0xd3, group2(), memoryWord(), "cl");
op(0xd4, "aam", immediateByte());
op(0xd5, "aad", immediateByte());
op(0xd6, "xlat"); //undocumented mirror
op(0xd7, "xlat");
//op(0xd8);
//op(0xd9);
//op(0xda);
//op(0xdb);
//op(0xdc);
//op(0xdd);
//op(0xde);
//op(0xdf);
op(0xe0, "loopnz");
op(0xe1, "loopz");
op(0xe2, "loop");
op(0xe3, "jcxz", relativeByte());
op(0xe4, "in", "al", immediateByte());
op(0xe5, "in", "ax", immediateWord());
op(0xe6, "out", immediateByte(), "al");
op(0xe7, "out", immediateWord(), "ax");
op(0xe8, "call", relativeWord());
op(0xe9, "jmp", relativeWord());
op(0xea, "jmp", immediateLong());
op(0xeb, "jmp", relativeByte());
op(0xec, "in", "al", "dx");
op(0xed, "in", "ax", "dx");
op(0xee, "out", "dx", "al");
op(0xef, "out", "dx", "ax");
op(0xf0, "lock:");
//op(0xf1);
op(0xf2, "repnz:");
op(0xf3, "repz:");
op(0xf4, "hlt");
op(0xf5, "cmc");
op(0xf6, group3(), memoryByte(), immediateByte(modRM()));
op(0xf7, group3(), memoryWord(), immediateWord(modRM()));
op(0xf8, "clc");
op(0xf9, "stc");
op(0xfa, "cli");
op(0xfb, "sti");
op(0xfc, "cld");
op(0xfd, "std");
op(0xfe, group4(), memoryByte(), immediateByte(modRM()));
op(0xff, group4(), memoryWord(), immediateWord(modRM()));
default: output.append("??? ", hex(read(0), 2L)); break;
}
#undef op
output.size(-48); //todo: determine the minimum value that will never clip here
output.append(" ",
" ax:", hex(r.ax, 4L),
" bx:", hex(r.bx, 4L),
" cx:", hex(r.cx, 4L),
" dx:", hex(r.dx, 4L),
" si:", hex(r.si, 4L),
" di:", hex(r.di, 4L),
" bp:", hex(r.bp, 4L),
" sp:", hex(r.sp, 4L),
" ip:", hex(r.ip, 4L),
" cs:", hex(r.cs, 4L),
" ds:", hex(r.ds, 4L),
" es:", hex(r.es, 4L),
" ss:", hex(r.ss, 4L), " ",
r.f.m ? "M" : "m",
r.f.v ? "V" : "v",
r.f.d ? "D" : "d",
r.f.i ? "I" : "i",
r.f.b ? "B" : "b",
r.f.s ? "S" : "s",
r.f.z ? "Z" : "z",
r.f.h ? "H" : "h",
r.f.p ? "P" : "p",
r.f.c ? "C" : "c"
);
return output;
}

View File

@ -1,294 +0,0 @@
auto V30MZ::interrupt(uint8 vector) -> void {
wait(32);
state.halt = false;
state.poll = true;
state.prefix = false;
//if an IRQ fires during a rep string instruction;
//flush prefix queue and seek back to first prefix.
//this allows the transfer to resume after the IRQ.
if(prefixes) {
r.ip -= prefixes.size();
prefixes.reset();
}
auto ip = read(Word, 0x0000, vector * 4 + 0);
auto cs = read(Word, 0x0000, vector * 4 + 2);
push(r.f);
push(r.cs);
push(r.ip);
r.f.m = true;
r.f.i = false;
r.f.b = false;
r.ip = ip;
r.cs = cs;
}
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
auto V30MZ::instruction() -> void {
switch(opcode = fetch()) {
op(0x00, AddMemReg, Byte)
op(0x01, AddMemReg, Word)
op(0x02, AddRegMem, Byte)
op(0x03, AddRegMem, Word)
op(0x04, AddAccImm, Byte)
op(0x05, AddAccImm, Word)
op(0x06, PushReg, r.es)
op(0x07, PopReg, r.es)
op(0x08, OrMemReg, Byte)
op(0x09, OrMemReg, Word)
op(0x0a, OrRegMem, Byte)
op(0x0b, OrRegMem, Word)
op(0x0c, OrAccImm, Byte)
op(0x0d, OrAccImm, Word)
op(0x0e, PushReg, r.cs)
op(0x0f, PopReg, r.cs)
op(0x10, AdcMemReg, Byte)
op(0x11, AdcMemReg, Word)
op(0x12, AdcRegMem, Byte)
op(0x13, AdcRegMem, Word)
op(0x14, AdcAccImm, Byte)
op(0x15, AdcAccImm, Word)
op(0x16, PushReg, r.ss)
op(0x17, PopReg, r.ss)
op(0x18, SbbMemReg, Byte)
op(0x19, SbbMemReg, Word)
op(0x1a, SbbRegMem, Byte)
op(0x1b, SbbRegMem, Word)
op(0x1c, SbbAccImm, Byte)
op(0x1d, SbbAccImm, Word)
op(0x1e, PushReg, r.ds)
op(0x1f, PopReg, r.ds)
op(0x20, AndMemReg, Byte)
op(0x21, AndMemReg, Word)
op(0x22, AndRegMem, Byte)
op(0x23, AndRegMem, Word)
op(0x24, AndAccImm, Byte)
op(0x25, AndAccImm, Word)
op(0x26, Segment, r.es)
op(0x27, DecimalAdjust, 0) //daa
op(0x28, SubMemReg, Byte)
op(0x29, SubMemReg, Word)
op(0x2a, SubRegMem, Byte)
op(0x2b, SubRegMem, Word)
op(0x2c, SubAccImm, Byte)
op(0x2d, SubAccImm, Word)
op(0x2e, Segment, r.cs)
op(0x2f, DecimalAdjust, 1) //das
op(0x30, XorMemReg, Byte)
op(0x31, XorMemReg, Word)
op(0x32, XorRegMem, Byte)
op(0x33, XorRegMem, Word)
op(0x34, XorAccImm, Byte)
op(0x35, XorAccImm, Word)
op(0x36, Segment, r.ss)
op(0x37, AsciiAdjust, 0) //aaa
op(0x38, CmpMemReg, Byte)
op(0x39, CmpMemReg, Word)
op(0x3a, CmpRegMem, Byte)
op(0x3b, CmpRegMem, Word)
op(0x3c, CmpAccImm, Byte)
op(0x3d, CmpAccImm, Word)
op(0x3e, Segment, r.ds)
op(0x3f, AsciiAdjust, 1) //aas
op(0x40, IncReg, r.ax)
op(0x41, IncReg, r.cx)
op(0x42, IncReg, r.dx)
op(0x43, IncReg, r.bx)
op(0x44, IncReg, r.sp)
op(0x45, IncReg, r.bp)
op(0x46, IncReg, r.si)
op(0x47, IncReg, r.di)
op(0x48, DecReg, r.ax)
op(0x49, DecReg, r.cx)
op(0x4a, DecReg, r.dx)
op(0x4b, DecReg, r.bx)
op(0x4c, DecReg, r.sp)
op(0x4d, DecReg, r.bp)
op(0x4e, DecReg, r.si)
op(0x4f, DecReg, r.di)
op(0x50, PushReg, r.ax)
op(0x51, PushReg, r.cx)
op(0x52, PushReg, r.dx)
op(0x53, PushReg, r.bx)
op(0x54, PushReg, r.sp)
op(0x55, PushReg, r.bp)
op(0x56, PushReg, r.si)
op(0x57, PushReg, r.di)
op(0x58, PopReg, r.ax)
op(0x59, PopReg, r.cx)
op(0x5a, PopReg, r.dx)
op(0x5b, PopReg, r.bx)
op(0x5c, PopReg, r.sp)
op(0x5d, PopReg, r.bp)
op(0x5e, PopReg, r.si)
op(0x5f, PopReg, r.di)
op(0x60, PushAll)
op(0x61, PopAll)
op(0x62, Bound)
//op(0x63, ...)
//op(0x64, ...) repnc
//op(0x65, ...) repc
//op(0x66, ...) fpo2
//op(0x67, ...) fpo2
op(0x68, PushImm, Word)
op(0x69, MultiplySignedRegMemImm, Word)
op(0x6a, PushImm, Byte)
op(0x6b, MultiplySignedRegMemImm, Byte)
op(0x6c, InString, Byte)
op(0x6d, InString, Word)
op(0x6e, OutString, Byte)
op(0x6f, OutString, Word)
op(0x70, JumpIf, r.f.v == 1)
op(0x71, JumpIf, r.f.v == 0)
op(0x72, JumpIf, r.f.c == 1)
op(0x73, JumpIf, r.f.c == 0)
op(0x74, JumpIf, r.f.z == 1)
op(0x75, JumpIf, r.f.z == 0)
op(0x76, JumpIf, r.f.z == 1 || r.f.c == 1)
op(0x77, JumpIf, r.f.z != 1 && r.f.c != 1)
op(0x78, JumpIf, r.f.s == 1)
op(0x79, JumpIf, r.f.s == 0)
op(0x7a, JumpIf, r.f.p == 1)
op(0x7b, JumpIf, r.f.p == 0)
op(0x7c, JumpIf, r.f.s != r.f.v && r.f.z == 0)
op(0x7d, JumpIf, r.f.s == r.f.v || r.f.z == 1)
op(0x7e, JumpIf, r.f.s != r.f.v || r.f.z == 1)
op(0x7f, JumpIf, r.f.s == r.f.v && r.f.z == 0)
op(0x80, Group1MemImm, Byte, 0)
op(0x81, Group1MemImm, Word, 0)
op(0x82, Group1MemImm, Byte, 1)
op(0x83, Group1MemImm, Word, 1)
op(0x84, TestMemReg, Byte)
op(0x85, TestMemReg, Word)
op(0x86, ExchangeMemReg, Byte)
op(0x87, ExchangeMemReg, Word)
op(0x88, MoveMemReg, Byte)
op(0x89, MoveMemReg, Word)
op(0x8a, MoveRegMem, Byte)
op(0x8b, MoveRegMem, Word)
op(0x8c, MoveMemSeg)
op(0x8d, LoadEffectiveAddressRegMem)
op(0x8e, MoveSegMem)
op(0x8f, PopMem)
op(0x90, Nop)
op(0x91, Exchange, r.ax, r.cx)
op(0x92, Exchange, r.ax, r.dx)
op(0x93, Exchange, r.ax, r.bx)
op(0x94, Exchange, r.ax, r.sp)
op(0x95, Exchange, r.ax, r.bp)
op(0x96, Exchange, r.ax, r.si)
op(0x97, Exchange, r.ax, r.di)
op(0x98, SignExtendByte)
op(0x99, SignExtendWord)
op(0x9a, CallFar)
op(0x9b, Wait)
op(0x9c, PushFlags)
op(0x9d, PopFlags)
op(0x9e, StoreFlagsAcc)
op(0x9f, LoadAccFlags)
op(0xa0, MoveAccMem, Byte)
op(0xa1, MoveAccMem, Word)
op(0xa2, MoveMemAcc, Byte)
op(0xa3, MoveMemAcc, Word)
op(0xa4, MoveString, Byte)
op(0xa5, MoveString, Word)
op(0xa6, CompareString, Byte)
op(0xa7, CompareString, Word)
op(0xa8, TestAcc, Byte)
op(0xa9, TestAcc, Word)
op(0xaa, StoreString, Byte)
op(0xab, StoreString, Word)
op(0xac, LoadString, Byte)
op(0xad, LoadString, Word)
op(0xae, ScanString, Byte)
op(0xaf, ScanString, Word)
op(0xb0, MoveRegImm, r.al)
op(0xb1, MoveRegImm, r.cl)
op(0xb2, MoveRegImm, r.dl)
op(0xb3, MoveRegImm, r.bl)
op(0xb4, MoveRegImm, r.ah)
op(0xb5, MoveRegImm, r.ch)
op(0xb6, MoveRegImm, r.dh)
op(0xb7, MoveRegImm, r.bh)
op(0xb8, MoveRegImm, r.ax)
op(0xb9, MoveRegImm, r.cx)
op(0xba, MoveRegImm, r.dx)
op(0xbb, MoveRegImm, r.bx)
op(0xbc, MoveRegImm, r.sp)
op(0xbd, MoveRegImm, r.bp)
op(0xbe, MoveRegImm, r.si)
op(0xbf, MoveRegImm, r.di)
op(0xc0, Group2MemImm, Byte)
op(0xc1, Group2MemImm, Word)
op(0xc2, ReturnImm)
op(0xc3, Return)
op(0xc4, LoadSegmentMem, r.es)
op(0xc5, LoadSegmentMem, r.ds)
op(0xc6, MoveMemImm, Byte)
op(0xc7, MoveMemImm, Word)
op(0xc8, Enter)
op(0xc9, Leave)
op(0xca, ReturnFarImm)
op(0xcb, ReturnFar)
op(0xcc, Int3)
op(0xcd, IntImm)
op(0xce, Into)
op(0xcf, ReturnInt)
op(0xd0, Group2MemImm, Byte, (uint8)1)
op(0xd1, Group2MemImm, Word, (uint8)1)
op(0xd2, Group2MemImm, Byte, (uint8)r.cl)
op(0xd3, Group2MemImm, Word, (uint8)r.cl)
op(0xd4, AdjustAfterMultiply)
op(0xd5, AdjustAfterDivide)
op(0xd6, Translate) //xlat (undocumented mirror)
op(0xd7, Translate) //xlat
//op(0xd8, ...) //fpo1
//op(0xd9, ...) //fpo1
//op(0xda, ...) //fpo1
//op(0xdb, ...) //fpo1
//op(0xdc, ...) //fpo1
//op(0xdd, ...) //fpo1
//op(0xde, ...) //fpo1
//op(0xdf, ...) //fpo1
op(0xe0, LoopWhile, 0) //loopnz
op(0xe1, LoopWhile, 1) //loopz
op(0xe2, Loop)
op(0xe3, JumpIf, r.cx == 0)
op(0xe4, In, Byte)
op(0xe5, In, Word)
op(0xe6, Out, Byte)
op(0xe7, Out, Word)
op(0xe8, CallNear)
op(0xe9, JumpNear)
op(0xea, JumpFar)
op(0xeb, JumpShort)
op(0xec, InDX, Byte)
op(0xed, InDX, Word)
op(0xee, OutDX, Byte)
op(0xef, OutDX, Word)
op(0xf0, Lock)
//op(0xf1, ...)
op(0xf2, Repeat) //repnz
op(0xf3, Repeat) //repz
op(0xf4, Halt)
op(0xf5, ComplementCarry)
op(0xf6, Group3MemImm, Byte)
op(0xf7, Group3MemImm, Word)
op(0xf8, ClearFlag, r.f.c.bit)
op(0xf9, SetFlag, r.f.c.bit)
op(0xfa, ClearFlag, r.f.i.bit)
op(0xfb, SetFlag, r.f.i.bit)
op(0xfc, ClearFlag, r.f.d.bit)
op(0xfd, SetFlag, r.f.d.bit)
op(0xfe, Group4MemImm, Byte)
op(0xff, Group4MemImm, Word)
}
}
#undef op

View File

@ -1,52 +0,0 @@
auto V30MZ::instructionDecimalAdjust(bool negate) -> void {
wait(9);
uint8 al = r.al;
if(r.f.h || ((al & 0x0f) > 0x09)) {
r.al += negate ? -0x06 : 0x06;
r.f.h = 1;
}
if(r.f.c || (al > 0x99)) {
r.al += negate ? -0x60 : 0x60;
r.f.c = 1;
}
r.f.s = r.al & 0x80;
r.f.z = r.al == 0;
r.f.p = parity(r.al);
}
auto V30MZ::instructionAsciiAdjust(bool negate) -> void {
wait(8);
if(r.f.h || ((r.al & 0x0f) > 0x09)) {
r.al += negate ? -0x06 : 0x06;
r.ah += negate ? -0x01 : 0x01;
r.f.h = 1;
r.f.c = 1;
} else {
r.f.h = 0;
r.f.c = 0;
}
r.al &= 0x0f;
}
auto V30MZ::instructionAdjustAfterMultiply() -> void {
wait(16);
auto imm = fetch();
if(imm == 0) return interrupt(0);
//NEC CPUs do not honor the immediate and always use (base) 10
r.ah = r.al / 10;
r.al %= imm;
r.f.p = parity(r.al);
r.f.s = r.ax & 0x8000;
r.f.z = r.ax == 0;
}
auto V30MZ::instructionAdjustAfterDivide() -> void {
wait(5);
auto imm = fetch();
//NEC CPUs do not honor the immediate and always use (base) 10
r.al += r.ah * 10;
r.ah = 0;
r.f.p = parity(r.al);
r.f.s = r.ax & 0x8000;
r.f.z = r.ax == 0;
}

View File

@ -1,142 +0,0 @@
auto V30MZ::instructionAddMemReg(Size size) -> void {
modRM();
setMem(size, ADD(size, getMem(size), getReg(size)));
}
auto V30MZ::instructionAddRegMem(Size size) -> void {
modRM();
setReg(size, ADD(size, getReg(size), getMem(size)));
}
auto V30MZ::instructionAddAccImm(Size size) -> void {
setAcc(size, ADD(size, getAcc(size), fetch(size)));
}
auto V30MZ::instructionOrMemReg(Size size) -> void {
modRM();
setMem(size, OR(size, getMem(size), getReg(size)));
}
auto V30MZ::instructionOrRegMem(Size size) -> void {
modRM();
setReg(size, OR(size, getReg(size), getMem(size)));
}
auto V30MZ::instructionOrAccImm(Size size) -> void {
setAcc(size, OR(size, getAcc(size), fetch(size)));
}
auto V30MZ::instructionAdcMemReg(Size size) -> void {
modRM();
setMem(size, ADC(size, getMem(size), getReg(size)));
}
auto V30MZ::instructionAdcRegMem(Size size) -> void {
modRM();
setReg(size, ADC(size, getReg(size), getMem(size)));
}
auto V30MZ::instructionAdcAccImm(Size size) -> void {
setAcc(size, ADC(size, getAcc(size), fetch(size)));
}
auto V30MZ::instructionSbbMemReg(Size size) -> void {
modRM();
setMem(size, SBB(size, getMem(size), getReg(size)));
}
auto V30MZ::instructionSbbRegMem(Size size) -> void {
modRM();
setReg(size, SBB(size, getReg(size), getMem(size)));
}
auto V30MZ::instructionSbbAccImm(Size size) -> void {
setAcc(size, SBB(size, getAcc(size), fetch(size)));
}
auto V30MZ::instructionAndMemReg(Size size) -> void {
modRM();
setMem(size, AND(size, getMem(size), getReg(size)));
}
auto V30MZ::instructionAndRegMem(Size size) -> void {
modRM();
setReg(size, AND(size, getReg(size), getMem(size)));
}
auto V30MZ::instructionAndAccImm(Size size) -> void {
setAcc(size, AND(size, getAcc(size), fetch(size)));
}
auto V30MZ::instructionSubMemReg(Size size) -> void {
modRM();
setMem(size, SUB(size, getMem(size), getReg(size)));
}
auto V30MZ::instructionSubRegMem(Size size) -> void {
modRM();
setReg(size, SUB(size, getReg(size), getMem(size)));
}
auto V30MZ::instructionSubAccImm(Size size) -> void {
setAcc(size, SUB(size, getAcc(size), fetch(size)));
}
auto V30MZ::instructionXorMemReg(Size size) -> void {
modRM();
setMem(size, XOR(size, getMem(size), getReg(size)));
}
auto V30MZ::instructionXorRegMem(Size size) -> void {
modRM();
setReg(size, XOR(size, getReg(size), getMem(size)));
}
auto V30MZ::instructionXorAccImm(Size size) -> void {
setAcc(size, XOR(size, getAcc(size), fetch(size)));
}
auto V30MZ::instructionCmpMemReg(Size size) -> void {
modRM();
SUB(size, getMem(size), getReg(size));
}
auto V30MZ::instructionCmpRegMem(Size size) -> void {
modRM();
SUB(size, getReg(size), getMem(size));
}
auto V30MZ::instructionCmpAccImm(Size size) -> void {
SUB(size, getAcc(size), fetch(size));
}
auto V30MZ::instructionTestAcc(Size size) -> void {
AND(size, getAcc(size), fetch(size));
}
auto V30MZ::instructionTestMemReg(Size size) -> void {
modRM();
AND(size, getMem(size), getReg(size));
}
auto V30MZ::instructionMultiplySignedRegMemImm(Size size) -> void {
wait(2);
modRM();
setReg(Word, MULI(Word, getMem(Word), size == Word ? (int16_t)fetch(Word) : (int8_t)fetch(Byte)));
}
auto V30MZ::instructionIncReg(uint16_t& reg) -> void {
reg = INC(Word, reg);
}
auto V30MZ::instructionDecReg(uint16_t& reg) -> void {
reg = DEC(Word, reg);
}
auto V30MZ::instructionSignExtendByte() -> void {
setAcc(Word, (int8)getAcc(Byte));
}
auto V30MZ::instructionSignExtendWord() -> void {
setAcc(Long, (int16)getAcc(Word));
}

View File

@ -1,192 +0,0 @@
auto V30MZ::instructionLoop() -> void {
wait(1);
auto offset = (int8)fetch();
if(--r.cx) {
wait(3);
r.ip += offset;
}
}
auto V30MZ::instructionLoopWhile(bool value) -> void {
wait(2);
auto offset = (int8)fetch();
if(--r.cx && r.f.z == value) {
wait(3);
r.ip += offset;
}
}
auto V30MZ::instructionJumpShort() -> void {
wait(3);
auto offset = (int8)fetch();
r.ip += offset;
}
auto V30MZ::instructionJumpIf(bool condition) -> void {
auto offset = (int8)fetch();
if(condition) r.ip += offset;
}
auto V30MZ::instructionJumpNear() -> void {
wait(3);
r.ip += (int16)fetch(Word);
}
auto V30MZ::instructionJumpFar() -> void {
wait(6);
auto ip = fetch(Word);
auto cs = fetch(Word);
r.cs = cs;
r.ip = ip;
}
auto V30MZ::instructionCallNear() -> void {
wait(4);
auto offset = (int16)fetch(Word);
push(r.ip);
r.ip += offset;
}
auto V30MZ::instructionCallFar() -> void {
wait(9);
auto ip = fetch(Word);
auto cs = fetch(Word);
push(r.cs);
push(r.ip);
r.cs = cs;
r.ip = ip;
}
auto V30MZ::instructionReturn() -> void {
wait(5);
r.ip = pop();
}
auto V30MZ::instructionReturnImm() -> void {
wait(5);
auto offset = fetch(Word);
r.ip = pop();
r.sp += offset;
}
auto V30MZ::instructionReturnFar() -> void {
wait(7);
r.ip = pop();
r.cs = pop();
}
auto V30MZ::instructionReturnFarImm() -> void {
wait(8);
auto offset = fetch(Word);
r.ip = pop();
r.cs = pop();
r.sp += offset;
}
auto V30MZ::instructionReturnInt() -> void {
wait(9);
r.ip = pop();
r.cs = pop();
r.f = pop();
state.poll = false;
}
auto V30MZ::instructionInt3() -> void {
wait(8);
interrupt(3);
}
auto V30MZ::instructionIntImm() -> void {
wait(9);
interrupt(fetch());
}
auto V30MZ::instructionInto() -> void {
wait(5);
interrupt(4);
}
auto V30MZ::instructionEnter() -> void {
wait(7);
auto offset = fetch(Word);
auto length = fetch(Byte) & 0x1f;
push(r.bp);
r.bp = r.sp;
r.sp -= offset;
if(length) {
wait(length > 1 ? 7 : 6);
for(uint n = 1; n < length; n++) {
wait(4);
auto data = read(Word, segment(r.ss), r.bp - n * 2);
push(data);
}
push(r.bp);
}
}
auto V30MZ::instructionLeave() -> void {
wait(1);
r.sp = r.bp;
r.bp = pop();
}
auto V30MZ::instructionPushReg(uint16_t& reg) -> void {
push(reg);
}
auto V30MZ::instructionPopReg(uint16_t& reg) -> void {
reg = pop();
if(&reg == &r.ss) state.poll = false;
}
auto V30MZ::instructionPushFlags() -> void {
wait(1);
push(r.f);
}
auto V30MZ::instructionPopFlags() -> void {
wait(2);
r.f = pop();
state.poll = false;
}
auto V30MZ::instructionPushAll() -> void {
wait(8);
auto sp = r.sp;
push(r.ax);
push(r.cx);
push(r.dx);
push(r.bx);
push(sp);
push(r.bp);
push(r.si);
push(r.di);
}
auto V30MZ::instructionPopAll() -> void {
wait(7);
r.di = pop();
r.si = pop();
r.bp = pop();
auto sp = pop();
r.bx = pop();
r.dx = pop();
r.cx = pop();
r.ax = pop();
//r.sp is not restored
}
auto V30MZ::instructionPushImm(Size size) -> void {
if(size == Byte) push((int8)fetch(Byte));
if(size == Word) push(fetch(Word));
}
auto V30MZ::instructionPopMem() -> void {
modRM();
auto data = pop();
//NEC bug: pop into a register will adjust the stack, but fail to set the register properly
//in practice, this isn't an issue as assemblers will favor one-byte pop instructions,
//but this difference can be used to distinguish Intel x86 chips from NEC V20/V30 chips.
if(modrm.mod != 3) setMem(Word, data);
}

View File

@ -1,25 +0,0 @@
auto V30MZ::instructionStoreFlagsAcc() -> void {
wait(3);
r.f = (r.f & 0xff00) | r.ah;
}
auto V30MZ::instructionLoadAccFlags() -> void {
wait(1);
r.ah = (r.f & 0x00ff);
}
auto V30MZ::instructionComplementCarry() -> void {
wait(3);
r.f.c = !r.f.c;
}
auto V30MZ::instructionClearFlag(uint bit) -> void {
wait(3);
r.f &= ~(1 << bit);
}
auto V30MZ::instructionSetFlag(uint bit) -> void {
wait(3);
r.f |= 1 << bit;
if(bit == r.f.i.bit) state.poll = false;
}

View File

@ -1,95 +0,0 @@
auto V30MZ::instructionGroup1MemImm(Size size, bool sign) -> void {
modRM();
auto mem = getMem(size);
uint16 imm = 0;
if(sign) imm = (int8)fetch();
else if(size == Byte) imm = fetch();
else imm = fetch(Word);
switch(modrm.reg) {
case 0: setMem(size, ADD(size, mem, imm)); break;
case 1: setMem(size, OR (size, mem, imm)); break;
case 2: setMem(size, ADC(size, mem, imm)); break;
case 3: setMem(size, SBB(size, mem, imm)); break;
case 4: setMem(size, AND(size, mem, imm)); break;
case 5: setMem(size, SUB(size, mem, imm)); break;
case 6: setMem(size, XOR(size, mem, imm)); break;
case 7: SUB(size, mem, imm); break;
}
}
auto V30MZ::instructionGroup2MemImm(Size size, maybe<uint8> imm) -> void {
modRM();
auto mem = getMem(size);
if(!imm) {
wait(2);
imm = fetch();
}
switch(modrm.reg) {
case 0: setMem(size, ROL(size, mem, *imm)); break;
case 1: setMem(size, ROR(size, mem, *imm)); break;
case 2: setMem(size, RCL(size, mem, *imm)); break;
case 3: setMem(size, RCR(size, mem, *imm)); break;
case 4: setMem(size, SHL(size, mem, *imm)); break;
case 5: setMem(size, SHR(size, mem, *imm)); break;
case 6: setMem(size, SAL(size, mem, *imm)); break;
case 7: setMem(size, SAR(size, mem, *imm)); break;
}
}
auto V30MZ::instructionGroup3MemImm(Size size) -> void {
modRM();
auto mem = getMem(size);
switch(modrm.reg) {
case 0: AND(size, mem, fetch(size)); break; //test
case 1: AND(size, mem, fetch(size)); break; //test (undocumented mirror)
case 2: wait(2); setMem(size, NOT(size, mem)); break;
case 3: wait(2); setMem(size, NEG(size, mem)); break;
case 4: wait(2); setAcc(size * 2, MUL(size, getAcc(size), mem)); break;
case 5: wait(2); setAcc(size * 2, MULI(size, getAcc(size), mem)); break; break;
case 6: wait(size == Byte ? 15 : 23); setAcc(size * 2, DIV(size, getAcc(size * 2), mem)); break;
case 7: wait(size == Byte ? 17 : 24); setAcc(size * 2, DIVI(size, getAcc(size * 2), mem)); break;
}
}
auto V30MZ::instructionGroup4MemImm(Size size) -> void {
modRM();
switch(modrm.reg) {
case 0: //inc
wait(2);
setMem(size, INC(size, getMem(size)));
break;
case 1: //dec
wait(2);
setMem(size, DEC(size, getMem(size)));
break;
case 2: //call
wait(5);
push(r.ip);
r.ip = getMem(Word);
break;
case 3: //callf
wait(11);
push(r.cs);
push(r.ip);
r.ip = getMem(Word, 0);
r.cs = getMem(Word, 2);
break;
case 4: //jmp
wait(4);
r.ip = getMem(Word);
break;
case 5: //jmpf
wait(9);
r.ip = getMem(Word, 0);
r.cs = getMem(Word, 2);
break;
case 6: //push
wait(1);
push(getMem(Word));
break;
case 7: //push (undocumented mirror)
wait(1);
push(getMem(Word));
break;
}
}

View File

@ -1,66 +0,0 @@
auto V30MZ::instructionSegment(uint16 segment) -> void {
if(prefixes.size() >= 7) prefixes.removeRight();
prefixes.prepend(opcode);
state.prefix = true;
state.poll = false;
}
auto V30MZ::instructionRepeat() -> void {
if(prefixes.size() >= 7) prefixes.removeRight();
prefixes.prepend(opcode);
wait(4);
state.prefix = true;
state.poll = false;
}
auto V30MZ::instructionLock() -> void {
if(prefixes.size() >= 7) prefixes.removeRight();
prefixes.prepend(opcode);
state.prefix = true;
state.poll = false;
}
auto V30MZ::instructionWait() -> void {
}
auto V30MZ::instructionHalt() -> void {
wait(8);
state.halt = true;
}
auto V30MZ::instructionNop() -> void {
}
auto V30MZ::instructionIn(Size size) -> void {
wait(5);
setAcc(size, in(size, fetch()));
}
auto V30MZ::instructionOut(Size size) -> void {
wait(5);
out(size, fetch(), getAcc(size));
}
auto V30MZ::instructionInDX(Size size) -> void {
wait(5);
setAcc(size, in(size, r.dx));
}
auto V30MZ::instructionOutDX(Size size) -> void {
wait(5);
out(size, r.dx, getAcc(size));
}
auto V30MZ::instructionTranslate() -> void {
wait(4);
r.al = read(Byte, segment(r.ds), r.bx + r.al);
}
auto V30MZ::instructionBound() -> void {
wait(12);
modRM();
auto lo = getMem(Word, 0);
auto hi = getMem(Word, 2);
auto reg = getReg(Word);
if(reg < lo || reg > hi) interrupt(5);
}

View File

@ -1,71 +0,0 @@
auto V30MZ::instructionMoveMemReg(Size size) -> void {
modRM();
setMem(size, getReg(size));
}
auto V30MZ::instructionMoveRegMem(Size size) -> void {
modRM();
setReg(size, getMem(size));
}
auto V30MZ::instructionMoveMemSeg() -> void {
modRM();
setMem(Word, getSeg());
state.poll = false;
}
auto V30MZ::instructionMoveSegMem() -> void {
wait(1);
modRM();
setSeg(getMem(Word));
if((modrm.reg & 3) == 3) state.poll = false;
}
auto V30MZ::instructionMoveAccMem(Size size) -> void {
setAcc(size, read(size, segment(r.ds), fetch(Word)));
}
auto V30MZ::instructionMoveMemAcc(Size size) -> void {
write(size, segment(r.ds), fetch(Word), getAcc(size));
}
auto V30MZ::instructionMoveRegImm(uint8_t& reg) -> void {
reg = fetch(Byte);
}
auto V30MZ::instructionMoveRegImm(uint16_t& reg) -> void {
reg = fetch(Word);
}
auto V30MZ::instructionMoveMemImm(Size size) -> void {
modRM();
setMem(size, fetch(size));
}
auto V30MZ::instructionExchange(uint16_t& x, uint16_t& y) -> void {
wait(2);
uint16 z = x;
x = y;
y = z;
}
auto V30MZ::instructionExchangeMemReg(Size size) -> void {
wait(2);
modRM();
auto mem = getMem(size);
auto reg = getReg(size);
setMem(size, reg);
setReg(size, mem);
}
auto V30MZ::instructionLoadEffectiveAddressRegMem() -> void {
modRM();
setReg(Word, modrm.address);
}
auto V30MZ::instructionLoadSegmentMem(uint16_t& segment) -> void {
wait(5);
modRM();
setReg(Word, getMem(Word));
segment = getMem(Word, 2);
}

View File

@ -1,103 +0,0 @@
auto V30MZ::instructionInString(Size size) -> void {
wait(5);
if(!repeat() || r.cx) {
auto data = in(size, r.dx);
write(size, r.es, r.di, data);
r.di += r.f.d ? -size : size;
if(!repeat() || !--r.cx) return;
state.prefix = true;
r.ip--;
}
}
auto V30MZ::instructionOutString(Size size) -> void {
wait(6);
if(!repeat() || r.cx) {
auto data = read(size, segment(r.ds), r.si);
out(size, r.dx, data);
r.si += r.f.d ? -size : size;
if(!repeat() || !--r.cx) return;
state.prefix = true;
r.ip--;
}
}
auto V30MZ::instructionMoveString(Size size) -> void {
wait(4);
if(!repeat() || r.cx) {
auto data = read(size, segment(r.ds), r.si);
write(size, r.es, r.di, data);
r.si += r.f.d ? -size : size;
r.di += r.f.d ? -size : size;
if(!repeat() || !--r.cx) return;
state.prefix = true;
r.ip--;
}
}
auto V30MZ::instructionCompareString(Size size) -> void {
wait(5);
if(!repeat() || r.cx) {
auto x = read(size, segment(r.ds), r.si);
auto y = read(size, r.es, r.di);
r.si += r.f.d ? -size : size;
r.di += r.f.d ? -size : size;
SUB(size, x, y);
if(!repeat() || !--r.cx) return;
if(repeat() == RepeatWhileZeroLo && r.f.z == 1) return;
if(repeat() == RepeatWhileZeroHi && r.f.z == 0) return;
state.prefix = true;
r.ip--;
}
}
auto V30MZ::instructionStoreString(Size size) -> void {
wait(2);
if(!repeat() || r.cx) {
write(size, r.es, r.di, getAcc(size));
r.di += r.f.d ? -size : size;
if(!repeat() || !--r.cx) return;
state.prefix = true;
r.ip--;
}
}
auto V30MZ::instructionLoadString(Size size) -> void {
wait(2);
if(!repeat() || r.cx) {
setAcc(size, read(size, segment(r.ds), r.si));
r.si += r.f.d ? -size : size;
if(!repeat() || !--r.cx) return;
state.prefix = true;
r.ip--;
}
}
auto V30MZ::instructionScanString(Size size) -> void {
wait(3);
if(!repeat() || r.cx) {
auto x = getAcc(size);
auto y = read(size, r.es, r.di);
r.di += r.f.d ? -size : size;
SUB(size, x, y);
if(!repeat() || !--r.cx) return;
if(repeat() == RepeatWhileZeroLo && r.f.z == 1) return;
if(repeat() == RepeatWhileZeroHi && r.f.z == 0) return;
state.prefix = true;
r.ip--;
}
}

View File

@ -1,47 +0,0 @@
auto V30MZ::read(Size size, uint16 segment, uint16 address) -> uint32 {
uint32 data;
if(size >= Byte) data.byte(0) = read(segment * 16 + address++);
if(size >= Word) data.byte(1) = read(segment * 16 + address++);
if(size >= Long) data.byte(2) = read(segment * 16 + address++);
if(size >= Long) data.byte(3) = read(segment * 16 + address++);
return data;
}
auto V30MZ::write(Size size, uint16 segment, uint16 address, uint16 data) -> void {
if(size >= Byte) write(segment * 16 + address++, data.byte(0));
if(size >= Word) write(segment * 16 + address++, data.byte(1));
}
//
auto V30MZ::in(Size size, uint16 address) -> uint16 {
uint16 data;
if(size >= Byte) data.byte(0) = in(address++);
if(size >= Word) data.byte(1) = in(address++);
return data;
}
auto V30MZ::out(Size size, uint16 address, uint16 data) -> void {
if(size >= Byte) out(address++, data.byte(0));
if(size >= Word) out(address++, data.byte(1));
}
//
auto V30MZ::fetch(Size size) -> uint16 {
wait(size);
uint16 data = read(size, r.cs, r.ip);
return r.ip += size, data;
}
//
auto V30MZ::pop() -> uint16 {
uint16 data = read(Word, r.ss, r.sp);
return r.sp += Word, data;
}
auto V30MZ::push(uint16 data) -> void {
r.sp -= Word;
write(Word, r.ss, r.sp, data);
}

View File

@ -1,62 +0,0 @@
auto V30MZ::modRM() -> void {
auto data = fetch();
modrm.mem = data.bits(0,2);
modrm.reg = data.bits(3,5);
modrm.mod = data.bits(6,7);
if(modrm.mod == 0 && modrm.mem == 6) {
modrm.segment = segment(r.ds);
modrm.address = fetch(Word);
} else {
switch(modrm.mem) {
case 0: modrm.segment = segment(r.ds); modrm.address = r.bx + r.si; break;
case 1: modrm.segment = segment(r.ds); modrm.address = r.bx + r.di; break;
case 2: modrm.segment = segment(r.ss); modrm.address = r.bp + r.si; break;
case 3: modrm.segment = segment(r.ss); modrm.address = r.bp + r.di; break;
case 4: modrm.segment = segment(r.ds); modrm.address = r.si; break;
case 5: modrm.segment = segment(r.ds); modrm.address = r.di; break;
case 6: modrm.segment = segment(r.ss); modrm.address = r.bp; break;
case 7: modrm.segment = segment(r.ds); modrm.address = r.bx; break;
}
if(modrm.mod == 1) modrm.address += (int8)fetch(Byte);
if(modrm.mod == 2) modrm.address += (int16)fetch(Word);
}
}
//
auto V30MZ::getMem(Size size, uint offset) -> uint16 {
if(modrm.mod != 3) return read(size, modrm.segment, modrm.address + offset);
if(size == Byte) return *r.b[modrm.mem];
if(size == Word) return *r.w[modrm.mem];
unreachable;
}
auto V30MZ::setMem(Size size, uint16 data) -> void {
if(modrm.mod != 3) return write(size, modrm.segment, modrm.address, data);
if(size == Byte) *r.b[modrm.mem] = data;
if(size == Word) *r.w[modrm.mem] = data;
}
//
auto V30MZ::getReg(Size size) -> uint16 {
if(size == Byte) return *r.b[modrm.reg];
if(size == Word) return *r.w[modrm.reg];
unreachable;
}
auto V30MZ::setReg(Size size, uint16 data) -> void {
if(size == Byte) *r.b[modrm.reg] = data;
if(size == Word) *r.w[modrm.reg] = data;
}
//
auto V30MZ::getSeg() -> uint16 {
return *r.s[modrm.reg];
}
auto V30MZ::setSeg(uint16 data) -> void {
*r.s[modrm.reg] = data;
}

View File

@ -1,30 +0,0 @@
auto V30MZ::repeat() -> uint8 {
for(auto prefix : prefixes) {
if(prefix == RepeatWhileZeroLo) return prefix;
if(prefix == RepeatWhileZeroHi) return prefix;
}
return {};
}
auto V30MZ::segment(uint16 segment) -> uint16 {
for(auto prefix : prefixes) {
if(prefix == SegmentOverrideES) return r.es;
if(prefix == SegmentOverrideCS) return r.cs;
if(prefix == SegmentOverrideSS) return r.ss;
if(prefix == SegmentOverrideDS) return r.ds;
}
return segment;
}
auto V30MZ::getAcc(Size size) -> uint32 {
if(size == Byte) return r.al;
if(size == Word) return r.ax;
if(size == Long) return r.dx << 16 | r.ax;
unreachable;
}
auto V30MZ::setAcc(Size size, uint32 data) -> void {
if(size == Byte) r.al = data;
if(size == Word) r.ax = data;
if(size == Long) r.ax = data, r.dx = data >> 16;
}

View File

@ -1,42 +0,0 @@
auto V30MZ::serialize(serializer& s) -> void {
s.integer(state.halt);
s.integer(state.poll);
s.integer(state.prefix);
s.integer(opcode);
if(s.mode() == serializer::Save) {
uint8 _prefixes[7] = {0};
uint8 _prefixCount = prefixes.size();
for(auto n : range(_prefixCount)) _prefixes[n] = prefixes[n];
s.integer(_prefixCount);
s.array(_prefixes);
} else {
uint8 _prefixes[7] = {0};
uint8 _prefixCount = 0;
s.integer(_prefixCount);
s.array(_prefixes);
prefixes.resize(_prefixCount);
for(auto n : range(_prefixCount)) prefixes[n] = _prefixes[n];
}
s.integer(modrm.mod);
s.integer(modrm.reg);
s.integer(modrm.mem);
s.integer(modrm.segment);
s.integer(modrm.address);
s.integer(r.ax);
s.integer(r.cx);
s.integer(r.dx);
s.integer(r.bx);
s.integer(r.sp);
s.integer(r.bp);
s.integer(r.si);
s.integer(r.di);
s.integer(r.es);
s.integer(r.cs);
s.integer(r.ss);
s.integer(r.ds);
s.integer(r.ip);
s.integer(r.f.data);
}

View File

@ -1,59 +0,0 @@
#include <processor/processor.hpp>
#include "v30mz.hpp"
namespace Processor {
#include "registers.cpp"
#include "modrm.cpp"
#include "memory.cpp"
#include "algorithms.cpp"
#include "instruction.cpp"
#include "instructions-adjust.cpp"
#include "instructions-alu.cpp"
#include "instructions-exec.cpp"
#include "instructions-flag.cpp"
#include "instructions-group.cpp"
#include "instructions-misc.cpp"
#include "instructions-move.cpp"
#include "instructions-string.cpp"
#include "serialization.cpp"
auto V30MZ::warning(string text) -> void {
//print(text, "\n");
}
auto V30MZ::power() -> void {
state.halt = false;
state.poll = true;
state.prefix = false;
prefixes.reset();
r.ax = 0x0000;
r.cx = 0x0000;
r.dx = 0x0000;
r.bx = 0x0000;
r.sp = 0x2000;
r.bp = 0x0000;
r.si = 0x0000;
r.di = 0x0000;
r.es = 0x0000;
r.cs = 0xffff;
r.ss = 0x0000;
r.ds = 0x0000;
r.ip = 0x0000;
r.f = 0x8000;
}
auto V30MZ::exec() -> void {
state.poll = true;
state.prefix = false;
if(state.halt) return wait(1);
instruction();
if(!state.prefix) prefixes.reset();
}
#undef bits
#include "disassembler.cpp"
}

View File

@ -1,316 +0,0 @@
//NEC V30MZ (reduced functionality NEC V30 for embedded use)
//V30 missing instructions:
// 0f 10,11,18,19 test1
// 0f 12,13,1a,1b clr1
// 0f 14,15,1c,1d set1
// 0f 16,17,1e,1f not1
// 0f 20 add4s
// 0f 22 sub4s
// 0f 26 cmp4s
// 0f 28 rol4
// 0f 2a ror4
// 0f 31,39 ins
// 0f 33,3b ext
// 0f ff brkem (8080 emulation mode) [retem, calln]
// 64 repnc
// 65 repc
// 66,67 fpo2
// d8-df fpo1
//x86 variant instructions:
// 8f c0-c7 pop reg [CPU bug: pops from stack; fails to set register]
// d4 xx aam [ignores the immediate; always uses (base) 10]
// d5 xx aad [ignores the immediate; always uses (base) 10]
// d6 xlat (mirror of d7) [this is salc on x86 CPUs]
// f1 ??? [this is int 0x1 on x86 CPUs; said to be a two-byte NOP on V20; unknown on V30/V30MZ]
// ff f8-ff push (mirror of ff f0-f7)
//x86 unemulated variation:
// after interrupts, NEC V20/V30 CPUs resume string instructions with prefixes intact. unlike x86 CPUs
// I need more information on this behavior in order to emulate it ...
// also, the opcode f1 behavior is not currently known
//V30 opcode prefix functionality:
// there is a seven-level stack for opcode prefixes. once full, older prefixes are pushed off the stack
//other notes:
// 0f pop cs (not nop) [on the V20; the V30 uses this for instruction extensions; unsure on the V30MZ]
// 8e xx mov cs,modRM (works as expected; able to set CS)
//I currently emulate opcode 0f as pop cs, although it's unknown if that is correct.
#pragma once
namespace Processor {
struct V30MZ {
using Size = uint;
enum : uint { Byte = 1, Word = 2, Long = 4 };
enum : uint {
SegmentOverrideES = 0x26,
SegmentOverrideCS = 0x2e,
SegmentOverrideSS = 0x36,
SegmentOverrideDS = 0x3e,
Lock = 0xf0,
RepeatWhileZeroLo = 0xf2,
RepeatWhileZeroHi = 0xf3,
};
virtual auto wait(uint clocks = 1) -> void = 0;
virtual auto read(uint20 addr) -> uint8 = 0;
virtual auto write(uint20 addr, uint8 data) -> void = 0;
virtual auto in(uint16 port) -> uint8 = 0;
virtual auto out(uint16 port, uint8 data) -> void = 0;
auto warning(string text) -> void;
auto power() -> void;
auto exec() -> void;
//instruction.cpp
auto interrupt(uint8 vector) -> void;
auto instruction() -> void;
//registers.cpp
auto repeat() -> uint8;
auto segment(uint16) -> uint16;
auto getAcc(Size) -> uint32;
auto setAcc(Size, uint32) -> void;
//modrm.cpp
auto modRM() -> void;
auto getMem(Size, uint offset = 0) -> uint16;
auto setMem(Size, uint16) -> void;
auto getReg(Size) -> uint16;
auto setReg(Size, uint16) -> void;
auto getSeg() -> uint16;
auto setSeg(uint16) -> void;
//memory.cpp
auto read(Size, uint16, uint16) -> uint32;
auto write(Size, uint16, uint16, uint16) -> void;
auto in(Size, uint16) -> uint16;
auto out(Size, uint16, uint16) -> void;
auto fetch(Size = Byte) -> uint16;
auto pop() -> uint16;
auto push(uint16) -> void;
//algorithms.cpp
auto parity(uint8) const -> bool;
auto ADC (Size, uint16, uint16) -> uint16;
auto ADD (Size, uint16, uint16) -> uint16;
auto AND (Size, uint16, uint16) -> uint16;
auto DEC (Size, uint16 ) -> uint16;
auto DIV (Size, uint32, uint32) -> uint32;
auto DIVI(Size, int32, int32) -> uint32;
auto INC (Size, uint16 ) -> uint16;
auto MUL (Size, uint16, uint16) -> uint32;
auto MULI(Size, int16, int16) -> uint32;
auto NEG (Size, uint16 ) -> uint16;
auto NOT (Size, uint16 ) -> uint16;
auto OR (Size, uint16, uint16) -> uint16;
auto RCL (Size, uint16, uint5) -> uint16;
auto RCR (Size, uint16, uint5) -> uint16;
auto ROL (Size, uint16, uint4) -> uint16;
auto ROR (Size, uint16, uint4) -> uint16;
auto SAL (Size, uint16, uint5) -> uint16;
auto SAR (Size, uint16, uint5) -> uint16;
auto SBB (Size, uint16, uint16) -> uint16;
auto SUB (Size, uint16, uint16) -> uint16;
auto SHL (Size, uint16, uint5) -> uint16;
auto SHR (Size, uint16, uint5) -> uint16;
auto XOR (Size, uint16, uint16) -> uint16;
//instructions-adjust.cpp
auto instructionDecimalAdjust(bool) -> void;
auto instructionAsciiAdjust(bool) -> void;
auto instructionAdjustAfterMultiply() -> void;
auto instructionAdjustAfterDivide() -> void;
//instructions-alu.cpp
auto instructionAddMemReg(Size) -> void;
auto instructionAddRegMem(Size) -> void;
auto instructionAddAccImm(Size) -> void;
auto instructionOrMemReg(Size) -> void;
auto instructionOrRegMem(Size) -> void;
auto instructionOrAccImm(Size) -> void;
auto instructionAdcMemReg(Size) -> void;
auto instructionAdcRegMem(Size) -> void;
auto instructionAdcAccImm(Size) -> void;
auto instructionSbbMemReg(Size) -> void;
auto instructionSbbRegMem(Size) -> void;
auto instructionSbbAccImm(Size) -> void;
auto instructionAndMemReg(Size) -> void;
auto instructionAndRegMem(Size) -> void;
auto instructionAndAccImm(Size) -> void;
auto instructionSubMemReg(Size) -> void;
auto instructionSubRegMem(Size) -> void;
auto instructionSubAccImm(Size) -> void;
auto instructionXorMemReg(Size) -> void;
auto instructionXorRegMem(Size) -> void;
auto instructionXorAccImm(Size) -> void;
auto instructionCmpMemReg(Size) -> void;
auto instructionCmpRegMem(Size) -> void;
auto instructionCmpAccImm(Size) -> void;
auto instructionTestMemReg(Size) -> void;
auto instructionTestAcc(Size) -> void;
auto instructionMultiplySignedRegMemImm(Size) -> void;
auto instructionIncReg(uint16_t&) -> void;
auto instructionDecReg(uint16_t&) -> void;
auto instructionSignExtendByte() -> void;
auto instructionSignExtendWord() -> void;
//instructions-exec.cpp
auto instructionLoop() -> void;
auto instructionLoopWhile(bool) -> void;
auto instructionJumpShort() -> void;
auto instructionJumpIf(bool) -> void;
auto instructionJumpNear() -> void;
auto instructionJumpFar() -> void;
auto instructionCallNear() -> void;
auto instructionCallFar() -> void;
auto instructionReturn() -> void;
auto instructionReturnImm() -> void;
auto instructionReturnFar() -> void;
auto instructionReturnFarImm() -> void;
auto instructionReturnInt() -> void;
auto instructionInt3() -> void;
auto instructionIntImm() -> void;
auto instructionInto() -> void;
auto instructionEnter() -> void;
auto instructionLeave() -> void;
auto instructionPushReg(uint16_t&) -> void;
auto instructionPopReg(uint16_t&) -> void;
auto instructionPushFlags() -> void;
auto instructionPopFlags() -> void;
auto instructionPushAll() -> void;
auto instructionPopAll() -> void;
auto instructionPushImm(Size) -> void;
auto instructionPopMem() -> void;
//instructions-flag.cpp
auto instructionStoreFlagsAcc() -> void;
auto instructionLoadAccFlags() -> void;
auto instructionComplementCarry() -> void;
auto instructionClearFlag(uint) -> void;
auto instructionSetFlag(uint) -> void;
//instructions-group.cpp
auto instructionGroup1MemImm(Size, bool) -> void;
auto instructionGroup2MemImm(Size, maybe<uint8> = {}) -> void;
auto instructionGroup3MemImm(Size) -> void;
auto instructionGroup4MemImm(Size) -> void;
//instructions-misc.cpp
auto instructionSegment(uint16) -> void;
auto instructionRepeat() -> void;
auto instructionLock() -> void;
auto instructionWait() -> void;
auto instructionHalt() -> void;
auto instructionNop() -> void;
auto instructionIn(Size) -> void;
auto instructionOut(Size) -> void;
auto instructionInDX(Size) -> void;
auto instructionOutDX(Size) -> void;
auto instructionTranslate() -> void;
auto instructionBound() -> void;
//instructions-move.cpp
auto instructionMoveMemReg(Size) -> void;
auto instructionMoveRegMem(Size) -> void;
auto instructionMoveMemSeg() -> void;
auto instructionMoveSegMem() -> void;
auto instructionMoveAccMem(Size) -> void;
auto instructionMoveMemAcc(Size) -> void;
auto instructionMoveRegImm(uint8_t&) -> void;
auto instructionMoveRegImm(uint16_t&) -> void;
auto instructionMoveMemImm(Size) -> void;
auto instructionExchange(uint16_t&, uint16_t&) -> void;
auto instructionExchangeMemReg(Size) -> void;
auto instructionLoadEffectiveAddressRegMem() -> void;
auto instructionLoadSegmentMem(uint16_t&) -> void;
//instructions-string.cpp
auto instructionInString(Size) -> void;
auto instructionOutString(Size) -> void;
auto instructionMoveString(Size) -> void;
auto instructionCompareString(Size) -> void;
auto instructionStoreString(Size) -> void;
auto instructionLoadString(Size) -> void;
auto instructionScanString(Size) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
//disassembler.cpp
auto disassemble() -> string;
auto disassemble(uint16 cs, uint16 ip) -> string;
struct State {
bool halt; //set to true for hlt instruction; blocks execution until next interrupt
bool poll; //set to false to suppress interrupt polling between CPU instructions
bool prefix; //set to true for prefix instructions; prevents flushing of Prefix struct
} state;
uint8 opcode;
vector<uint8> prefixes;
struct ModRM {
uint2 mod;
uint3 reg;
uint3 mem;
uint16 segment;
uint16 address;
} modrm;
struct Registers {
union { uint16_t ax; struct { uint8_t order_lsb2(al, ah); }; };
union { uint16_t cx; struct { uint8_t order_lsb2(cl, ch); }; };
union { uint16_t dx; struct { uint8_t order_lsb2(dl, dh); }; };
union { uint16_t bx; struct { uint8_t order_lsb2(bl, bh); }; };
uint16_t sp;
uint16_t bp;
uint16_t si;
uint16_t di;
uint16_t es;
uint16_t cs;
uint16_t ss;
uint16_t ds;
uint16_t ip;
uint8_t* b[8]{&al, &cl, &dl, &bl, &ah, &ch, &dh, &bh};
uint16_t* w[8]{&ax, &cx, &dx, &bx, &sp, &bp, &si, &di};
uint16_t* s[8]{&es, &cs, &ss, &ds, &es, &cs, &ss, &ds};
struct Flags {
union {
uint16_t data = 0;
BooleanBitField<uint16_t, 15> m; //mode
BooleanBitField<uint16_t, 11> v; //overflow
BooleanBitField<uint16_t, 10> d; //direction
BooleanBitField<uint16_t, 9> i; //interrupt
BooleanBitField<uint16_t, 8> b; //break
BooleanBitField<uint16_t, 7> s; //sign
BooleanBitField<uint16_t, 6> z; //zero
BooleanBitField<uint16_t, 4> h; //half-carry
BooleanBitField<uint16_t, 2> p; //parity
BooleanBitField<uint16_t, 0> c; //carry
};
operator uint() const { return data & 0x8fd5 | 0x7002; }
auto& operator =(uint value) { return data = value, *this; }
auto& operator&=(uint value) { return data &= value, *this; }
auto& operator|=(uint value) { return data |= value, *this; }
auto& operator^=(uint value) { return data ^= value, *this; }
} f;
} r;
};
}

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