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:
Tim Allen 2016-07-17 13:24:28 +10:00
parent 0d6a09f9f8
commit 059347e575
17 changed files with 348 additions and 244 deletions

View File

@ -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/";

View File

@ -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 {
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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)};
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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];

View File

@ -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;
}

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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: