mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
4b897ba791
commit
7ccfbe0206
|
@ -11,7 +11,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
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 License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -10,8 +10,8 @@ auto CPU::Enter() -> void {
|
|||
}
|
||||
|
||||
auto CPU::boot() -> void {
|
||||
r.da[A7] = read(1, 0) << 16 | read(1, 2) << 0;
|
||||
r.pc = read(1, 4) << 16 | read(1, 6) << 0;
|
||||
r.a[7] = read(1, 0) << 16 | read(1, 2) << 0;
|
||||
r.pc = read(1, 4) << 16 | read(1, 6) << 0;
|
||||
}
|
||||
|
||||
auto CPU::main() -> void {
|
||||
|
|
|
@ -17,36 +17,36 @@ template<uint Size> auto M68K::_readPC() -> uint32 {
|
|||
return clip<Size>(data);
|
||||
}
|
||||
|
||||
auto M68K::_register(Register r) -> string {
|
||||
static const string registers[16] = {
|
||||
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
|
||||
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
|
||||
};
|
||||
return registers[r.number];
|
||||
auto M68K::_register(DataRegister dr) -> string {
|
||||
return {"d", dr.number};
|
||||
}
|
||||
|
||||
auto M68K::_register(AddressRegister ar) -> string {
|
||||
return {"a", ar.number};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::_immediate() -> string {
|
||||
return {"#$", hex(_readPC<Size>(), 2 << Size)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::_address(EA ea) -> string {
|
||||
template<uint Size> auto M68K::_address(EffectiveAddress& ea) -> string {
|
||||
if(ea.mode == 9) return {"$", hex(_pc + (int16)_readPC(), 6L)};
|
||||
return "???";
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::_read(EA ea) -> string {
|
||||
if(ea.mode == 0) return {_register(ea.reg)};
|
||||
if(ea.mode == 1) return {_register(ea.reg)};
|
||||
if(ea.mode == 2) return {"(", _register(ea.reg), ")"};
|
||||
if(ea.mode == 3) return {"(", _register(ea.reg), ")+"};
|
||||
if(ea.mode == 4) return {"-(", _register(ea.reg), ")"};
|
||||
if(ea.mode == 5) return {"($", hex(read(ea.reg) + (int16)_readPC(), 6L), ")"};
|
||||
template<uint Size> auto M68K::_read(EffectiveAddress& ea) -> string {
|
||||
if(ea.mode == 0) return {_register(DataRegister{ea.reg})};
|
||||
if(ea.mode == 1) return {_register(AddressRegister{ea.reg})};
|
||||
if(ea.mode == 2) return {"(", _register(AddressRegister{ea.reg}), ")"};
|
||||
if(ea.mode == 3) return {"(", _register(AddressRegister{ea.reg}), ")+"};
|
||||
if(ea.mode == 4) return {"-(", _register(AddressRegister{ea.reg}), ")"};
|
||||
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 == 11) return {"#$", hex(_readPC<Size>(), 2 << Size)};
|
||||
return "???";
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::_write(EA ea) -> string {
|
||||
template<uint Size> auto M68K::_write(EffectiveAddress& ea) -> string {
|
||||
return _read<Size>(ea);
|
||||
}
|
||||
|
||||
|
@ -76,8 +76,8 @@ auto M68K::disassemble(uint32 pc) -> string {
|
|||
|
||||
auto M68K::disassembleRegisters() -> string {
|
||||
return {
|
||||
hex(r.da[D0], 8L), " ", hex(r.da[D1], 8L), " ", hex(r.da[D2], 8L), " ", hex(r.da[D3], 8L), " ",
|
||||
hex(r.da[D4], 8L), " ", hex(r.da[D5], 8L), " ", hex(r.da[D6], 8L), " ", hex(r.da[D7], 8L), " ",
|
||||
hex(r.d[0], 8L), " ", hex(r.d[1], 8L), " ", hex(r.d[2], 8L), " ", hex(r.d[3], 8L), " ",
|
||||
hex(r.d[4], 8L), " ", hex(r.d[5], 8L), " ", hex(r.d[6], 8L), " ", hex(r.d[7], 8L), " ",
|
||||
r.t ? "T" : "t",
|
||||
r.s ? "S" : "s",
|
||||
(uint)r.i,
|
||||
|
@ -86,27 +86,35 @@ auto M68K::disassembleRegisters() -> string {
|
|||
r.z ? "Z" : "z",
|
||||
r.n ? "N" : "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.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[0], 8L), " ", hex(r.a[1], 8L), " ", hex(r.a[2], 8L), " ", hex(r.a[3], 8L), " ",
|
||||
hex(r.a[4], 8L), " ", hex(r.a[5], 8L), " ", hex(r.a[6], 8L), " ", hex(r.a[7], 8L), " ", hex(r.sp, 8L)
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
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>(), " "};
|
||||
|
||||
if(direction == 0) {
|
||||
return {op, _read<Size>(ea), ",", _register(rd)};
|
||||
return {op, _read<Size>(ea), ",", _register(dr)};
|
||||
} 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)};
|
||||
}
|
||||
|
||||
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 cc = _condition(condition);
|
||||
if(condition == 0) cc = "ra";
|
||||
|
@ -114,46 +122,57 @@ auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string {
|
|||
return {"b", cc, " ", _branch(displacement)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleBTST(Register rd, EA ea) -> string {
|
||||
return {"btst ", _register(rd), ",", _read<Size>(ea)};
|
||||
template<uint Size> auto M68K::disassembleBTST(DataRegister dr, EffectiveAddress ea) -> string {
|
||||
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)};
|
||||
}
|
||||
|
||||
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)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleCMP(Register rd, EA ea) -> string {
|
||||
return {"cmp", _suffix<Size>(), " ", _read<Word>(ea), ",", _register(rd)};
|
||||
template<uint Size> auto M68K::disassembleCMP(DataRegister dr, EffectiveAddress ea) -> string {
|
||||
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 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 {
|
||||
return {"lea ", _address<Long>(ea), ",", _register(ra)};
|
||||
auto M68K::disassembleEORI_TO_CCR() -> string {
|
||||
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)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleMOVEA(Register ra, EA ea) -> string {
|
||||
return {"movea ", _read<Size>(ea), ",", _register(ra)};
|
||||
template<uint Size> auto M68K::disassembleMOVEA(AddressRegister ar, EffectiveAddress ea) -> string {
|
||||
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>(), " "};
|
||||
|
||||
uint16 list = _readPC();
|
||||
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(",");
|
||||
|
||||
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 {
|
||||
return {"moveq #$", hex(immediate, 2L), ",", _register(rd)};
|
||||
auto M68K::disassembleMOVEQ(DataRegister dr, uint8 immediate) -> string {
|
||||
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)};
|
||||
}
|
||||
|
||||
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"};
|
||||
}
|
||||
|
||||
auto M68K::disassembleMOVE_USP(uint1 direction, Register ra) -> string {
|
||||
auto M68K::disassembleMOVE_USP(uint1 direction, AddressRegister ar) -> string {
|
||||
if(direction == 0) {
|
||||
return {"move ", _register(ra), ",usp"};
|
||||
return {"move ", _register(ar), ",usp"};
|
||||
} else {
|
||||
return {"move usp,", _register(ra)};
|
||||
return {"move usp,", _register(ar)};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,10 +210,18 @@ auto M68K::disassembleNOP() -> string {
|
|||
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 {
|
||||
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)};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
switch(ea.mode) {
|
||||
|
||||
case DataRegisterDirect: {
|
||||
return read(ea.reg);
|
||||
return read(DataRegister{ea.reg});
|
||||
}
|
||||
|
||||
case AddressRegisterDirect: {
|
||||
return read(ea.reg);
|
||||
return read(AddressRegister{ea.reg});
|
||||
}
|
||||
|
||||
case AddressRegisterIndirect: {
|
||||
return read(ea.reg);
|
||||
return read(AddressRegister{ea.reg});
|
||||
}
|
||||
|
||||
case AddressRegisterIndirectWithPostIncrement: {
|
||||
return read(ea.reg);
|
||||
return read(AddressRegister{ea.reg});
|
||||
}
|
||||
|
||||
case AddressRegisterIndirectWithPreDecrement: {
|
||||
return read(ea.reg);
|
||||
return read(AddressRegister{ea.reg});
|
||||
}
|
||||
|
||||
case AddressRegisterIndirectWithDisplacement: {
|
||||
return read(ea.reg) + (int16)readPC();
|
||||
return read(AddressRegister{ea.reg}) + (int16)readPC();
|
||||
}
|
||||
|
||||
case AddressRegisterIndirectWithIndex: {
|
||||
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;
|
||||
return read(ea.reg) + index + (int8)extension;
|
||||
return read(AddressRegister{ea.reg}) + index + (int8)extension;
|
||||
}
|
||||
|
||||
case AbsoluteShortIndirect: {
|
||||
|
@ -50,7 +52,9 @@ template<uint Size> auto M68K::fetch(EA& ea) -> uint32 {
|
|||
case ProgramCounterIndirectWithIndex: {
|
||||
auto base = r.pc;
|
||||
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;
|
||||
return base + index + (int8)extension;
|
||||
}
|
||||
|
@ -64,7 +68,7 @@ template<uint Size> auto M68K::fetch(EA& ea) -> uint32 {
|
|||
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);
|
||||
|
||||
switch(ea.mode) {
|
||||
|
@ -83,13 +87,13 @@ template<uint Size, bool Update> auto M68K::read(EA& ea) -> uint32 {
|
|||
|
||||
case AddressRegisterIndirectWithPostIncrement: {
|
||||
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;
|
||||
}
|
||||
|
||||
case AddressRegisterIndirectWithPreDecrement: {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -126,17 +130,17 @@ template<uint Size, bool Update> auto M68K::read(EA& ea) -> uint32 {
|
|||
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);
|
||||
|
||||
switch(ea.mode) {
|
||||
|
||||
case DataRegisterDirect: {
|
||||
return write<Size>(ea.reg, data);
|
||||
return write<Size>(DataRegister{ea.reg}, data);
|
||||
}
|
||||
|
||||
case AddressRegisterDirect: {
|
||||
return write<Size>(ea.reg, data);
|
||||
return write<Size>(AddressRegister{ea.reg}, data);
|
||||
}
|
||||
|
||||
case AddressRegisterIndirect: {
|
||||
|
@ -145,13 +149,13 @@ template<uint Size, bool Update> auto M68K::write(EA& ea, uint32 data) -> void {
|
|||
|
||||
case AddressRegisterIndirectWithPostIncrement: {
|
||||
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;
|
||||
}
|
||||
|
||||
case AddressRegisterIndirectWithPreDecrement: {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
||||
case AddressRegisterIndirectWithPostIncrement: {
|
||||
write<Size>(ea.reg, data);
|
||||
write<Size>(AddressRegister{ea.reg}, data);
|
||||
return;
|
||||
}
|
||||
|
||||
case AddressRegisterIndirectWithPreDecrement: {
|
||||
write<Size>(ea.reg, data);
|
||||
write<Size>(AddressRegister{ea.reg}, data);
|
||||
return;
|
||||
}
|
||||
|
|
@ -8,9 +8,12 @@ auto M68K::trap() -> void {
|
|||
|
||||
auto M68K::instruction() -> void {
|
||||
instructionsExecuted++;
|
||||
//print(disassembleRegisters(), "\n");
|
||||
//print(disassemble(r.pc), "\n");
|
||||
//print("\n");
|
||||
|
||||
if(instructionsExecuted >= 20) trap();
|
||||
|
||||
print(disassembleRegisters(), "\n");
|
||||
print(disassemble(r.pc), "\n");
|
||||
print("\n");
|
||||
|
||||
opcode = readPC();
|
||||
return instructionTable[opcode]();
|
||||
|
@ -39,11 +42,11 @@ M68K::M68K() {
|
|||
auto opcode = pattern("1101 ---- ++-- ----") | dreg << 9 | direction << 8 | mode << 3 | reg << 0;
|
||||
if(direction == 1 && (mode == 0 || mode == 1 || (mode == 7 && reg >= 2))) continue;
|
||||
|
||||
Register rd{D0 + dreg};
|
||||
EA ea{mode, reg};
|
||||
bind(opcode | 0 << 6, ADD<Byte>, rd, direction, ea);
|
||||
bind(opcode | 1 << 6, ADD<Word>, rd, direction, ea);
|
||||
bind(opcode | 2 << 6, ADD<Long>, rd, direction, ea);
|
||||
DataRegister dr{dreg};
|
||||
EffectiveAddress ea{mode, reg};
|
||||
bind(opcode | 0 << 6, ADD<Byte>, dr, direction, ea);
|
||||
bind(opcode | 1 << 6, ADD<Word>, dr, direction, ea);
|
||||
bind(opcode | 2 << 6, ADD<Long>, dr, direction, ea);
|
||||
|
||||
if(direction == 0 && mode == 1) unbind(opcode | 0 << 6);
|
||||
}
|
||||
|
@ -54,12 +57,24 @@ M68K::M68K() {
|
|||
auto opcode = pattern("0000 0010 ++-- ----") | mode << 3 | reg << 0;
|
||||
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 | 1 << 6, ANDI<Word>, 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
|
||||
for(uint4 condition : range( 16))
|
||||
for(uint8 displacement : range(256)) {
|
||||
|
@ -75,10 +90,10 @@ M68K::M68K() {
|
|||
auto opcode = pattern("0000 ---1 00-- ----") | dreg << 9 | mode << 3 | reg << 0;
|
||||
if(mode == 1) continue;
|
||||
|
||||
Register rd{D0 + dreg};
|
||||
EA ea{mode, reg};
|
||||
if(mode == 0) bind(opcode, BTST<Long>, rd, ea);
|
||||
if(mode != 0) bind(opcode, BTST<Byte>, rd, ea);
|
||||
DataRegister dr{dreg};
|
||||
EffectiveAddress ea{mode, reg};
|
||||
if(mode == 0) bind(opcode, BTST<Long>, dr, ea);
|
||||
if(mode != 0) bind(opcode, BTST<Byte>, dr, ea);
|
||||
}
|
||||
|
||||
//BTST (immediate)
|
||||
|
@ -87,7 +102,7 @@ M68K::M68K() {
|
|||
auto opcode = pattern("0000 1000 00-- ----") | mode << 3 | reg << 0;
|
||||
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<Byte>, ea);
|
||||
}
|
||||
|
@ -98,7 +113,7 @@ M68K::M68K() {
|
|||
auto opcode = pattern("0100 0010 ++-- ----") | mode << 3 | reg << 0;
|
||||
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 | 1 << 6, CLR<Word>, ea);
|
||||
bind(opcode | 2 << 6, CLR<Long>, ea);
|
||||
|
@ -110,11 +125,11 @@ M68K::M68K() {
|
|||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("1011 ---0 ++-- ----") | dreg << 9 | mode << 3 | reg << 0;
|
||||
|
||||
Register rd{D0 + dreg};
|
||||
EA ea{mode, reg};
|
||||
bind(opcode | 0 << 6, CMP<Byte>, rd, ea);
|
||||
bind(opcode | 1 << 6, CMP<Word>, rd, ea);
|
||||
bind(opcode | 2 << 6, CMP<Long>, rd, ea);
|
||||
DataRegister dr{dreg};
|
||||
EffectiveAddress ea{mode, reg};
|
||||
bind(opcode | 0 << 6, CMP<Byte>, dr, ea);
|
||||
bind(opcode | 1 << 6, CMP<Word>, dr, ea);
|
||||
bind(opcode | 2 << 6, CMP<Long>, dr, ea);
|
||||
|
||||
if(mode == 1) unbind(opcode | 0 << 6);
|
||||
}
|
||||
|
@ -124,8 +139,20 @@ M68K::M68K() {
|
|||
for(uint3 dreg : range( 8)) {
|
||||
auto opcode = pattern("0101 ---- 1100 1---") | condition << 8 | dreg << 0;
|
||||
|
||||
Register rd{D0 + dreg};
|
||||
bind(opcode, DBCC, condition, rd);
|
||||
DataRegister dr{dreg};
|
||||
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
|
||||
|
@ -135,9 +162,9 @@ M68K::M68K() {
|
|||
auto opcode = pattern("0100 ---1 11-- ----") | areg << 9 | mode << 3 | reg << 0;
|
||||
if(mode <= 1 || mode == 3 || mode == 4 || (mode == 7 && reg == 4)) continue;
|
||||
|
||||
Register ra{A0 + areg};
|
||||
EA ea{mode, reg};
|
||||
bind(opcode, LEA, ra, ea);
|
||||
AddressRegister ar{areg};
|
||||
EffectiveAddress ea{mode, reg};
|
||||
bind(opcode, LEA, ar, ea);
|
||||
}
|
||||
|
||||
//MOVE
|
||||
|
@ -148,8 +175,8 @@ M68K::M68K() {
|
|||
auto opcode = pattern("00++ ---- ---- ----") | toReg << 9 | toMode << 6 | fromMode << 3 | fromReg << 0;
|
||||
if(toMode == 1 || (toMode == 7 && toReg >= 2)) continue;
|
||||
|
||||
EA to{toMode, toReg};
|
||||
EA from{fromMode, fromReg};
|
||||
EffectiveAddress to{toMode, toReg};
|
||||
EffectiveAddress from{fromMode, fromReg};
|
||||
bind(opcode | 1 << 12, MOVE<Byte>, to, from);
|
||||
bind(opcode | 3 << 12, MOVE<Word>, to, from);
|
||||
bind(opcode | 2 << 12, MOVE<Long>, to, from);
|
||||
|
@ -163,10 +190,10 @@ M68K::M68K() {
|
|||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("00++ ---0 01-- ----") | areg << 9 | mode << 3 | reg << 0;
|
||||
|
||||
Register ra{A0 + areg};
|
||||
EA ea{mode, reg};
|
||||
bind(opcode | 3 << 12, MOVEA<Word>, ra, ea);
|
||||
bind(opcode | 2 << 12, MOVEA<Long>, ra, ea);
|
||||
AddressRegister ar{areg};
|
||||
EffectiveAddress ea{mode, reg};
|
||||
bind(opcode | 3 << 12, MOVEA<Word>, ar, ea);
|
||||
bind(opcode | 2 << 12, MOVEA<Long>, ar, ea);
|
||||
}
|
||||
|
||||
//MOVEM
|
||||
|
@ -177,7 +204,7 @@ M68K::M68K() {
|
|||
if(direction == 0 && (mode <= 1 || mode == 3 || (mode == 7 && reg >= 2)));
|
||||
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 | 1 << 6, MOVEM<Long>, direction, ea);
|
||||
}
|
||||
|
@ -187,8 +214,8 @@ M68K::M68K() {
|
|||
for(uint8 immediate : range(256)) {
|
||||
auto opcode = pattern("0111 ---0 ---- ----") | dreg << 9 | immediate << 0;
|
||||
|
||||
Register rd{D0 + dreg};
|
||||
bind(opcode, MOVEQ, rd, immediate);
|
||||
DataRegister dr{dreg};
|
||||
bind(opcode, MOVEQ, dr, immediate);
|
||||
}
|
||||
|
||||
//MOVE_FROM_SR
|
||||
|
@ -197,17 +224,27 @@ M68K::M68K() {
|
|||
auto opcode = pattern("0100 0000 11-- ----") | mode << 3 | reg << 0;
|
||||
if(mode == 1 || (mode == 7 && reg >= 2)) continue;
|
||||
|
||||
EA ea{mode, reg};
|
||||
EffectiveAddress ea{mode, reg};
|
||||
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
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("0100 0110 11-- ----") | mode << 3 | reg << 0;
|
||||
if(mode == 1) continue;
|
||||
|
||||
EA ea{mode, reg};
|
||||
EffectiveAddress ea{mode, reg};
|
||||
bind(opcode, MOVE_TO_SR, ea);
|
||||
}
|
||||
|
||||
|
@ -216,8 +253,8 @@ M68K::M68K() {
|
|||
for(uint3 areg : range(8)) {
|
||||
auto opcode = pattern("0100 1110 0110 ----") | direction << 3 | areg << 0;
|
||||
|
||||
Register ra{A0 + areg};
|
||||
bind(opcode, MOVE_USP, direction, ra);
|
||||
AddressRegister ar{areg};
|
||||
bind(opcode, MOVE_USP, direction, ar);
|
||||
}
|
||||
|
||||
//NOP
|
||||
|
@ -226,6 +263,18 @@ M68K::M68K() {
|
|||
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
|
||||
{ auto opcode = pattern("0100 1110 0111 0101");
|
||||
|
||||
|
@ -238,7 +287,7 @@ M68K::M68K() {
|
|||
auto opcode = pattern("0100 1010 ++-- ----") | mode << 3 | reg << 0;
|
||||
if(mode == 7 && reg >= 2) continue;
|
||||
|
||||
EA ea{mode, reg};
|
||||
EffectiveAddress ea{mode, reg};
|
||||
bind(opcode | 0 << 6, TST<Byte>, ea);
|
||||
bind(opcode | 1 << 6, TST<Word>, ea);
|
||||
bind(opcode | 2 << 6, TST<Long>, ea);
|
||||
|
|
|
@ -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 target;
|
||||
uint32 result;
|
||||
|
||||
if(direction == 0) {
|
||||
source = read<Size>(ea);
|
||||
target = read<Size>(rd);
|
||||
target = read<Size>(dr);
|
||||
result = source + target;
|
||||
write<Size>(rd, result);
|
||||
write<Size>(dr, result);
|
||||
} else {
|
||||
source = read<Size>(rd);
|
||||
source = read<Size>(dr);
|
||||
target = read<Size>(ea);
|
||||
result = source + target;
|
||||
write<Size>(ea, result);
|
||||
|
@ -80,7 +80,7 @@ template<uint Size> auto M68K::instructionADD(Register rd, uint1 direction, EA e
|
|||
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 target = read<Size, NoUpdate>(ea);
|
||||
auto result = target & source;
|
||||
|
@ -92,6 +92,18 @@ template<uint Size> auto M68K::instructionANDI(EA ea) -> void {
|
|||
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 extension = readPC();
|
||||
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);
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::instructionBTST(Register rd, EA ea) -> void {
|
||||
auto bit = read<Size>(rd);
|
||||
template<uint Size> auto M68K::instructionBTST(DataRegister dr, EffectiveAddress ea) -> void {
|
||||
auto bit = read<Size>(dr);
|
||||
auto test = read<Size>(ea);
|
||||
bit &= bits<Size>() - 1;
|
||||
|
||||
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 test = read<Size>(ea);
|
||||
bit &= bits<Size>() - 1;
|
||||
|
@ -116,7 +128,7 @@ template<uint Size> auto M68K::instructionBTST(EA ea) -> void {
|
|||
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);
|
||||
write<Size>(ea, 0);
|
||||
|
||||
|
@ -126,9 +138,9 @@ template<uint Size> auto M68K::instructionCLR(EA ea) -> void {
|
|||
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 target = read<Size>(rd);
|
||||
auto target = read<Size>(dr);
|
||||
auto result = target - 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);
|
||||
}
|
||||
|
||||
auto M68K::instructionDBCC(uint4 condition, Register rd) -> void {
|
||||
auto M68K::instructionDBCC(uint4 condition, DataRegister dr) -> void {
|
||||
auto displacement = (int16)readPC();
|
||||
if(!testCondition(condition)) {
|
||||
uint16 result = read<Word>(rd);
|
||||
write<Word>(rd, result - 1);
|
||||
uint16 result = read<Word>(dr);
|
||||
write<Word>(dr, result - 1);
|
||||
if(result) r.pc -= 2, r.pc += displacement;
|
||||
}
|
||||
}
|
||||
|
||||
auto M68K::instructionLEA(Register ra, EA ea) -> void {
|
||||
write<Long>(ra, fetch<Long>(ea));
|
||||
auto M68K::instructionEORI_TO_CCR() -> void {
|
||||
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);
|
||||
write<Size>(to, data);
|
||||
|
||||
|
@ -160,28 +184,32 @@ template<uint Size> auto M68K::instructionMOVE(EA to, EA from) -> void {
|
|||
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);
|
||||
if(Size == Word) data = (int16)data;
|
||||
write<Long>(ra, data);
|
||||
write<Long>(ar, 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 addr = fetch<Size>(ea);
|
||||
|
||||
for(uint rn : range(16)) {
|
||||
if(list.bit(rn)) {
|
||||
write<Size>(Register{rn}, read<Size>(addr));
|
||||
addr += Size == Long ? 4 : 2;
|
||||
}
|
||||
for(uint n : range(8)) {
|
||||
if(!list.bit(0 + n)) continue;
|
||||
write<Size>(DataRegister{n}, read<Size>(addr));
|
||||
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);
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVEQ(Register rd, uint8 immediate) -> void {
|
||||
write<Byte>(rd, immediate);
|
||||
auto M68K::instructionMOVEQ(DataRegister dr, uint8 immediate) -> void {
|
||||
write<Byte>(dr, immediate);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
|
@ -189,34 +217,53 @@ auto M68K::instructionMOVEQ(Register rd, uint8 immediate) -> void {
|
|||
r.n = negative<Byte>(immediate);
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVE_FROM_SR(EA ea) -> void {
|
||||
write<Word>(ea, r.sr);
|
||||
auto M68K::instructionMOVE_FROM_SR(EffectiveAddress ea) -> void {
|
||||
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;
|
||||
|
||||
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(direction == 0) {
|
||||
r.sp = read<Long>(ra);
|
||||
r.sp = read<Long>(ar);
|
||||
} else {
|
||||
write<Long>(ra, r.sp);
|
||||
write<Long>(ar, r.sp);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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);
|
||||
|
||||
r.c = 0;
|
||||
|
|
|
@ -8,7 +8,7 @@ enum : bool { Reverse = 1 };
|
|||
|
||||
#include "registers.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "ea.cpp"
|
||||
#include "effective-address.cpp"
|
||||
#include "instruction.cpp"
|
||||
#include "instructions.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
@ -19,10 +19,19 @@ auto M68K::power() -> void {
|
|||
auto M68K::reset() -> void {
|
||||
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.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 {
|
||||
|
|
|
@ -8,7 +8,6 @@ struct M68K {
|
|||
enum : bool { User, Supervisor };
|
||||
enum : uint { Byte, Word, Long };
|
||||
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 {
|
||||
DataRegisterDirect,
|
||||
|
@ -36,15 +35,24 @@ struct M68K {
|
|||
auto supervisor() -> bool;
|
||||
|
||||
//registers.cpp
|
||||
struct Register {
|
||||
explicit Register(uint number_) : number(number_) {}
|
||||
|
||||
uint4 number;
|
||||
struct DataRegister {
|
||||
explicit DataRegister(uint number_) : number(number_) {}
|
||||
uint3 number;
|
||||
};
|
||||
template<uint Size = Long> auto read(DataRegister reg) -> uint32;
|
||||
template<uint Size = Long> auto write(DataRegister reg, uint32 data) -> void;
|
||||
|
||||
template<uint Size = Long> auto read(Register reg) -> uint32;
|
||||
template<uint Size = Long> auto write(Register reg, uint32 value) -> void;
|
||||
auto setSR(uint16 sr) -> void;
|
||||
struct AddressRegister {
|
||||
explicit AddressRegister(uint number_) : number(number_) {}
|
||||
uint3 number;
|
||||
};
|
||||
template<uint Size = Long> auto read(AddressRegister reg) -> uint32;
|
||||
template<uint Size = Long> auto write(AddressRegister reg, uint32 data) -> void;
|
||||
|
||||
auto readCCR() -> uint8;
|
||||
auto readSR() -> uint16;
|
||||
auto writeCCR(uint8 ccr) -> void;
|
||||
auto writeSR(uint16 sr) -> void;
|
||||
|
||||
//memory.cpp
|
||||
template<uint Size> auto read(uint32 addr) -> uint32;
|
||||
|
@ -53,24 +61,23 @@ struct M68K {
|
|||
template<uint Size> auto pop() -> uint32;
|
||||
template<uint Size> auto push(uint32 data) -> void;
|
||||
|
||||
//ea.cpp
|
||||
struct EA {
|
||||
explicit EA(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 != 0) reg.number += 8; //optimization: linear index to all registers: d0-d7; a0-a7
|
||||
//effective-address.cpp
|
||||
struct EffectiveAddress {
|
||||
explicit EffectiveAddress(uint mode_, uint reg_) : mode(mode_), reg(reg_) {
|
||||
if(mode == 7) mode += reg; //optimization: convert modes {7; 0-4} to {8-11}
|
||||
}
|
||||
|
||||
uint4 mode;
|
||||
Register reg;
|
||||
uint3 reg;
|
||||
|
||||
boolean valid;
|
||||
uint32 address;
|
||||
};
|
||||
|
||||
template<uint Size> auto fetch(EA& ea) -> uint32;
|
||||
template<uint Size, bool Update = 1> auto read(EA& ea) -> uint32;
|
||||
template<uint Size, bool Update = 1> auto write(EA& ea, uint32 data) -> void;
|
||||
template<uint Size> auto flush(EA& ea, uint32 data) -> void;
|
||||
template<uint Size> auto fetch(EffectiveAddress& ea) -> uint32;
|
||||
template<uint Size, bool Update = 1> auto read(EffectiveAddress& ea) -> uint32;
|
||||
template<uint Size, bool Update = 1> auto write(EffectiveAddress& ea, uint32 data) -> void;
|
||||
template<uint Size> auto flush(EffectiveAddress& ea, uint32 data) -> void;
|
||||
|
||||
//instruction.cpp
|
||||
auto trap() -> void;
|
||||
|
@ -89,48 +96,51 @@ struct M68K {
|
|||
template<uint Size> auto zero(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 instructionANDI(EA ea) -> void;
|
||||
template<uint Size> auto instructionADD(DataRegister dr, uint1 direction, EffectiveAddress 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;
|
||||
template<uint Size> auto instructionBTST(Register rd, EA ea) -> void;
|
||||
template<uint Size> auto instructionBTST(EA ea) -> void;
|
||||
template<uint Size> auto instructionCLR(EA ea) -> void;
|
||||
template<uint Size> auto instructionCMP(Register rd, EA ea) -> void;
|
||||
auto instructionDBCC(uint4 condition, Register rd) -> void;
|
||||
auto instructionLEA(Register ra, EA ea) -> void;
|
||||
template<uint Size> auto instructionMOVE(EA to, EA from) -> void;
|
||||
template<uint Size> auto instructionMOVEA(Register ra, EA ea) -> void;
|
||||
template<uint Size> auto instructionMOVEM(uint1 direction, EA ea) -> void;
|
||||
auto instructionMOVEQ(Register rd, uint8 immediate) -> void;
|
||||
auto instructionMOVE_FROM_SR(EA ea) -> void;
|
||||
auto instructionMOVE_TO_SR(EA ea) -> void;
|
||||
auto instructionMOVE_USP(uint1 direction, Register ra) -> void;
|
||||
template<uint Size> auto instructionBTST(DataRegister dr, EffectiveAddress ea) -> void;
|
||||
template<uint Size> auto instructionBTST(EffectiveAddress ea) -> void;
|
||||
template<uint Size> auto instructionCLR(EffectiveAddress ea) -> void;
|
||||
template<uint Size> auto instructionCMP(DataRegister dr, EffectiveAddress ea) -> void;
|
||||
auto instructionDBCC(uint4 condition, DataRegister dr) -> void;
|
||||
auto instructionEORI_TO_CCR() -> void;
|
||||
auto instructionEORI_TO_SR() -> void;
|
||||
auto instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void;
|
||||
template<uint Size> auto instructionMOVE(EffectiveAddress to, EffectiveAddress from) -> void;
|
||||
template<uint Size> auto instructionMOVEA(AddressRegister ar, EffectiveAddress ea) -> void;
|
||||
template<uint Size> auto instructionMOVEM(uint1 direction, EffectiveAddress ea) -> void;
|
||||
auto instructionMOVEQ(DataRegister dr, uint8 immediate) -> void;
|
||||
auto instructionMOVE_FROM_SR(EffectiveAddress ea) -> void;
|
||||
auto instructionMOVE_TO_CCR(EffectiveAddress ea) -> void;
|
||||
auto instructionMOVE_TO_SR(EffectiveAddress ea) -> void;
|
||||
auto instructionMOVE_USP(uint1 direction, AddressRegister ar) -> void;
|
||||
auto instructionNOP() -> void;
|
||||
auto instructionORI_TO_CCR() -> void;
|
||||
auto instructionORI_TO_SR() -> void;
|
||||
auto instructionRTS() -> void;
|
||||
template<uint Size> auto instructionTST(EA ea) -> void;
|
||||
template<uint Size> auto instructionTST(EffectiveAddress ea) -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassemble(uint32 pc) -> string;
|
||||
auto disassembleRegisters() -> string;
|
||||
|
||||
struct Registers {
|
||||
uint32 da[16]; //a7 = primary stack pointer
|
||||
uint32 sp; //sp = secondary stack pointer
|
||||
uint32 d[8];
|
||||
uint32 a[8];
|
||||
uint32 sp;
|
||||
uint32 pc;
|
||||
|
||||
union {
|
||||
uint16 sr;
|
||||
BooleanBitField<uint16_t, 0> c; //carry
|
||||
BooleanBitField<uint16_t, 1> v; //overflow
|
||||
BooleanBitField<uint16_t, 2> z; //zero
|
||||
BooleanBitField<uint16_t, 3> n; //negative
|
||||
BooleanBitField<uint16_t, 4> x; //extend
|
||||
NaturalBitField<uint16_t,8,10> i; //interrupt mask
|
||||
BooleanBitField<uint16_t, 13> s; //supervisor mode
|
||||
BooleanBitField<uint16_t, 15> t; //trace mode
|
||||
};
|
||||
|
||||
Registers() : sr(0) {}
|
||||
bool c; //carry
|
||||
bool v; //overflow
|
||||
bool z; //zero
|
||||
bool n; //negative
|
||||
bool x; //extend
|
||||
uint3 i; //interrupt mask
|
||||
bool s; //supervisor mode
|
||||
bool t; //trace mode
|
||||
} r;
|
||||
|
||||
uint16 opcode = 0;
|
||||
|
@ -140,33 +150,41 @@ struct M68K {
|
|||
|
||||
private:
|
||||
//disassembler.cpp
|
||||
template<uint Size> auto disassembleADD(Register rd, uint1 direction, EA ea) -> string;
|
||||
template<uint Size> auto disassembleANDI(EA ea) -> string;
|
||||
template<uint Size> auto disassembleADD(DataRegister dr, uint1 direction, EffectiveAddress 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;
|
||||
template<uint Size> auto disassembleBTST(Register rd, EA ea) -> string;
|
||||
template<uint Size> auto disassembleBTST(EA ea) -> string;
|
||||
template<uint Size> auto disassembleCLR(EA ea) -> string;
|
||||
template<uint Size> auto disassembleCMP(Register rd, EA ea) -> string;
|
||||
auto disassembleDBCC(uint4 condition, Register rd) -> string;
|
||||
auto disassembleLEA(Register ra, EA ea) -> string;
|
||||
template<uint Size> auto disassembleMOVE(EA to, EA from) -> string;
|
||||
template<uint Size> auto disassembleMOVEA(Register ra, EA ea) -> string;
|
||||
template<uint Size> auto disassembleMOVEM(uint1 direction, EA ea) -> string;
|
||||
auto disassembleMOVEQ(Register rd, uint8 immediate) -> string;
|
||||
auto disassembleMOVE_FROM_SR(EA ea) -> string;
|
||||
auto disassembleMOVE_TO_SR(EA ea) -> string;
|
||||
auto disassembleMOVE_USP(uint1 direction, Register ra) -> string;
|
||||
template<uint Size> auto disassembleBTST(DataRegister dr, EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleBTST(EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleCLR(EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleCMP(DataRegister dr, EffectiveAddress ea) -> string;
|
||||
auto disassembleDBCC(uint4 condition, DataRegister dr) -> string;
|
||||
auto disassembleEORI_TO_CCR() -> string;
|
||||
auto disassembleEORI_TO_SR() -> string;
|
||||
auto disassembleLEA(AddressRegister ar, EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleMOVE(EffectiveAddress to, EffectiveAddress from) -> string;
|
||||
template<uint Size> auto disassembleMOVEA(AddressRegister ar, EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleMOVEM(uint1 direction, EffectiveAddress ea) -> string;
|
||||
auto disassembleMOVEQ(DataRegister dr, uint8 immediate) -> string;
|
||||
auto disassembleMOVE_FROM_SR(EffectiveAddress ea) -> string;
|
||||
auto disassembleMOVE_TO_CCR(EffectiveAddress ea) -> string;
|
||||
auto disassembleMOVE_TO_SR(EffectiveAddress ea) -> string;
|
||||
auto disassembleMOVE_USP(uint1 direction, AddressRegister ar) -> string;
|
||||
auto disassembleNOP() -> string;
|
||||
auto disassembleORI_TO_CCR() -> string;
|
||||
auto disassembleORI_TO_SR() -> 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 = 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 _address(EA ea) -> string;
|
||||
template<uint Size> auto _read(EA ea) -> string;
|
||||
template<uint Size> auto _write(EA ea) -> string;
|
||||
template<uint Size> auto _address(EffectiveAddress& ea) -> string;
|
||||
template<uint Size> auto _read(EffectiveAddress& ea) -> string;
|
||||
template<uint Size> auto _write(EffectiveAddress& ea) -> string;
|
||||
auto _branch(uint8 displacement) -> string;
|
||||
template<uint Size> auto _suffix() -> string;
|
||||
auto _condition(uint4 condition) -> string;
|
||||
|
|
|
@ -80,12 +80,12 @@ template<> auto M68K::readPC<Long>() -> uint32 {
|
|||
//
|
||||
|
||||
template<uint Size> auto M68K::pop() -> uint32 {
|
||||
auto data = read<Size>((uint32)r.da[A7]);
|
||||
r.da[A7] += Size == Long ? 4 : 2;
|
||||
auto data = read<Size>((uint32)r.a[7]);
|
||||
r.a[7] += Size == Long ? 4 : 2;
|
||||
return data;
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::push(uint32 data) -> void {
|
||||
r.da[A7] -= Size == Long ? 4 : 2;
|
||||
return write<Size, Reverse>((uint32)r.da[A7], data);
|
||||
r.a[7] -= Size == Long ? 4 : 2;
|
||||
return write<Size, Reverse>((uint32)r.a[7], data);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,48 @@
|
|||
template<uint Size> auto M68K::read(Register reg) -> uint32 {
|
||||
return clip<Size>(r.da[reg.number]);
|
||||
template<uint Size> auto M68K::read(DataRegister reg) -> uint32 {
|
||||
return clip<Size>(r.d[reg.number]);
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::write(Register reg, uint32 data) -> void {
|
||||
r.da[reg.number] = (r.da[reg.number] & ~mask<Size>()) | (data & mask<Size>());
|
||||
template<uint Size> auto M68K::write(DataRegister reg, uint32 data) -> void {
|
||||
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
|
||||
if(r.sr.bit(13) != sr.bit(13)) swap(r.da[A7], r.sp);
|
||||
r.sr = sr;
|
||||
if(r.s != sr.bit(13)) swap(r.a[7], r.sp);
|
||||
|
||||
r.i = sr.bits(8,10);
|
||||
r.s = sr.bit(13);
|
||||
r.t = sr.bit(15);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue