mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
a03d91882c
commit
52f34ea470
|
@ -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}}
|
|
@ -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/";
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)};
|
||||
}
|
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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];
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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; }
|
|
@ -1,2 +0,0 @@
|
|||
auto TLCS900H::serialize(serializer& s) -> void {
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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};
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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(® == &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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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--;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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"
|
||||
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue