mirror of https://github.com/bsnes-emu/bsnes.git
Update to v101r03 release.
byuu says: The 68K core now implements all 88 instructions. It ended up being 111 instructions in my core due to splitting up opcodes with the same name but different addressing modes or directions (removes conditions at the expense of more code.) Technically, I don't have exceptions actually implemented yet, and RESET/STOP don't do anything but set flags. So there's still more to go. But ... close enough for statistics time! The M68K core source code is 124,712 bytes in size. The next largest core is the ARM7 core at 70,203 bytes in size. The M68K object size is 942KiB; with the next largest being the V30MZ core at 173KiB. There are a total of 19,656 invalid opcodes in the 68000 revision (unless of course I've made mistakes in my mappings, which is very probably.) Now the fun part ... figuring out how to fix bugs in this core without VDP emulation :/
This commit is contained in:
parent
0a57cac70c
commit
9b8c3ff8c0
|
@ -11,7 +11,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "101.02";
|
||||
static const string Version = "101.03";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -90,6 +90,10 @@ auto M68K::disassembleRegisters() -> string {
|
|||
|
||||
//
|
||||
|
||||
auto M68K::disassembleABCD(EffectiveAddress with, EffectiveAddress from) -> string {
|
||||
return {"abcd ", _effectiveAddress<Byte>(from), ",", _effectiveAddress<Byte>(with)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleADD(EffectiveAddress from, DataRegister with) -> string {
|
||||
return {"add", _suffix<Size>(), " ", _effectiveAddress<Size>(from), ",", _dataRegister(with)};
|
||||
}
|
||||
|
@ -197,6 +201,10 @@ template<uint Size> auto M68K::disassembleBTST(EffectiveAddress with) -> string
|
|||
return {"btst", _suffix<Size>(), " ", _immediate<Byte>(), ",", _effectiveAddress<Size>(with)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleCHK(DataRegister compare, EffectiveAddress maximum) -> string {
|
||||
return {"chk", _suffix<Word>(), " ", _effectiveAddress<Word>(maximum), ",", _dataRegister(compare)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleCLR(EffectiveAddress ea) -> string {
|
||||
return {"clr", _suffix<Size>(), " ", _effectiveAddress<Size>(ea)};
|
||||
}
|
||||
|
@ -223,6 +231,14 @@ auto M68K::disassembleDBCC(uint4 condition, DataRegister dr) -> string {
|
|||
return {"db", _condition(condition), " ", _dataRegister(dr), ",$", hex(base + displacement, 6L)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleDIVS(DataRegister with, EffectiveAddress from) -> string {
|
||||
return {"divs", _suffix<Word>(), " ", _effectiveAddress<Word>(from), ",", _dataRegister(with)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleDIVU(DataRegister with, EffectiveAddress from) -> string {
|
||||
return {"divu", _suffix<Word>(), " ", _effectiveAddress<Word>(from), ",", _dataRegister(with)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleEOR(DataRegister from, EffectiveAddress with) -> string {
|
||||
return {"eor", _suffix<Size>(), " ", _dataRegister(from), ",", _effectiveAddress<Size>(with)};
|
||||
}
|
||||
|
@ -239,6 +255,26 @@ auto M68K::disassembleEORI_TO_SR() -> string {
|
|||
return {"eori ", _immediate<Word>(), ",sr"};
|
||||
}
|
||||
|
||||
auto M68K::disassembleEXG(DataRegister x, DataRegister y) -> string {
|
||||
return {"exg ", _dataRegister(x), ",", _dataRegister(y)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleEXG(AddressRegister x, AddressRegister y) -> string {
|
||||
return {"exg ", _addressRegister(x), ",", _addressRegister(y)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleEXG(DataRegister x, AddressRegister y) -> string {
|
||||
return {"exg ", _dataRegister(x), ",", _addressRegister(y)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleEXT(DataRegister with) -> string {
|
||||
return {"ext", _suffix<Size>(), " ", _dataRegister(with)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleILLEGAL() -> string {
|
||||
return {"illegal "};
|
||||
}
|
||||
|
||||
auto M68K::disassembleJMP(EffectiveAddress target) -> string {
|
||||
return {"jmp ", _effectiveAddress<Long>(target)};
|
||||
}
|
||||
|
@ -251,6 +287,10 @@ auto M68K::disassembleLEA(AddressRegister ar, EffectiveAddress ea) -> string {
|
|||
return {"lea ", _address<Long>(ea), ",", _addressRegister(ar)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleLINK(AddressRegister with) -> string {
|
||||
return {"link ", _addressRegister(with), ",", _immediate<Word>()};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleLSL(uint4 immediate, DataRegister dr) -> string {
|
||||
return {"lsl", _suffix<Size>(), " #", immediate, ",", _dataRegister(dr)};
|
||||
}
|
||||
|
@ -283,7 +323,7 @@ template<uint Size> auto M68K::disassembleMOVEA(AddressRegister ar, EffectiveAdd
|
|||
return {"movea ", _effectiveAddress<Size>(ea), ",", _addressRegister(ar)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleMOVEM(uint1 direction, EffectiveAddress ea) -> string {
|
||||
template<uint Size> auto M68K::disassembleMOVEM_TO_MEM(EffectiveAddress to) -> string {
|
||||
string op{"movem", _suffix<Size>(), " "};
|
||||
|
||||
uint16 list = _readPC();
|
||||
|
@ -294,11 +334,29 @@ template<uint Size> auto M68K::disassembleMOVEM(uint1 direction, EffectiveAddres
|
|||
for(uint n : range(8)) if(list.bit(8 + n)) regs.append(_addressRegister(AddressRegister{n}), ",");
|
||||
regs.trimRight(",");
|
||||
|
||||
if(direction == 0) {
|
||||
return {op, regs, ",", _effectiveAddress<Size>(ea)};
|
||||
} else {
|
||||
return {op, _effectiveAddress<Size>(ea), ",", regs};
|
||||
}
|
||||
return {op, regs, ",", _effectiveAddress<Size>(to)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleMOVEM_TO_REG(EffectiveAddress from) -> string {
|
||||
string op{"movem", _suffix<Size>(), " "};
|
||||
|
||||
uint16 list = _readPC();
|
||||
string regs;
|
||||
for(uint n : range(8)) if(list.bit(0 + n)) regs.append(_dataRegister(DataRegister{n}), ",");
|
||||
regs.trimRight(",");
|
||||
if(regs && list >> 8) regs.append("/");
|
||||
for(uint n : range(8)) if(list.bit(8 + n)) regs.append(_addressRegister(AddressRegister{n}), ",");
|
||||
regs.trimRight(",");
|
||||
|
||||
return {op, _effectiveAddress<Size>(from), ",", regs};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleMOVEP(DataRegister from, EffectiveAddress to) -> string {
|
||||
return {"movep", _suffix<Size>(), " ", _dataRegister(from), ",", _effectiveAddress<Size>(to)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleMOVEP(EffectiveAddress from, DataRegister to) -> string {
|
||||
return {"movep", _suffix<Size>(), " ", _effectiveAddress<Size>(from), ",", _dataRegister(to)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleMOVEQ(DataRegister dr, uint8 immediate) -> string {
|
||||
|
@ -325,6 +383,18 @@ auto M68K::disassembleMOVE_TO_USP(AddressRegister from) -> string {
|
|||
return {"move ", _addressRegister(from), ",usp"};
|
||||
}
|
||||
|
||||
auto M68K::disassembleMULS(DataRegister with, EffectiveAddress from) -> string {
|
||||
return {"muls", _suffix<Word>(), " ", _effectiveAddress<Word>(from), ",", _dataRegister(with)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleMULU(DataRegister with, EffectiveAddress from) -> string {
|
||||
return {"mulu", _suffix<Word>(), " ", _effectiveAddress<Word>(from), ",", _dataRegister(with)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleNBCD(EffectiveAddress with) -> string {
|
||||
return {"nbcd ", _effectiveAddress<Byte>(with)};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleNEG(EffectiveAddress with) -> string {
|
||||
return {"neg", _suffix<Size>(), " ", _effectiveAddress<Size>(with)};
|
||||
}
|
||||
|
@ -361,6 +431,14 @@ auto M68K::disassembleORI_TO_SR() -> string {
|
|||
return {"ori ", _immediate<Word>(), ",sr"};
|
||||
}
|
||||
|
||||
auto M68K::disassemblePEA(EffectiveAddress from) -> string {
|
||||
return {"pea ", _effectiveAddress<Long>(from)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleRESET() -> string {
|
||||
return {"reset "};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleROL(uint4 shift, DataRegister modify) -> string {
|
||||
return {"rol", _suffix<Size>(), " #", shift, ",", _dataRegister(modify)};
|
||||
}
|
||||
|
@ -421,10 +499,18 @@ auto M68K::disassembleRTS() -> string {
|
|||
return {"rts "};
|
||||
}
|
||||
|
||||
auto M68K::disassembleSBCD(EffectiveAddress with, EffectiveAddress from) -> string {
|
||||
return {"sbcd ", _effectiveAddress<Byte>(from), ",", _effectiveAddress<Byte>(with)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleSCC(uint4 condition, EffectiveAddress to) -> string {
|
||||
return {"s", _condition(condition), " ", _effectiveAddress<Byte>(to)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleSTOP() -> string {
|
||||
return {"stop ", _immediate<Word>()};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleSUB(EffectiveAddress source, DataRegister target) -> string {
|
||||
return {"sub", _suffix<Size>(), " ", _effectiveAddress<Size>(source), ",", _dataRegister(target)};
|
||||
}
|
||||
|
@ -449,6 +535,26 @@ template<uint Size> auto M68K::disassembleSUBX(EffectiveAddress with, EffectiveA
|
|||
return {"subx", _suffix<Size>(), " ", _effectiveAddress<Size>(with), ",", _effectiveAddress<Size>(from)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleSWAP(DataRegister with) -> string {
|
||||
return {"swap ", _dataRegister(with)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleTAS(EffectiveAddress with) -> string {
|
||||
return {"tas ", _effectiveAddress<Byte>(with)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleTRAP(uint4 vector) -> string {
|
||||
return {"trap #", vector};
|
||||
}
|
||||
|
||||
auto M68K::disassembleTRAPV() -> string {
|
||||
return {"trapv "};
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::disassembleTST(EffectiveAddress ea) -> string {
|
||||
return {"tst", _suffix<Size>(), " ", _effectiveAddress<Size>(ea)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleUNLK(AddressRegister with) -> string {
|
||||
return {"unlk ", _addressRegister(with)};
|
||||
}
|
||||
|
|
|
@ -36,6 +36,20 @@ M68K::M68K() {
|
|||
#define pattern(s) \
|
||||
std::integral_constant<uint16_t, bit::test(s)>::value
|
||||
|
||||
//ABCD
|
||||
for(uint3 xreg : range(8))
|
||||
for(uint3 yreg : range(8)) {
|
||||
auto opcode = pattern("1100 ---1 0000 ----") | xreg << 9 | yreg << 0;
|
||||
|
||||
EffectiveAddress dataWith{DataRegisterDirect, xreg};
|
||||
EffectiveAddress dataFrom{DataRegisterDirect, yreg};
|
||||
bind(opcode | 0 << 3, ABCD, dataWith, dataFrom);
|
||||
|
||||
EffectiveAddress addressWith{AddressRegisterIndirectWithPreDecrement, xreg};
|
||||
EffectiveAddress addressFrom{AddressRegisterIndirectWithPreDecrement, yreg};
|
||||
bind(opcode | 1 << 3, ABCD, addressWith, addressFrom);
|
||||
}
|
||||
|
||||
//ADD
|
||||
for(uint3 dreg : range(8))
|
||||
for(uint3 mode : range(8))
|
||||
|
@ -349,6 +363,18 @@ M68K::M68K() {
|
|||
if(mode != 0) bind(opcode, BTST<Byte>, ea);
|
||||
}
|
||||
|
||||
//CHK
|
||||
for(uint3 dreg : range(8))
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("0100 ---1 10-- ----") | dreg << 9 | mode << 3 | reg << 0;
|
||||
if(mode == 1 || (mode == 7 && reg >= 5)) continue;
|
||||
|
||||
DataRegister compare{dreg};
|
||||
EffectiveAddress maximum{mode, reg};
|
||||
bind(opcode, CHK, compare, maximum);
|
||||
}
|
||||
|
||||
//CLR
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
|
@ -422,6 +448,30 @@ M68K::M68K() {
|
|||
bind(opcode, DBCC, condition, dr);
|
||||
}
|
||||
|
||||
//DIVS
|
||||
for(uint3 dreg : range(8))
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("1000 ---1 11-- ----") | dreg << 9 | mode << 3 | reg << 0;
|
||||
if(mode == 1 || (mode == 7 && reg >= 5)) continue;
|
||||
|
||||
DataRegister with{dreg};
|
||||
EffectiveAddress from{mode, reg};
|
||||
bind(opcode, DIVS, with, from);
|
||||
}
|
||||
|
||||
//DIVU
|
||||
for(uint3 dreg : range(8))
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("1000 ---0 11-- ----") | dreg << 9 | mode << 3 | reg << 0;
|
||||
if(mode == 1 || (mode == 7 && reg >= 5)) continue;
|
||||
|
||||
DataRegister with{dreg};
|
||||
EffectiveAddress from{mode, reg};
|
||||
bind(opcode, DIVU, with, from);
|
||||
}
|
||||
|
||||
//EOR
|
||||
for(uint3 dreg : range(8))
|
||||
for(uint3 mode : range(8))
|
||||
|
@ -460,6 +510,51 @@ M68K::M68K() {
|
|||
bind(opcode, EORI_TO_SR);
|
||||
}
|
||||
|
||||
//EXG
|
||||
for(uint3 xreg : range(8))
|
||||
for(uint3 yreg : range(8)) {
|
||||
auto opcode = pattern("1100 ---1 0100 0---") | xreg << 9 | yreg << 0;
|
||||
|
||||
DataRegister x{xreg};
|
||||
DataRegister y{yreg};
|
||||
bind(opcode, EXG, x, y);
|
||||
}
|
||||
|
||||
//EXG
|
||||
for(uint3 xreg : range(8))
|
||||
for(uint3 yreg : range(8)) {
|
||||
auto opcode = pattern("1100 ---1 0100 1---") | xreg << 9 | yreg << 0;
|
||||
|
||||
AddressRegister x{xreg};
|
||||
AddressRegister y{yreg};
|
||||
bind(opcode, EXG, x, y);
|
||||
}
|
||||
|
||||
//EXG
|
||||
for(uint3 xreg : range(8))
|
||||
for(uint3 yreg : range(8)) {
|
||||
auto opcode = pattern("1100 ---1 1000 1---") | xreg << 9 | yreg << 0;
|
||||
|
||||
DataRegister x{xreg};
|
||||
AddressRegister y{yreg};
|
||||
bind(opcode, EXG, x, y);
|
||||
}
|
||||
|
||||
//EXT
|
||||
for(uint3 dreg : range(8)) {
|
||||
auto opcode = pattern("0100 1000 1+00 0---") | dreg << 0;
|
||||
|
||||
DataRegister with{dreg};
|
||||
bind(opcode | 0 << 6, EXT<Word>, with);
|
||||
bind(opcode | 1 << 6, EXT<Long>, with);
|
||||
}
|
||||
|
||||
//ILLEGAL
|
||||
{ auto opcode = pattern("0100 1010 1111 1100");
|
||||
|
||||
bind(opcode, ILLEGAL);
|
||||
}
|
||||
|
||||
//JMP
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
|
@ -492,6 +587,14 @@ M68K::M68K() {
|
|||
bind(opcode, LEA, ar, ea);
|
||||
}
|
||||
|
||||
//LINK
|
||||
for(uint3 areg : range(8)) {
|
||||
auto opcode = pattern("0100 1110 0101 0---") | areg << 0;
|
||||
|
||||
AddressRegister with{areg};
|
||||
bind(opcode, LINK, with);
|
||||
}
|
||||
|
||||
//LSL (immediate)
|
||||
for(uint3 data : range(8))
|
||||
for(uint3 dreg : range(8)) {
|
||||
|
@ -592,16 +695,47 @@ M68K::M68K() {
|
|||
}
|
||||
|
||||
//MOVEM
|
||||
for(uint1 direction : range(2))
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("0100 1-00 1+-- ----") | direction << 10 | mode << 3 | reg << 0;
|
||||
if(direction == 0 && (mode <= 1 || mode == 3 || (mode == 7 && reg >= 2)));
|
||||
if(direction == 1 && (mode <= 1 || mode == 4 || (mode == 7 && reg >= 4)));
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("0100 1000 1+-- ----") | mode << 3 | reg << 0;
|
||||
if(mode <= 1 || mode == 3 || (mode == 7 && reg >= 2)) continue;
|
||||
|
||||
EffectiveAddress ea{mode, reg};
|
||||
bind(opcode | 0 << 6, MOVEM<Word>, direction, ea);
|
||||
bind(opcode | 1 << 6, MOVEM<Long>, direction, ea);
|
||||
EffectiveAddress to{mode, reg};
|
||||
bind(opcode | 0 << 6, MOVEM_TO_MEM<Word>, to);
|
||||
bind(opcode | 1 << 6, MOVEM_TO_MEM<Long>, to);
|
||||
}
|
||||
|
||||
//MOVEM
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("0100 1100 1+-- ----") | mode << 3 | reg << 0;
|
||||
if(mode <= 1 || mode == 4 || (mode == 7 && reg >= 4)) continue;
|
||||
|
||||
EffectiveAddress from{mode, reg};
|
||||
bind(opcode | 0 << 6, MOVEM_TO_REG<Word>, from);
|
||||
bind(opcode | 1 << 6, MOVEM_TO_REG<Long>, from);
|
||||
}
|
||||
|
||||
//MOVEP
|
||||
for(uint3 dreg : range(8))
|
||||
for(uint3 areg : range(8)) {
|
||||
auto opcode = pattern("0000 ---1 1+00 1---") | dreg << 9 | areg << 0;
|
||||
|
||||
DataRegister from{dreg};
|
||||
EffectiveAddress to{AddressRegisterIndirectWithDisplacement, areg};
|
||||
bind(opcode | 0 << 6, MOVEP<Word>, from, to);
|
||||
bind(opcode | 1 << 6, MOVEP<Long>, from, to);
|
||||
}
|
||||
|
||||
//MOVEP
|
||||
for(uint3 dreg : range(8))
|
||||
for(uint3 areg : range(8)) {
|
||||
auto opcode = pattern("0000 ---1 0+00 1---") | dreg << 9 | areg << 0;
|
||||
|
||||
DataRegister to{dreg};
|
||||
EffectiveAddress from{AddressRegisterIndirectWithDisplacement, areg};
|
||||
bind(opcode | 0 << 6, MOVEP<Word>, from, to);
|
||||
bind(opcode | 1 << 6, MOVEP<Long>, from, to);
|
||||
}
|
||||
|
||||
//MOVEQ
|
||||
|
@ -659,6 +793,40 @@ M68K::M68K() {
|
|||
bind(opcode, MOVE_TO_USP, from);
|
||||
}
|
||||
|
||||
//MULS
|
||||
for(uint3 dreg : range(8))
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("1100 ---1 11-- ----") | dreg << 9 | mode << 3 | reg << 0;
|
||||
if(mode == 1 || (mode == 7 && reg >= 5)) continue;
|
||||
|
||||
DataRegister with{dreg};
|
||||
EffectiveAddress from{mode, reg};
|
||||
bind(opcode, MULS, with, from);
|
||||
}
|
||||
|
||||
//MULU
|
||||
for(uint3 dreg : range(8))
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("1100 ---0 11-- ----") | dreg << 9 | mode << 3 | reg << 0;
|
||||
if(mode == 1 || (mode == 7 && reg >= 5)) continue;
|
||||
|
||||
DataRegister with{dreg};
|
||||
EffectiveAddress from{mode, reg};
|
||||
bind(opcode, MULU, with, from);
|
||||
}
|
||||
|
||||
//NBCD
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("0100 1000 00-- ----") | mode << 3 | reg << 0;
|
||||
if(mode == 1 || (mode == 7 && reg >= 2)) continue;
|
||||
|
||||
EffectiveAddress with{mode, reg};
|
||||
bind(opcode, NBCD, with);
|
||||
}
|
||||
|
||||
//NEG
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
|
@ -753,6 +921,22 @@ M68K::M68K() {
|
|||
bind(opcode, ORI_TO_SR);
|
||||
}
|
||||
|
||||
//PEA
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("0100 1000 01-- ----") | mode << 3 | reg << 0;
|
||||
if(mode <= 1 || mode == 3 || mode == 4 || (mode == 7 && reg >= 4)) continue;
|
||||
|
||||
EffectiveAddress from{mode, reg};
|
||||
bind(opcode, PEA, from);
|
||||
}
|
||||
|
||||
//RESET
|
||||
{ auto opcode = pattern("0100 1110 0111 0000");
|
||||
|
||||
bind(opcode, RESET);
|
||||
}
|
||||
|
||||
//ROL (immediate)
|
||||
for(uint3 count : range(8))
|
||||
for(uint3 dreg : range(8)) {
|
||||
|
@ -907,6 +1091,20 @@ M68K::M68K() {
|
|||
bind(opcode, RTS);
|
||||
}
|
||||
|
||||
//SBCD
|
||||
for(uint3 xreg : range(8))
|
||||
for(uint3 yreg : range(8)) {
|
||||
auto opcode = pattern("1000 ---1 0000 ----") | xreg << 9 | yreg << 0;
|
||||
|
||||
EffectiveAddress dataWith{DataRegisterDirect, xreg};
|
||||
EffectiveAddress dataFrom{DataRegisterDirect, yreg};
|
||||
bind(opcode | 0 << 3, SBCD, dataWith, dataFrom);
|
||||
|
||||
EffectiveAddress addressWith{AddressRegisterIndirectWithPreDecrement, xreg};
|
||||
EffectiveAddress addressFrom{AddressRegisterIndirectWithPreDecrement, yreg};
|
||||
bind(opcode | 1 << 3, SBCD, addressWith, addressFrom);
|
||||
}
|
||||
|
||||
//SCC
|
||||
for(uint4 condition : range(16))
|
||||
for(uint3 mode : range( 8))
|
||||
|
@ -918,6 +1116,12 @@ M68K::M68K() {
|
|||
bind(opcode, SCC, condition, to);
|
||||
}
|
||||
|
||||
//STOP
|
||||
{ auto opcode = pattern("0100 1110 0111 0010");
|
||||
|
||||
bind(opcode, STOP);
|
||||
}
|
||||
|
||||
//SUB
|
||||
for(uint3 dreg : range(8))
|
||||
for(uint3 mode : range(8))
|
||||
|
@ -1007,6 +1211,37 @@ M68K::M68K() {
|
|||
bind(opcode | 2 << 6 | 1 << 3, SUBX<Long>, addressTarget, addressSource);
|
||||
}
|
||||
|
||||
//SWAP
|
||||
for(uint3 dreg : range(8)) {
|
||||
auto opcode = pattern("0100 1000 0100 0---") | dreg << 0;
|
||||
|
||||
DataRegister with{dreg};
|
||||
bind(opcode, SWAP, with);
|
||||
}
|
||||
|
||||
//TAS
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
auto opcode = pattern("0100 1010 11-- ----") | mode << 3 | reg << 0;
|
||||
if(mode == 1 || (mode == 7 && reg >= 2)) continue;
|
||||
|
||||
EffectiveAddress with{mode, reg};
|
||||
bind(opcode, TAS, with);
|
||||
}
|
||||
|
||||
//TRAP
|
||||
for(uint4 vector : range(16)) {
|
||||
auto opcode = pattern("0100 1110 0100 ----") | vector << 0;
|
||||
|
||||
bind(opcode, TRAP, vector);
|
||||
}
|
||||
|
||||
//TRAPV
|
||||
{ auto opcode = pattern("0100 1110 0111 0110");
|
||||
|
||||
bind(opcode, TRAPV);
|
||||
}
|
||||
|
||||
//TST
|
||||
for(uint3 mode : range(8))
|
||||
for(uint3 reg : range(8)) {
|
||||
|
@ -1021,6 +1256,14 @@ M68K::M68K() {
|
|||
if(mode == 1) unbind(opcode | 0 << 6);
|
||||
}
|
||||
|
||||
//UNLK
|
||||
for(uint3 areg : range(8)) {
|
||||
auto opcode = pattern("0100 1110 0101 1---") | areg << 0;
|
||||
|
||||
AddressRegister with{areg};
|
||||
bind(opcode, UNLK, with);
|
||||
}
|
||||
|
||||
#undef bind
|
||||
#undef unbind
|
||||
#undef pattern
|
||||
|
|
|
@ -48,16 +48,35 @@ template<> auto M68K::sign<Byte>(uint32 data) -> int32 { return (int8)data; }
|
|||
template<> auto M68K::sign<Word>(uint32 data) -> int32 { return (int16)data; }
|
||||
template<> auto M68K::sign<Long>(uint32 data) -> int32 { return (int32)data; }
|
||||
|
||||
template<uint Size> auto M68K::zero(uint32 result) -> bool {
|
||||
return clip<Size>(result) == 0;
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::negative(uint32 result) -> bool {
|
||||
return sign<Size>(result) < 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto M68K::instructionABCD(EffectiveAddress with, EffectiveAddress from) -> void {
|
||||
auto source = read<Byte>(from);
|
||||
auto target = read<Byte, NoUpdate>(with);
|
||||
auto result = source + target + r.x;
|
||||
bool v = false;
|
||||
|
||||
if(((target ^ source ^ result) & 0x10) || (result & 0x0f) >= 0x0a) {
|
||||
auto previous = result;
|
||||
result += 0x06;
|
||||
v |= ((~previous & 0x80) & (result & 0x80));
|
||||
}
|
||||
|
||||
if(result >= 0xa0) {
|
||||
auto previous = result;
|
||||
result += 0x60;
|
||||
v |= ((~previous & 0x80) & (result & 0x80));
|
||||
}
|
||||
|
||||
write<Byte>(with, result);
|
||||
|
||||
r.c = sign<Byte>(result >> 1) < 0;
|
||||
r.v = v;
|
||||
r.z = clip<Byte>(result) == 0 ? 0 : r.z;
|
||||
r.n = sign<Byte>(result) < 0;
|
||||
r.x = r.c;
|
||||
}
|
||||
|
||||
template<uint Size, bool Extend> auto M68K::ADD(uint32 source, uint32 target) -> uint32 {
|
||||
uint64 result = (uint64)source + (uint64)target;
|
||||
if(Extend) result += r.x;
|
||||
|
@ -143,11 +162,6 @@ template<uint Size> auto M68K::instructionANDI(EffectiveAddress ea) -> void {
|
|||
auto target = read<Size, NoUpdate>(ea);
|
||||
auto result = AND<Size>(source, target);
|
||||
write<Size>(ea, result);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = zero<Size>(result);
|
||||
r.n = negative<Size>(result);
|
||||
}
|
||||
|
||||
auto M68K::instructionANDI_TO_CCR() -> void {
|
||||
|
@ -303,6 +317,22 @@ template<uint Size> auto M68K::instructionBTST(EffectiveAddress with) -> void {
|
|||
r.z = test.bit(index) == 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionCHK(DataRegister compare, EffectiveAddress maximum) -> void {
|
||||
auto source = read<Word>(maximum);
|
||||
auto target = read<Word>(compare);
|
||||
|
||||
r.z = clip<Word>(target) == 0;
|
||||
r.n = sign<Word>(target) < 0;
|
||||
if(r.n) return exception(Exception::BoundsCheck, Vector::BoundsCheck);
|
||||
|
||||
auto result = target - source;
|
||||
r.c = sign<Word>(result >> 1) < 0;
|
||||
r.v = sign<Word>((target ^ source) & (target ^ result)) < 0;
|
||||
r.z = clip<Word>(result) == 0;
|
||||
r.n = sign<Word>(result) < 0;
|
||||
if(r.n == r.v && !r.z) return exception(Exception::BoundsCheck, Vector::BoundsCheck);
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::instructionCLR(EffectiveAddress ea) -> void {
|
||||
read<Size>(ea);
|
||||
write<Size>(ea, 0);
|
||||
|
@ -357,6 +387,61 @@ auto M68K::instructionDBCC(uint4 condition, DataRegister dr) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
template<bool Sign> auto M68K::DIV(uint16 divisor, DataRegister with) -> void {
|
||||
auto dividend = read<Long>(with);
|
||||
bool negativeQuotient = false;
|
||||
bool negativeRemainder = false;
|
||||
bool overflow = false;
|
||||
|
||||
if(divisor == 0) return exception(Exception::DivisionByZero, Vector::DivisionByZero);
|
||||
|
||||
if(Sign) {
|
||||
negativeQuotient = (dividend >> 31) ^ (divisor >> 15);
|
||||
if(dividend >> 31) dividend = -dividend, negativeRemainder = true;
|
||||
if(divisor >> 15) divisor = -divisor;
|
||||
}
|
||||
|
||||
auto result = dividend;
|
||||
|
||||
for(auto _ : range(16)) {
|
||||
bool lb = false;
|
||||
if(result >= (uint32)divisor << 15) result -= divisor << 15, lb = true;
|
||||
|
||||
bool ob = result >> 31;
|
||||
result = result << 1 | lb;
|
||||
|
||||
if(ob) overflow = true;
|
||||
}
|
||||
|
||||
if(Sign) {
|
||||
if((uint16)result > 0x7fff + negativeQuotient) overflow = true;
|
||||
}
|
||||
|
||||
if(result >> 16 >= divisor) overflow = true;
|
||||
|
||||
if(Sign && !overflow) {
|
||||
if(negativeQuotient) result = ((-result) & 0xffff) | (result & 0xffff0000);
|
||||
if(negativeRemainder) result = (((-(result >> 16)) << 16) & 0xffff0000) | (result & 0xffff);
|
||||
}
|
||||
|
||||
if(!overflow) write<Long>(with, result);
|
||||
|
||||
r.c = 0;
|
||||
r.v = overflow;
|
||||
r.z = clip<Word>(result) == 0;
|
||||
r.n = sign<Word>(result) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionDIVS(DataRegister with, EffectiveAddress from) -> void {
|
||||
auto divisor = read<Word>(from);
|
||||
DIV<1>(divisor, with);
|
||||
}
|
||||
|
||||
auto M68K::instructionDIVU(DataRegister with, EffectiveAddress from) -> void {
|
||||
auto divisor = read<Word>(from);
|
||||
DIV<0>(divisor, with);
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::EOR(uint32 source, uint32 target) -> uint32 {
|
||||
uint32 result = target ^ source;
|
||||
|
||||
|
@ -394,6 +479,49 @@ auto M68K::instructionEORI_TO_SR() -> void {
|
|||
writeSR(readSR() ^ data);
|
||||
}
|
||||
|
||||
auto M68K::instructionEXG(DataRegister x, DataRegister y) -> void {
|
||||
auto z = read<Long>(x);
|
||||
write<Long>(x, read<Long>(y));
|
||||
write<Long>(y, z);
|
||||
}
|
||||
|
||||
auto M68K::instructionEXG(AddressRegister x, AddressRegister y) -> void {
|
||||
auto z = read<Long>(x);
|
||||
write<Long>(x, read<Long>(y));
|
||||
write<Long>(y, z);
|
||||
}
|
||||
|
||||
auto M68K::instructionEXG(DataRegister x, AddressRegister y) -> void {
|
||||
auto z = read<Long>(x);
|
||||
write<Long>(x, read<Long>(y));
|
||||
write<Long>(y, z);
|
||||
}
|
||||
|
||||
template<> auto M68K::instructionEXT<Word>(DataRegister with) -> void {
|
||||
auto result = (int8)read<Byte>(with);
|
||||
write<Word>(with, result);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = clip<Word>(result) == 0;
|
||||
r.n = sign<Word>(result) < 0;
|
||||
}
|
||||
|
||||
template<> auto M68K::instructionEXT<Long>(DataRegister with) -> void {
|
||||
auto result = (int16)read<Word>(with);
|
||||
write<Long>(with, result);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = clip<Long>(result) == 0;
|
||||
r.n = sign<Long>(result) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionILLEGAL() -> void {
|
||||
r.pc -= 2;
|
||||
return exception(Exception::Illegal, Vector::Illegal);
|
||||
}
|
||||
|
||||
auto M68K::instructionJMP(EffectiveAddress target) -> void {
|
||||
r.pc = fetch<Long>(target);
|
||||
}
|
||||
|
@ -407,6 +535,14 @@ auto M68K::instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void {
|
|||
write<Long>(ar, fetch<Long>(ea));
|
||||
}
|
||||
|
||||
auto M68K::instructionLINK(AddressRegister with) -> void {
|
||||
auto displacement = (int16)readPC<Word>();
|
||||
auto sp = AddressRegister{7};
|
||||
push<Long>(read<Long>(with));
|
||||
write<Long>(with, read<Long>(sp));
|
||||
write<Long>(sp, read<Long>(sp) + displacement);
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::LSL(uint32 result, uint shift) -> uint32 {
|
||||
bool carry = false;
|
||||
for(auto _ : range(shift)) {
|
||||
|
@ -477,8 +613,8 @@ template<uint Size> auto M68K::instructionMOVE(EffectiveAddress to, EffectiveAdd
|
|||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = zero<Size>(data);
|
||||
r.n = negative<Size>(data);
|
||||
r.z = clip<Size>(data) == 0;
|
||||
r.n = sign<Size>(data) < 0;
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::instructionMOVEA(AddressRegister ar, EffectiveAddress ea) -> void {
|
||||
|
@ -486,31 +622,64 @@ template<uint Size> auto M68K::instructionMOVEA(AddressRegister ar, EffectiveAdd
|
|||
write<Long>(ar, data);
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::instructionMOVEM(uint1 direction, EffectiveAddress ea) -> void {
|
||||
auto list = readPC();
|
||||
auto addr = fetch<Long>(ea);
|
||||
template<uint Size> auto M68K::instructionMOVEM_TO_MEM(EffectiveAddress to) -> void {
|
||||
auto list = readPC<Word>();
|
||||
auto addr = fetch<Long>(to);
|
||||
|
||||
for(uint n : range(16)) {
|
||||
if(!list.bit(n)) continue;
|
||||
|
||||
//pre-decrement mode traverses registers in reverse order {A7-A0, D7-D0}
|
||||
uint index = ea.mode == AddressRegisterIndirectWithPreDecrement ? 15 - n : n;
|
||||
uint index = to.mode == AddressRegisterIndirectWithPreDecrement ? 15 - n : n;
|
||||
|
||||
if(ea.mode == AddressRegisterIndirectWithPreDecrement) addr -= bytes<Size>();
|
||||
|
||||
if(direction == 0) {
|
||||
auto data = index < 8 ? read<Size>(DataRegister{index}) : read<Size>(AddressRegister{index});
|
||||
write<Size>(addr, data);
|
||||
} else {
|
||||
auto data = read<Size>(addr);
|
||||
data = sign<Size>(data);
|
||||
index < 8 ? write<Long>(DataRegister{index}, data) : write<Long>(AddressRegister{index}, data);
|
||||
}
|
||||
|
||||
if(ea.mode == AddressRegisterIndirectWithPostIncrement) addr += bytes<Size>();
|
||||
if(to.mode == AddressRegisterIndirectWithPreDecrement) addr -= bytes<Size>();
|
||||
auto data = index < 8 ? read<Size>(DataRegister{index}) : read<Size>(AddressRegister{index});
|
||||
write<Size>(addr, data);
|
||||
if(to.mode == AddressRegisterIndirectWithPostIncrement) addr += bytes<Size>();
|
||||
}
|
||||
|
||||
flush<Long>(ea, addr);
|
||||
flush<Long>(to, addr);
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::instructionMOVEM_TO_REG(EffectiveAddress from) -> void {
|
||||
auto list = readPC<Word>();
|
||||
auto addr = fetch<Long>(from);
|
||||
|
||||
for(uint n : range(16)) {
|
||||
if(!list.bit(n)) continue;
|
||||
uint index = from.mode == AddressRegisterIndirectWithPreDecrement ? 15 - n : n;
|
||||
|
||||
if(from.mode == AddressRegisterIndirectWithPreDecrement) addr -= bytes<Size>();
|
||||
auto data = read<Size>(addr);
|
||||
data = sign<Size>(data);
|
||||
index < 8 ? write<Long>(DataRegister{index}, data) : write<Long>(AddressRegister{index}, data);
|
||||
if(from.mode == AddressRegisterIndirectWithPostIncrement) addr += bytes<Size>();
|
||||
}
|
||||
|
||||
flush<Long>(from, addr);
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::instructionMOVEP(DataRegister from, EffectiveAddress to) -> void {
|
||||
auto address = fetch<Size>(to);
|
||||
auto data = read<Long>(from);
|
||||
uint shift = bits<Size>();
|
||||
for(auto _ : range(bytes<Size>())) {
|
||||
shift -= 8;
|
||||
write<Byte>(address, data >> shift);
|
||||
address += 2;
|
||||
}
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::instructionMOVEP(EffectiveAddress from, DataRegister to) -> void {
|
||||
auto address = fetch<Size>(from);
|
||||
auto data = read<Long>(to);
|
||||
uint shift = bits<Size>();
|
||||
for(auto _ : range(bytes<Size>())) {
|
||||
shift -= 8;
|
||||
data &= ~(0xff << shift);
|
||||
data |= read<Byte>(address) << shift;
|
||||
address += 2;
|
||||
}
|
||||
write<Long>(to, data);
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVEQ(DataRegister dr, uint8 immediate) -> void {
|
||||
|
@ -518,8 +687,8 @@ auto M68K::instructionMOVEQ(DataRegister dr, uint8 immediate) -> void {
|
|||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = zero<Byte>(immediate);
|
||||
r.n = negative<Byte>(immediate);
|
||||
r.z = clip<Byte>(immediate) == 0;
|
||||
r.n = sign<Byte>(immediate) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionMOVE_FROM_SR(EffectiveAddress ea) -> void {
|
||||
|
@ -551,6 +720,59 @@ auto M68K::instructionMOVE_TO_USP(AddressRegister from) -> void {
|
|||
r.sp = read<Long>(from);
|
||||
}
|
||||
|
||||
auto M68K::instructionMULS(DataRegister with, EffectiveAddress from) -> void {
|
||||
auto source = read<Word>(from);
|
||||
auto target = read<Word>(with);
|
||||
auto result = (int16)source * (int16)target;
|
||||
write<Long>(with, result);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = clip<Long>(result) == 0;
|
||||
r.n = sign<Long>(result) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionMULU(DataRegister with, EffectiveAddress from) -> void {
|
||||
auto source = read<Word>(from);
|
||||
auto target = read<Word>(with);
|
||||
auto result = source * target;
|
||||
write<Long>(with, result);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = clip<Long>(result) == 0;
|
||||
r.n = sign<Long>(result) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionNBCD(EffectiveAddress with) -> void {
|
||||
auto source = 0u;
|
||||
auto target = read<Byte, NoUpdate>(with);
|
||||
auto result = source - target - r.x;
|
||||
bool v = false;
|
||||
|
||||
const bool adjustLo = (target ^ source ^ result) & 0x10;
|
||||
const bool adjustHi = result & 0x100;
|
||||
|
||||
if(adjustLo) {
|
||||
auto previous = result;
|
||||
result -= 0x06;
|
||||
v |= (previous & 0x80) & (~result & 0x80);
|
||||
}
|
||||
|
||||
if(adjustHi) {
|
||||
auto previous = result;
|
||||
result -= 0x60;
|
||||
v |= (previous & 0x80) & (~result & 0x80);
|
||||
}
|
||||
|
||||
write<Byte>(with, result);
|
||||
|
||||
r.c = sign<Byte>(result >> 1) < 0;
|
||||
r.v = v;
|
||||
r.z = clip<Byte>(result) == 0 ? 0 : r.z;
|
||||
r.n = sign<Byte>(result) < 0;
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::instructionNEG(EffectiveAddress with) -> void {
|
||||
auto source = read<Size>(with);
|
||||
auto result = SUB<Size>(0, source);
|
||||
|
@ -620,6 +842,17 @@ auto M68K::instructionORI_TO_SR() -> void {
|
|||
writeSR(readSR() | data);
|
||||
}
|
||||
|
||||
auto M68K::instructionPEA(EffectiveAddress from) -> void {
|
||||
auto data = fetch<Long>(from);
|
||||
push<Long>(data);
|
||||
}
|
||||
|
||||
auto M68K::instructionRESET() -> void {
|
||||
if(!supervisor()) return;
|
||||
|
||||
r.reset = true;
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::ROL(uint32 result, uint shift) -> uint32 {
|
||||
bool carry = false;
|
||||
for(auto _ : range(shift)) {
|
||||
|
@ -767,11 +1000,48 @@ auto M68K::instructionRTS() -> void {
|
|||
r.pc = pop<Long>();
|
||||
}
|
||||
|
||||
auto M68K::instructionSBCD(EffectiveAddress with, EffectiveAddress from) -> void {
|
||||
auto source = read<Byte>(from);
|
||||
auto target = read<Byte, NoUpdate>(with);
|
||||
auto result = target - source - r.x;
|
||||
bool v = false;
|
||||
|
||||
const bool adjustLo = (target ^ source ^ result) & 0x10;
|
||||
const bool adjustHi = result & 0x100;
|
||||
|
||||
if(adjustLo) {
|
||||
auto previous = result;
|
||||
result -= 0x06;
|
||||
v |= (previous & 0x80) & (~result & 0x80);
|
||||
}
|
||||
|
||||
if(adjustHi) {
|
||||
auto previous = result;
|
||||
result -= 0x60;
|
||||
v |= (previous & 0x80) & (~result & 0x80);
|
||||
}
|
||||
|
||||
write<Byte>(with, result);
|
||||
|
||||
r.c = sign<Byte>(result >> 1) < 0;
|
||||
r.v = v;
|
||||
r.z = clip<Byte>(result) == 0 ? 0 : r.z;
|
||||
r.n = sign<Byte>(result) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionSCC(uint4 condition, EffectiveAddress to) -> void {
|
||||
uint8 result = testCondition(condition) ? ~0 : 0;
|
||||
write<Byte>(to, result);
|
||||
}
|
||||
|
||||
auto M68K::instructionSTOP() -> void {
|
||||
if(!supervisor()) return;
|
||||
|
||||
auto sr = readPC<Word>();
|
||||
writeSR(sr);
|
||||
r.stop = true;
|
||||
}
|
||||
|
||||
template<uint Size, bool Extend> auto M68K::SUB(uint32 source, uint32 target) -> uint32 {
|
||||
uint64 result = source - target;
|
||||
if(Extend) result -= r.x;
|
||||
|
@ -827,11 +1097,46 @@ template<uint Size> auto M68K::instructionSUBX(EffectiveAddress with, EffectiveA
|
|||
write<Size>(with, result);
|
||||
}
|
||||
|
||||
auto M68K::instructionSWAP(DataRegister with) -> void {
|
||||
auto result = read<Long>(with);
|
||||
result = result >> 16 | result << 16;
|
||||
write<Long>(with, result);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = clip<Long>(result) == 0;
|
||||
r.n = sign<Long>(result) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionTAS(EffectiveAddress with) -> void {
|
||||
auto data = read<Byte, NoUpdate>(with);
|
||||
write<Byte>(with, data | 0x80);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = clip<Byte>(data) == 0;
|
||||
r.n = sign<Byte>(data) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionTRAP(uint4 vector) -> void {
|
||||
exception(Exception::Trap, vector);
|
||||
}
|
||||
|
||||
auto M68K::instructionTRAPV() -> void {
|
||||
if(r.v) exception(Exception::Overflow, Vector::Overflow);
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::instructionTST(EffectiveAddress ea) -> void {
|
||||
auto data = read<Size>(ea);
|
||||
|
||||
r.c = 0;
|
||||
r.v = 0;
|
||||
r.z = zero<Size>(data);
|
||||
r.n = negative<Size>(data);
|
||||
r.z = clip<Size>(data) == 0;
|
||||
r.n = sign<Size>(data) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionUNLK(AddressRegister with) -> void {
|
||||
auto sp = AddressRegister{7};
|
||||
write<Long>(sp, read<Long>(with));
|
||||
write<Long>(with, pop<Long>());
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@ enum : bool { Reverse = 1 };
|
|||
#include "registers.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "effective-address.cpp"
|
||||
#include "instruction.cpp"
|
||||
#include "instructions.cpp"
|
||||
#include "disassembler.cpp"
|
||||
#include "instruction.cpp"
|
||||
|
||||
auto M68K::power() -> void {
|
||||
}
|
||||
|
@ -32,12 +32,20 @@ auto M68K::reset() -> void {
|
|||
r.i = 7;
|
||||
r.s = 1;
|
||||
r.t = 0;
|
||||
|
||||
r.stop = false;
|
||||
r.reset = false;
|
||||
}
|
||||
|
||||
auto M68K::supervisor() -> bool {
|
||||
if(r.s) return true;
|
||||
//todo: raise TRAP exception
|
||||
|
||||
r.pc -= 2;
|
||||
exception(Exception::Unprivileged, Vector::Unprivileged);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto M68K::exception(uint exception, uint vector) -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,24 @@ struct M68K {
|
|||
Immediate,
|
||||
};
|
||||
|
||||
struct Exception { enum : uint {
|
||||
Illegal,
|
||||
DivisionByZero,
|
||||
BoundsCheck,
|
||||
Overflow,
|
||||
Unprivileged,
|
||||
|
||||
Trap,
|
||||
};};
|
||||
|
||||
struct Vector { enum : uint {
|
||||
Illegal = 4,
|
||||
DivisionByZero = 5,
|
||||
BoundsCheck = 6,
|
||||
Overflow = 7,
|
||||
Unprivileged = 8,
|
||||
};};
|
||||
|
||||
M68K();
|
||||
|
||||
virtual auto step(uint clocks) -> void = 0;
|
||||
|
@ -33,6 +51,7 @@ struct M68K {
|
|||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
auto supervisor() -> bool;
|
||||
auto exception(uint exception, uint vector) -> void;
|
||||
|
||||
//registers.cpp
|
||||
struct DataRegister {
|
||||
|
@ -94,9 +113,7 @@ struct M68K {
|
|||
template<uint Size> auto clip(uint32 data) -> uint32;
|
||||
template<uint Size> auto sign(uint32 data) -> int32;
|
||||
|
||||
template<uint Size> auto zero(uint32 result) -> bool;
|
||||
template<uint Size> auto negative(uint32 result) -> bool;
|
||||
|
||||
auto instructionABCD(EffectiveAddress with, EffectiveAddress from) -> void;
|
||||
template<uint Size, bool Extend = false> auto ADD(uint32 source, uint32 target) -> uint32;
|
||||
template<uint Size> auto instructionADD(EffectiveAddress from, DataRegister with) -> void;
|
||||
template<uint Size> auto instructionADD(DataRegister from, EffectiveAddress with) -> void;
|
||||
|
@ -127,6 +144,7 @@ struct M68K {
|
|||
template<uint Size> auto instructionBSET(EffectiveAddress with) -> void;
|
||||
template<uint Size> auto instructionBTST(DataRegister bit, EffectiveAddress with) -> void;
|
||||
template<uint Size> auto instructionBTST(EffectiveAddress with) -> void;
|
||||
auto instructionCHK(DataRegister compare, EffectiveAddress maximum) -> void;
|
||||
template<uint Size> auto instructionCLR(EffectiveAddress ea) -> void;
|
||||
template<uint Size> auto CMP(uint32 source, uint32 target) -> uint32;
|
||||
template<uint Size> auto instructionCMP(DataRegister dr, EffectiveAddress ea) -> void;
|
||||
|
@ -134,14 +152,23 @@ struct M68K {
|
|||
template<uint Size> auto instructionCMPI(EffectiveAddress ea) -> void;
|
||||
template<uint Size> auto instructionCMPM(EffectiveAddress ax, EffectiveAddress ay) -> void;
|
||||
auto instructionDBCC(uint4 condition, DataRegister dr) -> void;
|
||||
template<bool Sign> auto DIV(uint16 divisor, DataRegister with) -> void;
|
||||
auto instructionDIVS(DataRegister with, EffectiveAddress from) -> void;
|
||||
auto instructionDIVU(DataRegister with, EffectiveAddress from) -> void;
|
||||
template<uint Size> auto EOR(uint32 source, uint32 target) -> uint32;
|
||||
template<uint Size> auto instructionEOR(DataRegister from, EffectiveAddress with) -> void;
|
||||
template<uint Size> auto instructionEORI(EffectiveAddress with) -> void;
|
||||
auto instructionEORI_TO_CCR() -> void;
|
||||
auto instructionEORI_TO_SR() -> void;
|
||||
auto instructionEXG(DataRegister x, DataRegister y) -> void;
|
||||
auto instructionEXG(AddressRegister x, AddressRegister y) -> void;
|
||||
auto instructionEXG(DataRegister x, AddressRegister y) -> void;
|
||||
template<uint Size> auto instructionEXT(DataRegister with) -> void;
|
||||
auto instructionILLEGAL() -> void;
|
||||
auto instructionJMP(EffectiveAddress target) -> void;
|
||||
auto instructionJSR(EffectiveAddress target) -> void;
|
||||
auto instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void;
|
||||
auto instructionLINK(AddressRegister with) -> void;
|
||||
template<uint Size> auto LSL(uint32 result, uint shift) -> uint32;
|
||||
template<uint Size> auto instructionLSL(uint4 immediate, DataRegister dr) -> void;
|
||||
template<uint Size> auto instructionLSL(DataRegister sr, DataRegister dr) -> void;
|
||||
|
@ -152,13 +179,19 @@ struct M68K {
|
|||
auto instructionLSR(EffectiveAddress ea) -> void;
|
||||
template<uint Size> auto instructionMOVE(EffectiveAddress to, EffectiveAddress from) -> void;
|
||||
template<uint Size> auto instructionMOVEA(AddressRegister ar, EffectiveAddress ea) -> void;
|
||||
template<uint Size> auto instructionMOVEM(uint1 direction, EffectiveAddress ea) -> void;
|
||||
template<uint Size> auto instructionMOVEM_TO_MEM(EffectiveAddress to) -> void;
|
||||
template<uint Size> auto instructionMOVEM_TO_REG(EffectiveAddress from) -> void;
|
||||
template<uint Size> auto instructionMOVEP(DataRegister from, EffectiveAddress to) -> void;
|
||||
template<uint Size> auto instructionMOVEP(EffectiveAddress from, DataRegister to) -> void;
|
||||
auto instructionMOVEQ(DataRegister dr, uint8 immediate) -> void;
|
||||
auto instructionMOVE_FROM_SR(EffectiveAddress ea) -> void;
|
||||
auto instructionMOVE_TO_CCR(EffectiveAddress ea) -> void;
|
||||
auto instructionMOVE_TO_SR(EffectiveAddress ea) -> void;
|
||||
auto instructionMOVE_FROM_USP(AddressRegister to) -> void;
|
||||
auto instructionMOVE_TO_USP(AddressRegister from) -> void;
|
||||
auto instructionMULS(DataRegister with, EffectiveAddress from) -> void;
|
||||
auto instructionMULU(DataRegister with, EffectiveAddress from) -> void;
|
||||
auto instructionNBCD(EffectiveAddress with) -> void;
|
||||
template<uint Size> auto instructionNEG(EffectiveAddress with) -> void;
|
||||
template<uint Size> auto instructionNEGX(EffectiveAddress with) -> void;
|
||||
auto instructionNOP() -> void;
|
||||
|
@ -169,6 +202,8 @@ struct M68K {
|
|||
template<uint Size> auto instructionORI(EffectiveAddress with) -> void;
|
||||
auto instructionORI_TO_CCR() -> void;
|
||||
auto instructionORI_TO_SR() -> void;
|
||||
auto instructionPEA(EffectiveAddress from) -> void;
|
||||
auto instructionRESET() -> void;
|
||||
template<uint Size> auto ROL(uint32 result, uint shift) -> uint32;
|
||||
template<uint Size> auto instructionROL(uint4 shift, DataRegister modify) -> void;
|
||||
template<uint Size> auto instructionROL(DataRegister shift, DataRegister modify) -> void;
|
||||
|
@ -188,7 +223,9 @@ struct M68K {
|
|||
auto instructionRTE() -> void;
|
||||
auto instructionRTR() -> void;
|
||||
auto instructionRTS() -> void;
|
||||
auto instructionSBCD(EffectiveAddress with, EffectiveAddress from) -> void;
|
||||
auto instructionSCC(uint4 condition, EffectiveAddress to) -> void;
|
||||
auto instructionSTOP() -> void;
|
||||
template<uint Size, bool Extend = false> auto SUB(uint32 source, uint32 target) -> uint32;
|
||||
template<uint Size> auto instructionSUB(EffectiveAddress source, DataRegister target) -> void;
|
||||
template<uint Size> auto instructionSUB(DataRegister source, EffectiveAddress target) -> void;
|
||||
|
@ -196,7 +233,12 @@ struct M68K {
|
|||
template<uint Size> auto instructionSUBI(EffectiveAddress with) -> void;
|
||||
template<uint Size> auto instructionSUBQ(uint4 immediate, EffectiveAddress ea) -> void;
|
||||
template<uint Size> auto instructionSUBX(EffectiveAddress with, EffectiveAddress from) -> void;
|
||||
auto instructionSWAP(DataRegister with) -> void;
|
||||
auto instructionTAS(EffectiveAddress with) -> void;
|
||||
auto instructionTRAP(uint4 vector) -> void;
|
||||
auto instructionTRAPV() -> void;
|
||||
template<uint Size> auto instructionTST(EffectiveAddress ea) -> void;
|
||||
auto instructionUNLK(AddressRegister with) -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassemble(uint32 pc) -> string;
|
||||
|
@ -216,6 +258,9 @@ struct M68K {
|
|||
uint3 i; //interrupt mask
|
||||
bool s; //supervisor mode
|
||||
bool t; //trace mode
|
||||
|
||||
bool stop;
|
||||
bool reset;
|
||||
} r;
|
||||
|
||||
uint16 opcode = 0;
|
||||
|
@ -225,6 +270,7 @@ struct M68K {
|
|||
|
||||
private:
|
||||
//disassembler.cpp
|
||||
auto disassembleABCD(EffectiveAddress with, EffectiveAddress from) -> string;
|
||||
template<uint Size> auto disassembleADD(EffectiveAddress from, DataRegister with) -> string;
|
||||
template<uint Size> auto disassembleADD(DataRegister from, EffectiveAddress with) -> string;
|
||||
template<uint Size> auto disassembleADDA(AddressRegister ar, EffectiveAddress ea) -> string;
|
||||
|
@ -251,19 +297,28 @@ private:
|
|||
template<uint Size> auto disassembleBSET(EffectiveAddress with) -> string;
|
||||
template<uint Size> auto disassembleBTST(DataRegister bit, EffectiveAddress with) -> string;
|
||||
template<uint Size> auto disassembleBTST(EffectiveAddress with) -> string;
|
||||
auto disassembleCHK(DataRegister compare, EffectiveAddress maximum) -> string;
|
||||
template<uint Size> auto disassembleCLR(EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleCMP(DataRegister dr, EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleCMPA(AddressRegister ar, EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleCMPI(EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleCMPM(EffectiveAddress ax, EffectiveAddress ay) -> string;
|
||||
auto disassembleDBCC(uint4 condition, DataRegister dr) -> string;
|
||||
auto disassembleDIVS(DataRegister with, EffectiveAddress from) -> string;
|
||||
auto disassembleDIVU(DataRegister with, EffectiveAddress from) -> string;
|
||||
template<uint Size> auto disassembleEOR(DataRegister from, EffectiveAddress with) -> string;
|
||||
template<uint Size> auto disassembleEORI(EffectiveAddress with) -> string;
|
||||
auto disassembleEORI_TO_CCR() -> string;
|
||||
auto disassembleEORI_TO_SR() -> string;
|
||||
auto disassembleEXG(DataRegister x, DataRegister y) -> string;
|
||||
auto disassembleEXG(AddressRegister x, AddressRegister y) -> string;
|
||||
auto disassembleEXG(DataRegister x, AddressRegister y) -> string;
|
||||
template<uint Size> auto disassembleEXT(DataRegister with) -> string;
|
||||
auto disassembleILLEGAL() -> string;
|
||||
auto disassembleJMP(EffectiveAddress target) -> string;
|
||||
auto disassembleJSR(EffectiveAddress target) -> string;
|
||||
auto disassembleLEA(AddressRegister ar, EffectiveAddress ea) -> string;
|
||||
auto disassembleLINK(AddressRegister with) -> string;
|
||||
template<uint Size> auto disassembleLSL(uint4 immediate, DataRegister dr) -> string;
|
||||
template<uint Size> auto disassembleLSL(DataRegister sr, DataRegister dr) -> string;
|
||||
auto disassembleLSL(EffectiveAddress ea) -> string;
|
||||
|
@ -272,13 +327,19 @@ private:
|
|||
auto disassembleLSR(EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleMOVE(EffectiveAddress to, EffectiveAddress from) -> string;
|
||||
template<uint Size> auto disassembleMOVEA(AddressRegister ar, EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleMOVEM(uint1 direction, EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleMOVEM_TO_MEM(EffectiveAddress to) -> string;
|
||||
template<uint Size> auto disassembleMOVEM_TO_REG(EffectiveAddress from) -> string;
|
||||
template<uint Size> auto disassembleMOVEP(DataRegister from, EffectiveAddress to) -> string;
|
||||
template<uint Size> auto disassembleMOVEP(EffectiveAddress from, DataRegister to) -> string;
|
||||
auto disassembleMOVEQ(DataRegister dr, uint8 immediate) -> string;
|
||||
auto disassembleMOVE_FROM_SR(EffectiveAddress ea) -> string;
|
||||
auto disassembleMOVE_TO_CCR(EffectiveAddress ea) -> string;
|
||||
auto disassembleMOVE_TO_SR(EffectiveAddress ea) -> string;
|
||||
auto disassembleMOVE_FROM_USP(AddressRegister to) -> string;
|
||||
auto disassembleMOVE_TO_USP(AddressRegister from) -> string;
|
||||
auto disassembleMULS(DataRegister with, EffectiveAddress from) -> string;
|
||||
auto disassembleMULU(DataRegister with, EffectiveAddress from) -> string;
|
||||
auto disassembleNBCD(EffectiveAddress with) -> string;
|
||||
template<uint Size> auto disassembleNEG(EffectiveAddress with) -> string;
|
||||
template<uint Size> auto disassembleNEGX(EffectiveAddress with) -> string;
|
||||
auto disassembleNOP() -> string;
|
||||
|
@ -288,6 +349,8 @@ private:
|
|||
template<uint Size> auto disassembleORI(EffectiveAddress with) -> string;
|
||||
auto disassembleORI_TO_CCR() -> string;
|
||||
auto disassembleORI_TO_SR() -> string;
|
||||
auto disassemblePEA(EffectiveAddress from) -> string;
|
||||
auto disassembleRESET() -> string;
|
||||
template<uint Size> auto disassembleROL(uint4 shift, DataRegister modify) -> string;
|
||||
template<uint Size> auto disassembleROL(DataRegister shift, DataRegister modify) -> string;
|
||||
auto disassembleROL(EffectiveAddress modify) -> string;
|
||||
|
@ -303,14 +366,21 @@ private:
|
|||
auto disassembleRTE() -> string;
|
||||
auto disassembleRTR() -> string;
|
||||
auto disassembleRTS() -> string;
|
||||
auto disassembleSBCD(EffectiveAddress with, EffectiveAddress from) -> string;
|
||||
auto disassembleSCC(uint4 condition, EffectiveAddress to) -> string;
|
||||
auto disassembleSTOP() -> string;
|
||||
template<uint Size> auto disassembleSUB(EffectiveAddress source, DataRegister target) -> string;
|
||||
template<uint Size> auto disassembleSUB(DataRegister source, EffectiveAddress target) -> string;
|
||||
template<uint Size> auto disassembleSUBA(AddressRegister to, EffectiveAddress from) -> string;
|
||||
template<uint Size> auto disassembleSUBI(EffectiveAddress with) -> string;
|
||||
template<uint Size> auto disassembleSUBQ(uint4 immediate, EffectiveAddress ea) -> string;
|
||||
template<uint Size> auto disassembleSUBX(EffectiveAddress with, EffectiveAddress from) -> string;
|
||||
auto disassembleSWAP(DataRegister with) -> string;
|
||||
auto disassembleTAS(EffectiveAddress with) -> string;
|
||||
auto disassembleTRAP(uint4 vector) -> string;
|
||||
auto disassembleTRAPV() -> string;
|
||||
template<uint Size> auto disassembleTST(EffectiveAddress ea) -> string;
|
||||
auto disassembleUNLK(AddressRegister with) -> string;
|
||||
|
||||
template<uint Size> auto _read(uint32 addr) -> uint32;
|
||||
template<uint Size = Word> auto _readPC() -> uint32;
|
||||
|
|
Loading…
Reference in New Issue