Update to v100r06 release.

byuu says:

Up to ten 68K instructions out of somewhere between 61 and 88, depending
upon which PDF you look at. Of course, some of them aren't 100% completed
yet, either. Lots of craziness with MOVEM, and BCC has a BSR variant
that needs stack push/pop functions.

This WIP actually took over eight hours to make, going through every
possible permutation on how to design the core itself. The updated design
now builds both the instruction decoder+dispatcher and the disassembler
decoder into the same main loop during M68K's constructor.

The special cases are also really psychotic on this processor, and
I'm afraid of missing something via the fallthrough cases. So instead,
I'm ordering the instructions alphabetically, and including exclusion
cases to ignore binding invalid cases. If I end up remapping an existing
register, then it'll throw a run-time assertion at program startup.

I wanted very much to get rid of struct EA (EffectiveAddress), but
it's too difficult to keep track of the internal effective address
without it. So I split out the size to a separate parameter, since
every opcode only has one size parameter, and otherwise it was getting
duplicated in opcodes that take two EAs, and was also awkward with the
flag testing. It's a bit more typing, but I feel it's more clean this way.

Overall, I'm really worried this is going to be too slow. I don't want
to turn the EA stuff into templates, because that will massively bloat
out compilation times and object sizes, and will also need a special DSL
preprocessor since C++ doesn't have a static for loop. I can definitely
optimize a lot of EA's address/read/write functions away once the core
is completed, but it's never going to hold a candle to a templatized
68K core.

----

Forgot to include the SA-1 regression fix. I always remember immediately
after I upload and archive the WIP. Will try to get that in next time,
I guess.
This commit is contained in:
Tim Allen 2016-07-16 18:39:44 +10:00
parent b72f35a13e
commit 0d6a09f9f8
9 changed files with 493 additions and 278 deletions

View File

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

View File

