Update to v100r09 release.

byuu says:

Another six hours in ...

I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.

Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:

- MOVE (EA to, EA from) case
  - read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
  - when using +/-(aN), RA can't actually be updated until the transfer
    is completed
- LEA (EA from) case
  - doesn't actually perform the final read; just returns the address
    to be read from
- ANDI (EA from-and-to) case
  - same EA has to be read from and written to
  - for -(aN), the read has to come from aN-2, but can't update aN yet;
    so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
  opcode decoding

To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(

If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
This commit is contained in:
Tim Allen 2016-07-19 19:12:05 +10:00
parent 92fe5b0813
commit be3f6ac0d5
10 changed files with 480 additions and 745 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.08"; static const string Version = "100.09";
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.ssp = readAbsolute(Long, 0); r.ssp = read(1, 0) << 16 | read(1, 2) << 0;
r.pc = readAbsolute(Long, 4); r.pc = read(1, 4) << 16 | read(1, 6) << 0;
} }
auto CPU::main() -> void { auto CPU::main() -> void {

View File

@ -1,68 +1,53 @@
auto M68K::_readByte(uint32 addr) -> uint8 { template<> auto M68K::_read<Byte>(uint32 addr) -> uint32 {
return read(0, addr); return read(0, addr);
} }
auto M68K::_readWord(uint32 addr) -> uint16 { template<> auto M68K::_read<Word>(uint32 addr) -> uint32 {
return read(1, addr); return read(1, addr);
} }
auto M68K::_readLong(uint32 addr) -> uint32 { template<> auto M68K::_read<Long>(uint32 addr) -> uint32 {
uint32 data = _readWord(addr + 0) << 16; uint32 data = _read<Word>(addr + 0) << 16;
return data |= _readWord(addr + 2) << 0; return data | _read<Word>(addr + 2) << 0;
} }
auto M68K::_readPC(uint2 size) -> uint32 { template<uint Size> auto M68K::_readPC() -> uint32 {
uint32 data = _readWord(_pc); auto data = _read<Size == Byte ? Word : Size>(_pc);
_pc += 2; _pc += Size == Long ? 4 : 2;
if(size == Byte) return (uint8)data; return clip<Size>(data);
if(size == Word) return data;
data = (data << 16) | _readWord(_pc);
_pc += 2;
return data;
} }
auto M68K::_immediate(uint2 size) -> string { auto M68K::_register(Register r) -> string {
if(size == Byte) return {"#$", hex(_readPC(Byte), 2L)}; static const string registers[16] = {
if(size == Word) return {"#$", hex(_readPC(Word), 4L)}; "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
if(size == Long) return {"#$", hex(_readPC(Long), 8L)}; "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
return "#???"; };
return registers[r.number];
} }
auto M68K::_address(uint8 ea) -> string { template<uint Size> auto M68K::_immediate() -> string {
uint3 mode = ea >> 5; return {"#$", hex(_readPC<Size>(), 2 << Size)};
uint3 reg = ea >> 2;
uint2 size = ea >> 0;
if(mode == 7) {
if(reg == 2) return {"$", hex(_pc + (int16)_readPC(Word), 6L)};
} }
template<uint Size> auto M68K::_address(EA ea) -> string {
if(ea.mode == 9) return {"$", hex(_pc + (int16)_readPC(), 6L)};
return "???"; return "???";
} }
auto M68K::_read(uint8 ea) -> string { template<uint Size> auto M68K::_read(EA ea) -> string {
uint3 mode = ea >> 5; if(ea.mode == 0) return {_register(ea.reg)};
uint3 reg = ea >> 2; if(ea.mode == 1) return {_register(ea.reg)};
uint2 size = ea >> 0; if(ea.mode == 2) return {"(", _register(ea.reg), ")"};
if(ea.mode == 3) return {"(", _register(ea.reg), ")+"};
if(mode == 0) return {"d", reg}; if(ea.mode == 4) return {"-(", _register(ea.reg), ")"};
if(mode == 1) return {"a", reg}; if(ea.mode == 5) return {"($", hex(read(ea.reg) + (int16)_readPC(), 6L), ")"};
if(mode == 2) return {"(a", reg, ")"}; if(ea.mode == 8) return {"($", hex(_readPC<Long>(), 6L), ")"};
if(mode == 3) return {"(a", reg, ")+"}; if(ea.mode == 11) return {"#$", hex(_readPC<Size>(), 2 << Size)};
if(mode == 4) return {"-(a", reg, ")"};
if(mode == 5) return {"($", hex(r.a(reg) + (int16)_readPC(Word), 6L), ")"};
if(mode == 7) {
if(reg == 1) return {"($", hex(_readPC(Long), 6L), ")"};
if(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 "???"; return "???";
} }
auto M68K::_write(uint8 ea) -> string { template<uint Size> auto M68K::_write(EA ea) -> string {
return _read(ea); return _read<Size>(ea);
} }
auto M68K::_branch(uint8 displacement) -> string { auto M68K::_branch(uint8 displacement) -> string {
@ -72,11 +57,8 @@ auto M68K::_branch(uint8 displacement) -> string {
return {"$", hex(_pc + displacement, 6L)}; return {"$", hex(_pc + displacement, 6L)};
} }
auto M68K::_suffix(uint2 size) -> string { template<uint Size> auto M68K::_suffix() -> string {
if(size == Byte) return ".b"; return Size == Byte ? ".b" : Size == Word ? ".w" : ".l";
if(size == Word) return ".w";
if(size == Long) return ".l";
return ".?";
} }
auto M68K::_condition(uint4 condition) -> string { auto M68K::_condition(uint4 condition) -> string {
@ -111,64 +93,60 @@ auto M68K::disassembleRegisters() -> string {
// //
template<uint Size> auto M68K::disassembleADD(uint3 reg, uint1 direction, EA ea) -> string { template<uint Size> auto M68K::disassembleADD(Register rd, uint1 direction, EA ea) -> string {
string op{"add", _suffix(ea.reg), " "}; string op{"add", _suffix<Size>(), " "};
return op;
if(direction == 0) { if(direction == 0) {
// return {op, _read(ea), ",d", reg}; return {op, _read<Size>(ea), ",", _register(rd)};
} else { } else {
// return {op, "d", reg, ",", _read(ea)}; return {op, "", _register(rd), ",", _read<Size>(ea)};
} }
} }
auto M68K::disassembleANDI(uint8 ea) -> string { template<uint Size> auto M68K::disassembleANDI(EA ea) -> string {
return {"andi", _suffix(ea), " ", _immediate(ea), ",", _read(ea)}; return {"andi", _suffix<Size>(), " ", _immediate<Size>(), ",", _read<Size>(ea)};
} }
auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string { auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string {
return {"b", _condition(condition), " ", _branch(displacement)}; return {"b", _condition(condition), " ", _branch(displacement)};
} }
auto M68K::disassembleLEA(uint3 to, uint8 ea) -> string { auto M68K::disassembleLEA(Register ra, EA ea) -> string {
return {"lea ", _address(ea), ",a", to}; return {"lea ", _address<Long>(ea), ",", _register(ra)};
} }
auto M68K::disassembleMOVE(uint8 to, uint8 from) -> string { template<uint Size> auto M68K::disassembleMOVE(EA to, EA from) -> string {
return {"move", _suffix(from), " ", _read(from), ",", _write(to)}; return {"move", _suffix<Size>(), " ", _read<Size>(from), ",", _write<Size>(to)};
} }
auto M68K::disassembleMOVEA(uint3 to, uint8 from) -> string { template<uint Size> auto M68K::disassembleMOVEA(Register ra, EA ea) -> string {
return {"movea ", _read(from), ",a", to}; return {"movea ", _read<Size>(ea), ",", _register(ra)};
} }
auto M68K::disassembleMOVEM(uint1 direction, uint8 ea) -> string { template<uint Size> auto M68K::disassembleMOVEM(uint1 direction, EA ea) -> string {
string op{"movem", _suffix(ea), " "}; string op{"movem", _suffix<Size>(), " "};
uint16 list = _readPC(); uint16 list = _readPC();
string regs; string regs;
for(auto n : range(8)) if(list.bit(0 + n)) regs.append("d", n, ","); for(uint rn : range(16)) if(list.bit(rn)) regs.append(_register(Register{rn}), ",");
regs.trimRight(",");
if(regs && list >> 8) regs.append("/");
for(auto n : range(8)) if(list.bit(8 + n)) regs.append("a", n, ",");
regs.trimRight(","); regs.trimRight(",");
if(direction == 0) { if(direction == 0) {
return {op, regs, ",", _read(ea)}; return {op, regs, ",", _read<Size>(ea)};
} else { } else {
return {op, _read(ea), ",", regs}; return {op, _read<Size>(ea), ",", regs};
} }
} }
auto M68K::disassembleMOVEQ(uint3 target, uint8 immediate) -> string { auto M68K::disassembleMOVEQ(Register rd, uint8 immediate) -> string {
return {"moveq #$", hex(immediate, 2L), ",d", target}; return {"moveq #$", hex(immediate, 2L), ",", _register(rd)};
} }
auto M68K::disassembleMOVE_USP(uint1 direction, uint3 reg) -> string { auto M68K::disassembleMOVE_USP(uint1 direction, Register ra) -> string {
if(direction == 0) { if(direction == 0) {
return {"move a", reg, ",usp"}; return {"move ", _register(ra), ",usp"};
} else { } else {
return {"move usp,a", reg}; return {"move usp,", _register(ra)};
} }
} }
@ -176,6 +154,6 @@ auto M68K::disassembleNOP() -> string {
return {"nop "}; return {"nop "};
} }
auto M68K::disassembleTST(uint8 ea) -> string { template<uint Size> auto M68K::disassembleTST(EA ea) -> string {
return {"tst", _suffix(ea), " ", _read(ea)}; return {"tst", _suffix<Size>(), " ", _read<Size>(ea)};
} }

View File

@ -1,423 +1,203 @@
//effective addressing template<uint Size> auto M68K::fetch(EA& ea) -> uint32 {
ea.valid = true;
//encoding: switch(ea.mode) {
// d7-d5: mode
// d4-d2: register
// d1-d0: size (0 = byte, 1 = word, 2 = long)
auto M68K::address(uint8 ea) -> uint32 { case 0: { //data register direct
switch(ea) { return read(ea.reg);
//data register direct
case 0b000'000'00 ... 0b000'111'11:
return r.d(ea >> 2);
//address register direct
case 0b001'000'00 ... 0b001'111'11:
return r.a(ea >> 2);
//address register indirect
case 0b010'000'00 ... 0b010'111'11:
return r.a(ea >> 2);
//address register indirect with post-increment
case 0b011'000'00 ... 0b011'111'11:
return r.a(ea >> 2);
//address register indirect with pre-decrement
case 0b100'000'00 ... 0b100'111'11:
return r.a(ea >> 2);
//address register indirect with displacement
case 0b101'000'00 ... 0b101'111'11:
return r.a(ea >> 2) + (int16)readPC();
//address register indirect with index
case 0b110'000'00 ... 0b110'111'11: {
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x800) index = (int16)index;
return r.a(ea >> 2) + index + (int8)word;
} }
//absolute short indirect case 1: { //data register indirect
case 0b111'000'00 ... 0b111'000'11: return read(ea.reg);
}
case 2: { //address register indirect
return read(ea.reg);
}
case 3: { //address register indirect with post-increment
return read(ea.reg);
}
case 4: { //address register indirect with pre-decrement
return read(ea.reg);
}
case 5: { //address register indirect with displacement
return read(ea.reg) + (int16)readPC();
}
case 6: { //address register indirect with index
auto extension = readPC();
auto index = read(Register{extension >> 12});
if(extension & 0x800) index = (int16)index;
return read(ea.reg) + index + (int8)extension;
}
case 7: { //absolute short indirect
return (int16)readPC(); return (int16)readPC();
//absolute long indirect
case 0b111'001'00 ... 0b111'001'11: {
uint32 address = readPC() << 16;
return address | readPC() << 0;
} }
//program counter indirect with displacement case 8: { //absolute long indirect
case 0b111'010'00 ... 0b111'010'11: { return readPC<Long>();
}
case 9: { //program counter indirect with displacement
auto base = r.pc; auto base = r.pc;
return base + (int16)readPC(); return base + (int16)readPC();
} }
//program counter indirect with index case 10: { //program counter indirect with index
case 0b111'011'00 ... 0b111'011'11: {
auto base = r.pc; auto base = r.pc;
auto word = readPC(); auto extension = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12); auto index = read(Register{extension >> 12});
if(word & 0x800) index = (int16)index; if(extension & 0x800) index = (int16)index;
return base + index + (int8)word; return base + index + (int8)extension;
}
case 11: { //immediate
return readPC<Size>();
} }
//immediate byte
case 0b111'100'00:
return (uint8)readPC();
//immediate word
case 0b111'100'01:
return readPC();
//immediate long
case 0b111'100'10: {
uint32 address = readPC() << 16;
return address | readPC() << 0;
} }
//invalid
default:
return 0; return 0;
}
} }
template<uint Size> auto M68K::read(EA ea) -> uint32 { template<uint Size, bool Update> auto M68K::read(EA& ea) -> uint32 {
if(!ea.valid) ea.address = fetch<Size>(ea);
switch(ea.mode) { switch(ea.mode) {
case 0: { //data register direct case 0: { //data register direct
return clip<Size>(r.d(ea.reg)); return clip<Size>(ea.address);
} }
case 1: { //address register direct case 1: { //address register direct
return clip<Size>(r.a(ea.reg)); return clip<Size>(ea.address);
} }
case 2: { //address register indirect case 2: { //address register indirect
auto& address = r.a(ea.reg); return read<Size>(ea.address);
return read<Size>(address);
} }
case 3: { //address register indirect with post-increment case 3: { //address register indirect with post-increment
auto& address = r.a(ea.reg); auto data = read<Size>(ea.address);
auto data = read<Size>(address); if(Update) write(ea.reg, ea.address += (Size == Long ? 4 : 2));
address += Size == Long ? 4 : 2;
return data; return data;
} }
case 4: { //address register indirect with pre-decrement case 4: { //address register indirect with pre-decrement
auto& address = r.a(ea.reg); auto data = read<Size>((uint32)(ea.address - (Size == Long ? 4 : 2)));
address -= Size == Long ? 4 : 2; if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2));
return read<Size>(address);
}
}
}
template<uint Size> auto M68K::write(EA ea, uint32 data) -> void {
switch(ea.mode) {
case 0: { //data register direct
r.d(ea.reg) = data;
return;
}
case 1: { //address register direct
r.a(ea.reg) = data;
return;
}
}
}
auto M68K::read(uint8 ea) -> uint32 {
switch(ea) {
//data register direct
case 0b000'000'00 ... 0b000'111'11:
return r.d(ea >> 2);
//address register direct
case 0b001'000'00 ... 0b001'111'11:
return r.a(ea >> 2);
//address register indirect
case 0b010'000'00 ... 0b010'111'11: {
auto address = r.a(ea >> 2);
return readAbsolute(ea, address);
}
//address register indirect with post-increment
case 0b011'000'00 ... 0b011'111'11: {
auto& address = r.a(ea >> 2);
auto data = readAbsolute(ea, address);
address += 2 + (ea & 2);
return data; return data;
} }
//address register indirect with pre-decrement case 5: { //address register indirect with displacement
case 0b100'000'00 ... 0b100'111'11: { return read<Size>(ea.address);
auto& address = r.a(ea >> 2);
address -= 2 + (ea & 2);
return readAbsolute(ea, address);
} }
//address register indirect with displacement case 6: { //address register indirect with index
case 0b101'000'00 ... 0b101'111'11: return read<Size>(ea.address);
return readAbsolute(ea, r.a(ea >> 2) + (int16)readPC());
//address register indirect with index
case 0b110'000'00 ... 0b110'111'11: {
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x800) index = (int16)index;
return readAbsolute(ea, r.a(ea >> 2) + index + (int8)word);
} }
//absolute short indirect case 7: { //absolute short indirect
case 0b111'000'00 ... 0b111'000'11: return read<Size>(ea.address);
return readAbsolute(ea, (int16)readPC());
//absolute long indirect
case 0b111'001'00 ... 0b111'001'11: {
uint32 address = readPC() << 16;
return readAbsolute(ea, address | readPC());
} }
//program counter indirect with displacement case 8: { //absolute long indirect
case 0b111'010'00 ... 0b111'010'11: { return read<Size>(ea.address);
auto base = r.pc;
return readAbsolute(ea, base + (int16)readPC());
} }
//program counter indirect with index case 9: { //program counter indirect with displacement
case 0b111'011'00 ... 0b111'011'11: { return read<Size>(ea.address);
auto base = r.pc; }
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12); case 10: { //program counter indirect with index
if(word & 0x800) index = (int16)index; return read<Size>(ea.address);
return readAbsolute(ea, base + index + (int8)word); }
case 11: { //immediate
return clip<Size>(ea.address);
} }
//immediate byte
case 0b111'100'00:
return (uint8)readPC();
//immediate word
case 0b111'100'01:
return readPC();
//immediate long
case 0b111'100'10: {
uint32 address = readPC() << 16;
return address | readPC() << 0;
} }
//invalid
default:
return 0; return 0;
}
} }
auto M68K::write(uint8 ea, uint32 data) -> void { template<uint Size, bool Update> auto M68K::write(EA& ea, uint32 data) -> void {
switch(ea) { if(!ea.valid) ea.address = fetch<Size>(ea);
//data register direct switch(ea.mode) {
case 0b000'000'00 ... 0b000'111'11:
r.d(ea >> 2) = data;
return;
//address register direct case 0: { //data register direct
case 0b001'000'00 ... 0b001'111'11: return write<Size>(ea.reg, data);
r.a(ea >> 2) = data;
return;
//address register indirect
case 0b010'000'00 ... 0b010'111'11: {
auto address = r.a(ea >> 2);
return writeAbsolute(ea, address, data);
} }
//address register indirect with post-increment case 1: { //address register direct
case 0b011'000'00 ... 0b011'111'11: { return write<Size>(ea.reg, data);
auto& address = r.a(ea >> 2); }
writeAbsolute(ea, address, data);
address += 2 + (ea & 2); case 2: { //address register indirect
return write<Size>(ea.address, data);
}
case 3: { //address register indirect with post-increment
write<Size>(ea.address, data);
if(Update) write(ea.reg, ea.address += (Size == Long ? 4 : 2));
return; return;
} }
//address register indirect with pre-decrement case 4: { //address register indirect with pre-decrement
case 0b100'000'00 ... 0b100'111'11: { write<Size>((uint32)(ea.address - (Size == Long ? 4 : 2)), data);
auto& address = r.a(ea >> 2); if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2));
address -= 2 + (ea & 2); return;
return writeAbsolute(ea, address, data);
} }
//address register indirect with displacement case 5: { //address register indirect with displacement
case 0b101'000'00 ... 0b101'111'11: return write<Size>(ea.address, data);
return writeAbsolute(ea, r.a(ea >> 2) + (int16)readPC(), data);
//address register indirect with index
case 0b110'000'00 ... 0b110'111'11: {
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x800) index = (int16)index;
return writeAbsolute(ea, r.a(ea >> 2) + index + (int8)word, data);
} }
//absolute short indirect case 6: { //address register indirect with index
case 0b111'000'00 ... 0b111'000'11: return write<Size>(ea.address, data);
return writeAbsolute(ea, (int16)readPC(), data);
//absolute long indirect
case 0b111'001'00 ... 0b111'001'11: {
uint32 address = readPC() << 16;
return writeAbsolute(ea, address | readPC(), data);
} }
//program counter indirect with displacement case 7: { //absolute short indirect
case 0b111'010'00 ... 0b111'010'11: { return write<Size>(ea.address, data);
auto base = r.pc;
return writeAbsolute(ea, base + (int16)readPC(), data);
} }
//program counter indirect with index case 8: { //absolute long indirect
case 0b111'011'00 ... 0b111'011'11: { return write<Size>(ea.address, data);
auto base = r.pc; }
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12); case 9: { //program counter indirect with displacement
if(word & 0x800) index = (int16)index; return write<Size>(ea.address, data);
return writeAbsolute(ea, base + index + (int8)word, data); }
case 10: { //program counter indirect with index
return write<Size>(ea.address, data);
}
case 11: { //immediate
return;
} }
} }
} }
auto M68K::modify(uint8 ea, uint32 data, const function<uint32 (uint32, uint32)>& op) -> uint32 { template<uint Size> auto M68K::flush(EA& ea, uint32 data) -> void {
switch(ea) { switch(ea.mode) {
//data register direct case 3: { //address register indirect with post-increment
case 0b000'000'00 ... 0b000'111'11: { write<Size>(ea.reg, data);
auto& address = r.d(ea >> 2); return;
return address = op(address, data);
} }
//address register direct case 4: { //address register indirect with pre-decrement
case 0b001'000'00 ... 0b001'111'11: { write<Size>(ea.reg, data);
auto& address = r.a(ea >> 2); return;
return address = op(address, data);
}
//address register indirect
case 0b010'000'00 ... 0b010'111'11: {
auto address = r.a(ea >> 2);
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//address register indirect with post-increment
case 0b011'000'00 ... 0b011'111'11: {
auto& address = r.a(ea >> 2);
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
address += 2 + (ea & 2);
return memory;
}
//address register indirect with pre-decrement
case 0b100'000'00 ... 0b100'111'11: {
auto& address = r.a(ea >> 2);
address -= 2 + (ea & 2);
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//address register indirect with displacement
case 0b101'000'00 ... 0b101'111'11: {
auto address = r.a(ea >> 2) + (int16)readPC();
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//address register indirect with index
case 0b110'000'00 ... 0b110'111'11: {
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x800) index = (int16)index;
auto address = r.a(ea >> 2) + index + (int8)word;
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//absolute short indirect
case 0b111'000'00 ... 0b111'000'11: {
auto address = (int16)readPC();
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//absolute long indirect
case 0b111'001'00 ... 0b111'001'11: {
auto word = readPC();
uint32 address = word << 16 | readPC();
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//program counter indirect with displacement
case 0b111'010'00 ... 0b111'010'11: {
auto address = r.pc;
address += (int16)readPC();
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//program counter indirect with index
case 0b111'011'00 ... 0b111'011'11: {
auto address = r.pc;
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x8000) index = (int16)index;
address += index + (int8)word;
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//immediate byte
case 0b111'100'00:
return op((uint8)readPC(), data);
//immediate word
case 0b111'100'01:
return op(readPC(), data);
//immediate long
case 0b111'100'10: {
uint32 immediate = readPC() << 16;
immediate |= readPC();
return op(immediate, data);
} }
} }
} }
auto M68K::flush(uint8 ea, uint32 address) -> void {
//address register indirect with post-increment
//address register indirect with pre-decrement
if(ea >= 0b011'000'00 && ea <= 0b100'111'11) {
r.a(ea >> 2) = address;
}
}

View File

@ -8,7 +8,9 @@ auto M68K::trap() -> void {
auto M68K::instruction() -> void { auto M68K::instruction() -> void {
instructionsExecuted++; instructionsExecuted++;
print(disassembleRegisters(), "\n", disassemble(r.pc), "\n\n"); print(disassembleRegisters(), "\n");
print(disassemble(r.pc), "\n");
print("\n");
opcode = readPC(); opcode = readPC();
return instructionTable[opcode](); return instructionTable[opcode]();
@ -18,180 +20,141 @@ M68K::M68K() {
#define bind(id, name, ...) \ #define bind(id, name, ...) \
assert(!instructionTable[id]); \ assert(!instructionTable[id]); \
instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \ instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \
disassembleTable[id] = [=] { return disassemble##name(__VA_ARGS__); }; \ disassembleTable[id] = [=] { return disassemble##name(__VA_ARGS__); };
#define pattern(s) \
std::integral_constant<uint16_t, bit::test(s)>::value
//ADD //ADD
for(uint3 d : range(8)) for(uint3 dreg : range(8))
for(uint1 direction : range(2)) for(uint1 direction : range(2))
for(uint3 mode : range(8)) for(uint3 mode : range(8))
for(uint3 reg : range(8)) { for(uint3 reg : range(8)) {
auto opcode = 0b1101'0000'0000'0000 | d << 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{0u + dreg};
EA ea{mode, reg}; EA ea{mode, reg};
bind(opcode | 0 << 6, ADD<Byte>, d, direction, ea); bind(opcode | 0 << 6, ADD<Byte>, rd, direction, ea);
bind(opcode | 1 << 6, ADD<Word>, d, direction, ea); bind(opcode | 1 << 6, ADD<Word>, rd, direction, ea);
bind(opcode | 2 << 6, ADD<Long>, d, direction, ea); bind(opcode | 2 << 6, ADD<Long>, rd, direction, ea);
} }
#undef bind
#define match(pattern) if( \
(opcode & std::integral_constant<uint16_t, bit::mask(pattern)>::value) \
== std::integral_constant<uint16_t, bit::test(pattern)>::value \
)
#define bind(name, ...) \
assert(!instructionTable[opcode]); \
instructionTable[opcode] = [=] { return instruction##name(__VA_ARGS__); }; \
disassembleTable[opcode] = [=] { return disassemble##name(__VA_ARGS__); }; \
#define bit(x) (uint)opcode.bit(x)
#define bits(x, y) (uint)opcode.bits(x, y)
for(uint16 opcode : range(65536)) {
/*
//ADD
match("1101 ---- ---- ----") {
uint3 r = bits(11,9);
uint1 direction = bit(8);
uint2 size = bits(7,6);
uint3 mode = bits(5,3);
uint3 reg = bits(2,0);
if(size != 3 && (direction == 0 || (mode == 2 || mode == 3 || mode == 4 || mode == 5 || mode == 6 || (mode == 7 && reg <= 1)))) {
uint8 ea = mode << 5 | reg << 2 | size;
bind(ADD, r, direction, ea);
}
}
*/
//ANDI //ANDI
match("0000 0010 ---- ----") { for(uint3 mode : range(8))
uint2 size = bits(7,6); for(uint3 reg : range(8)) {
uint3 mode = bits(5,3); auto opcode = pattern("0000 0010 ++-- ----") | mode << 3 | reg << 0;
uint3 reg = bits(2,0); if(mode == 1 || (mode == 7 && reg >= 4)) continue;
if(size != 3 && mode != 1) { EA ea{mode, reg};
uint8 ea = mode << 5 | reg << 2 | size; bind(opcode | 0 << 6, ANDI<Byte>, ea);
bind(ANDI, ea); bind(opcode | 1 << 6, ANDI<Word>, ea);
} bind(opcode | 2 << 6, ANDI<Long>, ea);
} }
//BCC //BCC
match("0110 ---- ---- ----") { for(uint4 condition : range( 16))
uint4 condition = bits(11,8); for(uint8 displacement : range(256)) {
uint8 displacement = bits(7,0); auto opcode = pattern("0110 ---- ---- ----") | condition << 8 | displacement << 0;
if(true) { bind(opcode, BCC, condition, displacement);
bind(BCC, condition, displacement);
}
} }
//LEA //LEA
match("0100 ---1 11-- ----") { for(uint3 areg : range(8))
uint3 target = bits(11,9); for(uint3 mode : range(8))
uint3 mode = bits(5,3); for(uint3 reg : range(8)) {
uint3 reg = bits(2,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 == 2 || mode == 5 || mode == 6 || (mode == 7 && reg <= 4)) { Register ra{8u + areg};
uint8 ea = mode << 5 | reg << 2 | Long; EA ea{mode, reg};
bind(LEA, target, ea); bind(opcode, LEA, ra, ea);
}
} }
//MOVE //MOVE
match("00-- ---- ---- ----") { for(uint3 toReg : range(8))
uint2 size = bits(13,12) == 1 ? Byte : bits(13,12) == 3 ? Word : bits(13,12) == 2 ? Long : 3; for(uint3 toMode : range(8))
uint3 targetReg = bits(11,9); for(uint3 fromMode : range(8))
uint3 targetMode = bits(8,6); for(uint3 fromReg : range(8)) {
uint3 sourceMode = bits(5,3); auto opcode = pattern("00++ ---- ---- ----") | toReg << 9 | toMode << 6 | fromMode << 3 | fromReg << 0;
uint3 sourceReg = bits(2,0); if(toMode == 1 || (toMode == 7 && toReg >= 4)) continue;
if(size != 3 && targetMode != 1) { EA to{toMode, toReg};
uint8 to = targetMode << 5 | targetReg << 2 | size; EA from{fromMode, fromReg};
uint8 from = sourceMode << 5 | sourceReg << 2 | size; bind(opcode | 1 << 12, MOVE<Byte>, to, from);
bind(MOVE, to, from); bind(opcode | 3 << 12, MOVE<Word>, to, from);
} bind(opcode | 2 << 12, MOVE<Long>, to, from);
} }
//MOVEA //MOVEA
match("00-- ---0 01-- ----") { for(uint3 areg : range(8))
uint2 size = bits(13,12) == 3 ? Word : bits(13,12) == 2 ? Long : 3; for(uint3 mode : range(8))
uint3 to = bits(11,9); for(uint3 reg : range(8)) {
uint3 mode = bits(5,3); auto opcode = pattern("00++ ---0 01-- ----") | areg << 9 | mode << 3 | reg << 0;
uint3 reg = bits(2,0);
if(size != 3) { Register ra{8u + areg};
uint8 from = mode << 5 | reg << 2 | size; EA ea{mode, reg};
bind(MOVEA, to, from); bind(opcode | 3 << 12, MOVEA<Word>, ra, ea);
} bind(opcode | 2 << 12, MOVEA<Long>, ra, ea);
} }
//MOVEM //MOVEM
match("0100 1-00 1--- ----") { for(uint1 direction : range(2))
uint1 direction = bit(10); for(uint3 mode : range(8))
uint2 size = 1 + bit(6); for(uint3 reg : range(8)) {
uint3 mode = bits(5,3); auto opcode = pattern("0100 1-00 1+-- ----") | direction << 10 | mode << 3 | reg << 0;
uint3 reg = bits(2,0); if(mode <= 1 || mode == 3 || (mode == 7 && reg >= 4));
if((direction == 0 && (mode == 2 || mode == 4 || mode == 5 || mode == 6 || (mode == 7 && reg <= 3))) EA ea{mode, reg};
|| (direction == 1 && (mode == 2 || mode == 3 || mode == 5 || mode == 6 || (mode == 7 && reg <= 3)))) { bind(opcode | 0 << 6, MOVEM<Word>, direction, ea);
uint8 ea = mode << 5 | reg << 2 | size; bind(opcode | 1 << 6, MOVEM<Long>, direction, ea);
bind(MOVEM, direction, ea);
}
} }
//MOVEQ //MOVEQ
match("0111 ---0 ---- ----") { for(uint3 dreg : range( 8))
uint3 target = bits(11,9); for(uint8 immediate : range(256)) {
uint8 immediate = bits(7,0); auto opcode = pattern("0111 ---0 ---- ----") | dreg << 9 | immediate << 0;
if(true) { Register rd{0u + dreg};
bind(MOVEQ, target, immediate); bind(opcode, MOVEQ, rd, immediate);
}
} }
//MOVE_USP //MOVE_USP
match("0100 1110 0110 ----") { for(uint1 direction : range(2))
uint1 direction = bit(3); for(uint3 areg : range(8)) {
uint3 reg = bits(2,0); auto opcode = pattern("0100 1110 0110 ----") | direction << 3 | areg << 0;
if(true) { Register ra{8u + areg};
bind(MOVE_USP, direction, reg); bind(opcode, MOVE_USP, direction, ra);
}
} }
//NOP //NOP
match("0100 1110 0111 0001") { { auto opcode = pattern("0100 1110 0111 0001");
if(true) {
bind(NOP); bind(opcode, NOP);
}
} }
//TST //TST
match("0100 1010 ---- ----") { for(uint3 mode : range(8))
uint2 size = bits(7,6); for(uint3 reg : range(8)) {
uint3 mode = bits(5,3); auto opcode = pattern("0100 1010 ++-- ----") | mode << 3 | reg << 0;
uint3 reg = bits(2,0);
if(size != 3) { EA ea{mode, reg};
uint8 ea = mode << 5 | reg << 2 | size << 0; bind(opcode | 0 << 6, TST<Byte>, ea);
bind(TST, ea); bind(opcode | 1 << 6, TST<Word>, ea);
} bind(opcode | 2 << 6, TST<Long>, ea);
} }
}
#undef match
#undef bind #undef bind
#undef bit #undef pattern
#undef bits
uint unimplemented = 0;
for(uint16 opcode : range(65536)) { for(uint16 opcode : range(65536)) {
if(instructionTable[opcode]) continue; if(instructionTable[opcode]) continue;
instructionTable[opcode] = [=] { trap(); }; instructionTable[opcode] = [=] { trap(); };
disassembleTable[opcode] = [=] { return string{"???"}; }; disassembleTable[opcode] = [=] { return string{"???"}; };
unimplemented++;
} }
//print("[M68K] unimplemented opcodes: ", unimplemented, "\n");
} }

View File

@ -46,30 +46,20 @@ template<uint Size> auto M68K::negative(uint32 result) -> bool {
return sign<Size>(result) < 0; return sign<Size>(result) < 0;
} }
auto M68K::zero(uint2 size, uint32 result) -> bool {
static const uint32 mask[4] = {0xff, 0xffff, 0xffffffff};
return (result & mask[size]) == 0;
}
auto M68K::negative(uint2 size, uint32 result) -> bool {
static const uint32 mask[4] = {0x80, 0x8000, 0x80000000};
return result & mask[size];
}
// //
template<uint Size> auto M68K::instructionADD(uint3 reg, uint1 direction, EA ea) -> void { template<uint Size> auto M68K::instructionADD(Register rd, uint1 direction, EA 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 = r.d(reg); target = read<Size>(rd);
result = source + target; result = source + target;
r.d(reg) = result; write<Size>(rd, result);
} else { } else {
source = r.d(reg); source = read<Size>(rd);
target = read<Size>(ea); target = read<Size>(ea);
result = source + target; result = source + target;
write<Size>(ea, result); write<Size>(ea, result);
@ -82,95 +72,86 @@ template<uint Size> auto M68K::instructionADD(uint3 reg, uint1 direction, EA ea)
r.x = r.c; r.x = r.c;
} }
auto M68K::instructionANDI(uint8 ea) -> void { template<uint Size> auto M68K::instructionANDI(EA ea) -> void {
auto result = modify(ea, readPC(ea), [&](auto x, auto y) -> uint32 { auto source = readPC<Size>();
return x & y; auto target = read<Size, NoUpdate>(ea);
}); auto result = target & source;
write<Size>(ea, result);
r.c = 0; r.c = 0;
r.v = 0; r.v = 0;
r.z = zero(ea, result); r.z = zero<Size>(result);
r.n = negative(ea, result); r.n = negative<Size>(result);
} }
auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void { auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void {
auto word = readPC(); auto extension = readPC();
if(displacement) displacement = (int8)displacement, r.pc -= 2; if(condition == 1); //push<Long>(r.pc);
else displacement = (int16)word; r.pc -= 2;
if(condition == 1) { if(!testCondition(condition == 1 ? (uint4)0 : condition)) return;
condition = 0; r.pc += displacement ? sign<Byte>(displacement) : sign<Word>(extension);
//pushLong(r.pc);
}
if(testCondition(condition)) r.pc += displacement;
} }
auto M68K::instructionLEA(uint3 target, uint8 ea) -> void { auto M68K::instructionLEA(Register ra, EA ea) -> void {
r.a(target) = address(ea); write<Long>(ra, fetch<Long>(ea));
} }
auto M68K::instructionMOVE(uint8 to, uint8 from) -> void { template<uint Size> auto M68K::instructionMOVE(EA to, EA from) -> void {
auto data = read(from); auto data = read<Size>(from);
write(to, data); write<Size>(to, data);
r.c = 0; r.c = 0;
r.v = 0; r.v = 0;
r.z = zero(from, data); r.z = zero<Size>(data);
r.n = negative(from, data); r.n = negative<Size>(data);
} }
auto M68K::instructionMOVEA(uint3 to, uint8 from) -> void { template<uint Size> auto M68K::instructionMOVEA(Register ra, EA ea) -> void {
auto data = read(from); auto data = read<Size>(ea);
if(from & 1) data = (int16)data; if(Size == Word) data = (int16)data;
r.a(to) = data; write<Size>(ra, data);
} }
auto M68K::instructionMOVEM(uint1 direction, uint8 ea) -> void { template<uint Size> auto M68K::instructionMOVEM(uint1 direction, EA ea) -> void {
auto list = readPC(); auto list = readPC();
auto addr = address(ea); auto addr = fetch<Size>(ea);
for(uint n : range(8)) { for(uint rn : range(16)) {
if(list.bit(0 + n)) { if(list.bit(rn)) {
r.d(n) = readAbsolute(ea, addr); write<Size>(Register{rn}, read<Size>(addr));
addr += 2 + (ea & 2); addr += Size == Long ? 4 : 2;
} }
} }
for(uint n : range(8)) { flush<Size>(ea, addr);
if(list.bit(8 + n)) {
r.a(n) = readAbsolute(ea, addr);
addr += 2 + (ea & 2);
}
} }
flush(ea, addr); auto M68K::instructionMOVEQ(Register rd, uint8 immediate) -> void {
} write<Byte>(rd, immediate);
auto M68K::instructionMOVEQ(uint3 target, uint8 immediate) -> void {
r.d(target) = immediate;
r.c = 0; r.c = 0;
r.v = 0; r.v = 0;
r.z = immediate == 0; r.z = zero<Byte>(immediate);
r.n = negative(Byte, immediate); r.n = negative<Byte>(immediate);
} }
auto M68K::instructionMOVE_USP(uint1 direction, uint3 reg) -> void { auto M68K::instructionMOVE_USP(uint1 direction, Register ra) -> void {
if(!r.s) trap(); //todo: proper trap if(!r.s) trap(); //todo: proper trap
if(direction == 0) { if(direction == 0) {
r.usp = r.a(reg); r.usp = read<Long>(ra);
} else { } else {
r.a(reg) = r.usp; write<Long>(ra, r.usp);
} }
} }
auto M68K::instructionNOP() -> void { auto M68K::instructionNOP() -> void {
} }
auto M68K::instructionTST(uint8 ea) -> void { template<uint Size> auto M68K::instructionTST(EA ea) -> void {
auto data = read(ea); auto data = read<Size>(ea);
r.c = 0; r.c = 0;
r.v = 0; r.v = 0;
r.z = zero(ea, data); r.z = zero<Size>(data);
r.n = negative(ea, data); r.n = negative<Size>(data);
} }

View File

@ -18,8 +18,7 @@ auto M68K::power() -> void {
auto M68K::reset() -> void { auto M68K::reset() -> void {
instructionsExecuted = 0; instructionsExecuted = 0;
for(uint n : range(8)) r.d(n) = 0; for(uint rn : range(15)) write<Long>(Register{rn}, 0);
for(uint n : range(7)) r.a(n) = 0;
r.ssp = 0; r.ssp = 0;
r.usp = 0; r.usp = 0;
r.pc = 0; r.pc = 0;

View File

@ -6,6 +6,7 @@ namespace Processor {
struct M68K { struct M68K {
enum : uint { Byte, Word, Long }; enum : uint { Byte, Word, Long };
enum : bool { NoUpdate = 0 };
M68K(); M68K();
@ -16,32 +17,39 @@ struct M68K {
auto power() -> void; auto power() -> void;
auto reset() -> void; auto reset() -> void;
//registers.cpp
struct Register {
Register(uint number) : number(number) {}
uint4 number;
};
template<uint Size = Long> auto read(Register reg) -> uint32;
template<uint Size = Long> auto write(Register reg, uint32 value) -> void;
//memory.cpp //memory.cpp
auto readAbsolute(uint2 size, uint32 addr) -> uint32;
auto writeAbsolute(uint2 size, uint32 addr, uint32 data) -> void;
auto readPC(uint2 size = Word) -> uint32;
template<uint Size> auto read(uint32 addr) -> uint32; template<uint Size> auto read(uint32 addr) -> uint32;
template<uint Size> auto write(uint32 addr, uint32 data) -> void;
template<uint Size = Word> auto readPC() -> uint32;
//ea.cpp //ea.cpp
struct EA { struct EA {
EA(uint3 mode, uint3 reg) : mode(mode), reg(reg) { EA(uint mode_, uint reg_) : mode(mode_), reg(reg_) {
if(mode == 7) mode += reg; //optimization: convert modes {7; 0-4} to {8-11} 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
} }
uint4 mode; uint4 mode;
uint3 reg; Register reg;
boolean valid;
uint32 address;
}; };
template<uint Size> auto read(EA ea) -> uint32; template<uint Size> auto fetch(EA& ea) -> uint32;
template<uint Size> auto write(EA ea, uint32 data) -> void; template<uint Size, bool Update = 1> auto read(EA& ea) -> uint32;
template<uint Size, bool Update = 1> auto write(EA& ea, uint32 data) -> void;
auto address(uint8 ea) -> uint32; template<uint Size> auto flush(EA& ea, uint32 data) -> void;
auto read(uint8 ea) -> uint32;
auto write(uint8 ea, uint32 data) -> void;
auto modify(uint8 ea, uint32 data, const function<uint32 (uint32, uint32)>& op) -> uint32;
auto flush(uint8 ea, uint32 address) -> void;
//instruction.cpp //instruction.cpp
auto trap() -> void; auto trap() -> void;
@ -57,29 +65,24 @@ struct M68K {
template<uint Size> auto overflow(uint32 result, uint32 source, uint32 target) -> bool; template<uint Size> auto overflow(uint32 result, uint32 source, uint32 target) -> bool;
template<uint Size> auto zero(uint32 result) -> bool; template<uint Size> auto zero(uint32 result) -> bool;
template<uint Size> auto negative(uint32 result) -> bool; template<uint Size> auto negative(uint32 result) -> bool;
auto zero(uint2 size, uint32 result) -> bool;
auto negative(uint2 size, uint32 result) -> bool;
template<uint Size> auto instructionADD(uint3 reg, uint1 direction, EA ea) -> void; template<uint Size> auto instructionADD(Register rd, uint1 direction, EA ea) -> void;
auto instructionANDI(uint8 ea) -> void; template<uint Size> auto instructionANDI(EA ea) -> void;
auto instructionBCC(uint4 condition, uint8 displacement) -> void; auto instructionBCC(uint4 condition, uint8 displacement) -> void;
auto instructionLEA(uint3 target, uint8 source) -> void; auto instructionLEA(Register ra, EA ea) -> void;
auto instructionMOVE(uint8 to, uint8 from) -> void; template<uint Size> auto instructionMOVE(EA to, EA from) -> void;
auto instructionMOVEA(uint3 to, uint8 ea) -> void; template<uint Size> auto instructionMOVEA(Register ra, EA ea) -> void;
auto instructionMOVEM(uint1 direction, uint8 ea) -> void; template<uint Size> auto instructionMOVEM(uint1 direction, EA ea) -> void;
auto instructionMOVEQ(uint3 target, uint8 immediate) -> void; auto instructionMOVEQ(Register rd, uint8 immediate) -> void;
auto instructionMOVE_USP(uint1 direction, uint3 reg) -> void; auto instructionMOVE_USP(uint1 direction, Register ra) -> void;
auto instructionNOP() -> void; auto instructionNOP() -> void;
auto instructionTST(uint8 ea) -> void; template<uint Size> auto instructionTST(EA 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 {
auto d(uint3 r) -> uint32&;
auto a(uint3 r) -> uint32&;
uint32 d0, d1, d2, d3, d4, d5, d6, d7; uint32 d0, d1, d2, d3, d4, d5, d6, d7;
uint32 a0, a1, a2, a3, a4, a5, a6, ssp, usp; uint32 a0, a1, a2, a3, a4, a5, a6, ssp, usp;
uint32 pc; uint32 pc;
@ -106,28 +109,27 @@ struct M68K {
private: private:
//disassembler.cpp //disassembler.cpp
template<uint Size> auto disassembleADD(uint3 reg, uint1 direction, EA ea) -> string; template<uint Size> auto disassembleADD(Register rd, uint1 direction, EA ea) -> string;
auto disassembleANDI(uint8 ea) -> string; template<uint Size> auto disassembleANDI(EA ea) -> string;
auto disassembleBCC(uint4 condition, uint8 displacement) -> string; auto disassembleBCC(uint4 condition, uint8 displacement) -> string;
auto disassembleLEA(uint3 target, uint8 ea) -> string; auto disassembleLEA(Register ra, EA ea) -> string;
auto disassembleMOVE(uint8 to, uint8 from) -> string; template<uint Size> auto disassembleMOVE(EA to, EA from) -> string;
auto disassembleMOVEA(uint3 to, uint8 from) -> string; template<uint Size> auto disassembleMOVEA(Register ra, EA ea) -> string;
auto disassembleMOVEM(uint1 direction, uint8 ea) -> string; template<uint Size> auto disassembleMOVEM(uint1 direction, EA ea) -> string;
auto disassembleMOVEQ(uint3 target, uint8 immediate) -> string; auto disassembleMOVEQ(Register rd, uint8 immediate) -> string;
auto disassembleMOVE_USP(uint1 direction, uint3 reg) -> string; auto disassembleMOVE_USP(uint1 direction, Register ra) -> string;
auto disassembleNOP() -> string; auto disassembleNOP() -> string;
auto disassembleTST(uint8 ea) -> string; template<uint Size> auto disassembleTST(EA ea) -> string;
auto _readByte(uint32 addr) -> uint8; template<uint Size> auto _read(uint32 addr) -> uint32;
auto _readWord(uint32 addr) -> uint16; template<uint Size = Word> auto _readPC() -> uint32;
auto _readLong(uint32 addr) -> uint32; auto _register(Register r) -> string;
auto _readPC(uint2 size = Word) -> uint32; template<uint Size> auto _immediate() -> string;
auto _immediate(uint2 size) -> string; template<uint Size> auto _address(EA ea) -> string;
auto _address(uint8 ea) -> string; template<uint Size> auto _read(EA ea) -> string;
auto _read(uint8 ea) -> string; template<uint Size> auto _write(EA ea) -> string;
auto _write(uint8 ea) -> string;
auto _branch(uint8 displacement) -> string; auto _branch(uint8 displacement) -> string;
auto _suffix(uint2 size) -> string; template<uint Size> auto _suffix() -> string;
auto _condition(uint4 condition) -> string; auto _condition(uint4 condition) -> string;
uint32 _pc; uint32 _pc;

View File

@ -1,24 +1,4 @@
auto M68K::readAbsolute(uint2 size, uint32 addr) -> uint32 { /*
step(4);
uint32 data = read(size != Byte, addr);
if(size != Long) return data;
step(4);
data = data << 16 | read(1, addr + 2);
return data;
}
auto M68K::writeAbsolute(uint2 size, uint32 addr, uint32 data) -> void {
if(size == Long) {
write(1, addr + 0, data >> 16);
write(1, addr + 2, data >> 0);
} else {
write(size != Byte, addr, data >> 0);
}
}
//
auto M68K::readPC(uint2 size) -> uint32 { auto M68K::readPC(uint2 size) -> uint32 {
step(4); step(4);
uint32 data = read(size != Byte, r.pc); uint32 data = read(size != Byte, r.pc);
@ -30,8 +10,7 @@ auto M68K::readPC(uint2 size) -> uint32 {
r.pc += 2; r.pc += 2;
return data; return data;
} }
*/
//
template<> auto M68K::read<Byte>(uint32 addr) -> uint32 { template<> auto M68K::read<Byte>(uint32 addr) -> uint32 {
step(4); step(4);
@ -49,3 +28,40 @@ template<> auto M68K::read<Long>(uint32 addr) -> uint32 {
step(4); step(4);
return data | read(1, addr + 2) << 0; return data | read(1, addr + 2) << 0;
} }
//
template<> auto M68K::write<Byte>(uint32 addr, uint32 data) -> void {
}
template<> auto M68K::write<Word>(uint32 addr, uint32 data) -> void {
}
template<> auto M68K::write<Long>(uint32 addr, uint32 data) -> void {
}
//
template<> auto M68K::readPC<Byte>() -> uint32 {
step(4);
uint32 data = read(1, r.pc);
r.pc += 2;
return (uint8)data;
}
template<> auto M68K::readPC<Word>() -> uint32 {
step(4);
uint32 data = read(1, r.pc);
r.pc += 2;
return data;
}
template<> auto M68K::readPC<Long>() -> uint32 {
step(4);
uint32 data = read(1, r.pc) << 16;
r.pc += 2;
step(4);
data |= read(1, r.pc);
r.pc += 2;
return data;
}

View File

@ -1,26 +1,42 @@
auto M68K::Registers::d(uint3 r) -> uint32& { template<uint Size> auto M68K::read(Register reg) -> uint32 {
switch(r) { switch(reg.number) {
case 0: return d0; case 0: return clip<Size>(r.d0);
case 1: return d1; case 1: return clip<Size>(r.d1);
case 2: return d2; case 2: return clip<Size>(r.d2);
case 3: return d3; case 3: return clip<Size>(r.d3);
case 4: return d4; case 4: return clip<Size>(r.d4);
case 5: return d5; case 5: return clip<Size>(r.d5);
case 6: return d6; case 6: return clip<Size>(r.d6);
case 7: return d7; case 7: return clip<Size>(r.d7);
case 8: return clip<Size>(r.a0);
case 9: return clip<Size>(r.a1);
case 10: return clip<Size>(r.a2);
case 11: return clip<Size>(r.a3);
case 12: return clip<Size>(r.a4);
case 13: return clip<Size>(r.a5);
case 14: return clip<Size>(r.a6);
case 15: return r.s ? clip<Size>(r.ssp) : clip<Size>(r.usp);
} }
unreachable; unreachable;
} }
auto M68K::Registers::a(uint3 r) -> uint32& { template<uint Size> auto M68K::write(Register reg, uint32 data) -> void {
switch(r) { switch(reg.number) {
case 0: return a0; case 0: r.d0 = clip<Size>(data); return;
case 1: return a1; case 1: r.d1 = clip<Size>(data); return;
case 2: return a2; case 2: r.d2 = clip<Size>(data); return;
case 3: return a3; case 3: r.d3 = clip<Size>(data); return;
case 4: return a4; case 4: r.d4 = clip<Size>(data); return;
case 5: return a5; case 5: r.d5 = clip<Size>(data); return;
case 6: return a6; case 6: r.d6 = clip<Size>(data); return;
case 7: return s ? ssp : usp; case 7: r.d7 = clip<Size>(data); return;
case 8: r.a0 = clip<Size>(data); return;
case 9: r.a1 = clip<Size>(data); return;
case 10: r.a2 = clip<Size>(data); return;
case 11: r.a3 = clip<Size>(data); return;
case 12: r.a4 = clip<Size>(data); return;
case 13: r.a5 = clip<Size>(data); return;
case 14: r.a6 = clip<Size>(data); return;
case 15: r.s ? r.ssp = clip<Size>(data) : r.usp = clip<Size>(data); return;
} }
} }