mirror of https://github.com/bsnes-emu/bsnes.git
Update to v100r07 release.
byuu says: Four and a half hours of work and ... zero new opcodes implemented. This was the best job I could do refining the effective address computations. Should have all twelve 68000 modes implemented now. Still have a billion questions about when and how I'm supposed to perform certain edge case operations, though.
This commit is contained in:
parent
0d6a09f9f8
commit
059347e575
|
@ -11,7 +11,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "100.06";
|
||||
static const string Version = "100.07";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -70,11 +70,13 @@ auto Cartridge::power() -> void {
|
|||
auto Cartridge::reset() -> void {
|
||||
}
|
||||
|
||||
auto Cartridge::read(uint24 addr) -> uint8 {
|
||||
return rom.data[addr & rom.mask];
|
||||
auto Cartridge::read(bool word, uint24 addr) -> uint16 {
|
||||
uint16 data = rom.data[addr & rom.mask];
|
||||
if(!word) return data;
|
||||
return data << 8 | rom.data[addr + 1 & rom.mask];
|
||||
}
|
||||
|
||||
auto Cartridge::write(uint24 addr, uint8 data) -> void {
|
||||
auto Cartridge::write(bool word, uint24 addr, uint16 data) -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ struct Cartridge {
|
|||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto read(uint24 addr) -> uint8;
|
||||
auto write(uint24 addr, uint8 data) -> void;
|
||||
auto read(bool word, uint24 addr) -> uint16;
|
||||
auto write(bool word, uint24 addr, uint16 data) -> void;
|
||||
|
||||
struct Information {
|
||||
uint pathID = 0;
|
||||
|
|
|
@ -10,8 +10,8 @@ auto CPU::Enter() -> void {
|
|||
}
|
||||
|
||||
auto CPU::boot() -> void {
|
||||
r.ssp = readLong(0);
|
||||
r.pc = readLong(4);
|
||||
r.ssp = readAbsolute(Long, 0);
|
||||
r.pc = readAbsolute(Long, 4);
|
||||
}
|
||||
|
||||
auto CPU::main() -> void {
|
||||
|
@ -35,17 +35,13 @@ auto CPU::reset() -> void {
|
|||
create(CPU::Enter, system.colorburst() * 15.0 / 7.0);
|
||||
}
|
||||
|
||||
auto CPU::read(uint32 addr) -> uint8 {
|
||||
addr = (uint24)addr;
|
||||
|
||||
if(addr < 0x400000) return cartridge.read(addr);
|
||||
return 0x00;
|
||||
auto CPU::read(bool word, uint24 addr) -> uint16 {
|
||||
if(addr < 0x400000) return cartridge.read(word, addr);
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
auto CPU::write(uint32 addr, uint8 data) -> void {
|
||||
addr = (uint24)addr;
|
||||
|
||||
if(addr < 0x400000) return cartridge.write(addr, data);
|
||||
auto CPU::write(bool word, uint24 addr, uint16 data) -> void {
|
||||
if(addr < 0x400000) return cartridge.write(word, addr, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ struct CPU : Processor::M68K, Thread {
|
|||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto read(uint32 addr) -> uint8 override;
|
||||
auto write(uint32 addr, uint8 data) -> void override;
|
||||
auto read(bool word, uint24 addr) -> uint16 override;
|
||||
auto write(bool word, uint24 addr, uint16 data) -> void override;
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
auto M68K::_readByte(uint32 addr) -> uint8 {
|
||||
return read(addr);
|
||||
return read(0, addr);
|
||||
}
|
||||
|
||||
auto M68K::_readWord(uint32 addr) -> uint16 {
|
||||
uint16 data = _readByte(addr + 0) << 8;
|
||||
return data |= _readByte(addr + 1) << 0;
|
||||
return read(1, addr);
|
||||
}
|
||||
|
||||
auto M68K::_readLong(uint32 addr) -> uint32 {
|
||||
|
@ -29,23 +28,23 @@ auto M68K::_immediate(uint size) -> string {
|
|||
return "#???";
|
||||
}
|
||||
|
||||
auto M68K::_address(uint size, EA& ea) -> string {
|
||||
if(ea.mode == 7) {
|
||||
if(ea.reg == 2) return {"$", hex(_pc + (int16)_readPC(Word), 6L)};
|
||||
auto M68K::_address(uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
if(mode == 7) {
|
||||
if(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) {
|
||||
auto M68K::_read(uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
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)};
|
||||
|
@ -54,11 +53,11 @@ auto M68K::_read(uint size, EA& ea) -> string {
|
|||
return "???";
|
||||
}
|
||||
|
||||
auto M68K::_write(uint size, EA& ea) -> string {
|
||||
return _read(size, ea);
|
||||
auto M68K::_write(uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
return _read(size, mode, reg);
|
||||
}
|
||||
|
||||
auto M68K::_branch(uint displacement) -> string {
|
||||
auto M68K::_branch(uint8 displacement) -> string {
|
||||
uint16 word = _readPC();
|
||||
if(displacement) displacement = (int8)displacement, _pc -= 2;
|
||||
else displacement = (int16)displacement;
|
||||
|
@ -72,12 +71,12 @@ auto M68K::_suffix(uint size) -> string {
|
|||
return ".?";
|
||||
}
|
||||
|
||||
auto M68K::_condition(uint condition) -> string {
|
||||
auto M68K::_condition(uint4 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];
|
||||
return conditions[condition];
|
||||
}
|
||||
|
||||
auto M68K::disassemble(uint32 pc) -> string {
|
||||
|
@ -104,27 +103,27 @@ auto M68K::disassembleRegisters() -> string {
|
|||
|
||||
//
|
||||
|
||||
auto M68K::disassembleANDI(uint size, EA modify) -> string {
|
||||
return {"andi", _suffix(size), " ", _immediate(size), ",", _read(size, modify)};
|
||||
auto M68K::disassembleANDI(uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
return {"andi", _suffix(size), " ", _immediate(size), ",", _read(size, mode, reg)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleBCC(uint condition, uint displacement) -> string {
|
||||
auto M68K::disassembleBCC(uint4 condition, uint8 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::disassembleLEA(uint3 target, uint3 mode, uint3 reg) -> string {
|
||||
return {"lea ", _address(Long, mode, reg), ",a", target};
|
||||
}
|
||||
|
||||
auto M68K::disassembleMOVE(uint size, EA target, EA source) -> string {
|
||||
return {"move", _suffix(size), " ", _read(size, source), ",", _write(size, target)};
|
||||
auto M68K::disassembleMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> string {
|
||||
return {"move", _suffix(size), " ", _read(size, sourceMode, sourceReg), ",", _write(size, targetMode, targetReg)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleMOVEA(uint size, uint target, EA source) -> string {
|
||||
return {"movea ", _read(size, source), ",a", target};
|
||||
auto M68K::disassembleMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> string {
|
||||
return {"movea ", _read(size, mode, reg), ",a", target};
|
||||
}
|
||||
|
||||
auto M68K::disassembleMOVEM(uint direction, uint size, EA source) -> string {
|
||||
auto M68K::disassembleMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
string op{"movem", _suffix(size), " "};
|
||||
|
||||
uint16 list = _readPC();
|
||||
|
@ -136,17 +135,17 @@ auto M68K::disassembleMOVEM(uint direction, uint size, EA source) -> string {
|
|||
regs.trimRight(",");
|
||||
|
||||
if(direction == 0) {
|
||||
return {op, regs, ",", _read(size, source)};
|
||||
return {op, regs, ",", _read(size, mode, reg)};
|
||||
} else {
|
||||
return {op, _read(size, source), ",", regs};
|
||||
return {op, _read(size, mode, reg), ",", regs};
|
||||
}
|
||||
}
|
||||
|
||||
auto M68K::disassembleMOVEQ(uint target, uint immediate) -> string {
|
||||
auto M68K::disassembleMOVEQ(uint3 target, uint8 immediate) -> string {
|
||||
return {"moveq #$", hex(immediate, 2L), ",d", target};
|
||||
}
|
||||
|
||||
auto M68K::disassembleMOVE_USP(uint direction, uint reg) -> string {
|
||||
auto M68K::disassembleMOVE_USP(uint1 direction, uint3 reg) -> string {
|
||||
if(direction == 0) {
|
||||
return {"move a", reg, ",usp"};
|
||||
} else {
|
||||
|
@ -158,6 +157,6 @@ auto M68K::disassembleNOP() -> string {
|
|||
return {"nop "};
|
||||
}
|
||||
|
||||
auto M68K::disassembleTST(uint size, EA source) -> string {
|
||||
return {"tst", _suffix(size), " ", _read(size, source)};
|
||||
auto M68K::disassembleTST(uint2 size, uint3 mode, uint3 reg) -> string {
|
||||
return {"tst", _suffix(size), " ", _read(size, mode, reg)};
|
||||
}
|
||||
|
|
|
@ -1,72 +1,137 @@
|
|||
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;
|
||||
M68K::EA::EA(M68K* self, uint2 size, uint3 mode, uint3 reg) : self(self), size(size), mode(mode), reg(reg) {
|
||||
if(this->mode == 7) this->mode += this->reg; //speed hack: convert cases {7; 0-4} to {8-12} for switch jump table
|
||||
address = fetch();
|
||||
}
|
||||
|
||||
M68K::EA::~EA() {
|
||||
flush();
|
||||
}
|
||||
|
||||
auto M68K::EA::pc() -> uint32& { return self->r.pc; }
|
||||
auto M68K::EA::d(uint3 reg) -> uint32& { return self->r.d(reg); }
|
||||
auto M68K::EA::a(uint3 reg) -> uint32& { return self->r.a(reg); }
|
||||
auto M68K::EA::readPC(uint2 size) -> uint32 { return self->readPC(size); }
|
||||
auto M68K::EA::read(uint32 addr) -> uint32 { return self->readAbsolute(size, addr); }
|
||||
auto M68K::EA::write(uint32 addr, uint32 data) -> void { return self->writeAbsolute(size, addr, data); }
|
||||
|
||||
auto M68K::EA::fetch() -> uint32 {
|
||||
switch(mode) {
|
||||
|
||||
//data register direct
|
||||
case 0: return d(reg);
|
||||
|
||||
//address register direct
|
||||
case 1: return a(reg);
|
||||
|
||||
//address register indirect
|
||||
case 2: return a(reg);
|
||||
|
||||
//address register indirect with post-increment
|
||||
case 3: return a(reg);
|
||||
|
||||
//address register indirect with pre-decrement
|
||||
case 4: return a(reg);
|
||||
|
||||
//address register with displacement
|
||||
case 5: return a(reg) + (int16)readPC(Word);
|
||||
|
||||
//address register with index
|
||||
case 6: {
|
||||
auto word = readPC(Word);
|
||||
auto index = word & 0x8000 ? a(word >> 12) : d(word >> 12);
|
||||
if(word & 0x800) index = (int16)index;
|
||||
return a(reg) + index + (int8)word;
|
||||
}
|
||||
|
||||
//absolute short
|
||||
case 7: return (int16)readPC(Word);
|
||||
|
||||
//absolute long
|
||||
case 8: return readPC(Long);
|
||||
|
||||
//program counter with displacement
|
||||
case 9: {
|
||||
auto base = pc();
|
||||
return base + (int16)readPC(Word);
|
||||
}
|
||||
|
||||
//program counter with index
|
||||
case 10: {
|
||||
auto base = pc();
|
||||
auto word = readPC(Word);
|
||||
auto index = word & 0x8000 ? a(word >> 12) : d(word >> 12);
|
||||
if(word & 0x800) index = (int16)index;
|
||||
return base + index + (int8)word;
|
||||
}
|
||||
|
||||
//immediate
|
||||
case 11: {
|
||||
if(size == Byte) return (uint8)readPC(Word);
|
||||
if(size == Word) return readPC(Word);
|
||||
if(size == Long) return readPC(Long);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
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)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(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;
|
||||
auto M68K::EA::read() -> uint32 {
|
||||
switch(mode) {
|
||||
case 0: return address;
|
||||
case 1: return address;
|
||||
case 2: return read(address);
|
||||
case 3: {
|
||||
auto data = read(address);
|
||||
address += size == Long ? 4 : 2;
|
||||
return data;
|
||||
}
|
||||
if(ea.mode == 4) {
|
||||
ea.address -= size, r.a(ea.reg) -= size;
|
||||
return read(size, ea.address);
|
||||
case 4: {
|
||||
address -= size == Long ? 4 : 2;
|
||||
return read(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;
|
||||
case 5: return read(address);
|
||||
case 6: return read(address);
|
||||
case 7: return read(address);
|
||||
case 8: return read(address);
|
||||
case 9: return read(address);
|
||||
case 10: return read(address);
|
||||
case 11: return address;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto M68K::write(uint size, EA& ea, uint32 data) -> void {
|
||||
address(size, ea);
|
||||
|
||||
if(ea.mode == 0) {
|
||||
r.d(ea.reg) = data;
|
||||
auto M68K::EA::write(uint32 data) -> void {
|
||||
switch(mode) {
|
||||
case 0: address = data; return;
|
||||
case 1: address = data; return;
|
||||
case 2: return write(address, data);
|
||||
case 3: {
|
||||
write(address, data);
|
||||
address += size == Long ? 4 : 2;
|
||||
return;
|
||||
}
|
||||
|
||||
if(ea.mode == 1) {
|
||||
r.a(ea.reg) = data;
|
||||
return;
|
||||
case 4: {
|
||||
address -= size == Long ? 4 : 2;
|
||||
return write(address, data);
|
||||
}
|
||||
case 5: return write(address, data);
|
||||
case 6: return write(address, data);
|
||||
case 7: return write(address, data);
|
||||
case 8: return write(address, data);
|
||||
case 9: return write(address, data);
|
||||
case 10: return write(address, data);
|
||||
case 11: address = data; return;
|
||||
}
|
||||
}
|
||||
|
||||
auto M68K::EA::flush() -> void {
|
||||
//address register indirect with post-increment
|
||||
if(mode == 3) a(reg) = address;
|
||||
|
||||
//address register indirect with pre-decrement
|
||||
if(mode == 4) a(reg) = address;
|
||||
|
||||
mode = 15;
|
||||
}
|
||||
|
|
|
@ -31,20 +31,20 @@ M68K::M68K() {
|
|||
|
||||
//ANDI
|
||||
match("0000 0010 ---- ----") {
|
||||
auto size = bits(7,6);
|
||||
auto mode = bits(5,3);
|
||||
auto reg = bits(2,0);
|
||||
uint2 size = bits(7,6);
|
||||
uint3 mode = bits(5,3);
|
||||
uint3 reg = bits(2,0);
|
||||
|
||||
size = size == 0 ? Byte : size == 1 ? Word : size == 2 ? Long : 0;
|
||||
if(size && mode != 1) {
|
||||
bind(ANDI, size, {mode, reg});
|
||||
bind(ANDI, size, mode, reg);
|
||||
}
|
||||
}
|
||||
|
||||
//BCC
|
||||
match("0110 ---- ---- ----") {
|
||||
auto condition = bits(11,8);
|
||||
auto displacement = bits(7,0);
|
||||
uint4 condition = bits(11,8);
|
||||
uint8 displacement = bits(7,0);
|
||||
|
||||
if(true) {
|
||||
bind(BCC, condition, displacement);
|
||||
|
@ -53,60 +53,60 @@ M68K::M68K() {
|
|||
|
||||
//LEA
|
||||
match("0100 ---1 11-- ----") {
|
||||
auto target = bits(11,9);
|
||||
auto mode = bits(5,3);
|
||||
auto reg = bits(2,0);
|
||||
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)) {
|
||||
bind(LEA, target, {mode, reg});
|
||||
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);
|
||||
uint2 size = bits(13,12);
|
||||
uint3 targetReg = bits(11,9);
|
||||
uint3 targetMode = bits(8,6);
|
||||
uint3 sourceMode = bits(5,3);
|
||||
uint3 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});
|
||||
bind(MOVE, size, targetReg, targetMode, 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);
|
||||
uint2 size = bits(13,12);
|
||||
uint3 target = bits(11,9);
|
||||
uint3 mode = bits(5,3);
|
||||
uint3 reg = bits(2,0);
|
||||
|
||||
size = size == 3 ? Word : size == 2 ? Long : 0;
|
||||
if(size) {
|
||||
bind(MOVEA, size, target, {sourceMode, sourceReg});
|
||||
bind(MOVEA, size, target, mode, reg);
|
||||
}
|
||||
}
|
||||
|
||||
//MOVEM
|
||||
match("0100 1-00 1--- ----") {
|
||||
auto direction = bit(10);
|
||||
auto size = bit(6);
|
||||
auto mode = bits(5,3);
|
||||
auto reg = bits(2,0);
|
||||
uint1 direction = bit(10);
|
||||
uint2 size = bit(6);
|
||||
uint3 mode = bits(5,3);
|
||||
uint3 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});
|
||||
bind(MOVEM, direction, size, mode, reg);
|
||||
}
|
||||
}
|
||||
|
||||
//MOVEQ
|
||||
match("0111 ---0 ---- ----") {
|
||||
auto target = bits(11,9);
|
||||
auto immediate = bits(7,0);
|
||||
uint3 target = bits(11,9);
|
||||
uint8 immediate = bits(7,0);
|
||||
|
||||
if(true) {
|
||||
bind(MOVEQ, target, immediate);
|
||||
|
@ -115,8 +115,8 @@ M68K::M68K() {
|
|||
|
||||
//MOVE_USP
|
||||
match("0100 1110 0110 ----") {
|
||||
auto direction = bit(3);
|
||||
auto reg = bits(2,0);
|
||||
uint1 direction = bit(3);
|
||||
uint3 reg = bits(2,0);
|
||||
|
||||
if(true) {
|
||||
bind(MOVE_USP, direction, reg);
|
||||
|
@ -132,13 +132,13 @@ M68K::M68K() {
|
|||
|
||||
//TST
|
||||
match("0100 1010 ---- ----") {
|
||||
auto size = bits(7,6);
|
||||
auto mode = bits(5,3);
|
||||
auto reg = bits(2,0);
|
||||
uint2 size = bits(7,6);
|
||||
uint3 mode = bits(5,3);
|
||||
uint3 reg = bits(2,0);
|
||||
|
||||
size = size == 0 ? Byte : size == 1 ? Word : size == 2 ? Long : 0;
|
||||
if(size) {
|
||||
bind(TST, size, {mode, reg});
|
||||
bind(TST, size, mode, reg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,9 +22,10 @@ auto M68K::testCondition(uint4 condition) -> bool {
|
|||
|
||||
//
|
||||
|
||||
auto M68K::instructionANDI(uint size, EA modify) -> void {
|
||||
auto M68K::instructionANDI(uint2 size, uint3 mode, uint3 reg) -> void {
|
||||
auto data = readPC(size);
|
||||
write(size, modify, data = read(size, modify) & data);
|
||||
EA modify{this, size, mode, reg};
|
||||
modify.write(data = modify.read() & data);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
|
@ -32,7 +33,7 @@ auto M68K::instructionANDI(uint size, EA modify) -> void {
|
|||
r.n = sign(size, data) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionBCC(uint condition, uint displacement) -> void {
|
||||
auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void {
|
||||
auto word = readPC();
|
||||
if(displacement) displacement = (int8)displacement, r.pc -= 2;
|
||||
else displacement = (int16)word;
|
||||
|
@ -43,13 +44,18 @@ auto M68K::instructionBCC(uint condition, uint displacement) -> void {
|
|||
if(testCondition(condition)) r.pc += displacement;
|
||||
}
|
||||
|
||||
auto M68K::instructionLEA(uint target, EA source) -> void {
|
||||
r.a(target) = address(Long, source);
|
||||
auto M68K::instructionLEA(uint3 target, uint3 mode, uint3 reg) -> void {
|
||||
EA source{this, Long, mode, reg};
|
||||
r.a(target) = source.address;
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVE(uint size, EA target, EA source) -> void {
|
||||
auto data = read(size, source);
|
||||
write(size, target, data);
|
||||
auto M68K::instructionMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> void {
|
||||
EA source{this, size, sourceMode, sourceReg};
|
||||
EA target{this, size, targetMode, targetReg};
|
||||
|
||||
auto data = source.read();
|
||||
source.flush();
|
||||
target.write(data);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
|
@ -57,23 +63,25 @@ auto M68K::instructionMOVE(uint size, EA target, EA source) -> void {
|
|||
r.n = sign(size, data) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVEA(uint size, uint target, EA source) -> void {
|
||||
r.d(target) = read(size, source);
|
||||
auto M68K::instructionMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> void {
|
||||
EA source{this, size, mode, reg};
|
||||
r.a(target) = source.read();
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVEM(uint direction, uint size, EA source) -> void {
|
||||
auto M68K::instructionMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> void {
|
||||
auto list = readPC();
|
||||
EA source{this, size, mode, reg};
|
||||
|
||||
for(uint n : range(8)) {
|
||||
if(list.bit(0 + n)) r.d(n) = read(size, source);
|
||||
if(list.bit(0 + n)) r.d(n) = source.read();
|
||||
}
|
||||
|
||||
for(uint n : range(8)) {
|
||||
if(list.bit(8 + n)) r.a(n) = read(size, source);
|
||||
if(list.bit(8 + n)) r.a(n) = source.read();
|
||||
}
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVEQ(uint target, uint immediate) -> void {
|
||||
auto M68K::instructionMOVEQ(uint3 target, uint8 immediate) -> void {
|
||||
r.d(target) = immediate;
|
||||
|
||||
r.c = 0;
|
||||
|
@ -82,8 +90,8 @@ auto M68K::instructionMOVEQ(uint target, uint immediate) -> void {
|
|||
r.v = sign(Byte, immediate) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVE_USP(uint direction, uint reg) -> void {
|
||||
if(!r.s) trap();
|
||||
auto M68K::instructionMOVE_USP(uint1 direction, uint3 reg) -> void {
|
||||
if(!r.s) trap(); //todo: proper trap
|
||||
if(direction == 0) {
|
||||
r.usp = r.a(reg);
|
||||
} else {
|
||||
|
@ -94,8 +102,9 @@ auto M68K::instructionMOVE_USP(uint direction, uint reg) -> void {
|
|||
auto M68K::instructionNOP() -> void {
|
||||
}
|
||||
|
||||
auto M68K::instructionTST(uint size, EA source) -> void {
|
||||
auto data = read(size, source);
|
||||
auto M68K::instructionTST(uint2 size, uint3 mode, uint3 reg) -> void {
|
||||
EA source{this, size, mode, reg};
|
||||
auto data = source.read();
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
|
|
|
@ -24,4 +24,11 @@ auto M68K::reset() -> void {
|
|||
r.sr = 0x2000;
|
||||
}
|
||||
|
||||
auto M68K::sign(uint2 size, uint32 data) -> int32 {
|
||||
if(size == Byte) return (int8)data;
|
||||
if(size == Word) return (int16)data;
|
||||
if(size == Long) return (int32)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,40 +5,50 @@
|
|||
namespace Processor {
|
||||
|
||||
struct M68K {
|
||||
enum : uint { Byte = 1, Word = 2, Long = 4 };
|
||||
enum : uint { Byte = 1, Word = 2, Long = 3 };
|
||||
|
||||
M68K();
|
||||
|
||||
virtual auto step(uint clocks) -> void = 0;
|
||||
virtual auto read(uint32 addr) -> uint8 = 0;
|
||||
virtual auto write(uint32 addr, uint8 data) -> void = 0;
|
||||
virtual auto read(bool word, uint24 addr) -> uint16 = 0;
|
||||
virtual auto write(bool word, uint24 addr, uint16 data) -> void = 0;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
//memory.cpp
|
||||
auto readByte(uint32 addr) -> uint8;
|
||||
auto readWord(uint32 addr) -> uint16;
|
||||
auto readLong(uint32 addr) -> uint32;
|
||||
auto sign(uint2 size, uint32 data) -> int32;
|
||||
|
||||
auto read(uint size, uint32 addr) -> uint32;
|
||||
auto readPC(uint size = Word) -> uint32;
|
||||
//memory.cpp
|
||||
auto readAbsolute(uint2 size, uint32 addr) -> uint32;
|
||||
auto writeAbsolute(uint2 size, uint32 addr, uint32 data) -> void;
|
||||
|
||||
auto readPC(uint2 size = Word) -> uint32;
|
||||
|
||||
//ea.cpp
|
||||
struct EA {
|
||||
uint mode;
|
||||
uint reg;
|
||||
EA(M68K* self, uint2 size, uint3 mode, uint3 reg);
|
||||
~EA();
|
||||
|
||||
auto pc() -> uint32&;
|
||||
auto d(uint3 reg) -> uint32&;
|
||||
auto a(uint3 reg) -> uint32&;
|
||||
auto readPC(uint2 size) -> uint32;
|
||||
auto read(uint32 addr) -> uint32;
|
||||
auto write(uint32 addr, uint32 data) -> void;
|
||||
|
||||
auto fetch() -> uint32;
|
||||
auto read() -> uint32;
|
||||
auto write(uint32 data) -> void;
|
||||
auto flush() -> void;
|
||||
|
||||
uint2 size;
|
||||
uint4 mode;
|
||||
uint3 reg;
|
||||
|
||||
boolean valid;
|
||||
uint32 address;
|
||||
M68K* self;
|
||||
};
|
||||
|
||||
auto sign(uint size, uint32 data) -> int32;
|
||||
|
||||
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;
|
||||
auto instruction() -> void;
|
||||
|
@ -46,16 +56,16 @@ struct M68K {
|
|||
//instructions.cpp
|
||||
auto testCondition(uint4 condition) -> bool;
|
||||
|
||||
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 instructionANDI(uint2 size, uint3 mode, uint3 reg) -> void;
|
||||
auto instructionBCC(uint4 condition, uint8 displacement) -> void;
|
||||
auto instructionLEA(uint3 target, uint3 mode, uint3 reg) -> void;
|
||||
auto instructionMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> void;
|
||||
auto instructionMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> void;
|
||||
auto instructionMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> void;
|
||||
auto instructionMOVEQ(uint3 target, uint8 immediate) -> void;
|
||||
auto instructionMOVE_USP(uint1 direction, uint3 reg) -> void;
|
||||
auto instructionNOP() -> void;
|
||||
auto instructionTST(uint size, EA source) -> void;
|
||||
auto instructionTST(uint2 size, uint3 mode, uint3 reg) -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassemble(uint32 pc) -> string;
|
||||
|
@ -91,28 +101,28 @@ struct M68K {
|
|||
|
||||
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 disassembleANDI(uint2 size, uint3 mode, uint3 reg) -> string;
|
||||
auto disassembleBCC(uint4 condition, uint8 displacement) -> string;
|
||||
auto disassembleLEA(uint3 target, uint3 mode, uint3 reg) -> string;
|
||||
auto disassembleMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> string;
|
||||
auto disassembleMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> string;
|
||||
auto disassembleMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> string;
|
||||
auto disassembleMOVEQ(uint3 target, uint8 immediate) -> string;
|
||||
auto disassembleMOVE_USP(uint1 direction, uint3 reg) -> string;
|
||||
auto disassembleNOP() -> string;
|
||||
auto disassembleTST(uint size, EA source) -> string;
|
||||
auto disassembleTST(uint2 size, uint3 mode, uint3 reg) -> 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 _address(uint2 size, uint3 mode, uint3 reg) -> string;
|
||||
auto _read(uint2 size, uint3 mode, uint3 reg) -> string;
|
||||
auto _write(uint2 size, uint3 mode, uint3 reg) -> string;
|
||||
auto _branch(uint8 displacement) -> string;
|
||||
auto _suffix(uint size) -> string;
|
||||
auto _condition(uint condition) -> string;
|
||||
auto _condition(uint4 condition) -> string;
|
||||
|
||||
uint32 _pc;
|
||||
function<string ()> disassembleTable[65536];
|
||||
|
|
|
@ -1,34 +1,32 @@
|
|||
auto M68K::readByte(uint32 addr) -> uint8 {
|
||||
auto M68K::readAbsolute(uint2 size, uint32 addr) -> uint32 {
|
||||
step(4);
|
||||
return read(addr);
|
||||
uint32 data = read(size != Byte, addr);
|
||||
if(size != Long) return data;
|
||||
|
||||
step(4);
|
||||
data = data << 16 | read(1, addr + 2);
|
||||
return data;
|
||||
}
|
||||
|
||||
auto M68K::readWord(uint32 addr) -> uint16 {
|
||||
step(4);
|
||||
uint16 data = read(addr + 0) << 8;
|
||||
return data |= read(addr + 1) << 0;
|
||||
}
|
||||
|
||||
auto M68K::readLong(uint32 addr) -> uint32 {
|
||||
uint32 data = readWord(addr + 0) << 16;
|
||||
return data |= readWord(addr + 2) << 0;
|
||||
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::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);
|
||||
auto M68K::readPC(uint2 size) -> uint32 {
|
||||
step(4);
|
||||
uint32 data = read(size != Byte, r.pc);
|
||||
r.pc += 2;
|
||||
if(size == Byte) return (uint8)data;
|
||||
if(size == Word) return data;
|
||||
data = data << 16 | readWord(r.pc);
|
||||
if(size != Long) return data;
|
||||
|
||||
step(4);
|
||||
data = data << 16 | read(1, r.pc);
|
||||
r.pc += 2;
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,20 @@ namespace Processor {
|
|||
#include "instructions-misc.cpp"
|
||||
#include "switch.cpp"
|
||||
|
||||
auto R65816::interrupt() -> void {
|
||||
read(r.pc.d);
|
||||
idle();
|
||||
N writeSP(r.pc.b);
|
||||
writeSP(r.pc.h);
|
||||
writeSP(r.pc.l);
|
||||
writeSP(r.e ? (r.p & ~0x10) : r.p);
|
||||
r.pc.l = read(r.vector + 0);
|
||||
r.p.i = 1;
|
||||
r.p.d = 0;
|
||||
r.pc.h = read(r.vector + 1);
|
||||
r.pc.b = 0x00;
|
||||
}
|
||||
|
||||
//immediate, 2-cycle opcodes with idle cycle will become bus read
|
||||
//when an IRQ is to be triggered immediately after opcode completion.
|
||||
//this affects the following opcodes:
|
||||
|
@ -54,20 +68,6 @@ auto R65816::idle6(uint16 addr) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto R65816::interrupt() -> void {
|
||||
read(r.pc.d);
|
||||
idle();
|
||||
N writeSP(r.pc.b);
|
||||
writeSP(r.pc.h);
|
||||
writeSP(r.pc.l);
|
||||
writeSP(r.e ? (r.p & ~0x10) : r.p);
|
||||
r.pc.l = read(r.vector + 0);
|
||||
r.p.i = 1;
|
||||
r.p.d = 0;
|
||||
r.pc.h = read(r.vector + 1);
|
||||
r.pc.b = 0x00;
|
||||
}
|
||||
|
||||
#undef E
|
||||
#undef N
|
||||
#undef L
|
||||
|
|
|
@ -18,6 +18,7 @@ struct R65816 {
|
|||
virtual auto write(uint24 addr, uint8 data) -> void = 0;
|
||||
virtual auto lastCycle() -> void = 0;
|
||||
virtual auto interruptPending() const -> bool = 0;
|
||||
virtual auto interrupt() -> void;
|
||||
|
||||
virtual auto readDisassembler(uint24 addr) -> uint8 { return 0; }
|
||||
|
||||
|
@ -26,7 +27,6 @@ struct R65816 {
|
|||
alwaysinline auto idle2() -> void;
|
||||
alwaysinline auto idle4(uint16 x, uint16 y) -> void;
|
||||
alwaysinline auto idle6(uint16 addr) -> void;
|
||||
auto interrupt() -> void;
|
||||
|
||||
//algorithms.cpp
|
||||
auto op_adc_b();
|
||||
|
|
|
@ -30,6 +30,20 @@ auto SA1::main() -> void {
|
|||
instruction();
|
||||
}
|
||||
|
||||
//override R65816::interrupt() to support SA-1 vector location IO registers
|
||||
auto SA1::interrupt() -> void {
|
||||
read(r.pc.d);
|
||||
idle();
|
||||
if(!r.e) writeSP(r.pc.b);
|
||||
writeSP(r.pc.h);
|
||||
writeSP(r.pc.l);
|
||||
writeSP(r.e ? (r.p & ~0x10) : r.p);
|
||||
r.pc.w = r.vector;
|
||||
r.pc.b = 0x00;
|
||||
r.p.i = 1;
|
||||
r.p.d = 0;
|
||||
}
|
||||
|
||||
auto SA1::lastCycle() -> void {
|
||||
if(mmio.sa1_nmi && !mmio.sa1_nmicl) {
|
||||
status.interruptPending = true;
|
||||
|
|
|
@ -3,6 +3,7 @@ struct SA1 : Processor::R65816, Cothread {
|
|||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto tick() -> void;
|
||||
auto interrupt() -> void override;
|
||||
|
||||
alwaysinline auto triggerIRQ() -> void;
|
||||
alwaysinline auto lastCycle() -> void override;
|
||||
|
|
|
@ -12,6 +12,9 @@ struct Boolean {
|
|||
inline operator bool() const { return data; }
|
||||
template<typename T> inline auto& operator=(const T& value) { data = value; return *this; }
|
||||
|
||||
inline auto raise() { return data == 0 ? data = 1, true : false; }
|
||||
inline auto lower() { return data == 1 ? data = 0, true : false; }
|
||||
|
||||
inline auto serialize(serializer& s) { s(data); }
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in New Issue