@ -1,160 +1,163 @@
auto M68K::_readByte(uint32 addr) -> uint8 {
return read(addr);
}
auto M68K::_readWord(uint32 addr) -> uint16 {
uint16 data = _readByte(addr + 0) << 8;
return data |= _readByte(addr + 1) << 0;
}
auto M68K::_readLong(uint32 addr) -> uint32 {
uint32 data = _readWord(addr + 0) << 16;
return data |= _readWord(addr + 2) << 0;
}
auto M68K::_readPC(uint size) -> uint32 {
uint32 data = _readWord(_pc);
_pc += 2;
if(size == Byte) return (uint8)data;
if(size == Word) return data;
data = (data << 16) | _readWord(_pc);
_pc += 2;
return data;
}
auto M68K::_immediate(uint size) -> string {
if(size == Byte) return {"#$", hex(_readPC(Byte), 2L)};
if(size == Word) return {"#$", hex(_readPC(Word), 4L)};
if(size == Long) return {"#$", hex(_readPC(Long), 8L)};
return "#???";
}
auto M68K::_address(uint size, EA& ea) -> string {
if(ea.mode == 7) {
if(ea.reg == 2) return {"$", hex(_pc + (int16)_readPC(Word), 6L)};
}
return "???";
}
auto M68K::_read(uint size, EA& ea) -> string {
if(ea.mode == 0) return {"d", ea.reg};
if(ea.mode == 1) return {"a", ea.reg};
if(ea.mode == 2) return {"(a", ea.reg, ")"};
if(ea.mode == 3) return {"(a", ea.reg, ")+"};
if(ea.mode == 4) return {"-(a", ea.reg, ")"};
if(ea.mode == 5) return {"($", hex(r.a(ea.reg) + (int16)_readPC(Word), 6L), ")"};
if(ea.mode == 7) {
if(ea.reg == 1) return {"($", hex(_readPC(Long), 6L), ")"};
if(ea.reg == 4) {
if(size == Byte) return {"#$", hex(_readPC(Byte), 2L)};
if(size == Word) return {"#$", hex(_readPC(Word), 4L)};
if(size == Long) return {"#$", hex(_readPC(Long), 8L)};
}
}
return "???";
}
auto M68K::_write(uint size, EA& ea) -> string {
return _read(size, ea);
}
auto M68K::_branch(uint displacement) -> string {
uint16 word = _readPC();
if(displacement) displacement = (int8)displacement, _pc -= 2;
else displacement = (int16)displacement;
return {"$", hex(_pc + displacement, 6L)};
}
auto M68K::_suffix(uint size) -> string {
if(size == Byte) return ".b";
if(size == Word) return ".w";
if(size == Long) return ".l";
return ".?";
}
auto M68K::_condition(uint condition) -> string {
static const string conditions[16] = {
"ra", "sr", "hi", "ls", "cc", "cs", "ne", "eq",
"vc", "vs", "pl", "mi", "ge", "lt", "gt", "le",
};
return conditions[(uint4)condition];
}
auto M68K::disassemble(uint32 pc) -> string {
auto readByte = [&](uint32 addr) -> uint8 {
return read(addr);
};
auto readWord = [&](uint32 addr) -> uint16 {
uint16 data = read(addr + 0) << 8;
return data |= read(addr + 1) << 0;
};
auto readLong = [&](uint32 addr) -> uint32 {
uint32 data = readWord(addr + 0) << 16;
return data |= readWord(addr + 2) << 0;
};
auto readWordPC = [&]() -> uint16 {
auto data = readWord(pc);
pc += 2;
return data;
};
auto readLongPC = [&]() -> uint32 {
uint32 data = readWordPC() << 16;
return data |= readWordPC() << 0;
};
auto size = [&](uint2 size) -> string {
if(size == 0) return ".b";
if(size == 1) return ".w";
if(size == 2) return ".l";
return ".?";
};
auto branch = [&](uint8 displacementByte) -> string {
uint16 displacementWord = readWordPC();
if(displacementByte) pc -= 2;
return {"$", hex(pc + (displacementByte ? (int8_t)displacementByte : ((int16_t)displacementWord - 2)), 6L)};
};
auto cc = [&](uint4 condition) -> string {
switch(condition) {
case 0: return "ra";
case 1: return "sr";
case 2: return "hi";
case 3: return "ls";
case 4: return "cc";
case 5: return "cs";
case 6: return "ne";
case 7: return "eq";
case 8: return "vc";
case 9: return "vs";
case 10: return "pl";
case 11: return "mi";
case 12: return "ge";
case 13: return "lt";
case 14: return "gt";
case 15: return "le";
}
unreachable;
};
auto ea = [&](uint2 size, uint3 mode, uint3 reg) -> string {
if(mode == 3) return {"(a", reg, ")+"};
if(mode == 7) {
if(reg == 0) return {"($", hex((int16)readWordPC(), 6L), ")"};
if(reg == 1) return {"($", hex(readLongPC(), 6L), ")"};
if(reg == 2) return {"($", hex(pc + (int16)readWordPC(), 6L), ")"};
}
return "???";
};
auto rd = [&](uint3 reg) -> string {
static const string name[8] = {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"};
return name[reg];
};
auto ra = [&](uint3 reg) -> string {
static const string name[8] = {"a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp"};
return name[reg];
};
string s, name, args;
s.append(hex(pc, 6L), " ");
auto opcode = readWordPC();
s.append(hex(opcode, 4L), " ");
if(0);
#define match(pattern) else if( \
(opcode & std::integral_constant<uint16_t, bit::mask(pattern)>::value) \
== std::integral_constant<uint16_t, bit::test(pattern)>::value \
)
#define bit(n) (opcode >> n & 1)
#define bits(hi, lo) ((opcode >> lo) & ((1 << (hi - lo + 1)) - 1))
//NOP
match("0100 1110 0111 0001") {
name = {"nop"};
}
//MOVEM
match("0100 1-00 1--- ----") {
name = {"movem", size(1 + bit(6))};
bool direction = bit(10);
uint16 list = readWordPC();
string regs;
for(auto n : range(8)) if(list & 1 << (0 + n)) regs.append("d", n, ",");
for(auto n : range(8)) if(list & 1 << (8 + n)) regs.append("a", n, ",");
regs.trimRight(",");
if(direction == 0) {
args = {regs, ",", ea(1 + bit(6), bits(5,3), bits(2,0))};
} else {
args = {ea(1 + bit(6), bits(5,3), bits(2,0)), ",", regs};
}
}
//TST
match("0100 1010 ---- ----") {
name = {"tst", size(bits(7,6))};
args = {ea(bits(7,6), bits(5,3), bits(2,0))};
}
//LEA
match("0100 ---1 11-- ----") {
name = {"lea"};
args = {ea(Long, bits(5,3), bits(2,0)), ",", ra(bits(11,9))};
}
//BCC
match("0110 ---- ---- ----") {
name = {"b", cc(bits(11,8))};
args = {branch(bits(7,0))};
}
#undef match
#undef bit
#undef bits
else {
name = {"???"};
}
s.append(name.size(-8), args);
return s;
uint16 opcode;
return {hex(_pc = pc, 6L), " ", hex(opcode = _readPC(), 4L), " ", disassembleTable[opcode]()};
}
auto M68K::disassembleRegisters() -> string {
return {
hex(r.d0, 8L), " ", hex(r.d1, 8L), " ", hex(r.d2, 8L), " ", hex(r.d3, 8L), " ",
hex(r.d4, 8L), " ", hex(r.d5, 8L), " ", hex(r.d6, 8L), " ", hex(r.d7, 8L), " ",
r.t ? "T" : "t",
r.s ? "S" : "s",
(uint)r.i,
r.c ? "C" : "c",
r.v ? "V" : "v",
r.z ? "Z" : "z",
r.n ? "N" : "n",
r.x ? "X" : "x", "\n",
hex(r.a0, 8L), " ", hex(r.a1, 8L), " ", hex(r.a2, 8L), " ", hex(r.a3, 8L), " ",
hex(r.a4, 8L), " ", hex(r.a5, 8L), " ", hex(r.a6, 8L), " ", hex(r.usp, 8L), " ", hex(r.ssp, 8L)
hex(r.a4, 8L), " ", hex(r.a5, 8L), " ", hex(r.a6, 8L), " ", hex(r.ssp, 8L), " ", hex(r.usp, 8L)
};
}
//
auto M68K::disassembleANDI(uint size, EA modify) -> string {
return {"andi", _suffix(size), " ", _immediate(size), ",", _read(size, modify)};
}
auto M68K::disassembleBCC(uint condition, uint displacement) -> string {
return {"b", _condition(condition), " ", _branch(displacement)};
}
auto M68K::disassembleLEA(uint target, EA source) -> string {
return {"lea ", _address(Long, source), ",a", target};
}
auto M68K::disassembleMOVE(uint size, EA target, EA source) -> string {
return {"move", _suffix(size), " ", _read(size, source), ",", _write(size, target)};
}
auto M68K::disassembleMOVEA(uint size, uint target, EA source) -> string {
return {"movea ", _read(size, source), ",a", target};
}
auto M68K::disassembleMOVEM(uint direction, uint size, EA source) -> string {
string op{"movem", _suffix(size), " "};
uint16 list = _readPC();
string regs;
for(auto n : range(8)) if(list.bit(0 + n)) regs.append("d", n, ",");
regs.trimRight(",");
if(regs && list >> 8) regs.append("/");
for(auto n : range(8)) if(list.bit(8 + n)) regs.append("a", n, ",");
regs.trimRight(",");
if(direction == 0) {
return {op, regs, ",", _read(size, source)};
} else {
return {op, _read(size, source), ",", regs};
}
}
auto M68K::disassembleMOVEQ(uint target, uint immediate) -> string {
return {"moveq #$", hex(immediate, 2L), ",d", target};
}
auto M68K::disassembleMOVE_USP(uint direction, uint reg) -> string {
if(direction == 0) {
return {"move a", reg, ",usp"};
} else {
return {"move usp,a", reg};
}
}
auto M68K::disassembleNOP() -> string {
return {"nop "};
}
auto M68K::disassembleTST(uint size, EA source) -> string {
return {"tst", _suffix(size), " ", _read(size, source)};
}

