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 {
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 License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -10,8 +10,8 @@ auto CPU::Enter() -> void {
}
auto CPU::boot() -> void {
r.ssp = readAbsolute(Long, 0);
r.pc = readAbsolute(Long, 4);
r.ssp = read(1, 0) << 16 | read(1, 2) << 0;
r.pc = read(1, 4) << 16 | read(1, 6) << 0;
}
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);
}
auto M68K::_readWord(uint32 addr) -> uint16 {
template<> auto M68K::_read<Word>(uint32 addr) -> uint32 {
return read(1, addr);
}
auto M68K::_readLong(uint32 addr) -> uint32 {
uint32 data = _readWord(addr + 0) << 16;
return data |= _readWord(addr + 2) << 0;
template<> auto M68K::_read<Long>(uint32 addr) -> uint32 {
uint32 data = _read<Word>(addr + 0) << 16;
return data | _read<Word>(addr + 2) << 0;
}
auto M68K::_readPC(uint2 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;
template<uint Size> auto M68K::_readPC() -> uint32 {
auto data = _read<Size == Byte ? Word : Size>(_pc);
_pc += Size == Long ? 4 : 2;
return clip<Size>(data);
}
auto M68K::_immediate(uint2 size) -> string {
if(size == Byte) return {"#$", hex(_readPC(Byte), 2L)};
if(size == Word) return {"#$", hex(_readPC(Word), 4L)};
if(size == Long) return {"#$", hex(_readPC(Long), 8L)};
return "#???";
auto M68K::_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::_address(uint8 ea) -> string {
uint3 mode = ea >> 5;
uint3 reg = ea >> 2;
uint2 size = ea >> 0;
template<uint Size> auto M68K::_immediate() -> string {
return {"#$", hex(_readPC<Size>(), 2 << Size)};
}
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 "???";
}
auto M68K::_read(uint8 ea) -> string {
uint3 mode = ea >> 5;
uint3 reg = ea >> 2;
uint2 size = ea >> 0;
if(mode == 0) return {"d", reg};
if(mode == 1) return {"a", reg};
if(mode == 2) return {"(a", reg, ")"};
if(mode == 3) return {"(a", reg, ")+"};
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)};
}
}
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), ")"};
if(ea.mode == 8) return {"($", hex(_readPC<Long>(), 6L), ")"};
if(ea.mode == 11) return {"#$", hex(_readPC<Size>(), 2 << Size)};
return "???";
}
auto M68K::_write(uint8 ea) -> string {
return _read(ea);
template<uint Size> auto M68K::_write(EA ea) -> string {
return _read<Size>(ea);
}
auto M68K::_branch(uint8 displacement) -> string {
@ -72,11 +57,8 @@ auto M68K::_branch(uint8 displacement) -> string {
return {"$", hex(_pc + displacement, 6L)};
}
auto M68K::_suffix(uint2 size) -> string {
if(size == Byte) return ".b";
if(size == Word) return ".w";
if(size == Long) return ".l";
return ".?";
template<uint Size> auto M68K::_suffix() -> string {
return Size == Byte ? ".b" : Size == Word ? ".w" : ".l";
}
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 {
string op{"add", _suffix(ea.reg), " "};
return op;
template<uint Size> auto M68K::disassembleADD(Register rd, uint1 direction, EA ea) -> string {
string op{"add", _suffix<Size>(), " "};
if(direction == 0) {
// return {op, _read(ea), ",d", reg};
return {op, _read<Size>(ea), ",", _register(rd)};
} else {
// return {op, "d", reg, ",", _read(ea)};
return {op, "", _register(rd), ",", _read<Size>(ea)};
}
}
auto M68K::disassembleANDI(uint8 ea) -> string {
return {"andi", _suffix(ea), " ", _immediate(ea), ",", _read(ea)};
template<uint Size> auto M68K::disassembleANDI(EA ea) -> string {
return {"andi", _suffix<Size>(), " ", _immediate<Size>(), ",", _read<Size>(ea)};
}
auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string {
return {"b", _condition(condition), " ", _branch(displacement)};
}
auto M68K::disassembleLEA(uint3 to, uint8 ea) -> string {
return {"lea ", _address(ea), ",a", to};
auto M68K::disassembleLEA(Register ra, EA ea) -> string {
return {"lea ", _address<Long>(ea), ",", _register(ra)};
}
auto M68K::disassembleMOVE(uint8 to, uint8 from) -> string {
return {"move", _suffix(from), " ", _read(from), ",", _write(to)};
template<uint Size> auto M68K::disassembleMOVE(EA to, EA from) -> string {
return {"move", _suffix<Size>(), " ", _read<Size>(from), ",", _write<Size>(to)};
}
auto M68K::disassembleMOVEA(uint3 to, uint8 from) -> string {
return {"movea ", _read(from), ",a", to};
template<uint Size> auto M68K::disassembleMOVEA(Register ra, EA ea) -> string {
return {"movea ", _read<Size>(ea), ",", _register(ra)};
}
auto M68K::disassembleMOVEM(uint1 direction, uint8 ea) -> string {
string op{"movem", _suffix(ea), " "};
template<uint Size> auto M68K::disassembleMOVEM(uint1 direction, EA ea) -> 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, ",");
for(uint rn : range(16)) if(list.bit(rn)) regs.append(_register(Register{rn}), ",");
regs.trimRight(",");
if(direction == 0) {
return {op, regs, ",", _read(ea)};
return {op, regs, ",", _read<Size>(ea)};
} else {
return {op, _read(ea), ",", regs};
return {op, _read<Size>(ea), ",", regs};
}
}
auto M68K::disassembleMOVEQ(uint3 target, uint8 immediate) -> string {
return {"moveq #$", hex(immediate, 2L), ",d", target};
auto M68K::disassembleMOVEQ(Register rd, uint8 immediate) -> string {
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) {
return {"move a", reg, ",usp"};
return {"move ", _register(ra), ",usp"};
} else {
return {"move usp,a", reg};
return {"move usp,", _register(ra)};
}
}
@ -176,6 +154,6 @@ auto M68K::disassembleNOP() -> string {
return {"nop "};
}
auto M68K::disassembleTST(uint8 ea) -> string {
return {"tst", _suffix(ea), " ", _read(ea)};
template<uint Size> auto M68K::disassembleTST(EA ea) -> string {
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:
// d7-d5: mode
// d4-d2: register
// d1-d0: size (0 = byte, 1 = word, 2 = long)
switch(ea.mode) {
auto M68K::address(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:
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;
case 0: { //data register direct
return read(ea.reg);
}
//absolute short indirect
case 0b111'000'00 ... 0b111'000'11:
case 1: { //data register indirect
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();
//absolute long indirect
case 0b111'001'00 ... 0b111'001'11: {
uint32 address = readPC() << 16;
return address | readPC() << 0;
}
//program counter indirect with displacement
case 0b111'010'00 ... 0b111'010'11: {
case 8: { //absolute long indirect
return readPC<Long>();
}
case 9: { //program counter indirect with displacement
auto base = r.pc;
return base + (int16)readPC();
}
//program counter indirect with index
case 0b111'011'00 ... 0b111'011'11: {
case 10: { //program counter indirect with index
auto base = r.pc;
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x800) index = (int16)index;
return base + index + (int8)word;
auto extension = readPC();
auto index = read(Register{extension >> 12});
if(extension & 0x800) index = (int16)index;
return base + index + (int8)extension;
}
//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;
case 11: { //immediate
return readPC<Size>();
}
//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) {
case 0: { //data register direct
return clip<Size>(r.d(ea.reg));
return clip<Size>(ea.address);
}
case 1: { //address register direct
return clip<Size>(r.a(ea.reg));
return clip<Size>(ea.address);
}
case 2: { //address register indirect
auto& address = r.a(ea.reg);
return read<Size>(address);
return read<Size>(ea.address);
}
case 3: { //address register indirect with post-increment
auto& address = r.a(ea.reg);
auto data = read<Size>(address);
address += Size == Long ? 4 : 2;
auto data = read<Size>(ea.address);
if(Update) write(ea.reg, ea.address += (Size == Long ? 4 : 2));
return data;
}
case 4: { //address register indirect with pre-decrement
auto& address = r.a(ea.reg);
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);
auto data = read<Size>((uint32)(ea.address - (Size == Long ? 4 : 2)));
if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2));
return data;
}
//address register indirect with pre-decrement
case 0b100'000'00 ... 0b100'111'11: {
auto& address = r.a(ea >> 2);
address -= 2 + (ea & 2);
return readAbsolute(ea, address);
case 5: { //address register indirect with displacement
return read<Size>(ea.address);
}
//address register indirect with displacement
case 0b101'000'00 ... 0b101'111'11:
return readAbsolute(ea, r.a(ea >> 2) + (int16)readPC());
//address register indirect with index
case 0b110'000'00 ... 0b110'111'11: {
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x800) index = (int16)index;
return readAbsolute(ea, r.a(ea >> 2) + index + (int8)word);
case 6: { //address register indirect with index
return read<Size>(ea.address);
}
//absolute short indirect
case 0b111'000'00 ... 0b111'000'11:
return readAbsolute(ea, (int16)readPC());
//absolute long indirect
case 0b111'001'00 ... 0b111'001'11: {
uint32 address = readPC() << 16;
return readAbsolute(ea, address | readPC());
case 7: { //absolute short indirect
return read<Size>(ea.address);
}
//program counter indirect with displacement
case 0b111'010'00 ... 0b111'010'11: {
auto base = r.pc;
return readAbsolute(ea, base + (int16)readPC());
case 8: { //absolute long indirect
return read<Size>(ea.address);
}
//program counter indirect with index
case 0b111'011'00 ... 0b111'011'11: {
auto base = r.pc;
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x800) index = (int16)index;
return readAbsolute(ea, base + index + (int8)word);
case 9: { //program counter indirect with displacement
return read<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;
case 10: { //program counter indirect with index
return read<Size>(ea.address);
}
//invalid
default:
return 0;
case 11: { //immediate
return clip<Size>(ea.address);
}
}
return 0;
}
auto M68K::write(uint8 ea, uint32 data) -> void {
switch(ea) {
template<uint Size, bool Update> auto M68K::write(EA& ea, uint32 data) -> void {
if(!ea.valid) ea.address = fetch<Size>(ea);
//data register direct
case 0b000'000'00 ... 0b000'111'11:
r.d(ea >> 2) = data;
return;
switch(ea.mode) {
//address register direct
case 0b001'000'00 ... 0b001'111'11:
r.a(ea >> 2) = data;
return;
//address register indirect
case 0b010'000'00 ... 0b010'111'11: {
auto address = r.a(ea >> 2);
return writeAbsolute(ea, address, data);
case 0: { //data register direct
return write<Size>(ea.reg, data);
}
//address register indirect with post-increment
case 0b011'000'00 ... 0b011'111'11: {
auto& address = r.a(ea >> 2);
writeAbsolute(ea, address, data);
address += 2 + (ea & 2);
case 1: { //address register direct
return write<Size>(ea.reg, data);
}
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;
}
//address register indirect with pre-decrement
case 0b100'000'00 ... 0b100'111'11: {
auto& address = r.a(ea >> 2);
address -= 2 + (ea & 2);
return writeAbsolute(ea, address, data);
case 4: { //address register indirect with pre-decrement
write<Size>((uint32)(ea.address - (Size == Long ? 4 : 2)), data);
if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2));
return;
}
//address register indirect with displacement
case 0b101'000'00 ... 0b101'111'11:
return writeAbsolute(ea, r.a(ea >> 2) + (int16)readPC(), data);
//address register indirect with index
case 0b110'000'00 ... 0b110'111'11: {
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x800) index = (int16)index;
return writeAbsolute(ea, r.a(ea >> 2) + index + (int8)word, data);
case 5: { //address register indirect with displacement
return write<Size>(ea.address, data);
}
//absolute short indirect
case 0b111'000'00 ... 0b111'000'11:
return writeAbsolute(ea, (int16)readPC(), data);
//absolute long indirect
case 0b111'001'00 ... 0b111'001'11: {
uint32 address = readPC() << 16;
return writeAbsolute(ea, address | readPC(), data);
case 6: { //address register indirect with index
return write<Size>(ea.address, data);
}
//program counter indirect with displacement
case 0b111'010'00 ... 0b111'010'11: {
auto base = r.pc;
return writeAbsolute(ea, base + (int16)readPC(), data);
case 7: { //absolute short indirect
return write<Size>(ea.address, data);
}
//program counter indirect with index
case 0b111'011'00 ... 0b111'011'11: {
auto base = r.pc;
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x800) index = (int16)index;
return writeAbsolute(ea, base + index + (int8)word, data);
case 8: { //absolute long indirect
return write<Size>(ea.address, data);
}
case 9: { //program counter indirect with displacement
return write<Size>(ea.address, 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 {
switch(ea) {
template<uint Size> auto M68K::flush(EA& ea, uint32 data) -> void {
switch(ea.mode) {
//data register direct
case 0b000'000'00 ... 0b000'111'11: {
auto& address = r.d(ea >> 2);
return address = op(address, data);
case 3: { //address register indirect with post-increment
write<Size>(ea.reg, data);
return;
}
//address register direct
case 0b001'000'00 ... 0b001'111'11: {
auto& address = r.a(ea >> 2);
return address = op(address, data);
}
//address register indirect
case 0b010'000'00 ... 0b010'111'11: {
auto address = r.a(ea >> 2);
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//address register indirect with post-increment
case 0b011'000'00 ... 0b011'111'11: {
auto& address = r.a(ea >> 2);
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
address += 2 + (ea & 2);
return memory;
}
//address register indirect with pre-decrement
case 0b100'000'00 ... 0b100'111'11: {
auto& address = r.a(ea >> 2);
address -= 2 + (ea & 2);
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//address register indirect with displacement
case 0b101'000'00 ... 0b101'111'11: {
auto address = r.a(ea >> 2) + (int16)readPC();
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//address register indirect with index
case 0b110'000'00 ... 0b110'111'11: {
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x800) index = (int16)index;
auto address = r.a(ea >> 2) + index + (int8)word;
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//absolute short indirect
case 0b111'000'00 ... 0b111'000'11: {
auto address = (int16)readPC();
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//absolute long indirect
case 0b111'001'00 ... 0b111'001'11: {
auto word = readPC();
uint32 address = word << 16 | readPC();
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//program counter indirect with displacement
case 0b111'010'00 ... 0b111'010'11: {
auto address = r.pc;
address += (int16)readPC();
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//program counter indirect with index
case 0b111'011'00 ... 0b111'011'11: {
auto address = r.pc;
auto word = readPC();
auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12);
if(word & 0x8000) index = (int16)index;
address += index + (int8)word;
auto memory = readAbsolute(ea, address);
writeAbsolute(ea, address, memory = op(memory, data));
return memory;
}
//immediate byte
case 0b111'100'00:
return op((uint8)readPC(), data);
//immediate word
case 0b111'100'01:
return op(readPC(), data);
//immediate long
case 0b111'100'10: {
uint32 immediate = readPC() << 16;
immediate |= readPC();
return op(immediate, data);
case 4: { //address register indirect with pre-decrement
write<Size>(ea.reg, data);
return;
}
}
}
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 {
instructionsExecuted++;
print(disassembleRegisters(), "\n", disassemble(r.pc), "\n\n");
print(disassembleRegisters(), "\n");
print(disassemble(r.pc), "\n");
print("\n");
opcode = readPC();
return instructionTable[opcode]();
@ -18,180 +20,141 @@ M68K::M68K() {
#define bind(id, name, ...) \
assert(!instructionTable[id]); \
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
for(uint3 d : range(8))
for(uint3 dreg : range(8))
for(uint1 direction : range(2))
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = 0b1101'0000'0000'0000 | d << 9 | direction << 8 | mode << 3 | reg << 0;
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{0u + dreg};
EA ea{mode, reg};
bind(opcode | 0 << 6, ADD<Byte>, d, direction, ea);
bind(opcode | 1 << 6, ADD<Word>, d, direction, ea);
bind(opcode | 2 << 6, ADD<Long>, d, direction, ea);
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);
}
//ANDI
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("0000 0010 ++-- ----") | mode << 3 | reg << 0;
if(mode == 1 || (mode == 7 && reg >= 4)) continue;
EA ea{mode, reg};
bind(opcode | 0 << 6, ANDI<Byte>, ea);
bind(opcode | 1 << 6, ANDI<Word>, ea);
bind(opcode | 2 << 6, ANDI<Long>, ea);
}
//BCC
for(uint4 condition : range( 16))
for(uint8 displacement : range(256)) {
auto opcode = pattern("0110 ---- ---- ----") | condition << 8 | displacement << 0;
bind(opcode, BCC, condition, displacement);
}
//LEA
for(uint3 areg : range(8))
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
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{8u + areg};
EA ea{mode, reg};
bind(opcode, LEA, ra, ea);
}
//MOVE
for(uint3 toReg : range(8))
for(uint3 toMode : range(8))
for(uint3 fromMode : range(8))
for(uint3 fromReg : range(8)) {
auto opcode = pattern("00++ ---- ---- ----") | toReg << 9 | toMode << 6 | fromMode << 3 | fromReg << 0;
if(toMode == 1 || (toMode == 7 && toReg >= 4)) continue;
EA to{toMode, toReg};
EA 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);
}
//MOVEA
for(uint3 areg : range(8))
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("00++ ---0 01-- ----") | areg << 9 | mode << 3 | reg << 0;
Register ra{8u + areg};
EA ea{mode, reg};
bind(opcode | 3 << 12, MOVEA<Word>, ra, ea);
bind(opcode | 2 << 12, MOVEA<Long>, ra, ea);
}
//MOVEM
for(uint1 direction : range(2))
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("0100 1-00 1+-- ----") | direction << 10 | mode << 3 | reg << 0;
if(mode <= 1 || mode == 3 || (mode == 7 && reg >= 4));
EA ea{mode, reg};
bind(opcode | 0 << 6, MOVEM<Word>, direction, ea);
bind(opcode | 1 << 6, MOVEM<Long>, direction, ea);
}
//MOVEQ
for(uint3 dreg : range( 8))
for(uint8 immediate : range(256)) {
auto opcode = pattern("0111 ---0 ---- ----") | dreg << 9 | immediate << 0;
Register rd{0u + dreg};
bind(opcode, MOVEQ, rd, immediate);
}
//MOVE_USP
for(uint1 direction : range(2))
for(uint3 areg : range(8)) {
auto opcode = pattern("0100 1110 0110 ----") | direction << 3 | areg << 0;
Register ra{8u + areg};
bind(opcode, MOVE_USP, direction, ra);
}
//NOP
{ auto opcode = pattern("0100 1110 0111 0001");
bind(opcode, NOP);
}
//TST
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("0100 1010 ++-- ----") | mode << 3 | reg << 0;
EA ea{mode, reg};
bind(opcode | 0 << 6, TST<Byte>, ea);
bind(opcode | 1 << 6, TST<Word>, ea);
bind(opcode | 2 << 6, TST<Long>, ea);
}
#undef bind
#undef pattern
#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
match("0000 0010 ---- ----") {
uint2 size = bits(7,6);
uint3 mode = bits(5,3);
uint3 reg = bits(2,0);
if(size != 3 && mode != 1) {
uint8 ea = mode << 5 | reg << 2 | size;
bind(ANDI, ea);
}
}
//BCC
match("0110 ---- ---- ----") {
uint4 condition = bits(11,8);
uint8 displacement = bits(7,0);
if(true) {
bind(BCC, condition, displacement);
}
}
//LEA
match("0100 ---1 11-- ----") {
uint3 target = bits(11,9);
uint3 mode = bits(5,3);
uint3 reg = bits(2,0);
if(mode == 2 || mode == 5 || mode == 6 || (mode == 7 && reg <= 4)) {
uint8 ea = mode << 5 | reg << 2 | Long;
bind(LEA, target, ea);
}
}
//MOVE
match("00-- ---- ---- ----") {
uint2 size = bits(13,12) == 1 ? Byte : bits(13,12) == 3 ? Word : bits(13,12) == 2 ? Long : 3;
uint3 targetReg = bits(11,9);
uint3 targetMode = bits(8,6);
uint3 sourceMode = bits(5,3);
uint3 sourceReg = bits(2,0);
if(size != 3 && targetMode != 1) {
uint8 to = targetMode << 5 | targetReg << 2 | size;
uint8 from = sourceMode << 5 | sourceReg << 2 | size;
bind(MOVE, to, from);
}
}
//MOVEA
match("00-- ---0 01-- ----") {
uint2 size = bits(13,12) == 3 ? Word : bits(13,12) == 2 ? Long : 3;
uint3 to = bits(11,9);
uint3 mode = bits(5,3);
uint3 reg = bits(2,0);
if(size != 3) {
uint8 from = mode << 5 | reg << 2 | size;
bind(MOVEA, to, from);
}
}
//MOVEM
match("0100 1-00 1--- ----") {
uint1 direction = bit(10);
uint2 size = 1 + bit(6);
uint3 mode = bits(5,3);
uint3 reg = bits(2,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)))) {
uint8 ea = mode << 5 | reg << 2 | size;
bind(MOVEM, direction, ea);
}
}
//MOVEQ
match("0111 ---0 ---- ----") {
uint3 target = bits(11,9);
uint8 immediate = bits(7,0);
if(true) {
bind(MOVEQ, target, immediate);
}
}
//MOVE_USP
match("0100 1110 0110 ----") {
uint1 direction = bit(3);
uint3 reg = bits(2,0);
if(true) {
bind(MOVE_USP, direction, reg);
}
}
//NOP
match("0100 1110 0111 0001") {
if(true) {
bind(NOP);
}
}
//TST
match("0100 1010 ---- ----") {
uint2 size = bits(7,6);
uint3 mode = bits(5,3);
uint3 reg = bits(2,0);
if(size != 3) {
uint8 ea = mode << 5 | reg << 2 | size << 0;
bind(TST, ea);
}
}
}
#undef match
#undef bind
#undef bit
#undef bits
uint unimplemented = 0;
for(uint16 opcode : range(65536)) {
if(instructionTable[opcode]) continue;
instructionTable[opcode] = [=] { trap(); };
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;
}
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 target;
uint32 result;
if(direction == 0) {
source = read<Size>(ea);
target = r.d(reg);
target = read<Size>(rd);
result = source + target;
r.d(reg) = result;
write<Size>(rd, result);
} else {
source = r.d(reg);
source = read<Size>(rd);
target = read<Size>(ea);
result = source + target;
write<Size>(ea, result);
@ -82,95 +72,86 @@ template<uint Size> auto M68K::instructionADD(uint3 reg, uint1 direction, EA ea)
r.x = r.c;
}
auto M68K::instructionANDI(uint8 ea) -> void {
auto result = modify(ea, readPC(ea), [&](auto x, auto y) -> uint32 {
return x & y;
});
template<uint Size> auto M68K::instructionANDI(EA ea) -> void {
auto source = readPC<Size>();
auto target = read<Size, NoUpdate>(ea);
auto result = target & source;
write<Size>(ea, result);
r.c = 0;
r.v = 0;
r.z = zero(ea, result);
r.n = negative(ea, result);
r.z = zero<Size>(result);
r.n = negative<Size>(result);
}
auto M68K::instructionBCC(uint4 condition, uint8 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 += displacement;
auto extension = readPC();
if(condition == 1); //push<Long>(r.pc);
r.pc -= 2;
if(!testCondition(condition == 1 ? (uint4)0 : condition)) return;
r.pc += displacement ? sign<Byte>(displacement) : sign<Word>(extension);
}
auto M68K::instructionLEA(uint3 target, uint8 ea) -> void {
r.a(target) = address(ea);
auto M68K::instructionLEA(Register ra, EA ea) -> void {
write<Long>(ra, fetch<Long>(ea));
}
auto M68K::instructionMOVE(uint8 to, uint8 from) -> void {
auto data = read(from);
write(to, data);
template<uint Size> auto M68K::instructionMOVE(EA to, EA from) -> void {
auto data = read<Size>(from);
write<Size>(to, data);
r.c = 0;
r.v = 0;
r.z = zero(from, data);
r.n = negative(from, data);
r.z = zero<Size>(data);
r.n = negative<Size>(data);
}
auto M68K::instructionMOVEA(uint3 to, uint8 from) -> void {
auto data = read(from);
if(from & 1) data = (int16)data;
r.a(to) = data;
template<uint Size> auto M68K::instructionMOVEA(Register ra, EA ea) -> void {
auto data = read<Size>(ea);
if(Size == Word) data = (int16)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 addr = address(ea);
auto addr = fetch<Size>(ea);
for(uint n : range(8)) {
if(list.bit(0 + n)) {
r.d(n) = readAbsolute(ea, addr);
addr += 2 + (ea & 2);
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(8 + n)) {
r.a(n) = readAbsolute(ea, addr);
addr += 2 + (ea & 2);
}
}
flush(ea, addr);
flush<Size>(ea, addr);
}
auto M68K::instructionMOVEQ(uint3 target, uint8 immediate) -> void {
r.d(target) = immediate;
auto M68K::instructionMOVEQ(Register rd, uint8 immediate) -> void {
write<Byte>(rd, immediate);
r.c = 0;
r.v = 0;
r.z = immediate == 0;
r.n = negative(Byte, immediate);
r.z = zero<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(direction == 0) {
r.usp = r.a(reg);
r.usp = read<Long>(ra);
} else {
r.a(reg) = r.usp;
write<Long>(ra, r.usp);
}
}
auto M68K::instructionNOP() -> void {
}
auto M68K::instructionTST(uint8 ea) -> void {
auto data = read(ea);
template<uint Size> auto M68K::instructionTST(EA ea) -> void {
auto data = read<Size>(ea);
r.c = 0;
r.v = 0;
r.z = zero(ea, data);
r.n = negative(ea, data);
r.z = zero<Size>(data);
r.n = negative<Size>(data);
}

View File

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

View File

@ -6,6 +6,7 @@ namespace Processor {
struct M68K {
enum : uint { Byte, Word, Long };
enum : bool { NoUpdate = 0 };
M68K();
@ -16,32 +17,39 @@ struct M68K {
auto power() -> 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
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 write(uint32 addr, uint32 data) -> void;
template<uint Size = Word> auto readPC() -> uint32;
//ea.cpp
struct EA {
EA(uint3 mode, uint3 reg) : mode(mode), reg(reg) {
if(mode == 7) mode += reg; //optimization: convert modes {7; 0-4} to {8-11}
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
}
uint4 mode;
uint3 reg;
Register reg;
boolean valid;
uint32 address;
};
template<uint Size> auto read(EA ea) -> uint32;
template<uint Size> auto write(EA ea, uint32 data) -> void;
auto address(uint8 ea) -> uint32;
auto read(uint8 ea) -> uint32;
auto write(uint8 ea, uint32 data) -> void;
auto modify(uint8 ea, uint32 data, const function<uint32 (uint32, uint32)>& op) -> uint32;
auto flush(uint8 ea, uint32 address) -> void;
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;
//instruction.cpp
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 zero(uint32 result) -> bool;
template<uint Size> auto negative(uint32 result) -> bool;
auto zero(uint2 size, uint32 result) -> bool;
auto negative(uint2 size, uint32 result) -> bool;
template<uint Size> auto instructionADD(uint3 reg, uint1 direction, EA ea) -> void;
auto instructionANDI(uint8 ea) -> void;
auto instructionBCC(uint4 condition, uint8 displacement) -> void;
auto instructionLEA(uint3 target, uint8 source) -> void;
auto instructionMOVE(uint8 to, uint8 from) -> void;
auto instructionMOVEA(uint3 to, uint8 ea) -> void;
auto instructionMOVEM(uint1 direction, uint8 ea) -> void;
auto instructionMOVEQ(uint3 target, uint8 immediate) -> void;
auto instructionMOVE_USP(uint1 direction, uint3 reg) -> void;
auto instructionNOP() -> void;
auto instructionTST(uint8 ea) -> void;
template<uint Size> auto instructionADD(Register rd, uint1 direction, EA ea) -> void;
template<uint Size> auto instructionANDI(EA ea) -> void;
auto instructionBCC(uint4 condition, uint8 displacement) -> 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_USP(uint1 direction, Register ra) -> void;
auto instructionNOP() -> void;
template<uint Size> auto instructionTST(EA ea) -> void;
//disassembler.cpp
auto disassemble(uint32 pc) -> string;
auto disassembleRegisters() -> string;
struct Registers {
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, ssp, usp;
uint32 pc;
@ -106,28 +109,27 @@ struct M68K {
private:
//disassembler.cpp
template<uint Size> auto disassembleADD(uint3 reg, uint1 direction, EA ea) -> string;
auto disassembleANDI(uint8 ea) -> string;
auto disassembleBCC(uint4 condition, uint8 displacement) -> string;
auto disassembleLEA(uint3 target, uint8 ea) -> string;
auto disassembleMOVE(uint8 to, uint8 from) -> string;
auto disassembleMOVEA(uint3 to, uint8 from) -> string;
auto disassembleMOVEM(uint1 direction, uint8 ea) -> string;
auto disassembleMOVEQ(uint3 target, uint8 immediate) -> string;
auto disassembleMOVE_USP(uint1 direction, uint3 reg) -> string;
auto disassembleNOP() -> string;
auto disassembleTST(uint8 ea) -> string;
template<uint Size> auto disassembleADD(Register rd, uint1 direction, EA ea) -> string;
template<uint Size> auto disassembleANDI(EA ea) -> string;
auto disassembleBCC(uint4 condition, uint8 displacement) -> 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_USP(uint1 direction, Register ra) -> string;
auto disassembleNOP() -> string;
template<uint Size> auto disassembleTST(EA ea) -> string;
auto _readByte(uint32 addr) -> uint8;
auto _readWord(uint32 addr) -> uint16;
auto _readLong(uint32 addr) -> uint32;
auto _readPC(uint2 size = Word) -> uint32;
auto _immediate(uint2 size) -> string;
auto _address(uint8 ea) -> string;
auto _read(uint8 ea) -> string;
auto _write(uint8 ea) -> string;
template<uint Size> auto _read(uint32 addr) -> uint32;
template<uint Size = Word> auto _readPC() -> uint32;
auto _register(Register r) -> 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;
auto _branch(uint8 displacement) -> string;
auto _suffix(uint2 size) -> string;
template<uint Size> auto _suffix() -> string;
auto _condition(uint4 condition) -> string;
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 {
step(4);
uint32 data = read(size != Byte, r.pc);
@ -30,8 +10,7 @@ auto M68K::readPC(uint2 size) -> uint32 {
r.pc += 2;
return data;
}
//
*/
template<> auto M68K::read<Byte>(uint32 addr) -> uint32 {
step(4);
@ -49,3 +28,40 @@ template<> auto M68K::read<Long>(uint32 addr) -> uint32 {
step(4);
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& {
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;
template<uint Size> auto M68K::read(Register reg) -> uint32 {
switch(reg.number) {
case 0: return clip<Size>(r.d0);
case 1: return clip<Size>(r.d1);
case 2: return clip<Size>(r.d2);
case 3: return clip<Size>(r.d3);
case 4: return clip<Size>(r.d4);
case 5: return clip<Size>(r.d5);
case 6: return clip<Size>(r.d6);
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;
}
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;
template<uint Size> auto M68K::write(Register reg, uint32 data) -> void {
switch(reg.number) {
case 0: r.d0 = clip<Size>(data); return;
case 1: r.d1 = clip<Size>(data); return;
case 2: r.d2 = clip<Size>(data); return;
case 3: r.d3 = clip<Size>(data); return;
case 4: r.d4 = clip<Size>(data); return;
case 5: r.d5 = clip<Size>(data); return;
case 6: r.d6 = clip<Size>(data); return;
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;
}
}