Update to v100r10 release.

byuu says:

Redesigned the handling of reading/writing registers to be about eight
times faster than the old system. More work may be needed ... it seems
data registers tend to preserve their upper bits upon assignment; whereas
address registers tend to sign-extend values into them. It may make
sense to have DataRegister and AddressRegister classes with separate
read/write handlers. I'd have to hold two Register objects inside the
EffectiveAddress (EA) class if we do that.

Implemented 19 opcodes now (out of somewhere between 60 and 90.) That gets
the first ~530,000 instructions in Sonic the Hedgehog running (though
probably wrong. But we can run a lot thanks to large initialization
loops.)

If I force the core to loop back to the reset vector on an invalid opcode,
I'm getting about 1500fps with a dumb 320x240 blit 60 times a second and
just the 68K running alone (no Z80, PSG, VDP, YM2612.) I don't know if
that's good or not. I guess we'll find out.

I had to stop tonight because the final opcode I execute is an RTS
(return from subroutine) that's branching back to address 0; which is
invalid ... meaning something went terribly wrong and the system crashed.
This commit is contained in:
Tim Allen 2016-07-22 22:03:25 +10:00
parent be3f6ac0d5
commit 4b897ba791
10 changed files with 386 additions and 139 deletions

View File

@ -11,7 +11,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "100.09";
static const string Version = "100.10";
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 = read(1, 0) << 16 | read(1, 2) << 0;
r.pc = read(1, 4) << 16 | read(1, 6) << 0;
r.da[A7] = read(1, 0) << 16 | read(1, 2) << 0;
r.pc = read(1, 4) << 16 | read(1, 6) << 0;
}
auto CPU::main() -> void {

View File

@ -63,7 +63,7 @@ template<uint Size> auto M68K::_suffix() -> string {
auto M68K::_condition(uint4 condition) -> string {
static const string conditions[16] = {
"ra", "sr", "hi", "ls", "cc", "cs", "ne", "eq",
"t ", "f ", "hi", "ls", "cc", "cs", "ne", "eq",
"vc", "vs", "pl", "mi", "ge", "lt", "gt", "le",
};
return conditions[condition];
@ -76,8 +76,8 @@ auto M68K::disassemble(uint32 pc) -> string {
auto M68K::disassembleRegisters() -> string {
return {
hex(r.d0, 8L), " ", hex(r.d1, 8L), " ", hex(r.d2, 8L), " ", hex(r.d3, 8L), " ",
hex(r.d4, 8L), " ", hex(r.d5, 8L), " ", hex(r.d6, 8L), " ", hex(r.d7, 8L), " ",
hex(r.da[D0], 8L), " ", hex(r.da[D1], 8L), " ", hex(r.da[D2], 8L), " ", hex(r.da[D3], 8L), " ",
hex(r.da[D4], 8L), " ", hex(r.da[D5], 8L), " ", hex(r.da[D6], 8L), " ", hex(r.da[D7], 8L), " ",
r.t ? "T" : "t",
r.s ? "S" : "s",
(uint)r.i,
@ -86,8 +86,8 @@ auto M68K::disassembleRegisters() -> string {
r.z ? "Z" : "z",
r.n ? "N" : "n",
r.x ? "X" : "x", "\n",
hex(r.a0, 8L), " ", hex(r.a1, 8L), " ", hex(r.a2, 8L), " ", hex(r.a3, 8L), " ",
hex(r.a4, 8L), " ", hex(r.a5, 8L), " ", hex(r.a6, 8L), " ", hex(r.ssp, 8L), " ", hex(r.usp, 8L)
hex(r.da[A0], 8L), " ", hex(r.da[A1], 8L), " ", hex(r.da[A2], 8L), " ", hex(r.da[A3], 8L), " ",
hex(r.da[A4], 8L), " ", hex(r.da[A5], 8L), " ", hex(r.da[A6], 8L), " ", hex(r.da[A7], 8L), " ", hex(r.sp, 8L)
};
}
@ -108,7 +108,32 @@ template<uint Size> auto M68K::disassembleANDI(EA ea) -> string {
}
auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string {
return {"b", _condition(condition), " ", _branch(displacement)};
auto cc = _condition(condition);
if(condition == 0) cc = "ra";
if(condition == 1) cc = "sr";
return {"b", cc, " ", _branch(displacement)};
}
template<uint Size> auto M68K::disassembleBTST(Register rd, EA ea) -> string {
return {"btst ", _register(rd), ",", _read<Size>(ea)};
}
template<uint Size> auto M68K::disassembleBTST(EA ea) -> string {
return {"btst ", _immediate<Byte>(), ",", _read<Size>(ea)};
}
template<uint Size> auto M68K::disassembleCLR(EA ea) -> string {
return {"clr", _suffix<Size>(), " ", _read<Size>(ea)};
}
template<uint Size> auto M68K::disassembleCMP(Register rd, EA ea) -> string {
return {"cmp", _suffix<Size>(), " ", _read<Word>(ea), ",", _register(rd)};
}
auto M68K::disassembleDBCC(uint4 condition, Register rd) -> string {
auto base = _pc;
auto displacement = (int16)_readPC();
return {"db", _condition(condition), " ", _register(rd), ",$", hex(base + displacement, 6L)};
}
auto M68K::disassembleLEA(Register ra, EA ea) -> string {
@ -142,6 +167,14 @@ auto M68K::disassembleMOVEQ(Register rd, uint8 immediate) -> string {
return {"moveq #$", hex(immediate, 2L), ",", _register(rd)};
}
auto M68K::disassembleMOVE_FROM_SR(EA ea) -> string {
return {"move sr,", _read<Word>(ea)};
}
auto M68K::disassembleMOVE_TO_SR(EA ea) -> string {
return {"move ", _read<Word>(ea), ",sr"};
}
auto M68K::disassembleMOVE_USP(uint1 direction, Register ra) -> string {
if(direction == 0) {
return {"move ", _register(ra), ",usp"};
@ -154,6 +187,10 @@ auto M68K::disassembleNOP() -> string {
return {"nop "};
}
auto M68K::disassembleRTS() -> string {
return {"rts "};
}
template<uint Size> auto M68K::disassembleTST(EA ea) -> string {
return {"tst", _suffix<Size>(), " ", _read<Size>(ea)};
}

View File

@ -1,53 +1,53 @@
template<uint Size> auto M68K::fetch(EA& ea) -> uint32 {
ea.valid = true;
if(!ea.valid.raise()) return ea.address;
switch(ea.mode) {
case 0: { //data register direct
case DataRegisterDirect: {
return read(ea.reg);
}
case 1: { //data register indirect
case AddressRegisterDirect: {
return read(ea.reg);
}
case 2: { //address register indirect
case AddressRegisterIndirect: {
return read(ea.reg);
}
case 3: { //address register indirect with post-increment
case AddressRegisterIndirectWithPostIncrement: {
return read(ea.reg);
}
case 4: { //address register indirect with pre-decrement
case AddressRegisterIndirectWithPreDecrement: {
return read(ea.reg);
}
case 5: { //address register indirect with displacement
case AddressRegisterIndirectWithDisplacement: {
return read(ea.reg) + (int16)readPC();
}
case 6: { //address register indirect with index
case AddressRegisterIndirectWithIndex: {
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
case AbsoluteShortIndirect: {
return (int16)readPC();
}
case 8: { //absolute long indirect
case AbsoluteLongIndirect: {
return readPC<Long>();
}
case 9: { //program counter indirect with displacement
case ProgramCounterIndirectWithDisplacement: {
auto base = r.pc;
return base + (int16)readPC();
}
case 10: { //program counter indirect with index
case ProgramCounterIndirectWithIndex: {
auto base = r.pc;
auto extension = readPC();
auto index = read(Register{extension >> 12});
@ -55,7 +55,7 @@ template<uint Size> auto M68K::fetch(EA& ea) -> uint32 {
return base + index + (int8)extension;
}
case 11: { //immediate
case Immediate: {
return readPC<Size>();
}
@ -65,59 +65,59 @@ template<uint Size> auto M68K::fetch(EA& ea) -> uint32 {
}
template<uint Size, bool Update> auto M68K::read(EA& ea) -> uint32 {
if(!ea.valid) ea.address = fetch<Size>(ea);
ea.address = fetch<Size>(ea);
switch(ea.mode) {
case 0: { //data register direct
case DataRegisterDirect: {
return clip<Size>(ea.address);
}
case 1: { //address register direct
case AddressRegisterDirect: {
return clip<Size>(ea.address);
}
case 2: { //address register indirect
case AddressRegisterIndirect: {
return read<Size>(ea.address);
}
case 3: { //address register indirect with post-increment
case AddressRegisterIndirectWithPostIncrement: {
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 data = read<Size>((uint32)(ea.address - (Size == Long ? 4 : 2)));
case AddressRegisterIndirectWithPreDecrement: {
auto data = read<Size>(ea.address - (Size == Long ? 4 : 2));
if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2));
return data;
}
case 5: { //address register indirect with displacement
case AddressRegisterIndirectWithDisplacement: {
return read<Size>(ea.address);
}
case 6: { //address register indirect with index
case AddressRegisterIndirectWithIndex: {
return read<Size>(ea.address);
}
case 7: { //absolute short indirect
case AbsoluteShortIndirect: {
return read<Size>(ea.address);
}
case 8: { //absolute long indirect
case AbsoluteLongIndirect: {
return read<Size>(ea.address);
}
case 9: { //program counter indirect with displacement
case ProgramCounterIndirectWithDisplacement: {
return read<Size>(ea.address);
}
case 10: { //program counter indirect with index
case ProgramCounterIndirectWithIndex: {
return read<Size>(ea.address);
}
case 11: { //immediate
case Immediate: {
return clip<Size>(ea.address);
}
@ -127,59 +127,59 @@ template<uint Size, bool Update> auto M68K::read(EA& ea) -> uint32 {
}
template<uint Size, bool Update> auto M68K::write(EA& ea, uint32 data) -> void {
if(!ea.valid) ea.address = fetch<Size>(ea);
ea.address = fetch<Size>(ea);
switch(ea.mode) {
case 0: { //data register direct
case DataRegisterDirect: {
return write<Size>(ea.reg, data);
}
case 1: { //address register direct
case AddressRegisterDirect: {
return write<Size>(ea.reg, data);
}
case 2: { //address register indirect
case AddressRegisterIndirect: {
return write<Size>(ea.address, data);
}
case 3: { //address register indirect with post-increment
case AddressRegisterIndirectWithPostIncrement: {
write<Size>(ea.address, data);
if(Update) write(ea.reg, ea.address += (Size == Long ? 4 : 2));
return;
}
case 4: { //address register indirect with pre-decrement
write<Size>((uint32)(ea.address - (Size == Long ? 4 : 2)), data);
case AddressRegisterIndirectWithPreDecrement: {
write<Size, Reverse>(ea.address - (Size == Long ? 4 : 2), data);
if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2));
return;
}
case 5: { //address register indirect with displacement
case AddressRegisterIndirectWithDisplacement: {
return write<Size>(ea.address, data);
}
case 6: { //address register indirect with index
case AddressRegisterIndirectWithIndex: {
return write<Size>(ea.address, data);
}
case 7: { //absolute short indirect
case AbsoluteShortIndirect: {
return write<Size>(ea.address, data);
}
case 8: { //absolute long indirect
case AbsoluteLongIndirect: {
return write<Size>(ea.address, data);
}
case 9: { //program counter indirect with displacement
case ProgramCounterIndirectWithDisplacement: {
return write<Size>(ea.address, data);
}
case 10: { //program counter indirect with index
case ProgramCounterIndirectWithIndex: {
return write<Size>(ea.address, data);
}
case 11: { //immediate
case Immediate: {
return;
}
@ -189,12 +189,12 @@ template<uint Size, bool Update> auto M68K::write(EA& ea, uint32 data) -> void {
template<uint Size> auto M68K::flush(EA& ea, uint32 data) -> void {
switch(ea.mode) {
case 3: { //address register indirect with post-increment
case AddressRegisterIndirectWithPostIncrement: {
write<Size>(ea.reg, data);
return;
}
case 4: { //address register indirect with pre-decrement
case AddressRegisterIndirectWithPreDecrement: {
write<Size>(ea.reg, data);
return;
}

View File

@ -8,19 +8,25 @@ auto M68K::trap() -> void {
auto M68K::instruction() -> void {
instructionsExecuted++;
print(disassembleRegisters(), "\n");
print(disassemble(r.pc), "\n");
print("\n");
//print(disassembleRegisters(), "\n");
//print(disassemble(r.pc), "\n");
//print("\n");
opcode = readPC();
return instructionTable[opcode]();
}
M68K::M68K() {
#define bind(id, name, ...) \
#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 unbind(id) { \
instructionTable[id].reset(); \
disassembleTable[id].reset(); \
}
#define pattern(s) \
std::integral_constant<uint16_t, bit::test(s)>::value
@ -33,18 +39,20 @@ M68K::M68K() {
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};
Register rd{D0 + dreg};
EA ea{mode, reg};
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);
if(direction == 0 && mode == 1) unbind(opcode | 0 << 6);
}
//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;
if(mode == 1 || (mode == 7 && reg >= 2)) continue;
EA ea{mode, reg};
bind(opcode | 0 << 6, ANDI<Byte>, ea);
@ -60,14 +68,74 @@ M68K::M68K() {
bind(opcode, BCC, condition, displacement);
}
//BTST (register)
for(uint3 dreg : range(8))
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("0000 ---1 00-- ----") | dreg << 9 | mode << 3 | reg << 0;
if(mode == 1) continue;
Register rd{D0 + dreg};
EA ea{mode, reg};
if(mode == 0) bind(opcode, BTST<Long>, rd, ea);
if(mode != 0) bind(opcode, BTST<Byte>, rd, ea);
}
//BTST (immediate)
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("0000 1000 00-- ----") | mode << 3 | reg << 0;
if(mode == 1 || (mode == 7 && reg == 2)) continue;
EA ea{mode, reg};
if(mode == 0) bind(opcode, BTST<Long>, ea);
if(mode != 0) bind(opcode, BTST<Byte>, ea);
}
//CLR
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("0100 0010 ++-- ----") | mode << 3 | reg << 0;
if(mode == 1 || (mode == 7 && reg >= 2)) continue;
EA ea{mode, reg};
bind(opcode | 0 << 6, CLR<Byte>, ea);
bind(opcode | 1 << 6, CLR<Word>, ea);
bind(opcode | 2 << 6, CLR<Long>, ea);
}
//CMP
for(uint3 dreg : range(8))
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("1011 ---0 ++-- ----") | dreg << 9 | mode << 3 | reg << 0;
Register rd{D0 + dreg};
EA ea{mode, reg};
bind(opcode | 0 << 6, CMP<Byte>, rd, ea);
bind(opcode | 1 << 6, CMP<Word>, rd, ea);
bind(opcode | 2 << 6, CMP<Long>, rd, ea);
if(mode == 1) unbind(opcode | 0 << 6);
}
//DBCC
for(uint4 condition : range(16))
for(uint3 dreg : range( 8)) {
auto opcode = pattern("0101 ---- 1100 1---") | condition << 8 | dreg << 0;
Register rd{D0 + dreg};
bind(opcode, DBCC, condition, rd);
}
//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;
if(mode <= 1 || mode == 3 || mode == 4 || (mode == 7 && reg == 4)) continue;
Register ra{8u + areg};
Register ra{A0 + areg};
EA ea{mode, reg};
bind(opcode, LEA, ra, ea);
}
@ -78,13 +146,15 @@ M68K::M68K() {
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;
if(toMode == 1 || (toMode == 7 && toReg >= 2)) 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);
if(fromMode == 1) unbind(opcode | 1 << 12);
}
//MOVEA
@ -93,7 +163,7 @@ M68K::M68K() {
for(uint3 reg : range(8)) {
auto opcode = pattern("00++ ---0 01-- ----") | areg << 9 | mode << 3 | reg << 0;
Register ra{8u + areg};
Register ra{A0 + areg};
EA ea{mode, reg};
bind(opcode | 3 << 12, MOVEA<Word>, ra, ea);
bind(opcode | 2 << 12, MOVEA<Long>, ra, ea);
@ -104,7 +174,8 @@ M68K::M68K() {
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));
if(direction == 0 && (mode <= 1 || mode == 3 || (mode == 7 && reg >= 2)));
if(direction == 1 && (mode <= 1 || mode == 4 || (mode == 7 && reg == 4)));
EA ea{mode, reg};
bind(opcode | 0 << 6, MOVEM<Word>, direction, ea);
@ -116,16 +187,36 @@ M68K::M68K() {
for(uint8 immediate : range(256)) {
auto opcode = pattern("0111 ---0 ---- ----") | dreg << 9 | immediate << 0;
Register rd{0u + dreg};
Register rd{D0 + dreg};
bind(opcode, MOVEQ, rd, immediate);
}
//MOVE_FROM_SR
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("0100 0000 11-- ----") | mode << 3 | reg << 0;
if(mode == 1 || (mode == 7 && reg >= 2)) continue;
EA ea{mode, reg};
bind(opcode, MOVE_FROM_SR, ea);
}
//MOVE_TO_SR
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("0100 0110 11-- ----") | mode << 3 | reg << 0;
if(mode == 1) continue;
EA ea{mode, reg};
bind(opcode, MOVE_TO_SR, ea);
}
//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};
Register ra{A0 + areg};
bind(opcode, MOVE_USP, direction, ra);
}
@ -135,18 +226,28 @@ M68K::M68K() {
bind(opcode, NOP);
}
//RTS
{ auto opcode = pattern("0100 1110 0111 0101");
bind(opcode, RTS);
}
//TST
for(uint3 mode : range(8))
for(uint3 reg : range(8)) {
auto opcode = pattern("0100 1010 ++-- ----") | mode << 3 | reg << 0;
if(mode == 7 && reg >= 2) continue;
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);
if(mode == 1) unbind(opcode | 0 << 6);
}
#undef bind
#undef unbind
#undef pattern
uint unimplemented = 0;
@ -156,5 +257,5 @@ M68K::M68K() {
disassembleTable[opcode] = [=] { return string{"???"}; };
unimplemented++;
}
//print("[M68K] unimplemented opcodes: ", unimplemented, "\n");
print("[M68K] unimplemented opcodes: ", unimplemented, "\n");
}

View File

@ -1,7 +1,7 @@
auto M68K::testCondition(uint4 condition) -> bool {
switch(condition) {
case 0: return true; //RA
case 1: return false; //NV,SR
case 0: return true; //T
case 1: return false; //F
case 2: return !r.c && !r.z; //HI
case 3: return r.c || r.z; //LS
case 4: return !r.c; //CC,HS
@ -22,6 +22,14 @@ auto M68K::testCondition(uint4 condition) -> bool {
//
template<> auto M68K::bits<Byte>() -> uint { return 8; }
template<> auto M68K::bits<Word>() -> uint { return 16; }
template<> auto M68K::bits<Long>() -> uint { return 32; }
template<> auto M68K::mask<Byte>() -> uint32 { return 0xff; }
template<> auto M68K::mask<Word>() -> uint32 { return 0xffff; }
template<> auto M68K::mask<Long>() -> uint32 { return 0xffffffff; }
template<> auto M68K::clip<Byte>(uint32 data) -> uint32 { return data & 0xff; }
template<> auto M68K::clip<Word>(uint32 data) -> uint32 { return data & 0xffff; }
template<> auto M68K::clip<Long>(uint32 data) -> uint32 { return data & 0xffffffff; }
@ -86,12 +94,58 @@ template<uint Size> auto M68K::instructionANDI(EA ea) -> void {
auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void {
auto extension = readPC();
if(condition == 1); //push<Long>(r.pc);
if(condition == 1) push<Long>(r.pc);
r.pc -= 2;
if(!testCondition(condition == 1 ? (uint4)0 : condition)) return;
if(condition >= 2 && !testCondition(condition)) return; //0 = BRA; 1 = BSR
r.pc += displacement ? sign<Byte>(displacement) : sign<Word>(extension);
}
template<uint Size> auto M68K::instructionBTST(Register rd, EA ea) -> void {
auto bit = read<Size>(rd);
auto test = read<Size>(ea);
bit &= bits<Size>() - 1;
r.z = test.bit(bit) == 0;
}
template<uint Size> auto M68K::instructionBTST(EA ea) -> void {
auto bit = (uint8)readPC<Word>();
auto test = read<Size>(ea);
bit &= bits<Size>() - 1;
r.z = test.bit(bit) == 0;
}
template<uint Size> auto M68K::instructionCLR(EA ea) -> void {
read<Size>(ea);
write<Size>(ea, 0);
r.c = 0;
r.v = 0;
r.z = 1;
r.n = 0;
}
template<uint Size> auto M68K::instructionCMP(Register rd, EA ea) -> void {
auto source = read<Size>(ea);
auto target = read<Size>(rd);
auto result = target - source;
r.c = carry<Size>(result, source);
r.v = overflow<Size>(result, source, target);
r.z = zero<Size>(result);
r.n = negative<Size>(result);
}
auto M68K::instructionDBCC(uint4 condition, Register rd) -> void {
auto displacement = (int16)readPC();
if(!testCondition(condition)) {
uint16 result = read<Word>(rd);
write<Word>(rd, result - 1);
if(result) r.pc -= 2, r.pc += displacement;
}
}
auto M68K::instructionLEA(Register ra, EA ea) -> void {
write<Long>(ra, fetch<Long>(ea));
}
@ -109,7 +163,7 @@ template<uint Size> auto M68K::instructionMOVE(EA to, EA from) -> void {
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);
write<Long>(ra, data);
}
template<uint Size> auto M68K::instructionMOVEM(uint1 direction, EA ea) -> void {
@ -135,18 +189,33 @@ auto M68K::instructionMOVEQ(Register rd, uint8 immediate) -> void {
r.n = negative<Byte>(immediate);
}
auto M68K::instructionMOVE_FROM_SR(EA ea) -> void {
write<Word>(ea, r.sr);
}
auto M68K::instructionMOVE_TO_SR(EA ea) -> void {
if(!supervisor()) return;
setSR(read<Word>(ea));
}
auto M68K::instructionMOVE_USP(uint1 direction, Register ra) -> void {
if(!r.s) trap(); //todo: proper trap
if(!supervisor()) return;
if(direction == 0) {
r.usp = read<Long>(ra);
r.sp = read<Long>(ra);
} else {
write<Long>(ra, r.usp);
write<Long>(ra, r.sp);
}
}
auto M68K::instructionNOP() -> void {
}
auto M68K::instructionRTS() -> void {
r.pc = pop<Long>();
}
template<uint Size> auto M68K::instructionTST(EA ea) -> void {
auto data = read<Size>(ea);

View File

@ -4,6 +4,7 @@
namespace Processor {
enum : uint { Byte, Word, Long };
enum : bool { Reverse = 1 };
#include "registers.cpp"
#include "memory.cpp"
@ -18,11 +19,16 @@ auto M68K::power() -> void {
auto M68K::reset() -> void {
instructionsExecuted = 0;
for(uint rn : range(15)) write<Long>(Register{rn}, 0);
r.ssp = 0;
r.usp = 0;
for(auto& da : r.da) da = 0;
r.sp = 0;
r.pc = 0;
r.sr = 0x2000;
}
auto M68K::supervisor() -> bool {
if(r.s) return true;
//todo: raise TRAP exception
return false;
}
}

View File

@ -5,8 +5,25 @@
namespace Processor {
struct M68K {
enum : bool { User, Supervisor };
enum : uint { Byte, Word, Long };
enum : bool { NoUpdate = 0 };
enum : bool { NoUpdate = 0, Reverse = 1 };
enum : uint { D0, D1, D2, D3, D4, D5, D6, D7, A0, A1, A2, A3, A4, A5, A6, A7 };
enum : uint {
DataRegisterDirect,
AddressRegisterDirect,
AddressRegisterIndirect,
AddressRegisterIndirectWithPostIncrement,
AddressRegisterIndirectWithPreDecrement,
AddressRegisterIndirectWithDisplacement,
AddressRegisterIndirectWithIndex,
AbsoluteShortIndirect,
AbsoluteLongIndirect,
ProgramCounterIndirectWithDisplacement,
ProgramCounterIndirectWithIndex,
Immediate,
};
M68K();
@ -16,25 +33,29 @@ struct M68K {
auto power() -> void;
auto reset() -> void;
auto supervisor() -> bool;
//registers.cpp
struct Register {
Register(uint number) : number(number) {}
explicit 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;
auto setSR(uint16 sr) -> void;
//memory.cpp
template<uint Size> auto read(uint32 addr) -> uint32;
template<uint Size> auto write(uint32 addr, uint32 data) -> void;
template<uint Size, bool Order = 0> auto write(uint32 addr, uint32 data) -> void;
template<uint Size = Word> auto readPC() -> uint32;
template<uint Size> auto pop() -> uint32;
template<uint Size> auto push(uint32 data) -> void;
//ea.cpp
struct EA {
EA(uint mode_, uint reg_) : mode(mode_), reg(reg_) {
explicit 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
}
@ -58,6 +79,8 @@ struct M68K {
//instructions.cpp
auto testCondition(uint4 condition) -> bool;
template<uint Size> auto bits() -> uint;
template<uint Size> auto mask() -> uint32;
template<uint Size> auto clip(uint32 data) -> uint32;
template<uint Size> auto sign(uint32 data) -> int32;
@ -69,13 +92,21 @@ struct M68K {
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;
template<uint Size> auto instructionBTST(Register rd, EA ea) -> void;
template<uint Size> auto instructionBTST(EA ea) -> void;
template<uint Size> auto instructionCLR(EA ea) -> void;
template<uint Size> auto instructionCMP(Register rd, EA ea) -> void;
auto instructionDBCC(uint4 condition, Register rd) -> 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_FROM_SR(EA ea) -> void;
auto instructionMOVE_TO_SR(EA ea) -> void;
auto instructionMOVE_USP(uint1 direction, Register ra) -> void;
auto instructionNOP() -> void;
auto instructionRTS() -> void;
template<uint Size> auto instructionTST(EA ea) -> void;
//disassembler.cpp
@ -83,8 +114,8 @@ struct M68K {
auto disassembleRegisters() -> string;
struct Registers {
uint32 d0, d1, d2, d3, d4, d5, d6, d7;
uint32 a0, a1, a2, a3, a4, a5, a6, ssp, usp;
uint32 da[16]; //a7 = primary stack pointer
uint32 sp; //sp = secondary stack pointer
uint32 pc;
union {
@ -112,13 +143,21 @@ private:
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;
template<uint Size> auto disassembleBTST(Register rd, EA ea) -> string;
template<uint Size> auto disassembleBTST(EA ea) -> string;
template<uint Size> auto disassembleCLR(EA ea) -> string;
template<uint Size> auto disassembleCMP(Register rd, EA ea) -> string;
auto disassembleDBCC(uint4 condition, Register rd) -> 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_FROM_SR(EA ea) -> string;
auto disassembleMOVE_TO_SR(EA ea) -> string;
auto disassembleMOVE_USP(uint1 direction, Register ra) -> string;
auto disassembleNOP() -> string;
auto disassembleRTS() -> string;
template<uint Size> auto disassembleTST(EA ea) -> string;
template<uint Size> auto _read(uint32 addr) -> uint32;

View File

@ -1,17 +1,3 @@
/*
auto M68K::readPC(uint2 size) -> uint32 {
step(4);
uint32 data = read(size != Byte, r.pc);
r.pc += 2;
if(size != Long) return data;
step(4);
data = data << 16 | read(1, r.pc);
r.pc += 2;
return data;
}
*/
template<> auto M68K::read<Byte>(uint32 addr) -> uint32 {
step(4);
return read(0, addr);
@ -32,36 +18,74 @@ template<> auto M68K::read<Long>(uint32 addr) -> uint32 {
//
template<> auto M68K::write<Byte>(uint32 addr, uint32 data) -> void {
step(4);
return write(0, addr, data);
}
template<> auto M68K::write<Word>(uint32 addr, uint32 data) -> void {
step(4);
return write(1, addr, data);
}
template<> auto M68K::write<Long>(uint32 addr, uint32 data) -> void {
step(4);
write(1, addr + 0, data >> 16);
step(4);
write(1, addr + 2, data >> 0);
}
template<> auto M68K::write<Byte, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
return write(0, addr, data);
}
template<> auto M68K::write<Word, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
return write(1, addr, data);
}
template<> auto M68K::write<Long, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
write(1, addr + 2, data >> 0);
step(4);
write(1, addr + 0, data >> 16);
}
//
template<> auto M68K::readPC<Byte>() -> uint32 {
step(4);
uint32 data = read(1, r.pc);
auto 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);
auto 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;
auto hi = read(1, r.pc);
r.pc += 2;
step(4);
data |= read(1, r.pc);
auto lo = read(1, r.pc);
r.pc += 2;
return hi << 16 | lo << 0;
}
//
template<uint Size> auto M68K::pop() -> uint32 {
auto data = read<Size>((uint32)r.da[A7]);
r.da[A7] += Size == Long ? 4 : 2;
return data;
}
template<uint Size> auto M68K::push(uint32 data) -> void {
r.da[A7] -= Size == Long ? 4 : 2;
return write<Size, Reverse>((uint32)r.da[A7], data);
}

View File

@ -1,42 +1,13 @@
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;
return clip<Size>(r.da[reg.number]);
}
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;
}
r.da[reg.number] = (r.da[reg.number] & ~mask<Size>()) | (data & mask<Size>());
}
auto M68K::setSR(uint16 sr) -> void {
//when entering or exiting supervisor mode; swap SSP and USP into A7
if(r.sr.bit(13) != sr.bit(13)) swap(r.da[A7], r.sp);
r.sr = sr;
}