View File

@ -1,34 +1,72 @@
auto M68K::signExtend(uint2 size, uint32 data) -> int32 {
if(size == 0) return (int8)data;
if(size == 1) return (int16)data;
if(size == 2) return (int32)data;
auto M68K::sign(uint size, uint32 data) -> int32 {
if(size == Byte) return (int8)data;
if(size == Word) return (int16)data;
if(size == Long) return (int32)data;
return 0;
}
//
auto M68K::address(EA& ea) -> uint32 {
auto M68K::address(uint size, EA& ea) -> uint32 {
if(ea.valid) return ea.address;
ea.valid = true;
if(ea.mode == 0) return ea.address = r.d(ea.reg);
if(ea.mode == 1) return ea.address = r.a(ea.reg);
if(ea.mode == 2) return ea.address = r.a(ea.reg);
if(ea.mode == 3) return ea.address = r.a(ea.reg);
if(ea.mode == 4) return ea.address = r.a(ea.reg);
if(ea.mode == 5) return ea.address = r.a(ea.reg) + (int16)readPC(Word);
if(ea.mode == 7) {
if(ea.reg == 0) return ea.address = (int16)readWordPC();
if(ea.reg == 1) return ea.address = readLongPC();
if(ea.reg == 2) return ea.address = r.pc, ea.address += (int16)readWordPC();
if(ea.reg == 0) return ea.address = (int16)readPC(Word);
if(ea.reg == 1) return ea.address = readPC(Long);
if(ea.reg == 2) return ea.address = r.pc, ea.address += (int16)readPC(Word);
if(ea.reg == 4) {
if(size == Byte) return ea.address = readPC(Byte);
if(size == Word) return ea.address = readPC(Word);
if(size == Long) return ea.address = readPC(Long);
}
}
return ea.address = 0;
}
auto M68K::read(EA& ea) -> uint32 {
address(ea);
if(ea.mode < 2 || (ea.mode == 7 && ea.reg == 4)) return ea.address;
return readAbsolute(ea.size, ea.address);
auto M68K::read(uint size, EA& ea) -> uint32 {
address(size, ea);
if(ea.mode == 0) return r.d(ea.reg);
if(ea.mode == 1) return r.a(ea.reg);
if(ea.mode == 2) return read(size, ea.address);
if(ea.mode == 3) {
auto data = read(size, ea.address);
ea.address += size, r.a(ea.reg) += size;
return data;
}
if(ea.mode == 4) {
ea.address -= size, r.a(ea.reg) -= size;
return read(size, ea.address);
}
if(ea.mode == 5) return read(size, ea.address);
if(ea.mode == 7) {
if(ea.reg == 0) return read(size, ea.address);
if(ea.reg == 1) return read(size, ea.address);
if(ea.reg == 2) return read(size, ea.address);
if(ea.reg == 4) return ea.address;
}
return 0;
}
auto M68K::write(EA& ea, uint32 data) -> void {
address(ea);
auto M68K::write(uint size, EA& ea, uint32 data) -> void {
address(size, ea);
if(ea.mode == 0) {
r.d(ea.reg) = data;
return;
}
if(ea.mode == 1) {
r.a(ea.reg) = data;
return;
}
}

View File

@ -10,50 +10,148 @@ auto M68K::instruction() -> void {
instructionsExecuted++;
print(disassembleRegisters(), "\n", disassemble(r.pc), "\n\n");
opcode = readWordPC();
opcode = readPC();
return instructionTable[opcode]();
}
M68K::M68K() {
for(uint opcode : range(65536)) instructionTable[opcode] = [=] { trap(); };
#define match(pattern) else if( \
#define match(pattern) if( \
(opcode & std::integral_constant<uint16_t, bit::mask(pattern)>::value) \
== std::integral_constant<uint16_t, bit::test(pattern)>::value \
) instructionTable[opcode] = [=]
#define bit(n) (opcode >> n & 1)
#define bits(hi, lo) ((opcode >> lo) & ((1 << (hi - lo + 1)) - 1))
)
for(uint opcode : range(65536)) {
if(0);
#define bind(name, ...) \
instructionTable[opcode] = [=] { return instruction##name(__VA_ARGS__); }; \
disassembleTable[opcode] = [=] { return disassemble##name(__VA_ARGS__); }; \
#define bit(x) (uint)opcode.bit(x)
#define bits(x, y) (uint)opcode.bits(x, y)
for(uint16 opcode : range(65536)) {
//ANDI
match("0000 0010 ---- ----") {
auto size = bits(7,6);
auto mode = bits(5,3);
auto reg = bits(2,0);
size = size == 0 ? Byte : size == 1 ? Word : size == 2 ? Long : 0;
if(size && mode != 1) {
bind(ANDI, size, {mode, reg});
}
}
//BCC
match("0110 ---- ---- ----") {
auto condition = bits(11,8);
auto displacement = bits(7,0);
if(true) {
bind(BCC, condition, displacement);
}
}
//LEA
match("0100 ---1 11-- ----") {
auto target = bits(11,9);
auto mode = bits(5,3);
auto reg = bits(2,0);
if(mode == 2 || mode == 5 || mode == 6 || (mode == 7 && reg <= 4)) {
bind(LEA, target, {mode, reg});
}
}
//MOVE
match("00-- ---- ---- ----") {
auto size = bits(13,12);
auto targetReg = bits(11,9);
auto targetMode = bits(8,6);
auto sourceMode = bits(5,3);
auto sourceReg = bits(2,0);
size = size == 1 ? Byte : size == 3 ? Word : size == 2 ? Long : 0;
if(size && targetMode != 1) {
bind(MOVE, size, {targetMode, targetReg}, {sourceMode, sourceReg});
}
}
//MOVEA
match("00-- ---0 01-- ----") {
auto size = bits(13,12);
auto target = bits(11,9);
auto sourceMode = bits(5,3);
auto sourceReg = bits(2,0);
size = size == 3 ? Word : size == 2 ? Long : 0;
if(size) {
bind(MOVEA, size, target, {sourceMode, sourceReg});
}
}
//MOVEM
match("0100 1-00 1--- ----") {
auto direction = bit(10);
auto size = bit(6);
auto mode = bits(5,3);
auto reg = bits(2,0);
size = size == 0 ? Word : size == 1 ? Long : 0;
if((direction == 0 && (mode == 2 || mode == 4 || mode == 5 || mode == 6 || (mode == 7 && reg <= 3)))
|| (direction == 1 && (mode == 2 || mode == 3 || mode == 5 || mode == 6 || (mode == 7 && reg <= 3)))) {
bind(MOVEM, direction, size, {mode, reg});
}
}
//MOVEQ
match("0111 ---0 ---- ----") {
auto target = bits(11,9);
auto immediate = bits(7,0);
if(true) {
bind(MOVEQ, target, immediate);
}
}
//MOVE_USP
match("0100 1110 0110 ----") {
auto direction = bit(3);
auto reg = bits(2,0);
if(true) {
bind(MOVE_USP, direction, reg);
}
}
//NOP
match("0100 1110 0111 0001") {
instructionNOP();
};
if(true) {
bind(NOP);
}
}
//MOVEM (direction, size, mode, register)
match("0100 1-00 1--- ----") {
instructionMOVEM(bit(10), EA{1 + bit(6), bits(5,3), bits(2,0)});
};
//TST (size, mode, register)
//TST
match("0100 1010 ---- ----") {
instructionTST(EA{bits(7,6), bits(5,3), bits(2,0)});
};
auto size = bits(7,6);
auto mode = bits(5,3);
auto reg = bits(2,0);
//LEA (An, mode, register)
match("0100 ---1 11-- ----") {
instructionLEA(bits(11,9), EA{Long, bits(5,3), bits(2,0)});
};
size = size == 0 ? Byte : size == 1 ? Word : size == 2 ? Long : 0;
if(size) {
bind(TST, size, {mode, reg});
}
}
//BCC (condition, displacement)
match("0110 ---- ---- ----") {
instructionBCC(bits(11,8), bits(7,0));
};
}
for(uint16 opcode : range(65536)) {
if(instructionTable[opcode]) continue;
instructionTable[opcode] = [=] { trap(); };
disassembleTable[opcode] = [=] { return string{"???"}; };
}
#undef match
#undef bind
#undef bit
#undef bits
}

View File

@ -22,34 +22,83 @@ auto M68K::testCondition(uint4 condition) -> bool {
//
auto M68K::instructionBCC(uint4 condition, uint8 displacementByte) -> void {
uint16 displacementWord = readWordPC();
if(displacementByte) r.pc -= 2;
auto M68K::instructionANDI(uint size, EA modify) -> void {
auto data = readPC(size);
write(size, modify, data = read(size, modify) & data);
r.c = 0;
r.v = 0;
r.z = data == 0;
r.n = sign(size, data) < 0;
}
auto M68K::instructionBCC(uint condition, uint displacement) -> void {
auto word = readPC();
if(displacement) displacement = (int8)displacement, r.pc -= 2;
else displacement = (int16)word;
if(condition == 1) {
condition = 0;
//pushLong(r.pc);
}
if(testCondition(condition)) {
r.pc += displacementByte ? (int8_t)displacementByte : ((int16_t)displacementWord - 2);
if(testCondition(condition)) r.pc += displacement;
}
auto M68K::instructionLEA(uint target, EA source) -> void {
r.a(target) = address(Long, source);
}
auto M68K::instructionMOVE(uint size, EA target, EA source) -> void {
auto data = read(size, source);
write(size, target, data);
r.c = 0;
r.v = 0;
r.z = data == 0;
r.n = sign(size, data) < 0;
}
auto M68K::instructionMOVEA(uint size, uint target, EA source) -> void {
r.d(target) = read(size, source);
}
auto M68K::instructionMOVEM(uint direction, uint size, EA source) -> void {
auto list = readPC();
for(uint n : range(8)) {
if(list.bit(0 + n)) r.d(n) = read(size, source);
}
for(uint n : range(8)) {
if(list.bit(8 + n)) r.a(n) = read(size, source);
}
}
auto M68K::instructionLEA(uint3 wr, EA ea) -> void {
r.a(wr) = address(ea);
auto M68K::instructionMOVEQ(uint target, uint immediate) -> void {
r.d(target) = immediate;
r.c = 0;
r.v = 0;
r.z = immediate == 0;
r.v = sign(Byte, immediate) < 0;
}
auto M68K::instructionMOVEM(uint1 direction, EA ea) -> void {
auto list = readWordPC();
auto M68K::instructionMOVE_USP(uint direction, uint reg) -> void {
if(!r.s) trap();
if(direction == 0) {
r.usp = r.a(reg);
} else {
r.a(reg) = r.usp;
}
}
auto M68K::instructionNOP() -> void {
}
auto M68K::instructionTST(EA ea) -> void {
auto data = read(ea);
auto M68K::instructionTST(uint size, EA source) -> void {
auto data = read(size, source);
r.c = 0;
r.v = 0;
r.z = data == 0;
r.n = signExtend(ea.size, data) < 0;
r.n = sign(size, data) < 0;
}

View File

@ -3,6 +3,7 @@
namespace Processor {
#include "registers.cpp"
#include "memory.cpp"
#include "ea.cpp"
#include "instruction.cpp"
@ -15,40 +16,12 @@ auto M68K::power() -> void {
auto M68K::reset() -> void {
instructionsExecuted = 0;
r.d0 = r.d1 = r.d2 = r.d3 = r.d4 = r.d5 = r.d6 = r.d7 = 0;
r.a0 = r.a1 = r.a2 = r.a3 = r.a4 = r.a5 = r.a6 = r.usp = r.ssp = 0;
for(uint n : range(8)) r.d(n) = 0;
for(uint n : range(7)) r.a(n) = 0;
r.ssp = 0;
r.usp = 0;
r.pc = 0;
r.ccr = 0;
}
//
auto M68K::Registers::d(uint3 reg) -> uint32& {
switch(reg) {
case 0: return d0;
case 1: return d1;
case 2: return d2;
case 3: return d3;
case 4: return d4;
case 5: return d5;
case 6: return d6;
case 7: return d7;
}
unreachable;
}
auto M68K::Registers::a(uint3 reg) -> uint32& {
switch(reg) {
case 0: return a0;
case 1: return a1;
case 2: return a2;
case 3: return a3;
case 4: return a4;
case 5: return a5;
case 6: return a6;
case 7: return ssp;
}
unreachable;
r.sr = 0x2000;
}
}

View File

@ -5,6 +5,8 @@
namespace Processor {
struct M68K {
enum : uint { Byte = 1, Word = 2, Long = 4 };
M68K();
virtual auto step(uint clocks) -> void = 0;
@ -19,28 +21,23 @@ struct M68K {
auto readWord(uint32 addr) -> uint16;
auto readLong(uint32 addr) -> uint32;
auto readWordPC() -> uint16;
auto readLongPC() -> uint32;
auto readAbsolute(uint2 size, uint32 addr) -> uint32;
auto read(uint size, uint32 addr) -> uint32;
auto readPC(uint size = Word) -> uint32;
//ea.cpp
struct EA {
EA(uint2 size, uint3 mode, uint3 reg) : size(size), mode(mode), reg(reg) {}
uint2 size;
uint3 mode;
uint3 reg;
uint mode;
uint reg;
boolean valid;
uint32 address;
};
auto signExtend(uint2 size, uint32 data) -> int32;
auto sign(uint size, uint32 data) -> int32;
auto address(EA& ea) -> uint32;
auto read(EA& ea) -> uint32;
auto write(EA& ea, uint32 data) -> void;
auto address(uint size, EA& ea) -> uint32;
auto read(uint size, EA& ea) -> uint32;
auto write(uint size, EA& ea, uint32 data) -> void;
//instruction.cpp
auto trap() -> void;
@ -49,42 +46,76 @@ struct M68K {
//instructions.cpp
auto testCondition(uint4 condition) -> bool;
auto instructionBCC(uint4 condition, uint8 displacementByte) -> void;
auto instructionLEA(uint3 wr, EA ea) -> void;
auto instructionMOVEM(uint1 direction, EA ea) -> void;
auto instructionANDI(uint size, EA modify) -> void;
auto instructionBCC(uint condition, uint displacement) -> void;
auto instructionLEA(uint target, EA source) -> void;
auto instructionMOVE(uint size, EA target, EA source) -> void;
auto instructionMOVEA(uint size, uint target, EA source) -> void;
auto instructionMOVEM(uint direction, uint size, EA source) -> void;
auto instructionMOVEQ(uint target, uint immediate) -> void;
auto instructionMOVE_USP(uint direction, uint reg) -> void;
auto instructionNOP() -> void;
auto instructionTST(EA ea) -> void;
auto instructionTST(uint size, EA source) -> void;
//disassembler.cpp
auto disassemble(uint32 pc) -> string;
auto disassembleRegisters() -> string;
enum : uint { Byte = 0, Word = 1, Long = 2 };
struct Registers {
auto d(uint3 reg) -> uint32&;
auto a(uint3 reg) -> uint32&;
auto d(uint3 r) -> uint32&;
auto a(uint3 r) -> uint32&;
uint32 d0, d1, d2, d3, d4, d5, d6, d7;
uint32 a0, a1, a2, a3, a4, a5, a6, usp, ssp;
uint32 a0, a1, a2, a3, a4, a5, a6, ssp, usp;
uint32 pc;
union {
uint8 ccr;
BooleanBitField<uint8_t, 0> c; //carry
BooleanBitField<uint8_t, 1> v; //overflow
BooleanBitField<uint8_t, 2> z; //zero
BooleanBitField<uint8_t, 3> n; //negative
BooleanBitField<uint8_t, 4> x; //extend
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() : ccr(0) {}
Registers() : sr(0) {}
} r;
uint16 opcode = 0;
uint instructionsExecuted = 0;
function<void ()> instructionTable[65536];
private:
//disassembler.cpp
auto disassembleANDI(uint size, EA modify) -> string;
auto disassembleBCC(uint condition, uint displacement) -> string;
auto disassembleLEA(uint target, EA source) -> string;
auto disassembleMOVE(uint size, EA target, EA source) -> string;
auto disassembleMOVEA(uint size, uint target, EA source) -> string;
auto disassembleMOVEM(uint direction, uint size, EA source) -> string;
auto disassembleMOVEQ(uint target, uint immediate) -> string;
auto disassembleMOVE_USP(uint direction, uint reg) -> string;
auto disassembleNOP() -> string;
auto disassembleTST(uint size, EA source) -> string;
auto _readByte(uint32 addr) -> uint8;
auto _readWord(uint32 addr) -> uint16;
auto _readLong(uint32 addr) -> uint32;
auto _readPC(uint size = Word) -> uint32;
auto _immediate(uint size) -> string;
auto _address(uint size, EA& ea) -> string;
auto _read(uint size, EA& ea) -> string;
auto _write(uint size, EA& ea) -> string;
auto _branch(uint displacement) -> string;
auto _suffix(uint size) -> string;
auto _condition(uint condition) -> string;
uint32 _pc;
function<string ()> disassembleTable[65536];
};
}

View File

@ -16,22 +16,19 @@ auto M68K::readLong(uint32 addr) -> uint32 {
//
auto M68K::readWordPC() -> uint16 {
uint16 data = readWord(r.pc);
auto M68K::read(uint size, uint32 addr) -> uint32 {
if(size == Byte) return readByte(addr);
if(size == Word) return readWord(addr);
if(size == Long) return readLong(addr);
return 0;
}
auto M68K::readPC(uint size) -> uint32 {
uint32 data = readWord(r.pc);
r.pc += 2;
if(size == Byte) return (uint8)data;
if(size == Word) return data;
data = data << 16 | readWord(r.pc);
r.pc += 2;
return data;
}
auto M68K::readLongPC() -> uint32 {
uint32 data = readWordPC() << 16;
return data |= readWordPC() << 0;
}
//
auto M68K::readAbsolute(uint2 size, uint32 addr) -> uint32 {
if(size == 0) return readByte(addr);
if(size == 1) return readWord(addr);
if(size == 2) return readLong(addr);
return 0;
}

View File

@ -0,0 +1,26 @@
auto M68K::Registers::d(uint3 r) -> uint32& {
switch(r) {
case 0: return d0;
case 1: return d1;
case 2: return d2;
case 3: return d3;
case 4: return d4;
case 5: return d5;
case 6: return d6;
case 7: return d7;
}
unreachable;
}
auto M68K::Registers::a(uint3 r) -> uint32& {
switch(r) {
case 0: return a0;
case 1: return a1;
case 2: return a2;
case 3: return a3;
case 4: return a4;
case 5: return a5;
case 6: return a6;
case 7: return s ? ssp : usp;
}
}