Update to v100r11 release.

byuu says:

I split the Register class and read/write handlers into DataRegister and
AddressRegister, given that they have different behaviors on byte/word
accesses (data tends to preserve the upper bits; address tends to
sign-extend things.)

I expanded EA to EffectiveAddress. No sense in abbreviating things
to death.

I've now implemented 26 instructions. But the new ones are just all the
stupid from/to ccr/sr instructions.

Ryphecha confirmed that you can't set the undefined bits, so I don't
think the BitField concept is appropriate for the CCR/SR. Instead, I'm
just storing direct flags and have (read,write)(CCR,SR) instead. This
isn't like the 65816 where you have subroutines that push and pop the
flag register. It's much more common to access individual flags. Doesn't
match the consistency angle of the other CPU cores, but ... I think this
is the right thing to for the 68K specifically.
This commit is contained in:
Tim Allen 2016-07-23 12:32:35 +10:00
parent 4b897ba791
commit 7ccfbe0206
10 changed files with 421 additions and 228 deletions

View File

@ -11,7 +11,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "100.10"; static const string Version = "100.11";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; static const string Website = "http://byuu.org/";

View File

@ -10,8 +10,8 @@ auto CPU::Enter() -> void {
} }
auto CPU::boot() -> void { auto CPU::boot() -> void {
r.da[A7] = read(1, 0) << 16 | read(1, 2) << 0; r.a[7] = read(1, 0) << 16 | read(1, 2) << 0;
r.pc = read(1, 4) << 16 | read(1, 6) << 0; r.pc = read(1, 4) << 16 | read(1, 6) << 0;
} }
auto CPU::main() -> void { auto CPU::main() -> void {

View File

@ -17,36 +17,36 @@ template<uint Size> auto M68K::_readPC() -> uint32 {
return clip<Size>(data); return clip<Size>(data);
} }
auto M68K::_register(Register r) -> string { auto M68K::_register(DataRegister dr) -> string {
static const string registers[16] = { return {"d", dr.number};
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", }
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
}; auto M68K::_register(AddressRegister ar) -> string {
return registers[r.number]; return {"a", ar.number};
} }
template<uint Size> auto M68K::_immediate() -> string { template<uint Size> auto M68K::_immediate() -> string {
return {"#$", hex(_readPC<Size>(), 2 << Size)}; return {"#$", hex(_readPC<Size>(), 2 << Size)};
} }
template<uint Size> auto M68K::_address(EA ea) -> string { template<uint Size> auto M68K::_address(EffectiveAddress& ea) -> string {
if(ea.mode == 9) return {"$", hex(_pc + (int16)_readPC(), 6L)}; if(ea.mode == 9) return {"$", hex(_pc + (int16)_readPC(), 6L)};
return "???"; return "???";
} }
template<uint Size> auto M68K::_read(EA ea) -> string { template<uint Size> auto M68K::_read(EffectiveAddress& ea) -> string {
if(ea.mode == 0) return {_register(ea.reg)}; if(ea.mode == 0) return {_register(DataRegister{ea.reg})};
if(ea.mode == 1) return {_register(ea.reg)}; if(ea.mode == 1) return {_register(AddressRegister{ea.reg})};
if(ea.mode == 2) return {"(", _register(ea.reg), ")"}; if(ea.mode == 2) return {"(", _register(AddressRegister{ea.reg}), ")"};
if(ea.mode == 3) return {"(", _register(ea.reg), ")+"}; if(ea.mode == 3) return {"(", _register(AddressRegister{ea.reg}), ")+"};
if(ea.mode == 4) return {"-(", _register(ea.reg), ")"}; if(ea.mode == 4) return {"-(", _register(AddressRegister{ea.reg}), ")"};
if(ea.mode == 5) return {"($", hex(read(ea.reg) + (int16)_readPC(), 6L), ")"}; if(ea.mode == 5) return {"($", hex(read(AddressRegister{ea.reg}) + (int16)_readPC(), 6L), ")"};
if(ea.mode == 8) return {"($", hex(_readPC<Long>(), 6L), ")"}; if(ea.mode == 8) return {"($", hex(_readPC<Long>(), 6L), ")"};
if(ea.mode == 11) return {"#$", hex(_readPC<Size>(), 2 << Size)}; if(ea.mode == 11) return {"#$", hex(_readPC<Size>(), 2 << Size)};
return "???"; return "???";
} }
template<uint Size> auto M68K::_write(EA ea) -> string { template<uint Size> auto M68K::_write(EffectiveAddress& ea) -> string {
return _read<Size>(ea); return _read<Size>(ea);
} }
@ -76,8 +76,8 @@ auto M68K::disassemble(uint32 pc) -> string {
auto M68K::disassembleRegisters() -> string { auto M68K::disassembleRegisters() -> string {
return { return {
hex(r.da[D0], 8L), " ", hex(r.da[D1], 8L), " ", hex(r.da[D2], 8L), " ", hex(r.da[D3], 8L), " ", hex(r.d[0], 8L), " ", hex(r.d[1], 8L), " ", hex(r.d[2], 8L), " ", hex(r.d[3], 8L), " ",
hex(r.da[D4], 8L), " ", hex(r.da[D5], 8L), " ", hex(r.da[D6], 8L), " ", hex(r.da[D7], 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.t ? "T" : "t",
r.s ? "S" : "s", r.s ? "S" : "s",
(uint)r.i, (uint)r.i,
@ -86,27 +86,35 @@ auto M68K::disassembleRegisters() -> string {
r.z ? "Z" : "z", r.z ? "Z" : "z",
r.n ? "N" : "n", r.n ? "N" : "n",
r.x ? "X" : "x", "\n", r.x ? "X" : "x", "\n",
hex(r.da[A0], 8L), " ", hex(r.da[A1], 8L), " ", hex(r.da[A2], 8L), " ", hex(r.da[A3], 8L), " ", hex(r.a[0], 8L), " ", hex(r.a[1], 8L), " ", hex(r.a[2], 8L), " ", hex(r.a[3], 8L), " ",
hex(r.da[A4], 8L), " ", hex(r.da[A5], 8L), " ", hex(r.da[A6], 8L), " ", hex(r.da[A7], 8L), " ", hex(r.sp, 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)
}; };
} }
// //
template<uint Size> auto M68K::disassembleADD(Register rd, uint1 direction, EA ea) -> string { template<uint Size> auto M68K::disassembleADD(DataRegister dr, uint1 direction, EffectiveAddress ea) -> string {
string op{"add", _suffix<Size>(), " "}; string op{"add", _suffix<Size>(), " "};
if(direction == 0) { if(direction == 0) {
return {op, _read<Size>(ea), ",", _register(rd)}; return {op, _read<Size>(ea), ",", _register(dr)};
} else { } else {
return {op, "", _register(rd), ",", _read<Size>(ea)}; return {op, "", _register(dr), ",", _read<Size>(ea)};
} }
} }
template<uint Size> auto M68K::disassembleANDI(EA ea) -> string { template<uint Size> auto M68K::disassembleANDI(EffectiveAddress ea) -> string {
return {"andi", _suffix<Size>(), " ", _immediate<Size>(), ",", _read<Size>(ea)}; return {"andi", _suffix<Size>(), " ", _immediate<Size>(), ",", _read<Size>(ea)};
} }
auto M68K::disassembleANDI_TO_CCR() -> string {
return {"andi ", _immediate<Byte>(), ",ccr"};
}
auto M68K::disassembleANDI_TO_SR() -> string {
return {"andi ", _immediate<Word>(), ",sr"};
}
auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string { auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string {
auto cc = _condition(condition); auto cc = _condition(condition);
if(condition == 0) cc = "ra"; if(condition == 0) cc = "ra";
@ -114,46 +122,57 @@ auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string {
return {"b", cc, " ", _branch(displacement)}; return {"b", cc, " ", _branch(displacement)};
} }
template<uint Size> auto M68K::disassembleBTST(Register rd, EA ea) -> string { template<uint Size> auto M68K::disassembleBTST(DataRegister dr, EffectiveAddress ea) -> string {
return {"btst ", _register(rd), ",", _read<Size>(ea)}; return {"btst ", _register(dr), ",", _read<Size>(ea)};
} }
template<uint Size> auto M68K::disassembleBTST(EA ea) -> string { template<uint Size> auto M68K::disassembleBTST(EffectiveAddress ea) -> string {
return {"btst ", _immediate<Byte>(), ",", _read<Size>(ea)}; return {"btst ", _immediate<Byte>(), ",", _read<Size>(ea)};
} }
template<uint Size> auto M68K::disassembleCLR(EA ea) -> string { template<uint Size> auto M68K::disassembleCLR(EffectiveAddress ea) -> string {
return {"clr", _suffix<Size>(), " ", _read<Size>(ea)}; return {"clr", _suffix<Size>(), " ", _read<Size>(ea)};
} }
template<uint Size> auto M68K::disassembleCMP(Register rd, EA ea) -> string { template<uint Size> auto M68K::disassembleCMP(DataRegister dr, EffectiveAddress ea) -> string {
return {"cmp", _suffix<Size>(), " ", _read<Word>(ea), ",", _register(rd)}; return {"cmp", _suffix<Size>(), " ", _read<Word>(ea), ",", _register(dr)};
} }
auto M68K::disassembleDBCC(uint4 condition, Register rd) -> string { auto M68K::disassembleDBCC(uint4 condition, DataRegister dr) -> string {
auto base = _pc; auto base = _pc;
auto displacement = (int16)_readPC(); auto displacement = (int16)_readPC();
return {"db", _condition(condition), " ", _register(rd), ",$", hex(base + displacement, 6L)}; return {"db", _condition(condition), " ", _register(dr), ",$", hex(base + displacement, 6L)};
} }
auto M68K::disassembleLEA(Register ra, EA ea) -> string { auto M68K::disassembleEORI_TO_CCR() -> string {
return {"lea ", _address<Long>(ea), ",", _register(ra)}; return {"eori ", _immediate<Byte>(), ",ccr"};
} }
template<uint Size> auto M68K::disassembleMOVE(EA to, EA from) -> string { auto M68K::disassembleEORI_TO_SR() -> string {
return {"eori ", _immediate<Word>(), ",sr"};
}
auto M68K::disassembleLEA(AddressRegister ar, EffectiveAddress ea) -> string {
return {"lea ", _address<Long>(ea), ",", _register(ar)};
}
template<uint Size> auto M68K::disassembleMOVE(EffectiveAddress to, EffectiveAddress from) -> string {
return {"move", _suffix<Size>(), " ", _read<Size>(from), ",", _write<Size>(to)}; return {"move", _suffix<Size>(), " ", _read<Size>(from), ",", _write<Size>(to)};
} }
template<uint Size> auto M68K::disassembleMOVEA(Register ra, EA ea) -> string { template<uint Size> auto M68K::disassembleMOVEA(AddressRegister ar, EffectiveAddress ea) -> string {
return {"movea ", _read<Size>(ea), ",", _register(ra)}; return {"movea ", _read<Size>(ea), ",", _register(ar)};
} }
template<uint Size> auto M68K::disassembleMOVEM(uint1 direction, EA ea) -> string { template<uint Size> auto M68K::disassembleMOVEM(uint1 direction, EffectiveAddress ea) -> string {
string op{"movem", _suffix<Size>(), " "}; string op{"movem", _suffix<Size>(), " "};
uint16 list = _readPC(); uint16 list = _readPC();
string regs; string regs;
for(uint rn : range(16)) if(list.bit(rn)) regs.append(_register(Register{rn}), ","); for(uint n : range(8)) if(list.bit(0 + n)) regs.append(_register(DataRegister{n}), ",");
regs.trimRight(",");
if(regs && list >> 8) regs.append("/");
for(uint n : range(8)) if(list.bit(8 + n)) regs.append(_register(AddressRegister{n}), ",");
regs.trimRight(","); regs.trimRight(",");
if(direction == 0) { if(direction == 0) {
@ -163,23 +182,27 @@ template<uint Size> auto M68K::disassembleMOVEM(uint1 direction, EA ea) -> strin
} }
} }
auto M68K::disassembleMOVEQ(Register rd, uint8 immediate) -> string { auto M68K::disassembleMOVEQ(DataRegister dr, uint8 immediate) -> string {
return {"moveq #$", hex(immediate, 2L), ",", _register(rd)}; return {"moveq #$", hex(immediate, 2L), ",", _register(dr)};
} }
auto M68K::disassembleMOVE_FROM_SR(EA ea) -> string { auto M68K::disassembleMOVE_FROM_SR(EffectiveAddress ea) -> string {
return {"move sr,", _read<Word>(ea)}; return {"move sr,", _read<Word>(ea)};
} }
auto M68K::disassembleMOVE_TO_SR(EA ea) -> string { auto M68K::disassembleMOVE_TO_CCR(EffectiveAddress ea) -> string {
return {"move ", _read<Byte>(ea), ",ccr"};
}
auto M68K::disassembleMOVE_TO_SR(EffectiveAddress ea) -> string {
return {"move ", _read<Word>(ea), ",sr"}; return {"move ", _read<Word>(ea), ",sr"};
} }
auto M68K::disassembleMOVE_USP(uint1 direction, Register ra) -> string { auto M68K::disassembleMOVE_USP(uint1 direction, AddressRegister ar) -> string {
if(direction == 0) { if(direction == 0) {
return {"move ", _register(ra), ",usp"}; return {"move ", _register(ar), ",usp"};
} else { } else {
return {"move usp,", _register(ra)}; return {"move usp,", _register(ar)};
} }
} }
@ -187,10 +210,18 @@ auto M68K::disassembleNOP() -> string {
return {"nop "}; return {"nop "};
} }
auto M68K::disassembleORI_TO_CCR() -> string {
return {"ori ", _immediate<Byte>(), ",ccr"};
}
auto M68K::disassembleORI_TO_SR() -> string {
return {"ori ", _immediate<Word>(), ",sr"};
}
auto M68K::disassembleRTS() -> string { auto M68K::disassembleRTS() -> string {
return {"rts "}; return {"rts "};
} }
template<uint Size> auto M68K::disassembleTST(EA ea) -> string { template<uint Size> auto M68K::disassembleTST(EffectiveAddress ea) -> string {
return {"tst", _suffix<Size>(), " ", _read<Size>(ea)}; return {"tst", _suffix<Size>(), " ", _read<Size>(ea)};
} }

View File

@ -1,37 +1,39 @@
template<uint Size> auto M68K::fetch(EA& ea) -> uint32 { template<uint Size> auto M68K::fetch(EffectiveAddress& ea) -> uint32 {
if(!ea.valid.raise()) return ea.address; if(!ea.valid.raise()) return ea.address;
switch(ea.mode) { switch(ea.mode) {
case DataRegisterDirect: { case DataRegisterDirect: {
return read(ea.reg); return read(DataRegister{ea.reg});
} }
case AddressRegisterDirect: { case AddressRegisterDirect: {
return read(ea.reg); return read(AddressRegister{ea.reg});
} }
case AddressRegisterIndirect: { case AddressRegisterIndirect: {
return read(ea.reg); return read(AddressRegister{ea.reg});
} }
case AddressRegisterIndirectWithPostIncrement: { case AddressRegisterIndirectWithPostIncrement: {
return read(ea.reg); return read(AddressRegister{ea.reg});
} }
case AddressRegisterIndirectWithPreDecrement: { case AddressRegisterIndirectWithPreDecrement: {
return read(ea.reg); return read(AddressRegister{ea.reg});
} }
case AddressRegisterIndirectWithDisplacement: { case AddressRegisterIndirectWithDisplacement: {
return read(ea.reg) + (int16)readPC(); return read(AddressRegister{ea.reg}) + (int16)readPC();
} }
case AddressRegisterIndirectWithIndex: { case AddressRegisterIndirectWithIndex: {
auto extension = readPC(); auto extension = readPC();
auto index = read(Register{extension >> 12}); auto index = extension & 0x8000
? read(AddressRegister{extension >> 12})
: read(DataRegister{extension >> 12});
if(extension & 0x800) index = (int16)index; if(extension & 0x800) index = (int16)index;
return read(ea.reg) + index + (int8)extension; return read(AddressRegister{ea.reg}) + index + (int8)extension;
} }
case AbsoluteShortIndirect: { case AbsoluteShortIndirect: {
@ -50,7 +52,9 @@ template<uint Size> auto M68K::fetch(EA& ea) -> uint32 {
case ProgramCounterIndirectWithIndex: { case ProgramCounterIndirectWithIndex: {
auto base = r.pc; auto base = r.pc;
auto extension = readPC(); auto extension = readPC();
auto index = read(Register{extension >> 12}); auto index = extension & 0x8000
? read(AddressRegister{extension >> 12})
: read(DataRegister{extension >> 12});
if(extension & 0x800) index = (int16)index; if(extension & 0x800) index = (int16)index;
return base + index + (int8)extension; return base + index + (int8)extension;
} }
@ -64,7 +68,7 @@ template<uint Size> auto M68K::fetch(EA& ea) -> uint32 {
return 0; return 0;
} }
template<uint Size, bool Update> auto M68K::read(EA& ea) -> uint32 { template<uint Size, bool Update> auto M68K::read(EffectiveAddress& ea) -> uint32 {
ea.address = fetch<Size>(ea); ea.address = fetch<Size>(ea);
switch(ea.mode) { switch(ea.mode) {
@ -83,13 +87,13 @@ template<uint Size, bool Update> auto M68K::read(EA& ea) -> uint32 {
case AddressRegisterIndirectWithPostIncrement: { case AddressRegisterIndirectWithPostIncrement: {
auto data = read<Size>(ea.address); auto data = read<Size>(ea.address);
if(Update) write(ea.reg, ea.address += (Size == Long ? 4 : 2)); if(Update) write(AddressRegister{ea.reg}, ea.address += (Size == Long ? 4 : 2));
return data; return data;
} }
case AddressRegisterIndirectWithPreDecrement: { case AddressRegisterIndirectWithPreDecrement: {
auto data = read<Size>(ea.address - (Size == Long ? 4 : 2)); auto data = read<Size>(ea.address - (Size == Long ? 4 : 2));
if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2)); if(Update) write(AddressRegister{ea.reg}, ea.address -= (Size == Long ? 4 : 2));
return data; return data;
} }
@ -126,17 +130,17 @@ template<uint Size, bool Update> auto M68K::read(EA& ea) -> uint32 {
return 0; return 0;
} }
template<uint Size, bool Update> auto M68K::write(EA& ea, uint32 data) -> void { template<uint Size, bool Update> auto M68K::write(EffectiveAddress& ea, uint32 data) -> void {
ea.address = fetch<Size>(ea); ea.address = fetch<Size>(ea);
switch(ea.mode) { switch(ea.mode) {
case DataRegisterDirect: { case DataRegisterDirect: {
return write<Size>(ea.reg, data); return write<Size>(DataRegister{ea.reg}, data);
} }
case AddressRegisterDirect: { case AddressRegisterDirect: {
return write<Size>(ea.reg, data); return write<Size>(AddressRegister{ea.reg}, data);
} }
case AddressRegisterIndirect: { case AddressRegisterIndirect: {
@ -145,13 +149,13 @@ template<uint Size, bool Update> auto M68K::write(EA& ea, uint32 data) -> void {
case AddressRegisterIndirectWithPostIncrement: { case AddressRegisterIndirectWithPostIncrement: {
write<Size>(ea.address, data); write<Size>(ea.address, data);
if(Update) write(ea.reg, ea.address += (Size == Long ? 4 : 2)); if(Update) write(AddressRegister{ea.reg}, ea.address += (Size == Long ? 4 : 2));
return; return;
} }
case AddressRegisterIndirectWithPreDecrement: { case AddressRegisterIndirectWithPreDecrement: {
write<Size, Reverse>(ea.address - (Size == Long ? 4 : 2), data); write<Size, Reverse>(ea.address - (Size == Long ? 4 : 2), data);
if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2)); if(Update) write(AddressRegister{ea.reg}, ea.address -= (Size == Long ? 4 : 2));
return; return;
} }
@ -186,16 +190,16 @@ template<uint Size, bool Update> auto M68K::write(EA& ea, uint32 data) -> void {
} }
} }
template<uint Size> auto M68K::flush(EA& ea, uint32 data) -> void { template<uint Size> auto M68K::flush(EffectiveAddress& ea, uint32 data) -> void {
switch(ea.mode) { switch(ea.mode) {
case AddressRegisterIndirectWithPostIncrement: { case AddressRegisterIndirectWithPostIncrement: {
write<Size>(ea.reg, data); write<Size>(AddressRegister{ea.reg}, data);
return; return;
} }
case AddressRegisterIndirectWithPreDecrement: { case AddressRegisterIndirectWithPreDecrement: {
write<Size>(ea.reg, data); write<Size>(AddressRegister{ea.reg}, data);
return; return;
} }

View File

@ -8,9 +8,12 @@ auto M68K::trap() -> void {
auto M68K::instruction() -> void { auto M68K::instruction() -> void {
instructionsExecuted++; instructionsExecuted++;
//print(disassembleRegisters(), "\n");
//print(disassemble(r.pc), "\n"); if(instructionsExecuted >= 20) trap();
//print("\n");
print(disassembleRegisters(), "\n");
print(disassemble(r.pc), "\n");
print("\n");
opcode = readPC(); opcode = readPC();
return instructionTable[opcode](); return instructionTable[opcode]();
@ -39,11 +42,11 @@ M68K::M68K() {
auto opcode = pattern("1101 ---- ++-- ----") | dreg << 9 | direction << 8 | mode << 3 | reg << 0; auto opcode = pattern("1101 ---- ++-- ----") | dreg << 9 | direction << 8 | mode << 3 | reg << 0;
if(direction == 1 && (mode == 0 || mode == 1 || (mode == 7 && reg >= 2))) continue; if(direction == 1 && (mode == 0 || mode == 1 || (mode == 7 && reg >= 2))) continue;
Register rd{D0 + dreg}; DataRegister dr{dreg};
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
bind(opcode | 0 << 6, ADD<Byte>, rd, direction, ea); bind(opcode | 0 << 6, ADD<Byte>, dr, direction, ea);
bind(opcode | 1 << 6, ADD<Word>, rd, direction, ea); bind(opcode | 1 << 6, ADD<Word>, dr, direction, ea);
bind(opcode | 2 << 6, ADD<Long>, rd, direction, ea); bind(opcode | 2 << 6, ADD<Long>, dr, direction, ea);
if(direction == 0 && mode == 1) unbind(opcode | 0 << 6); if(direction == 0 && mode == 1) unbind(opcode | 0 << 6);
} }
@ -54,12 +57,24 @@ M68K::M68K() {
auto opcode = pattern("0000 0010 ++-- ----") | mode << 3 | reg << 0; auto opcode = pattern("0000 0010 ++-- ----") | mode << 3 | reg << 0;
if(mode == 1 || (mode == 7 && reg >= 2)) continue; if(mode == 1 || (mode == 7 && reg >= 2)) continue;
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
bind(opcode | 0 << 6, ANDI<Byte>, ea); bind(opcode | 0 << 6, ANDI<Byte>, ea);
bind(opcode | 1 << 6, ANDI<Word>, ea); bind(opcode | 1 << 6, ANDI<Word>, ea);
bind(opcode | 2 << 6, ANDI<Long>, ea); bind(opcode | 2 << 6, ANDI<Long>, ea);
} }
//ANDI_TO_CCR
{ auto opcode = pattern("0000 0010 0011 1100");
bind(opcode, ANDI_TO_CCR);
}
//ANDI_TO_SR
{ auto opcode = pattern("0000 0010 0111 1100");
bind(opcode, ANDI_TO_SR);
}
//BCC //BCC
for(uint4 condition : range( 16)) for(uint4 condition : range( 16))
for(uint8 displacement : range(256)) { for(uint8 displacement : range(256)) {
@ -75,10 +90,10 @@ M68K::M68K() {
auto opcode = pattern("0000 ---1 00-- ----") | dreg << 9 | mode << 3 | reg << 0; auto opcode = pattern("0000 ---1 00-- ----") | dreg << 9 | mode << 3 | reg << 0;
if(mode == 1) continue; if(mode == 1) continue;
Register rd{D0 + dreg}; DataRegister dr{dreg};
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
if(mode == 0) bind(opcode, BTST<Long>, rd, ea); if(mode == 0) bind(opcode, BTST<Long>, dr, ea);
if(mode != 0) bind(opcode, BTST<Byte>, rd, ea); if(mode != 0) bind(opcode, BTST<Byte>, dr, ea);
} }
//BTST (immediate) //BTST (immediate)
@ -87,7 +102,7 @@ M68K::M68K() {
auto opcode = pattern("0000 1000 00-- ----") | mode << 3 | reg << 0; auto opcode = pattern("0000 1000 00-- ----") | mode << 3 | reg << 0;
if(mode == 1 || (mode == 7 && reg == 2)) continue; if(mode == 1 || (mode == 7 && reg == 2)) continue;
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
if(mode == 0) bind(opcode, BTST<Long>, ea); if(mode == 0) bind(opcode, BTST<Long>, ea);
if(mode != 0) bind(opcode, BTST<Byte>, ea); if(mode != 0) bind(opcode, BTST<Byte>, ea);
} }
@ -98,7 +113,7 @@ M68K::M68K() {
auto opcode = pattern("0100 0010 ++-- ----") | mode << 3 | reg << 0; auto opcode = pattern("0100 0010 ++-- ----") | mode << 3 | reg << 0;
if(mode == 1 || (mode == 7 && reg >= 2)) continue; if(mode == 1 || (mode == 7 && reg >= 2)) continue;
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
bind(opcode | 0 << 6, CLR<Byte>, ea); bind(opcode | 0 << 6, CLR<Byte>, ea);
bind(opcode | 1 << 6, CLR<Word>, ea); bind(opcode | 1 << 6, CLR<Word>, ea);
bind(opcode | 2 << 6, CLR<Long>, ea); bind(opcode | 2 << 6, CLR<Long>, ea);
@ -110,11 +125,11 @@ M68K::M68K() {
for(uint3 reg : range(8)) { for(uint3 reg : range(8)) {
auto opcode = pattern("1011 ---0 ++-- ----") | dreg << 9 | mode << 3 | reg << 0; auto opcode = pattern("1011 ---0 ++-- ----") | dreg << 9 | mode << 3 | reg << 0;
Register rd{D0 + dreg}; DataRegister dr{dreg};
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
bind(opcode | 0 << 6, CMP<Byte>, rd, ea); bind(opcode | 0 << 6, CMP<Byte>, dr, ea);
bind(opcode | 1 << 6, CMP<Word>, rd, ea); bind(opcode | 1 << 6, CMP<Word>, dr, ea);
bind(opcode | 2 << 6, CMP<Long>, rd, ea); bind(opcode | 2 << 6, CMP<Long>, dr, ea);
if(mode == 1) unbind(opcode | 0 << 6); if(mode == 1) unbind(opcode | 0 << 6);
} }
@ -124,8 +139,20 @@ M68K::M68K() {
for(uint3 dreg : range( 8)) { for(uint3 dreg : range( 8)) {
auto opcode = pattern("0101 ---- 1100 1---") | condition << 8 | dreg << 0; auto opcode = pattern("0101 ---- 1100 1---") | condition << 8 | dreg << 0;
Register rd{D0 + dreg}; DataRegister dr{dreg};
bind(opcode, DBCC, condition, rd); bind(opcode, DBCC, condition, dr);
}
//EORI_TO_CCR
{ auto opcode = pattern("0000 1010 0011 1100");
bind(opcode, EORI_TO_CCR);
}
//EORI_TO_SR
{ auto opcode = pattern("0000 1010 0111 1100");
bind(opcode, EORI_TO_SR);
} }
//LEA //LEA
@ -135,9 +162,9 @@ M68K::M68K() {
auto opcode = pattern("0100 ---1 11-- ----") | areg << 9 | mode << 3 | reg << 0; auto opcode = pattern("0100 ---1 11-- ----") | areg << 9 | mode << 3 | reg << 0;
if(mode <= 1 || mode == 3 || mode == 4 || (mode == 7 && reg == 4)) continue; if(mode <= 1 || mode == 3 || mode == 4 || (mode == 7 && reg == 4)) continue;
Register ra{A0 + areg}; AddressRegister ar{areg};
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
bind(opcode, LEA, ra, ea); bind(opcode, LEA, ar, ea);
} }
//MOVE //MOVE
@ -148,8 +175,8 @@ M68K::M68K() {
auto opcode = pattern("00++ ---- ---- ----") | toReg << 9 | toMode << 6 | fromMode << 3 | fromReg << 0; auto opcode = pattern("00++ ---- ---- ----") | toReg << 9 | toMode << 6 | fromMode << 3 | fromReg << 0;
if(toMode == 1 || (toMode == 7 && toReg >= 2)) continue; if(toMode == 1 || (toMode == 7 && toReg >= 2)) continue;
EA to{toMode, toReg}; EffectiveAddress to{toMode, toReg};
EA from{fromMode, fromReg}; EffectiveAddress from{fromMode, fromReg};
bind(opcode | 1 << 12, MOVE<Byte>, to, from); bind(opcode | 1 << 12, MOVE<Byte>, to, from);
bind(opcode | 3 << 12, MOVE<Word>, to, from); bind(opcode | 3 << 12, MOVE<Word>, to, from);
bind(opcode | 2 << 12, MOVE<Long>, to, from); bind(opcode | 2 << 12, MOVE<Long>, to, from);
@ -163,10 +190,10 @@ M68K::M68K() {
for(uint3 reg : range(8)) { for(uint3 reg : range(8)) {
auto opcode = pattern("00++ ---0 01-- ----") | areg << 9 | mode << 3 | reg << 0; auto opcode = pattern("00++ ---0 01-- ----") | areg << 9 | mode << 3 | reg << 0;
Register ra{A0 + areg}; AddressRegister ar{areg};
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
bind(opcode | 3 << 12, MOVEA<Word>, ra, ea); bind(opcode | 3 << 12, MOVEA<Word>, ar, ea);
bind(opcode | 2 << 12, MOVEA<Long>, ra, ea); bind(opcode | 2 << 12, MOVEA<Long>, ar, ea);
} }
//MOVEM //MOVEM
@ -177,7 +204,7 @@ M68K::M68K() {
if(direction == 0 && (mode <= 1 || mode == 3 || (mode == 7 && reg >= 2))); if(direction == 0 && (mode <= 1 || mode == 3 || (mode == 7 && reg >= 2)));
if(direction == 1 && (mode <= 1 || mode == 4 || (mode == 7 && reg == 4))); if(direction == 1 && (mode <= 1 || mode == 4 || (mode == 7 && reg == 4)));
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
bind(opcode | 0 << 6, MOVEM<Word>, direction, ea); bind(opcode | 0 << 6, MOVEM<Word>, direction, ea);
bind(opcode | 1 << 6, MOVEM<Long>, direction, ea); bind(opcode | 1 << 6, MOVEM<Long>, direction, ea);
} }
@ -187,8 +214,8 @@ M68K::M68K() {
for(uint8 immediate : range(256)) { for(uint8 immediate : range(256)) {
auto opcode = pattern("0111 ---0 ---- ----") | dreg << 9 | immediate << 0; auto opcode = pattern("0111 ---0 ---- ----") | dreg << 9 | immediate << 0;
Register rd{D0 + dreg}; DataRegister dr{dreg};
bind(opcode, MOVEQ, rd, immediate); bind(opcode, MOVEQ, dr, immediate);
} }
//MOVE_FROM_SR //MOVE_FROM_SR
@ -197,17 +224,27 @@ M68K::M68K() {
auto opcode = pattern("0100 0000 11-- ----") | mode << 3 | reg << 0; auto opcode = pattern("0100 0000 11-- ----") | mode << 3 | reg << 0;
if(mode == 1 || (mode == 7 && reg >= 2)) continue; if(mode == 1 || (mode == 7 && reg >= 2)) continue;
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
bind(opcode, MOVE_FROM_SR, ea); bind(opcode, MOVE_FROM_SR, ea);
} }
//MOVE_TO_CCR
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("0100 0100 11-- ----") | mode << 3 | reg << 0;
if(mode == 1) continue;
EffectiveAddress ea{mode, reg};
bind(opcode, MOVE_TO_CCR, ea);
}
//MOVE_TO_SR //MOVE_TO_SR
for(uint3 mode : range(8)) for(uint3 mode : range(8))
for(uint3 reg : range(8)) { for(uint3 reg : range(8)) {
auto opcode = pattern("0100 0110 11-- ----") | mode << 3 | reg << 0; auto opcode = pattern("0100 0110 11-- ----") | mode << 3 | reg << 0;
if(mode == 1) continue; if(mode == 1) continue;
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
bind(opcode, MOVE_TO_SR, ea); bind(opcode, MOVE_TO_SR, ea);
} }
@ -216,8 +253,8 @@ M68K::M68K() {
for(uint3 areg : range(8)) { for(uint3 areg : range(8)) {
auto opcode = pattern("0100 1110 0110 ----") | direction << 3 | areg << 0; auto opcode = pattern("0100 1110 0110 ----") | direction << 3 | areg << 0;
Register ra{A0 + areg}; AddressRegister ar{areg};
bind(opcode, MOVE_USP, direction, ra); bind(opcode, MOVE_USP, direction, ar);
} }
//NOP //NOP
@ -226,6 +263,18 @@ M68K::M68K() {
bind(opcode, NOP); bind(opcode, NOP);
} }
//ORI_TO_CCR
{ auto opcode = pattern("0000 0000 0011 1100");
bind(opcode, ORI_TO_CCR);
}
//ORI_TO_SR
{ auto opcode = pattern("0000 0000 0111 1100");
bind(opcode, ORI_TO_SR);
}
//RTS //RTS
{ auto opcode = pattern("0100 1110 0111 0101"); { auto opcode = pattern("0100 1110 0111 0101");
@ -238,7 +287,7 @@ M68K::M68K() {
auto opcode = pattern("0100 1010 ++-- ----") | mode << 3 | reg << 0; auto opcode = pattern("0100 1010 ++-- ----") | mode << 3 | reg << 0;
if(mode == 7 && reg >= 2) continue; if(mode == 7 && reg >= 2) continue;
EA ea{mode, reg}; EffectiveAddress ea{mode, reg};
bind(opcode | 0 << 6, TST<Byte>, ea); bind(opcode | 0 << 6, TST<Byte>, ea);
bind(opcode | 1 << 6, TST<Word>, ea); bind(opcode | 1 << 6, TST<Word>, ea);
bind(opcode | 2 << 6, TST<Long>, ea); bind(opcode | 2 << 6, TST<Long>, ea);

View File

@ -56,18 +56,18 @@ template<uint Size> auto M68K::negative(uint32 result) -> bool {
// //
template<uint Size> auto M68K::instructionADD(Register rd, uint1 direction, EA ea) -> void { template<uint Size> auto M68K::instructionADD(DataRegister dr, uint1 direction, EffectiveAddress ea) -> void {
uint32 source; uint32 source;
uint32 target; uint32 target;
uint32 result; uint32 result;
if(direction == 0) { if(direction == 0) {
source = read<Size>(ea); source = read<Size>(ea);
target = read<Size>(rd); target = read<Size>(dr);
result = source + target; result = source + target;
write<Size>(rd, result); write<Size>(dr, result);
} else { } else {
source = read<Size>(rd); source = read<Size>(dr);
target = read<Size>(ea); target = read<Size>(ea);
result = source + target; result = source + target;
write<Size>(ea, result); write<Size>(ea, result);
@ -80,7 +80,7 @@ template<uint Size> auto M68K::instructionADD(Register rd, uint1 direction, EA e
r.x = r.c; r.x = r.c;
} }
template<uint Size> auto M68K::instructionANDI(EA ea) -> void { template<uint Size> auto M68K::instructionANDI(EffectiveAddress ea) -> void {
auto source = readPC<Size>(); auto source = readPC<Size>();
auto target = read<Size, NoUpdate>(ea); auto target = read<Size, NoUpdate>(ea);
auto result = target & source; auto result = target & source;
@ -92,6 +92,18 @@ template<uint Size> auto M68K::instructionANDI(EA ea) -> void {
r.n = negative<Size>(result); r.n = negative<Size>(result);
} }
auto M68K::instructionANDI_TO_CCR() -> void {
auto data = readPC<Word>();
writeCCR(readCCR() & data);
}
auto M68K::instructionANDI_TO_SR() -> void {
if(!supervisor()) return;
auto data = readPC<Word>();
writeSR(readSR() & data);
}
auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void { auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void {
auto extension = readPC(); auto extension = readPC();
if(condition == 1) push<Long>(r.pc); if(condition == 1) push<Long>(r.pc);
@ -100,15 +112,15 @@ auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void {
r.pc += displacement ? sign<Byte>(displacement) : sign<Word>(extension); r.pc += displacement ? sign<Byte>(displacement) : sign<Word>(extension);
} }
template<uint Size> auto M68K::instructionBTST(Register rd, EA ea) -> void { template<uint Size> auto M68K::instructionBTST(DataRegister dr, EffectiveAddress ea) -> void {
auto bit = read<Size>(rd); auto bit = read<Size>(dr);
auto test = read<Size>(ea); auto test = read<Size>(ea);
bit &= bits<Size>() - 1; bit &= bits<Size>() - 1;
r.z = test.bit(bit) == 0; r.z = test.bit(bit) == 0;
} }
template<uint Size> auto M68K::instructionBTST(EA ea) -> void { template<uint Size> auto M68K::instructionBTST(EffectiveAddress ea) -> void {
auto bit = (uint8)readPC<Word>(); auto bit = (uint8)readPC<Word>();
auto test = read<Size>(ea); auto test = read<Size>(ea);
bit &= bits<Size>() - 1; bit &= bits<Size>() - 1;
@ -116,7 +128,7 @@ template<uint Size> auto M68K::instructionBTST(EA ea) -> void {
r.z = test.bit(bit) == 0; r.z = test.bit(bit) == 0;
} }
template<uint Size> auto M68K::instructionCLR(EA ea) -> void { template<uint Size> auto M68K::instructionCLR(EffectiveAddress ea) -> void {
read<Size>(ea); read<Size>(ea);
write<Size>(ea, 0); write<Size>(ea, 0);
@ -126,9 +138,9 @@ template<uint Size> auto M68K::instructionCLR(EA ea) -> void {
r.n = 0; r.n = 0;
} }
template<uint Size> auto M68K::instructionCMP(Register rd, EA ea) -> void { template<uint Size> auto M68K::instructionCMP(DataRegister dr, EffectiveAddress ea) -> void {
auto source = read<Size>(ea); auto source = read<Size>(ea);
auto target = read<Size>(rd); auto target = read<Size>(dr);
auto result = target - source; auto result = target - source;
r.c = carry<Size>(result, source); r.c = carry<Size>(result, source);
@ -137,20 +149,32 @@ template<uint Size> auto M68K::instructionCMP(Register rd, EA ea) -> void {
r.n = negative<Size>(result); r.n = negative<Size>(result);
} }
auto M68K::instructionDBCC(uint4 condition, Register rd) -> void { auto M68K::instructionDBCC(uint4 condition, DataRegister dr) -> void {
auto displacement = (int16)readPC(); auto displacement = (int16)readPC();
if(!testCondition(condition)) { if(!testCondition(condition)) {
uint16 result = read<Word>(rd); uint16 result = read<Word>(dr);
write<Word>(rd, result - 1); write<Word>(dr, result - 1);
if(result) r.pc -= 2, r.pc += displacement; if(result) r.pc -= 2, r.pc += displacement;
} }
} }
auto M68K::instructionLEA(Register ra, EA ea) -> void { auto M68K::instructionEORI_TO_CCR() -> void {
write<Long>(ra, fetch<Long>(ea)); auto data = readPC<Word>();
writeCCR(readCCR() ^ data);
} }
template<uint Size> auto M68K::instructionMOVE(EA to, EA from) -> void { auto M68K::instructionEORI_TO_SR() -> void {
if(!supervisor()) return;
auto data = readPC<Word>();
writeSR(readSR() ^ data);
}
auto M68K::instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void {
write<Long>(ar, fetch<Long>(ea));
}
template<uint Size> auto M68K::instructionMOVE(EffectiveAddress to, EffectiveAddress from) -> void {
auto data = read<Size>(from); auto data = read<Size>(from);
write<Size>(to, data); write<Size>(to, data);
@ -160,28 +184,32 @@ template<uint Size> auto M68K::instructionMOVE(EA to, EA from) -> void {
r.n = negative<Size>(data); r.n = negative<Size>(data);
} }
template<uint Size> auto M68K::instructionMOVEA(Register ra, EA ea) -> void { template<uint Size> auto M68K::instructionMOVEA(AddressRegister ar, EffectiveAddress ea) -> void {
auto data = read<Size>(ea); auto data = read<Size>(ea);
if(Size == Word) data = (int16)data; write<Long>(ar, data);
write<Long>(ra, data);
} }
template<uint Size> auto M68K::instructionMOVEM(uint1 direction, EA ea) -> void { template<uint Size> auto M68K::instructionMOVEM(uint1 direction, EffectiveAddress ea) -> void {
auto list = readPC(); auto list = readPC();
auto addr = fetch<Size>(ea); auto addr = fetch<Size>(ea);
for(uint rn : range(16)) { for(uint n : range(8)) {
if(list.bit(rn)) { if(!list.bit(0 + n)) continue;
write<Size>(Register{rn}, read<Size>(addr)); write<Size>(DataRegister{n}, read<Size>(addr));
addr += Size == Long ? 4 : 2; addr += Size == Long ? 4 : 2;
} }
for(uint n : range(8)) {
if(!list.bit(8 + n)) continue;
write<Size>(AddressRegister{n}, read<Size>(addr));
addr += Size == Long ? 4 : 2;
} }
flush<Size>(ea, addr); flush<Size>(ea, addr);
} }
auto M68K::instructionMOVEQ(Register rd, uint8 immediate) -> void { auto M68K::instructionMOVEQ(DataRegister dr, uint8 immediate) -> void {
write<Byte>(rd, immediate); write<Byte>(dr, immediate);
r.c = 0; r.c = 0;
r.v = 0; r.v = 0;
@ -189,34 +217,53 @@ auto M68K::instructionMOVEQ(Register rd, uint8 immediate) -> void {
r.n = negative<Byte>(immediate); r.n = negative<Byte>(immediate);
} }
auto M68K::instructionMOVE_FROM_SR(EA ea) -> void { auto M68K::instructionMOVE_FROM_SR(EffectiveAddress ea) -> void {
write<Word>(ea, r.sr); auto data = readSR();
write<Word>(ea, data);
} }
auto M68K::instructionMOVE_TO_SR(EA ea) -> void { auto M68K::instructionMOVE_TO_CCR(EffectiveAddress ea) -> void {
auto data = read<Byte>(ea);
writeCCR(data);
}
auto M68K::instructionMOVE_TO_SR(EffectiveAddress ea) -> void {
if(!supervisor()) return; if(!supervisor()) return;
setSR(read<Word>(ea)); auto data = read<Word>(ea);
writeSR(data);
} }
auto M68K::instructionMOVE_USP(uint1 direction, Register ra) -> void { auto M68K::instructionMOVE_USP(uint1 direction, AddressRegister ar) -> void {
if(!supervisor()) return; if(!supervisor()) return;
if(direction == 0) { if(direction == 0) {
r.sp = read<Long>(ra); r.sp = read<Long>(ar);
} else { } else {
write<Long>(ra, r.sp); write<Long>(ar, r.sp);
} }
} }
auto M68K::instructionNOP() -> void { auto M68K::instructionNOP() -> void {
} }
auto M68K::instructionORI_TO_CCR() -> void {
auto data = readPC<Word>();
writeCCR(readCCR() | data);
}
auto M68K::instructionORI_TO_SR() -> void {
if(!supervisor()) return;
auto data = readPC<Word>();
writeSR(readSR() | data);
}
auto M68K::instructionRTS() -> void { auto M68K::instructionRTS() -> void {
r.pc = pop<Long>(); r.pc = pop<Long>();
} }
template<uint Size> auto M68K::instructionTST(EA ea) -> void { template<uint Size> auto M68K::instructionTST(EffectiveAddress ea) -> void {
auto data = read<Size>(ea); auto data = read<Size>(ea);
r.c = 0; r.c = 0;

View File

@ -8,7 +8,7 @@ enum : bool { Reverse = 1 };
#include "registers.cpp" #include "registers.cpp"
#include "memory.cpp" #include "memory.cpp"
#include "ea.cpp" #include "effective-address.cpp"
#include "instruction.cpp" #include "instruction.cpp"
#include "instructions.cpp" #include "instructions.cpp"
#include "disassembler.cpp" #include "disassembler.cpp"
@ -19,10 +19,19 @@ auto M68K::power() -> void {
auto M68K::reset() -> void { auto M68K::reset() -> void {
instructionsExecuted = 0; instructionsExecuted = 0;
for(auto& da : r.da) da = 0; for(auto& dr : r.d) dr = 0;
for(auto& ar : r.a) ar = 0;
r.sp = 0; r.sp = 0;
r.pc = 0; r.pc = 0;
r.sr = 0x2000;
r.c = 0;
r.v = 0;
r.z = 0;
r.n = 0;
r.x = 0;
r.i = 0;
r.s = 1;
r.t = 0;
} }
auto M68K::supervisor() -> bool { auto M68K::supervisor() -> bool {

View File

@ -8,7 +8,6 @@ struct M68K {
enum : bool { User, Supervisor }; enum : bool { User, Supervisor };
enum : uint { Byte, Word, Long }; enum : uint { Byte, Word, Long };
enum : bool { NoUpdate = 0, Reverse = 1 }; enum : bool { NoUpdate = 0, Reverse = 1 };
enum : uint { D0, D1, D2, D3, D4, D5, D6, D7, A0, A1, A2, A3, A4, A5, A6, A7 };
enum : uint { enum : uint {
DataRegisterDirect, DataRegisterDirect,
@ -36,15 +35,24 @@ struct M68K {
auto supervisor() -> bool; auto supervisor() -> bool;
//registers.cpp //registers.cpp
struct Register { struct DataRegister {
explicit Register(uint number_) : number(number_) {} explicit DataRegister(uint number_) : number(number_) {}
uint3 number;
uint4 number;
}; };
template<uint Size = Long> auto read(DataRegister reg) -> uint32;
template<uint Size = Long> auto write(DataRegister reg, uint32 data) -> void;
template<uint Size = Long> auto read(Register reg) -> uint32; struct AddressRegister {
template<uint Size = Long> auto write(Register reg, uint32 value) -> void; explicit AddressRegister(uint number_) : number(number_) {}
auto setSR(uint16 sr) -> void; 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 //memory.cpp
template<uint Size> auto read(uint32 addr) -> uint32; template<uint Size> auto read(uint32 addr) -> uint32;
@ -53,24 +61,23 @@ struct M68K {
template<uint Size> auto pop() -> uint32; template<uint Size> auto pop() -> uint32;
template<uint Size> auto push(uint32 data) -> void; template<uint Size> auto push(uint32 data) -> void;
//ea.cpp //effective-address.cpp
struct EA { struct EffectiveAddress {
explicit EA(uint mode_, uint reg_) : mode(mode_), reg(reg_) { explicit EffectiveAddress(uint mode_, uint reg_) : mode(mode_), reg(reg_) {
if(mode == 7) mode += reg.number; //optimization: convert modes {7; 0-4} to {8-11} if(mode == 7) mode += reg; //optimization: convert modes {7; 0-4} to {8-11}
if(mode != 0) reg.number += 8; //optimization: linear index to all registers: d0-d7; a0-a7
} }
uint4 mode; uint4 mode;
Register reg; uint3 reg;
boolean valid; boolean valid;
uint32 address; uint32 address;
}; };
template<uint Size> auto fetch(EA& ea) -> uint32; template<uint Size> auto fetch(EffectiveAddress& ea) -> uint32;
template<uint Size, bool Update = 1> auto read(EA& ea) -> uint32; template<uint Size, bool Update = 1> auto read(EffectiveAddress& ea) -> uint32;
template<uint Size, bool Update = 1> auto write(EA& ea, uint32 data) -> void; template<uint Size, bool Update = 1> auto write(EffectiveAddress& ea, uint32 data) -> void;
template<uint Size> auto flush(EA& ea, uint32 data) -> void; template<uint Size> auto flush(EffectiveAddress& ea, uint32 data) -> void;
//instruction.cpp //instruction.cpp
auto trap() -> void; auto trap() -> void;
@ -89,48 +96,51 @@ struct M68K {
template<uint Size> auto zero(uint32 result) -> bool; template<uint Size> auto zero(uint32 result) -> bool;
template<uint Size> auto negative(uint32 result) -> bool; template<uint Size> auto negative(uint32 result) -> bool;
template<uint Size> auto instructionADD(Register rd, uint1 direction, EA ea) -> void; template<uint Size> auto instructionADD(DataRegister dr, uint1 direction, EffectiveAddress ea) -> void;
template<uint Size> auto instructionANDI(EA ea) -> void; template<uint Size> auto instructionANDI(EffectiveAddress ea) -> void;
auto instructionANDI_TO_CCR() -> void;
auto instructionANDI_TO_SR() -> void;
auto instructionBCC(uint4 condition, uint8 displacement) -> void; auto instructionBCC(uint4 condition, uint8 displacement) -> void;
template<uint Size> auto instructionBTST(Register rd, EA ea) -> void; template<uint Size> auto instructionBTST(DataRegister dr, EffectiveAddress ea) -> void;
template<uint Size> auto instructionBTST(EA ea) -> void; template<uint Size> auto instructionBTST(EffectiveAddress ea) -> void;
template<uint Size> auto instructionCLR(EA ea) -> void; template<uint Size> auto instructionCLR(EffectiveAddress ea) -> void;
template<uint Size> auto instructionCMP(Register rd, EA ea) -> void; template<uint Size> auto instructionCMP(DataRegister dr, EffectiveAddress ea) -> void;
auto instructionDBCC(uint4 condition, Register rd) -> void; auto instructionDBCC(uint4 condition, DataRegister dr) -> void;
auto instructionLEA(Register ra, EA ea) -> void; auto instructionEORI_TO_CCR() -> void;
template<uint Size> auto instructionMOVE(EA to, EA from) -> void; auto instructionEORI_TO_SR() -> void;
template<uint Size> auto instructionMOVEA(Register ra, EA ea) -> void; auto instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void;
template<uint Size> auto instructionMOVEM(uint1 direction, EA ea) -> void; template<uint Size> auto instructionMOVE(EffectiveAddress to, EffectiveAddress from) -> void;
auto instructionMOVEQ(Register rd, uint8 immediate) -> void; template<uint Size> auto instructionMOVEA(AddressRegister ar, EffectiveAddress ea) -> void;
auto instructionMOVE_FROM_SR(EA ea) -> void; template<uint Size> auto instructionMOVEM(uint1 direction, EffectiveAddress ea) -> void;
auto instructionMOVE_TO_SR(EA ea) -> void; auto instructionMOVEQ(DataRegister dr, uint8 immediate) -> void;
auto instructionMOVE_USP(uint1 direction, Register ra) -> void; auto instructionMOVE_FROM_SR(EffectiveAddress ea) -> void;
auto instructionMOVE_TO_CCR(EffectiveAddress ea) -> void;
auto instructionMOVE_TO_SR(EffectiveAddress ea) -> void;
auto instructionMOVE_USP(uint1 direction, AddressRegister ar) -> void;
auto instructionNOP() -> void; auto instructionNOP() -> void;
auto instructionORI_TO_CCR() -> void;
auto instructionORI_TO_SR() -> void;
auto instructionRTS() -> void; auto instructionRTS() -> void;
template<uint Size> auto instructionTST(EA ea) -> void; template<uint Size> auto instructionTST(EffectiveAddress ea) -> void;
//disassembler.cpp //disassembler.cpp
auto disassemble(uint32 pc) -> string; auto disassemble(uint32 pc) -> string;
auto disassembleRegisters() -> string; auto disassembleRegisters() -> string;
struct Registers { struct Registers {
uint32 da[16]; //a7 = primary stack pointer uint32 d[8];
uint32 sp; //sp = secondary stack pointer uint32 a[8];
uint32 sp;
uint32 pc; uint32 pc;
union { bool c; //carry
uint16 sr; bool v; //overflow
BooleanBitField<uint16_t, 0> c; //carry bool z; //zero
BooleanBitField<uint16_t, 1> v; //overflow bool n; //negative
BooleanBitField<uint16_t, 2> z; //zero bool x; //extend
BooleanBitField<uint16_t, 3> n; //negative uint3 i; //interrupt mask
BooleanBitField<uint16_t, 4> x; //extend bool s; //supervisor mode
NaturalBitField<uint16_t,8,10> i; //interrupt mask bool t; //trace mode
BooleanBitField<uint16_t, 13> s; //supervisor mode
BooleanBitField<uint16_t, 15> t; //trace mode
};
Registers() : sr(0) {}
} r; } r;
uint16 opcode = 0; uint16 opcode = 0;
@ -140,33 +150,41 @@ struct M68K {
private: private:
//disassembler.cpp //disassembler.cpp
template<uint Size> auto disassembleADD(Register rd, uint1 direction, EA ea) -> string; template<uint Size> auto disassembleADD(DataRegister dr, uint1 direction, EffectiveAddress ea) -> string;
template<uint Size> auto disassembleANDI(EA ea) -> string; template<uint Size> auto disassembleANDI(EffectiveAddress ea) -> string;
auto disassembleANDI_TO_CCR() -> string;
auto disassembleANDI_TO_SR() -> string;
auto disassembleBCC(uint4 condition, uint8 displacement) -> string; auto disassembleBCC(uint4 condition, uint8 displacement) -> string;
template<uint Size> auto disassembleBTST(Register rd, EA ea) -> string; template<uint Size> auto disassembleBTST(DataRegister dr, EffectiveAddress ea) -> string;
template<uint Size> auto disassembleBTST(EA ea) -> string; template<uint Size> auto disassembleBTST(EffectiveAddress ea) -> string;
template<uint Size> auto disassembleCLR(EA ea) -> string; template<uint Size> auto disassembleCLR(EffectiveAddress ea) -> string;
template<uint Size> auto disassembleCMP(Register rd, EA ea) -> string; template<uint Size> auto disassembleCMP(DataRegister dr, EffectiveAddress ea) -> string;
auto disassembleDBCC(uint4 condition, Register rd) -> string; auto disassembleDBCC(uint4 condition, DataRegister dr) -> string;
auto disassembleLEA(Register ra, EA ea) -> string; auto disassembleEORI_TO_CCR() -> string;
template<uint Size> auto disassembleMOVE(EA to, EA from) -> string; auto disassembleEORI_TO_SR() -> string;
template<uint Size> auto disassembleMOVEA(Register ra, EA ea) -> string; auto disassembleLEA(AddressRegister ar, EffectiveAddress ea) -> string;
template<uint Size> auto disassembleMOVEM(uint1 direction, EA ea) -> string; template<uint Size> auto disassembleMOVE(EffectiveAddress to, EffectiveAddress from) -> string;
auto disassembleMOVEQ(Register rd, uint8 immediate) -> string; template<uint Size> auto disassembleMOVEA(AddressRegister ar, EffectiveAddress ea) -> string;
auto disassembleMOVE_FROM_SR(EA ea) -> string; template<uint Size> auto disassembleMOVEM(uint1 direction, EffectiveAddress ea) -> string;
auto disassembleMOVE_TO_SR(EA ea) -> string; auto disassembleMOVEQ(DataRegister dr, uint8 immediate) -> string;
auto disassembleMOVE_USP(uint1 direction, Register ra) -> string; auto disassembleMOVE_FROM_SR(EffectiveAddress ea) -> string;
auto disassembleMOVE_TO_CCR(EffectiveAddress ea) -> string;
auto disassembleMOVE_TO_SR(EffectiveAddress ea) -> string;
auto disassembleMOVE_USP(uint1 direction, AddressRegister ar) -> string;
auto disassembleNOP() -> string; auto disassembleNOP() -> string;
auto disassembleORI_TO_CCR() -> string;
auto disassembleORI_TO_SR() -> string;
auto disassembleRTS() -> string; auto disassembleRTS() -> string;
template<uint Size> auto disassembleTST(EA ea) -> string; template<uint Size> auto disassembleTST(EffectiveAddress ea) -> string;
template<uint Size> auto _read(uint32 addr) -> uint32; template<uint Size> auto _read(uint32 addr) -> uint32;
template<uint Size = Word> auto _readPC() -> uint32; template<uint Size = Word> auto _readPC() -> uint32;
auto _register(Register r) -> string; auto _register(DataRegister dr) -> string;
auto _register(AddressRegister ar) -> string;
template<uint Size> auto _immediate() -> string; template<uint Size> auto _immediate() -> string;
template<uint Size> auto _address(EA ea) -> string; template<uint Size> auto _address(EffectiveAddress& ea) -> string;
template<uint Size> auto _read(EA ea) -> string; template<uint Size> auto _read(EffectiveAddress& ea) -> string;
template<uint Size> auto _write(EA ea) -> string; template<uint Size> auto _write(EffectiveAddress& ea) -> string;
auto _branch(uint8 displacement) -> string; auto _branch(uint8 displacement) -> string;
template<uint Size> auto _suffix() -> string; template<uint Size> auto _suffix() -> string;
auto _condition(uint4 condition) -> string; auto _condition(uint4 condition) -> string;

View File

@ -80,12 +80,12 @@ template<> auto M68K::readPC<Long>() -> uint32 {
// //
template<uint Size> auto M68K::pop() -> uint32 { template<uint Size> auto M68K::pop() -> uint32 {
auto data = read<Size>((uint32)r.da[A7]); auto data = read<Size>((uint32)r.a[7]);
r.da[A7] += Size == Long ? 4 : 2; r.a[7] += Size == Long ? 4 : 2;
return data; return data;
} }
template<uint Size> auto M68K::push(uint32 data) -> void { template<uint Size> auto M68K::push(uint32 data) -> void {
r.da[A7] -= Size == Long ? 4 : 2; r.a[7] -= Size == Long ? 4 : 2;
return write<Size, Reverse>((uint32)r.da[A7], data); return write<Size, Reverse>((uint32)r.a[7], data);
} }

View File

@ -1,13 +1,48 @@
template<uint Size> auto M68K::read(Register reg) -> uint32 { template<uint Size> auto M68K::read(DataRegister reg) -> uint32 {
return clip<Size>(r.da[reg.number]); return clip<Size>(r.d[reg.number]);
} }
template<uint Size> auto M68K::write(Register reg, uint32 data) -> void { template<uint Size> auto M68K::write(DataRegister reg, uint32 data) -> void {
r.da[reg.number] = (r.da[reg.number] & ~mask<Size>()) | (data & mask<Size>()); r.d[reg.number] = (r.d[reg.number] & ~mask<Size>()) | (data & mask<Size>());
} }
auto M68K::setSR(uint16 sr) -> void { //
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 //when entering or exiting supervisor mode; swap SSP and USP into A7
if(r.sr.bit(13) != sr.bit(13)) swap(r.da[A7], r.sp); if(r.s != sr.bit(13)) swap(r.a[7], r.sp);
r.sr = sr;
r.i = sr.bits(8,10);
r.s = sr.bit(13);
r.t = sr.bit(15);
} }