mirror of https://github.com/bsnes-emu/bsnes.git
Update to v100r08 release.
byuu says: Six and a half hours this time ... one new opcode, and all old opcodes now in a deprecated format. Hooray, progress! For building the table, I've decided to move from: for(uint opcode : range(65536)) { if(match(...)) bind(opNAME, ...); } To instead having separate for loops for each supported opcode. This lets me specialize parts I want with templates. And to this aim, I'm moving to replace all of the (read,write)(size, ...) functions with (read,write)<Size>(...) functions. This will amount to the ~70ish instructions being triplicated ot ~210ish instructions; but I think this is really important. When I was getting into flag calculations, a ton of conditionals were needed to mask sizes to byte/word/long. There was also lots of conditionals in all the memory access handlers. The template code is ugly, but we eliminate a huge amount of branch conditions this way.
This commit is contained in:
parent
059347e575
commit
92fe5b0813
|
@ -11,7 +11,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "100.07";
|
||||
static const string Version = "100.08";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -11,7 +11,7 @@ auto M68K::_readLong(uint32 addr) -> uint32 {
|
|||
return data |= _readWord(addr + 2) << 0;
|
||||
}
|
||||
|
||||
auto M68K::_readPC(uint size) -> uint32 {
|
||||
auto M68K::_readPC(uint2 size) -> uint32 {
|
||||
uint32 data = _readWord(_pc);
|
||||
_pc += 2;
|
||||
if(size == Byte) return (uint8)data;
|
||||
|
@ -21,21 +21,29 @@ auto M68K::_readPC(uint size) -> uint32 {
|
|||
return data;
|
||||
}
|
||||
|
||||
auto M68K::_immediate(uint size) -> string {
|
||||
auto M68K::_immediate(uint2 size) -> string {
|
||||
if(size == Byte) return {"#$", hex(_readPC(Byte), 2L)};
|
||||
if(size == Word) return {"#$", hex(_readPC(Word), 4L)};
|
||||
if(size == Long) return {"#$", hex(_readPC(Long), 8L)};
|
||||
return "#???";
|
||||
}
|
||||
|
||||
auto M68K::_address(uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
auto M68K::_address(uint8 ea) -> string {
|
||||
uint3 mode = ea >> 5;
|
||||
uint3 reg = ea >> 2;
|
||||
uint2 size = ea >> 0;
|
||||
|
||||
if(mode == 7) {
|
||||
if(reg == 2) return {"$", hex(_pc + (int16)_readPC(Word), 6L)};
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
auto M68K::_read(uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
auto M68K::_read(uint8 ea) -> string {
|
||||
uint3 mode = ea >> 5;
|
||||
uint3 reg = ea >> 2;
|
||||
uint2 size = ea >> 0;
|
||||
|
||||
if(mode == 0) return {"d", reg};
|
||||
if(mode == 1) return {"a", reg};
|
||||
if(mode == 2) return {"(a", reg, ")"};
|
||||
|
@ -53,8 +61,8 @@ auto M68K::_read(uint2 size, uint3 mode, uint3 reg) -> string {
|
|||
return "???";
|
||||
}
|
||||
|
||||
auto M68K::_write(uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
return _read(size, mode, reg);
|
||||
auto M68K::_write(uint8 ea) -> string {
|
||||
return _read(ea);
|
||||
}
|
||||
|
||||
auto M68K::_branch(uint8 displacement) -> string {
|
||||
|
@ -64,7 +72,7 @@ auto M68K::_branch(uint8 displacement) -> string {
|
|||
return {"$", hex(_pc + displacement, 6L)};
|
||||
}
|
||||
|
||||
auto M68K::_suffix(uint size) -> string {
|
||||
auto M68K::_suffix(uint2 size) -> string {
|
||||
if(size == Byte) return ".b";
|
||||
if(size == Word) return ".w";
|
||||
if(size == Long) return ".l";
|
||||
|
@ -103,28 +111,39 @@ auto M68K::disassembleRegisters() -> string {
|
|||
|
||||
//
|
||||
|
||||
auto M68K::disassembleANDI(uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
return {"andi", _suffix(size), " ", _immediate(size), ",", _read(size, mode, reg)};
|
||||
template<uint Size> auto M68K::disassembleADD(uint3 reg, uint1 direction, EA ea) -> string {
|
||||
string op{"add", _suffix(ea.reg), " "};
|
||||
return op;
|
||||
|
||||
if(direction == 0) {
|
||||
// return {op, _read(ea), ",d", reg};
|
||||
} else {
|
||||
// return {op, "d", reg, ",", _read(ea)};
|
||||
}
|
||||
}
|
||||
|
||||
auto M68K::disassembleANDI(uint8 ea) -> string {
|
||||
return {"andi", _suffix(ea), " ", _immediate(ea), ",", _read(ea)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string {
|
||||
return {"b", _condition(condition), " ", _branch(displacement)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleLEA(uint3 target, uint3 mode, uint3 reg) -> string {
|
||||
return {"lea ", _address(Long, mode, reg), ",a", target};
|
||||
auto M68K::disassembleLEA(uint3 to, uint8 ea) -> string {
|
||||
return {"lea ", _address(ea), ",a", to};
|
||||
}
|
||||
|
||||
auto M68K::disassembleMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> string {
|
||||
return {"move", _suffix(size), " ", _read(size, sourceMode, sourceReg), ",", _write(size, targetMode, targetReg)};
|
||||
auto M68K::disassembleMOVE(uint8 to, uint8 from) -> string {
|
||||
return {"move", _suffix(from), " ", _read(from), ",", _write(to)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> string {
|
||||
return {"movea ", _read(size, mode, reg), ",a", target};
|
||||
auto M68K::disassembleMOVEA(uint3 to, uint8 from) -> string {
|
||||
return {"movea ", _read(from), ",a", to};
|
||||
}
|
||||
|
||||
auto M68K::disassembleMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
string op{"movem", _suffix(size), " "};
|
||||
auto M68K::disassembleMOVEM(uint1 direction, uint8 ea) -> string {
|
||||
string op{"movem", _suffix(ea), " "};
|
||||
|
||||
uint16 list = _readPC();
|
||||
string regs;
|
||||
|
@ -135,9 +154,9 @@ auto M68K::disassembleMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg)
|
|||
regs.trimRight(",");
|
||||
|
||||
if(direction == 0) {
|
||||
return {op, regs, ",", _read(size, mode, reg)};
|
||||
return {op, regs, ",", _read(ea)};
|
||||
} else {
|
||||
return {op, _read(size, mode, reg), ",", regs};
|
||||
return {op, _read(ea), ",", regs};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,6 +176,6 @@ auto M68K::disassembleNOP() -> string {
|
|||
return {"nop "};
|
||||
}
|
||||
|
||||
auto M68K::disassembleTST(uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
return {"tst", _suffix(size), " ", _read(size, mode, reg)};
|
||||
auto M68K::disassembleTST(uint8 ea) -> string {
|
||||
return {"tst", _suffix(ea), " ", _read(ea)};
|
||||
}
|
||||
|
|
|
@ -1,137 +1,423 @@
|
|||
M68K::EA::EA(M68K* self, uint2 size, uint3 mode, uint3 reg) : self(self), size(size), mode(mode), reg(reg) {
|
||||
if(this->mode == 7) this->mode += this->reg; //speed hack: convert cases {7; 0-4} to {8-12} for switch jump table
|
||||
address = fetch();
|
||||
}
|
||||
//effective addressing
|
||||
|
||||
M68K::EA::~EA() {
|
||||
flush();
|
||||
}
|
||||
//encoding:
|
||||
// d7-d5: mode
|
||||
// d4-d2: register
|
||||
// d1-d0: size (0 = byte, 1 = word, 2 = long)
|
||||
|
||||
auto M68K::EA::pc() -> uint32& { return self->r.pc; }
|
||||
auto M68K::EA::d(uint3 reg) -> uint32& { return self->r.d(reg); }
|
||||
auto M68K::EA::a(uint3 reg) -> uint32& { return self->r.a(reg); }
|
||||
auto M68K::EA::readPC(uint2 size) -> uint32 { return self->readPC(size); }
|
||||
auto M68K::EA::read(uint32 addr) -> uint32 { return self->readAbsolute(size, addr); }
|
||||
auto M68K::EA::write(uint32 addr, uint32 data) -> void { return self->writeAbsolute(size, addr, data); }
|
||||
|
||||
auto M68K::EA::fetch() -> uint32 {
|
||||
switch(mode) {
|
||||
auto M68K::address(uint8 ea) -> uint32 {
|
||||
switch(ea) {
|
||||
|
||||
//data register direct
|
||||
case 0: return d(reg);
|
||||
case 0b000'000'00 ... 0b000'111'11:
|
||||
return r.d(ea >> 2);
|
||||
|
||||
//address register direct
|
||||
case 1: return a(reg);
|
||||
case 0b001'000'00 ... 0b001'111'11:
|
||||
return r.a(ea >> 2);
|
||||
|
||||
//address register indirect
|
||||
case 2: return a(reg);
|
||||
case 0b010'000'00 ... 0b010'111'11:
|
||||
return r.a(ea >> 2);
|
||||
|
||||
//address register indirect with post-increment
|
||||
case 3: return a(reg);
|
||||
case 0b011'000'00 ... 0b011'111'11:
|
||||
return r.a(ea >> 2);
|
||||
|
||||
//address register indirect with pre-decrement
|
||||
case 4: return a(reg);
|
||||
case 0b100'000'00 ... 0b100'111'11:
|
||||
return r.a(ea >> 2);
|
||||
|
||||
//address register with displacement
|
||||
case 5: return a(reg) + (int16)readPC(Word);
|
||||
//address register indirect with displacement
|
||||
case 0b101'000'00 ... 0b101'111'11:
|
||||
return r.a(ea >> 2) + (int16)readPC();
|
||||
|
||||
//address register with index
|
||||
case 6: {
|
||||
auto word = readPC(Word);
|
||||
auto index = word & 0x8000 ? a(word >> 12) : d(word >> 12);
|
||||
//address register indirect with index
|
||||
case 0b110'000'00 ... 0b110'111'11: {
|
||||
auto word = readPC();
|
||||
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
|
||||
if(word & 0x800) index = (int16)index;
|
||||
return a(reg) + index + (int8)word;
|
||||
return r.a(ea >> 2) + index + (int8)word;
|
||||
}
|
||||
|
||||
//absolute short
|
||||
case 7: return (int16)readPC(Word);
|
||||
//absolute short indirect
|
||||
case 0b111'000'00 ... 0b111'000'11:
|
||||
return (int16)readPC();
|
||||
|
||||
//absolute long
|
||||
case 8: return readPC(Long);
|
||||
|
||||
//program counter with displacement
|
||||
case 9: {
|
||||
auto base = pc();
|
||||
return base + (int16)readPC(Word);
|
||||
//absolute long indirect
|
||||
case 0b111'001'00 ... 0b111'001'11: {
|
||||
uint32 address = readPC() << 16;
|
||||
return address | readPC() << 0;
|
||||
}
|
||||
|
||||
//program counter with index
|
||||
case 10: {
|
||||
auto base = pc();
|
||||
auto word = readPC(Word);
|
||||
auto index = word & 0x8000 ? a(word >> 12) : d(word >> 12);
|
||||
//program counter indirect with displacement
|
||||
case 0b111'010'00 ... 0b111'010'11: {
|
||||
auto base = r.pc;
|
||||
return base + (int16)readPC();
|
||||
}
|
||||
|
||||
//program counter indirect with index
|
||||
case 0b111'011'00 ... 0b111'011'11: {
|
||||
auto base = r.pc;
|
||||
auto word = readPC();
|
||||
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
|
||||
if(word & 0x800) index = (int16)index;
|
||||
return base + index + (int8)word;
|
||||
}
|
||||
|
||||
//immediate
|
||||
case 11: {
|
||||
if(size == Byte) return (uint8)readPC(Word);
|
||||
if(size == Word) return readPC(Word);
|
||||
if(size == Long) return readPC(Long);
|
||||
}
|
||||
|
||||
//immediate byte
|
||||
case 0b111'100'00:
|
||||
return (uint8)readPC();
|
||||
|
||||
//immediate word
|
||||
case 0b111'100'01:
|
||||
return readPC();
|
||||
|
||||
//immediate long
|
||||
case 0b111'100'10: {
|
||||
uint32 address = readPC() << 16;
|
||||
return address | readPC() << 0;
|
||||
}
|
||||
|
||||
//invalid
|
||||
default:
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
auto M68K::EA::read() -> uint32 {
|
||||
switch(mode) {
|
||||
case 0: return address;
|
||||
case 1: return address;
|
||||
case 2: return read(address);
|
||||
case 3: {
|
||||
auto data = read(address);
|
||||
address += size == Long ? 4 : 2;
|
||||
template<uint Size> auto M68K::read(EA ea) -> uint32 {
|
||||
switch(ea.mode) {
|
||||
|
||||
case 0: { //data register direct
|
||||
return clip<Size>(r.d(ea.reg));
|
||||
}
|
||||
|
||||
case 1: { //address register direct
|
||||
return clip<Size>(r.a(ea.reg));
|
||||
}
|
||||
|
||||
case 2: { //address register indirect
|
||||
auto& address = r.a(ea.reg);
|
||||
return read<Size>(address);
|
||||
}
|
||||
|
||||
case 3: { //address register indirect with post-increment
|
||||
auto& address = r.a(ea.reg);
|
||||
auto data = read<Size>(address);
|
||||
address += Size == Long ? 4 : 2;
|
||||
return data;
|
||||
}
|
||||
case 4: {
|
||||
address -= size == Long ? 4 : 2;
|
||||
return read(address);
|
||||
}
|
||||
case 5: return read(address);
|
||||
case 6: return read(address);
|
||||
case 7: return read(address);
|
||||
case 8: return read(address);
|
||||
case 9: return read(address);
|
||||
case 10: return read(address);
|
||||
case 11: return address;
|
||||
|
||||
case 4: { //address register indirect with pre-decrement
|
||||
auto& address = r.a(ea.reg);
|
||||
address -= Size == Long ? 4 : 2;
|
||||
return read<Size>(address);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto M68K::EA::write(uint32 data) -> void {
|
||||
switch(mode) {
|
||||
case 0: address = data; return;
|
||||
case 1: address = data; return;
|
||||
case 2: return write(address, data);
|
||||
case 3: {
|
||||
write(address, data);
|
||||
address += size == Long ? 4 : 2;
|
||||
template<uint Size> auto M68K::write(EA ea, uint32 data) -> void {
|
||||
switch(ea.mode) {
|
||||
|
||||
case 0: { //data register direct
|
||||
r.d(ea.reg) = data;
|
||||
return;
|
||||
}
|
||||
case 4: {
|
||||
address -= size == Long ? 4 : 2;
|
||||
return write(address, data);
|
||||
|
||||
case 1: { //address register direct
|
||||
r.a(ea.reg) = data;
|
||||
return;
|
||||
}
|
||||
case 5: return write(address, data);
|
||||
case 6: return write(address, data);
|
||||
case 7: return write(address, data);
|
||||
case 8: return write(address, data);
|
||||
case 9: return write(address, data);
|
||||
case 10: return write(address, data);
|
||||
case 11: address = data; return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
auto M68K::EA::flush() -> void {
|
||||
auto M68K::read(uint8 ea) -> uint32 {
|
||||
switch(ea) {
|
||||
|
||||
//data register direct
|
||||
case 0b000'000'00 ... 0b000'111'11:
|
||||
return r.d(ea >> 2);
|
||||
|
||||
//address register direct
|
||||
case 0b001'000'00 ... 0b001'111'11:
|
||||
return r.a(ea >> 2);
|
||||
|
||||
//address register indirect
|
||||
case 0b010'000'00 ... 0b010'111'11: {
|
||||
auto address = r.a(ea >> 2);
|
||||
return readAbsolute(ea, address);
|
||||
}
|
||||
|
||||
//address register indirect with post-increment
|
||||
if(mode == 3) a(reg) = address;
|
||||
case 0b011'000'00 ... 0b011'111'11: {
|
||||
auto& address = r.a(ea >> 2);
|
||||
auto data = readAbsolute(ea, address);
|
||||
address += 2 + (ea & 2);
|
||||
return data;
|
||||
}
|
||||
|
||||
//address register indirect with pre-decrement
|
||||
if(mode == 4) a(reg) = address;
|
||||
|
||||
mode = 15;
|
||||
case 0b100'000'00 ... 0b100'111'11: {
|
||||
auto& address = r.a(ea >> 2);
|
||||
address -= 2 + (ea & 2);
|
||||
return readAbsolute(ea, address);
|
||||
}
|
||||
|
||||
//address register indirect with displacement
|
||||
case 0b101'000'00 ... 0b101'111'11:
|
||||
return readAbsolute(ea, r.a(ea >> 2) + (int16)readPC());
|
||||
|
||||
//address register indirect with index
|
||||
case 0b110'000'00 ... 0b110'111'11: {
|
||||
auto word = readPC();
|
||||
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
|
||||
if(word & 0x800) index = (int16)index;
|
||||
return readAbsolute(ea, r.a(ea >> 2) + index + (int8)word);
|
||||
}
|
||||
|
||||
//absolute short indirect
|
||||
case 0b111'000'00 ... 0b111'000'11:
|
||||
return readAbsolute(ea, (int16)readPC());
|
||||
|
||||
//absolute long indirect
|
||||
case 0b111'001'00 ... 0b111'001'11: {
|
||||
uint32 address = readPC() << 16;
|
||||
return readAbsolute(ea, address | readPC());
|
||||
}
|
||||
|
||||
//program counter indirect with displacement
|
||||
case 0b111'010'00 ... 0b111'010'11: {
|
||||
auto base = r.pc;
|
||||
return readAbsolute(ea, base + (int16)readPC());
|
||||
}
|
||||
|
||||
//program counter indirect with index
|
||||
case 0b111'011'00 ... 0b111'011'11: {
|
||||
auto base = r.pc;
|
||||
auto word = readPC();
|
||||
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
|
||||
if(word & 0x800) index = (int16)index;
|
||||
return readAbsolute(ea, base + index + (int8)word);
|
||||
}
|
||||
|
||||
//immediate byte
|
||||
case 0b111'100'00:
|
||||
return (uint8)readPC();
|
||||
|
||||
//immediate word
|
||||
case 0b111'100'01:
|
||||
return readPC();
|
||||
|
||||
//immediate long
|
||||
case 0b111'100'10: {
|
||||
uint32 address = readPC() << 16;
|
||||
return address | readPC() << 0;
|
||||
}
|
||||
|
||||
//invalid
|
||||
default:
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
auto M68K::write(uint8 ea, uint32 data) -> void {
|
||||
switch(ea) {
|
||||
|
||||
//data register direct
|
||||
case 0b000'000'00 ... 0b000'111'11:
|
||||
r.d(ea >> 2) = data;
|
||||
return;
|
||||
|
||||
//address register direct
|
||||
case 0b001'000'00 ... 0b001'111'11:
|
||||
r.a(ea >> 2) = data;
|
||||
return;
|
||||
|
||||
//address register indirect
|
||||
case 0b010'000'00 ... 0b010'111'11: {
|
||||
auto address = r.a(ea >> 2);
|
||||
return writeAbsolute(ea, address, data);
|
||||
}
|
||||
|
||||
//address register indirect with post-increment
|
||||
case 0b011'000'00 ... 0b011'111'11: {
|
||||
auto& address = r.a(ea >> 2);
|
||||
writeAbsolute(ea, address, data);
|
||||
address += 2 + (ea & 2);
|
||||
return;
|
||||
}
|
||||
|
||||
//address register indirect with pre-decrement
|
||||
case 0b100'000'00 ... 0b100'111'11: {
|
||||
auto& address = r.a(ea >> 2);
|
||||
address -= 2 + (ea & 2);
|
||||
return writeAbsolute(ea, address, data);
|
||||
}
|
||||
|
||||
//address register indirect with displacement
|
||||
case 0b101'000'00 ... 0b101'111'11:
|
||||
return writeAbsolute(ea, r.a(ea >> 2) + (int16)readPC(), data);
|
||||
|
||||
//address register indirect with index
|
||||
case 0b110'000'00 ... 0b110'111'11: {
|
||||
auto word = readPC();
|
||||
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
|
||||
if(word & 0x800) index = (int16)index;
|
||||
return writeAbsolute(ea, r.a(ea >> 2) + index + (int8)word, data);
|
||||
}
|
||||
|
||||
//absolute short indirect
|
||||
case 0b111'000'00 ... 0b111'000'11:
|
||||
return writeAbsolute(ea, (int16)readPC(), data);
|
||||
|
||||
//absolute long indirect
|
||||
case 0b111'001'00 ... 0b111'001'11: {
|
||||
uint32 address = readPC() << 16;
|
||||
return writeAbsolute(ea, address | readPC(), data);
|
||||
}
|
||||
|
||||
//program counter indirect with displacement
|
||||
case 0b111'010'00 ... 0b111'010'11: {
|
||||
auto base = r.pc;
|
||||
return writeAbsolute(ea, base + (int16)readPC(), data);
|
||||
}
|
||||
|
||||
//program counter indirect with index
|
||||
case 0b111'011'00 ... 0b111'011'11: {
|
||||
auto base = r.pc;
|
||||
auto word = readPC();
|
||||
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
|
||||
if(word & 0x800) index = (int16)index;
|
||||
return writeAbsolute(ea, base + index + (int8)word, data);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
auto M68K::modify(uint8 ea, uint32 data, const function<uint32 (uint32, uint32)>& op) -> uint32 {
|
||||
switch(ea) {
|
||||
|
||||
//data register direct
|
||||
case 0b000'000'00 ... 0b000'111'11: {
|
||||
auto& address = r.d(ea >> 2);
|
||||
return address = op(address, data);
|
||||
}
|
||||
|
||||
//address register direct
|
||||
case 0b001'000'00 ... 0b001'111'11: {
|
||||
auto& address = r.a(ea >> 2);
|
||||
return address = op(address, data);
|
||||
}
|
||||
|
||||
//address register indirect
|
||||
case 0b010'000'00 ... 0b010'111'11: {
|
||||
auto address = r.a(ea >> 2);
|
||||
auto memory = readAbsolute(ea, address);
|
||||
writeAbsolute(ea, address, memory = op(memory, data));
|
||||
return memory;
|
||||
}
|
||||
|
||||
//address register indirect with post-increment
|
||||
case 0b011'000'00 ... 0b011'111'11: {
|
||||
auto& address = r.a(ea >> 2);
|
||||
auto memory = readAbsolute(ea, address);
|
||||
writeAbsolute(ea, address, memory = op(memory, data));
|
||||
address += 2 + (ea & 2);
|
||||
return memory;
|
||||
}
|
||||
|
||||
//address register indirect with pre-decrement
|
||||
case 0b100'000'00 ... 0b100'111'11: {
|
||||
auto& address = r.a(ea >> 2);
|
||||
address -= 2 + (ea & 2);
|
||||
auto memory = readAbsolute(ea, address);
|
||||
writeAbsolute(ea, address, memory = op(memory, data));
|
||||
return memory;
|
||||
}
|
||||
|
||||
//address register indirect with displacement
|
||||
case 0b101'000'00 ... 0b101'111'11: {
|
||||
auto address = r.a(ea >> 2) + (int16)readPC();
|
||||
auto memory = readAbsolute(ea, address);
|
||||
writeAbsolute(ea, address, memory = op(memory, data));
|
||||
return memory;
|
||||
}
|
||||
|
||||
//address register indirect with index
|
||||
case 0b110'000'00 ... 0b110'111'11: {
|
||||
auto word = readPC();
|
||||
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
|
||||
if(word & 0x800) index = (int16)index;
|
||||
auto address = r.a(ea >> 2) + index + (int8)word;
|
||||
auto memory = readAbsolute(ea, address);
|
||||
writeAbsolute(ea, address, memory = op(memory, data));
|
||||
return memory;
|
||||
}
|
||||
|
||||
//absolute short indirect
|
||||
case 0b111'000'00 ... 0b111'000'11: {
|
||||
auto address = (int16)readPC();
|
||||
auto memory = readAbsolute(ea, address);
|
||||
writeAbsolute(ea, address, memory = op(memory, data));
|
||||
return memory;
|
||||
}
|
||||
|
||||
//absolute long indirect
|
||||
case 0b111'001'00 ... 0b111'001'11: {
|
||||
auto word = readPC();
|
||||
uint32 address = word << 16 | readPC();
|
||||
auto memory = readAbsolute(ea, address);
|
||||
writeAbsolute(ea, address, memory = op(memory, data));
|
||||
return memory;
|
||||
}
|
||||
|
||||
//program counter indirect with displacement
|
||||
case 0b111'010'00 ... 0b111'010'11: {
|
||||
auto address = r.pc;
|
||||
address += (int16)readPC();
|
||||
auto memory = readAbsolute(ea, address);
|
||||
writeAbsolute(ea, address, memory = op(memory, data));
|
||||
return memory;
|
||||
}
|
||||
|
||||
//program counter indirect with index
|
||||
case 0b111'011'00 ... 0b111'011'11: {
|
||||
auto address = r.pc;
|
||||
auto word = readPC();
|
||||
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
|
||||
if(word & 0x8000) index = (int16)index;
|
||||
address += index + (int8)word;
|
||||
auto memory = readAbsolute(ea, address);
|
||||
writeAbsolute(ea, address, memory = op(memory, data));
|
||||
return memory;
|
||||
}
|
||||
|
||||
//immediate byte
|
||||
case 0b111'100'00:
|
||||
return op((uint8)readPC(), data);
|
||||
|
||||
//immediate word
|
||||
case 0b111'100'01:
|
||||
return op(readPC(), data);
|
||||
|
||||
//immediate long
|
||||
case 0b111'100'10: {
|
||||
uint32 immediate = readPC() << 16;
|
||||
immediate |= readPC();
|
||||
return op(immediate, data);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
auto M68K::flush(uint8 ea, uint32 address) -> void {
|
||||
//address register indirect with post-increment
|
||||
//address register indirect with pre-decrement
|
||||
if(ea >= 0b011'000'00 && ea <= 0b100'111'11) {
|
||||
r.a(ea >> 2) = address;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,12 +15,34 @@ auto M68K::instruction() -> void {
|
|||
}
|
||||
|
||||
M68K::M68K() {
|
||||
#define bind(id, name, ...) \
|
||||
assert(!instructionTable[id]); \
|
||||
instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \
|
||||
disassembleTable[id] = [=] { return disassemble##name(__VA_ARGS__); }; \
|
||||
|
||||
//ADD
|
||||
for(uint3 d : range(8))
|
||||
for(uint1 direction : range(2))
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = 0b1101'0000'0000'0000 | d << 9 | direction << 8 | mode << 3 | reg << 0;
|
||||
if(direction == 1 && (mode == 0 || mode == 1 || (mode == 7 && reg >= 2))) continue;
|
||||
|
||||
EA ea{mode, reg};
|
||||
bind(opcode | 0 << 6, ADD<Byte>, d, direction, ea);
|
||||
bind(opcode | 1 << 6, ADD<Word>, d, direction, ea);
|
||||
bind(opcode | 2 << 6, ADD<Long>, d, direction, ea);
|
||||
}
|
||||
|
||||
#undef bind
|
||||
|
||||
#define match(pattern) if( \
|
||||
(opcode & std::integral_constant<uint16_t, bit::mask(pattern)>::value) \
|
||||
== std::integral_constant<uint16_t, bit::test(pattern)>::value \
|
||||
)
|
||||
|
||||
#define bind(name, ...) \
|
||||
assert(!instructionTable[opcode]); \
|
||||
instructionTable[opcode] = [=] { return instruction##name(__VA_ARGS__); }; \
|
||||
disassembleTable[opcode] = [=] { return disassemble##name(__VA_ARGS__); }; \
|
||||
|
||||
|
@ -29,15 +51,31 @@ M68K::M68K() {
|
|||
|
||||
for(uint16 opcode : range(65536)) {
|
||||
|
||||
/*
|
||||
//ADD
|
||||
match("1101 ---- ---- ----") {
|
||||
uint3 r = bits(11,9);
|
||||
uint1 direction = bit(8);
|
||||
uint2 size = bits(7,6);
|
||||
uint3 mode = bits(5,3);
|
||||
uint3 reg = bits(2,0);
|
||||
|
||||
if(size != 3 && (direction == 0 || (mode == 2 || mode == 3 || mode == 4 || mode == 5 || mode == 6 || (mode == 7 && reg <= 1)))) {
|
||||
uint8 ea = mode << 5 | reg << 2 | size;
|
||||
bind(ADD, r, direction, ea);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//ANDI
|
||||
match("0000 0010 ---- ----") {
|
||||
uint2 size = bits(7,6);
|
||||
uint3 mode = bits(5,3);
|
||||
uint3 reg = bits(2,0);
|
||||
|
||||
size = size == 0 ? Byte : size == 1 ? Word : size == 2 ? Long : 0;
|
||||
if(size && mode != 1) {
|
||||
bind(ANDI, size, mode, reg);
|
||||
if(size != 3 && mode != 1) {
|
||||
uint8 ea = mode << 5 | reg << 2 | size;
|
||||
bind(ANDI, ea);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,48 +96,50 @@ M68K::M68K() {
|
|||
uint3 reg = bits(2,0);
|
||||
|
||||
if(mode == 2 || mode == 5 || mode == 6 || (mode == 7 && reg <= 4)) {
|
||||
bind(LEA, target, mode, reg);
|
||||
uint8 ea = mode << 5 | reg << 2 | Long;
|
||||
bind(LEA, target, ea);
|
||||
}
|
||||
}
|
||||
|
||||
//MOVE
|
||||
match("00-- ---- ---- ----") {
|
||||
uint2 size = bits(13,12);
|
||||
uint2 size = bits(13,12) == 1 ? Byte : bits(13,12) == 3 ? Word : bits(13,12) == 2 ? Long : 3;
|
||||
uint3 targetReg = bits(11,9);
|
||||
uint3 targetMode = bits(8,6);
|
||||
uint3 sourceMode = bits(5,3);
|
||||
uint3 sourceReg = bits(2,0);
|
||||
|
||||
size = size == 1 ? Byte : size == 3 ? Word : size == 2 ? Long : 0;
|
||||
if(size && targetMode != 1) {
|
||||
bind(MOVE, size, targetReg, targetMode, sourceMode, sourceReg);
|
||||
if(size != 3 && targetMode != 1) {
|
||||
uint8 to = targetMode << 5 | targetReg << 2 | size;
|
||||
uint8 from = sourceMode << 5 | sourceReg << 2 | size;
|
||||
bind(MOVE, to, from);
|
||||
}
|
||||
}
|
||||
|
||||
//MOVEA
|
||||
match("00-- ---0 01-- ----") {
|
||||
uint2 size = bits(13,12);
|
||||
uint3 target = bits(11,9);
|
||||
uint2 size = bits(13,12) == 3 ? Word : bits(13,12) == 2 ? Long : 3;
|
||||
uint3 to = bits(11,9);
|
||||
uint3 mode = bits(5,3);
|
||||
uint3 reg = bits(2,0);
|
||||
|
||||
size = size == 3 ? Word : size == 2 ? Long : 0;
|
||||
if(size) {
|
||||
bind(MOVEA, size, target, mode, reg);
|
||||
if(size != 3) {
|
||||
uint8 from = mode << 5 | reg << 2 | size;
|
||||
bind(MOVEA, to, from);
|
||||
}
|
||||
}
|
||||
|
||||
//MOVEM
|
||||
match("0100 1-00 1--- ----") {
|
||||
uint1 direction = bit(10);
|
||||
uint2 size = bit(6);
|
||||
uint2 size = 1 + bit(6);
|
||||
uint3 mode = bits(5,3);
|
||||
uint3 reg = bits(2,0);
|
||||
|
||||
size = size == 0 ? Word : size == 1 ? Long : 0;
|
||||
if((direction == 0 && (mode == 2 || mode == 4 || mode == 5 || mode == 6 || (mode == 7 && reg <= 3)))
|
||||
|| (direction == 1 && (mode == 2 || mode == 3 || mode == 5 || mode == 6 || (mode == 7 && reg <= 3)))) {
|
||||
bind(MOVEM, direction, size, mode, reg);
|
||||
uint8 ea = mode << 5 | reg << 2 | size;
|
||||
bind(MOVEM, direction, ea);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,22 +176,22 @@ M68K::M68K() {
|
|||
uint3 mode = bits(5,3);
|
||||
uint3 reg = bits(2,0);
|
||||
|
||||
size = size == 0 ? Byte : size == 1 ? Word : size == 2 ? Long : 0;
|
||||
if(size) {
|
||||
bind(TST, size, mode, reg);
|
||||
if(size != 3) {
|
||||
uint8 ea = mode << 5 | reg << 2 | size << 0;
|
||||
bind(TST, ea);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(uint16 opcode : range(65536)) {
|
||||
if(instructionTable[opcode]) continue;
|
||||
instructionTable[opcode] = [=] { trap(); };
|
||||
disassembleTable[opcode] = [=] { return string{"???"}; };
|
||||
}
|
||||
|
||||
#undef match
|
||||
#undef bind
|
||||
#undef bit
|
||||
#undef bits
|
||||
|
||||
for(uint16 opcode : range(65536)) {
|
||||
if(instructionTable[opcode]) continue;
|
||||
instructionTable[opcode] = [=] { trap(); };
|
||||
disassembleTable[opcode] = [=] { return string{"???"}; };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,15 +22,75 @@ auto M68K::testCondition(uint4 condition) -> bool {
|
|||
|
||||
//
|
||||
|
||||
auto M68K::instructionANDI(uint2 size, uint3 mode, uint3 reg) -> void {
|
||||
auto data = readPC(size);
|
||||
EA modify{this, size, mode, reg};
|
||||
modify.write(data = modify.read() & data);
|
||||
template<> auto M68K::clip<Byte>(uint32 data) -> uint32 { return data & 0xff; }
|
||||
template<> auto M68K::clip<Word>(uint32 data) -> uint32 { return data & 0xffff; }
|
||||
template<> auto M68K::clip<Long>(uint32 data) -> uint32 { return data & 0xffffffff; }
|
||||
|
||||
template<> auto M68K::sign<Byte>(uint32 data) -> int32 { return (int8)data; }
|
||||
template<> auto M68K::sign<Word>(uint32 data) -> int32 { return (int16)data; }
|
||||
template<> auto M68K::sign<Long>(uint32 data) -> int32 { return (int32)data; }
|
||||
|
||||
template<uint Size> auto M68K::carry(uint32 result, uint32 source) -> bool {
|
||||
return clip<Size>(result) < clip<Size>(source);
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::overflow(uint32 result, uint32 source, uint32 target) -> bool {
|
||||
return sign<Size>((target ^ source) & (target ^ result)) < 0;
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::zero(uint32 result) -> bool {
|
||||
return clip<Size>(result) == 0;
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::negative(uint32 result) -> bool {
|
||||
return sign<Size>(result) < 0;
|
||||
}
|
||||
|
||||
auto M68K::zero(uint2 size, uint32 result) -> bool {
|
||||
static const uint32 mask[4] = {0xff, 0xffff, 0xffffffff};
|
||||
return (result & mask[size]) == 0;
|
||||
}
|
||||
|
||||
auto M68K::negative(uint2 size, uint32 result) -> bool {
|
||||
static const uint32 mask[4] = {0x80, 0x8000, 0x80000000};
|
||||
return result & mask[size];
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
template<uint Size> auto M68K::instructionADD(uint3 reg, uint1 direction, EA ea) -> void {
|
||||
uint32 source;
|
||||
uint32 target;
|
||||
uint32 result;
|
||||
|
||||
if(direction == 0) {
|
||||
source = read<Size>(ea);
|
||||
target = r.d(reg);
|
||||
result = source + target;
|
||||
r.d(reg) = result;
|
||||
} else {
|
||||
source = r.d(reg);
|
||||
target = read<Size>(ea);
|
||||
result = source + target;
|
||||
write<Size>(ea, result);
|
||||
}
|
||||
|
||||
r.c = carry<Size>(result, source);
|
||||
r.v = overflow<Size>(result, source, target);
|
||||
r.z = zero<Size>(result);
|
||||
r.n = negative<Size>(result);
|
||||
r.x = r.c;
|
||||
}
|
||||
|
||||
auto M68K::instructionANDI(uint8 ea) -> void {
|
||||
auto result = modify(ea, readPC(ea), [&](auto x, auto y) -> uint32 {
|
||||
return x & y;
|
||||
});
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = data == 0;
|
||||
r.n = sign(size, data) < 0;
|
||||
r.z = zero(ea, result);
|
||||
r.n = negative(ea, result);
|
||||
}
|
||||
|
||||
auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void {
|
||||
|
@ -44,50 +104,54 @@ auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void {
|
|||
if(testCondition(condition)) r.pc += displacement;
|
||||
}
|
||||
|
||||
auto M68K::instructionLEA(uint3 target, uint3 mode, uint3 reg) -> void {
|
||||
EA source{this, Long, mode, reg};
|
||||
r.a(target) = source.address;
|
||||
auto M68K::instructionLEA(uint3 target, uint8 ea) -> void {
|
||||
r.a(target) = address(ea);
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> void {
|
||||
EA source{this, size, sourceMode, sourceReg};
|
||||
EA target{this, size, targetMode, targetReg};
|
||||
|
||||
auto data = source.read();
|
||||
source.flush();
|
||||
target.write(data);
|
||||
auto M68K::instructionMOVE(uint8 to, uint8 from) -> void {
|
||||
auto data = read(from);
|
||||
write(to, data);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = data == 0;
|
||||
r.n = sign(size, data) < 0;
|
||||
r.z = zero(from, data);
|
||||
r.n = negative(from, data);
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> void {
|
||||
EA source{this, size, mode, reg};
|
||||
r.a(target) = source.read();
|
||||
auto M68K::instructionMOVEA(uint3 to, uint8 from) -> void {
|
||||
auto data = read(from);
|
||||
if(from & 1) data = (int16)data;
|
||||
r.a(to) = data;
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> void {
|
||||
auto M68K::instructionMOVEM(uint1 direction, uint8 ea) -> void {
|
||||
auto list = readPC();
|
||||
EA source{this, size, mode, reg};
|
||||
auto addr = address(ea);
|
||||
|
||||
for(uint n : range(8)) {
|
||||
if(list.bit(0 + n)) r.d(n) = source.read();
|
||||
if(list.bit(0 + n)) {
|
||||
r.d(n) = readAbsolute(ea, addr);
|
||||
addr += 2 + (ea & 2);
|
||||
}
|
||||
}
|
||||
|
||||
for(uint n : range(8)) {
|
||||
if(list.bit(8 + n)) r.a(n) = source.read();
|
||||
if(list.bit(8 + n)) {
|
||||
r.a(n) = readAbsolute(ea, addr);
|
||||
addr += 2 + (ea & 2);
|
||||
}
|
||||
}
|
||||
|
||||
flush(ea, addr);
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVEQ(uint3 target, uint8 immediate) -> void {
|
||||
r.d(target) = immediate;
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = immediate == 0;
|
||||
r.v = sign(Byte, immediate) < 0;
|
||||
r.n = negative(Byte, immediate);
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVE_USP(uint1 direction, uint3 reg) -> void {
|
||||
|
@ -102,12 +166,11 @@ auto M68K::instructionMOVE_USP(uint1 direction, uint3 reg) -> void {
|
|||
auto M68K::instructionNOP() -> void {
|
||||
}
|
||||
|
||||
auto M68K::instructionTST(uint2 size, uint3 mode, uint3 reg) -> void {
|
||||
EA source{this, size, mode, reg};
|
||||
auto data = source.read();
|
||||
auto M68K::instructionTST(uint8 ea) -> void {
|
||||
auto data = read(ea);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = data == 0;
|
||||
r.n = sign(size, data) < 0;
|
||||
r.z = zero(ea, data);
|
||||
r.n = negative(ea, data);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
namespace Processor {
|
||||
|
||||
enum : uint { Byte, Word, Long };
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "ea.cpp"
|
||||
|
@ -24,11 +26,4 @@ auto M68K::reset() -> void {
|
|||
r.sr = 0x2000;
|
||||
}
|
||||
|
||||
auto M68K::sign(uint2 size, uint32 data) -> int32 {
|
||||
if(size == Byte) return (int8)data;
|
||||
if(size == Word) return (int16)data;
|
||||
if(size == Long) return (int32)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace Processor {
|
||||
|
||||
struct M68K {
|
||||
enum : uint { Byte = 1, Word = 2, Long = 3 };
|
||||
enum : uint { Byte, Word, Long };
|
||||
|
||||
M68K();
|
||||
|
||||
|
@ -16,39 +16,33 @@ struct M68K {
|
|||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto sign(uint2 size, uint32 data) -> int32;
|
||||
|
||||
//memory.cpp
|
||||
auto readAbsolute(uint2 size, uint32 addr) -> uint32;
|
||||
auto writeAbsolute(uint2 size, uint32 addr, uint32 data) -> void;
|
||||
|
||||
auto readPC(uint2 size = Word) -> uint32;
|
||||
|
||||
template<uint Size> auto read(uint32 addr) -> uint32;
|
||||
|
||||
//ea.cpp
|
||||
struct EA {
|
||||
EA(M68K* self, uint2 size, uint3 mode, uint3 reg);
|
||||
~EA();
|
||||
EA(uint3 mode, uint3 reg) : mode(mode), reg(reg) {
|
||||
if(mode == 7) mode += reg; //optimization: convert modes {7; 0-4} to {8-11}
|
||||
}
|
||||
|
||||
auto pc() -> uint32&;
|
||||
auto d(uint3 reg) -> uint32&;
|
||||
auto a(uint3 reg) -> uint32&;
|
||||
auto readPC(uint2 size) -> uint32;
|
||||
auto read(uint32 addr) -> uint32;
|
||||
auto write(uint32 addr, uint32 data) -> void;
|
||||
|
||||
auto fetch() -> uint32;
|
||||
auto read() -> uint32;
|
||||
auto write(uint32 data) -> void;
|
||||
auto flush() -> void;
|
||||
|
||||
uint2 size;
|
||||
uint4 mode;
|
||||
uint3 reg;
|
||||
|
||||
uint32 address;
|
||||
M68K* self;
|
||||
};
|
||||
|
||||
template<uint Size> auto read(EA ea) -> uint32;
|
||||
template<uint Size> auto write(EA ea, uint32 data) -> void;
|
||||
|
||||
auto address(uint8 ea) -> uint32;
|
||||
auto read(uint8 ea) -> uint32;
|
||||
auto write(uint8 ea, uint32 data) -> void;
|
||||
auto modify(uint8 ea, uint32 data, const function<uint32 (uint32, uint32)>& op) -> uint32;
|
||||
auto flush(uint8 ea, uint32 address) -> void;
|
||||
|
||||
//instruction.cpp
|
||||
auto trap() -> void;
|
||||
auto instruction() -> void;
|
||||
|
@ -56,16 +50,27 @@ struct M68K {
|
|||
//instructions.cpp
|
||||
auto testCondition(uint4 condition) -> bool;
|
||||
|
||||
auto instructionANDI(uint2 size, uint3 mode, uint3 reg) -> void;
|
||||
template<uint Size> auto clip(uint32 data) -> uint32;
|
||||
template<uint Size> auto sign(uint32 data) -> int32;
|
||||
|
||||
template<uint Size> auto carry(uint32 result, uint32 source) -> bool;
|
||||
template<uint Size> auto overflow(uint32 result, uint32 source, uint32 target) -> bool;
|
||||
template<uint Size> auto zero(uint32 result) -> bool;
|
||||
template<uint Size> auto negative(uint32 result) -> bool;
|
||||
auto zero(uint2 size, uint32 result) -> bool;
|
||||
auto negative(uint2 size, uint32 result) -> bool;
|
||||
|
||||
template<uint Size> auto instructionADD(uint3 reg, uint1 direction, EA ea) -> void;
|
||||
auto instructionANDI(uint8 ea) -> void;
|
||||
auto instructionBCC(uint4 condition, uint8 displacement) -> void;
|
||||
auto instructionLEA(uint3 target, uint3 mode, uint3 reg) -> void;
|
||||
auto instructionMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> void;
|
||||
auto instructionMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> void;
|
||||
auto instructionMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> void;
|
||||
auto instructionLEA(uint3 target, uint8 source) -> void;
|
||||
auto instructionMOVE(uint8 to, uint8 from) -> void;
|
||||
auto instructionMOVEA(uint3 to, uint8 ea) -> void;
|
||||
auto instructionMOVEM(uint1 direction, uint8 ea) -> void;
|
||||
auto instructionMOVEQ(uint3 target, uint8 immediate) -> void;
|
||||
auto instructionMOVE_USP(uint1 direction, uint3 reg) -> void;
|
||||
auto instructionNOP() -> void;
|
||||
auto instructionTST(uint2 size, uint3 mode, uint3 reg) -> void;
|
||||
auto instructionTST(uint8 ea) -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassemble(uint32 pc) -> string;
|
||||
|
@ -101,27 +106,28 @@ struct M68K {
|
|||
|
||||
private:
|
||||
//disassembler.cpp
|
||||
auto disassembleANDI(uint2 size, uint3 mode, uint3 reg) -> string;
|
||||
template<uint Size> auto disassembleADD(uint3 reg, uint1 direction, EA ea) -> string;
|
||||
auto disassembleANDI(uint8 ea) -> string;
|
||||
auto disassembleBCC(uint4 condition, uint8 displacement) -> string;
|
||||
auto disassembleLEA(uint3 target, uint3 mode, uint3 reg) -> string;
|
||||
auto disassembleMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> string;
|
||||
auto disassembleMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> string;
|
||||
auto disassembleMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> string;
|
||||
auto disassembleLEA(uint3 target, uint8 ea) -> string;
|
||||
auto disassembleMOVE(uint8 to, uint8 from) -> string;
|
||||
auto disassembleMOVEA(uint3 to, uint8 from) -> string;
|
||||
auto disassembleMOVEM(uint1 direction, uint8 ea) -> string;
|
||||
auto disassembleMOVEQ(uint3 target, uint8 immediate) -> string;
|
||||
auto disassembleMOVE_USP(uint1 direction, uint3 reg) -> string;
|
||||
auto disassembleNOP() -> string;
|
||||
auto disassembleTST(uint2 size, uint3 mode, uint3 reg) -> string;
|
||||
auto disassembleTST(uint8 ea) -> string;
|
||||
|
||||
auto _readByte(uint32 addr) -> uint8;
|
||||
auto _readWord(uint32 addr) -> uint16;
|
||||
auto _readLong(uint32 addr) -> uint32;
|
||||
auto _readPC(uint size = Word) -> uint32;
|
||||
auto _immediate(uint size) -> string;
|
||||
auto _address(uint2 size, uint3 mode, uint3 reg) -> string;
|
||||
auto _read(uint2 size, uint3 mode, uint3 reg) -> string;
|
||||
auto _write(uint2 size, uint3 mode, uint3 reg) -> string;
|
||||
auto _readPC(uint2 size = Word) -> uint32;
|
||||
auto _immediate(uint2 size) -> string;
|
||||
auto _address(uint8 ea) -> string;
|
||||
auto _read(uint8 ea) -> string;
|
||||
auto _write(uint8 ea) -> string;
|
||||
auto _branch(uint8 displacement) -> string;
|
||||
auto _suffix(uint size) -> string;
|
||||
auto _suffix(uint2 size) -> string;
|
||||
auto _condition(uint4 condition) -> string;
|
||||
|
||||
uint32 _pc;
|
||||
|
|
|
@ -30,3 +30,22 @@ auto M68K::readPC(uint2 size) -> uint32 {
|
|||
r.pc += 2;
|
||||
return data;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
template<> auto M68K::read<Byte>(uint32 addr) -> uint32 {
|
||||
step(4);
|
||||
return read(0, addr);
|
||||
}
|
||||
|
||||
template<> auto M68K::read<Word>(uint32 addr) -> uint32 {
|
||||
step(4);
|
||||
return read(1, addr);
|
||||
}
|
||||
|
||||
template<> auto M68K::read<Long>(uint32 addr) -> uint32 {
|
||||
step(4);
|
||||
uint32 data = read(1, addr + 0) << 16;
|
||||
step(4);
|
||||
return data | read(1, addr + 2) << 0;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ template<typename R, typename... P> struct function<auto (P...) -> R> {
|
|||
static constexpr bool value = decltype(exists<L>(0))::value;
|
||||
};
|
||||
|
||||
function() = default;
|
||||
function() {}
|
||||
function(const function& source) { operator=(source); }
|
||||
function(void* function) { if(function) callback = new global((auto (*)(P...) -> R)function); }
|
||||
function(auto (*function)(P...) -> R) { callback = new global(function); }
|
||||
|
|
Loading…
Reference in New Issue