mirror of https://github.com/bsnes-emu/bsnes.git
Update to v106r75 release.
byuu says: So tired ... so much left to do still ... sigh. If someone's up for some code golf, open to suggestions on how to handle the INTNEST control register. It's the only pure 16-bit register on the system, and it breaks my `map`/`load`/`store<uint8,16,32>` abstraction. Basically what I suspect happens is when you access INTNEST in 32-bit mode, the upper 16-bits are just undefined (probably zero.) But `map<uint32>(INTNEST)` must return a uint32& or nothing at all. So for the time being, I'm just making store(ControlRegister) check if it's the INTNEST ID, and clearing the upper bits of the written byte in that case. It's hacky, but ... it's the best I can think of. I added LDX, which is a 900H-only instruction, and the control register map is for the 900/H CPU. I found the detailed differences between the CPUs, and it doesn't look likely that I'm gonna support the 900 or 900/H1 at all. Not that there was a reason to anyway, but it's nice to support more stuff when possible. Oh well. The 4-byte instruction fetch queue is going to have to get implemented inside fetch, or just not implemented at all ... not like I'd be able to figure out the details of it anyway. The manual isn't clear on how the MULA flags are calculated, but since MUL doesn't set any flags, I assume the flags are based on the addition after the multiplication, eg: uint32 a = indirect<int16>(XDE) * indirect<int16>(XHL); uint32 b = reg16; //opcode parameter uint32 c = a + b; //flags set based on a+b No idea if it's right or not. It doesn't set carry or half-carry, so it's not just simply the same as calling algorithmAdd. Up to almost 70KB, not even halfway done, don't even have a disassembler started yet. There's a real chance this could overtake the 68K for the biggest CPU core in higan, although at this point I'm still thinking the 68K will end up larger.
This commit is contained in:
parent
41148b1024
commit
95d0020297
|
@ -30,7 +30,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "106.74";
|
||||
static const string Version = "106.75";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org/";
|
||||
|
|
|
@ -21,57 +21,57 @@ template<> auto TLCS900H::parity<uint32>(uint32 data) const -> bool {
|
|||
|
||||
template<typename T> auto TLCS900H::algorithmAdd(T target, T source, uint1 carry) -> T {
|
||||
uint64 result = target + source + carry;
|
||||
setCarry(result.bit(T::bits()));
|
||||
setNegative(0);
|
||||
setOverflow(T(~(target ^ source) & (target ^ result)).negative());
|
||||
setHalfCarry(T(target ^ source ^ result).bit(4));
|
||||
if constexpr(is_same<T, uint32>::value) setHalfCarry(Undefined);
|
||||
setZero(T(result).zero());
|
||||
setSign(result.negative());
|
||||
CF = result.bit(T::bits());
|
||||
NF = 0;
|
||||
VF = T(~(target ^ source) & (target ^ result)).negative();
|
||||
HF = T(target ^ source ^ result).bit(4);
|
||||
if constexpr(is_same<T, uint32>::value) HF = Undefined;
|
||||
ZF = T(result).zero();
|
||||
SF = result.negative();
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T> auto TLCS900H::algorithmAnd(T target, T source) -> T {
|
||||
T result = target & source;
|
||||
setCarry(0);
|
||||
setNegative(0);
|
||||
setParity(parity(result));
|
||||
setHalfCarry(1);
|
||||
setZero(result.zero());
|
||||
setSign(result.negative());
|
||||
CF = 0;
|
||||
NF = 0;
|
||||
PF = parity(result);
|
||||
HF = 1;
|
||||
ZF = result.zero();
|
||||
SF = result.negative();
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T> auto TLCS900H::algorithmOr(T target, T source) -> T {
|
||||
T result = target | source;
|
||||
setCarry(0);
|
||||
setNegative(0);
|
||||
setParity(parity(result));
|
||||
setHalfCarry(0);
|
||||
setZero(result.zero());
|
||||
setSign(result.negative());
|
||||
CF = 0;
|
||||
NF = 0;
|
||||
PF = parity(result);
|
||||
HF = 0;
|
||||
ZF = result.zero();
|
||||
SF = result.negative();
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T> auto TLCS900H::algorithmSubtract(T target, T source, uint1 carry) -> T {
|
||||
uint64 result = target - source - carry;
|
||||
setCarry(result.bit(T::bits()));
|
||||
setNegative(1);
|
||||
setOverflow(T((target ^ source) & (target ^ result)).negative());
|
||||
setHalfCarry(T(target ^ source ^ result).bit(4));
|
||||
if constexpr(is_same<T, uint32>::value) setHalfCarry(Undefined);
|
||||
setZero(T(result).zero());
|
||||
setSign(result.negative());
|
||||
CF = result.bit(T::bits());
|
||||
NF = 1;
|
||||
VF = T((target ^ source) & (target ^ result)).negative();
|
||||
HF = T(target ^ source ^ result).bit(4);
|
||||
if constexpr(is_same<T, uint32>::value) HF = Undefined;
|
||||
ZF = T(result).zero();
|
||||
SF = result.negative();
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T> auto TLCS900H::algorithmXor(T target, T source) -> T {
|
||||
T result = target ^ source;
|
||||
setCarry(0);
|
||||
setNegative(0);
|
||||
setParity(parity(result));
|
||||
setHalfCarry(0);
|
||||
setZero(result.zero());
|
||||
setSign(result.negative());
|
||||
CF = 0;
|
||||
NF = 0;
|
||||
PF = parity(result);
|
||||
HF = 0;
|
||||
ZF = result.zero();
|
||||
SF = result.negative();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
auto TLCS900H::condition(uint4 code) -> bool {
|
||||
switch(code) {
|
||||
case 0: return 0 == 1; //F (false)
|
||||
case 1: return (sign() ^ overflow()) == 1; //LT (signed less than)
|
||||
case 2: return (zero() | (sign() ^ overflow())) == 1; //LE (signed less than or equal)
|
||||
case 3: return (carry() | zero()) == 1; //ULE (unsigned less than or equal)
|
||||
case 4: return overflow() == 1; //OV (overflow)
|
||||
case 5: return sign() == 1; //MI (minus)
|
||||
case 6: return zero() == 1; //EQ (equal)
|
||||
case 7: return carry() == 1; //ULT (unsigned less than)
|
||||
case 8: return 0 == 0; //T (true)
|
||||
case 9: return (sign() ^ overflow()) == 0; //GE (signed greater than or equal)
|
||||
case 10: return (zero() | (sign() ^ overflow())) == 0; //GT (signed greater than)
|
||||
case 11: return (carry() | zero()) == 0; //UGT (unsigned greater than)
|
||||
case 12: return overflow() == 0; //NOV (no overflow)
|
||||
case 13: return sign() == 0; //PL (plus)
|
||||
case 14: return zero() == 0; //NE (not equal)
|
||||
case 15: return carry() == 0; //UGE (unsigned greater than or equal)
|
||||
case 0: return 0 == 1; //F (false)
|
||||
case 1: return (SF ^ VF) == 1; //LT (signed less than)
|
||||
case 2: return (ZF | (SF ^ VF)) == 1; //LE (signed less than or equal)
|
||||
case 3: return (CF | ZF) == 1; //ULE (unsigned less than or equal)
|
||||
case 4: return VF == 1; //OV (overflow)
|
||||
case 5: return SF == 1; //MI (minus)
|
||||
case 6: return ZF == 1; //EQ (equal)
|
||||
case 7: return CF == 1; //ULT (unsigned less than)
|
||||
case 8: return 0 == 0; //T (true)
|
||||
case 9: return (SF ^ VF) == 0; //GE (signed greater than or equal)
|
||||
case 10: return (ZF | (SF ^ VF)) == 0; //GT (signed greater than)
|
||||
case 11: return (CF | ZF) == 0; //UGT (unsigned greater than)
|
||||
case 12: return VF == 0; //NOV (no overflow)
|
||||
case 13: return SF == 0; //PL (plus)
|
||||
case 14: return ZF == 0; //NE (not equal)
|
||||
case 15: return CF == 0; //UGE (unsigned greater than or equal)
|
||||
} unreachable;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
template<> auto TLCS900H::map(ControlRegister<uint8> register) -> maybe<uint8&> {
|
||||
switch(register.id) {
|
||||
#define r(id, name) case id: return r.name;
|
||||
r(0x00, dmas[0].b.b0) r(0x01, dmas[0].b.b1) r(0x02, dmas[0].b.b2) r(0x03, dmas[0].b.b3)
|
||||
r(0x04, dmas[1].b.b0) r(0x05, dmas[1].b.b1) r(0x06, dmas[1].b.b2) r(0x07, dmas[1].b.b3)
|
||||
r(0x08, dmas[2].b.b0) r(0x09, dmas[2].b.b1) r(0x0a, dmas[2].b.b2) r(0x0b, dmas[2].b.b3)
|
||||
r(0x0c, dmas[3].b.b0) r(0x0d, dmas[3].b.b1) r(0x0e, dmas[3].b.b2) r(0x0f, dmas[3].b.b3)
|
||||
r(0x10, dmad[0].b.b0) r(0x11, dmad[0].b.b1) r(0x12, dmad[0].b.b2) r(0x13, dmad[0].b.b3)
|
||||
r(0x14, dmad[1].b.b0) r(0x15, dmad[1].b.b1) r(0x16, dmad[1].b.b2) r(0x17, dmad[1].b.b3)
|
||||
r(0x18, dmad[2].b.b0) r(0x19, dmad[2].b.b1) r(0x1a, dmad[2].b.b2) r(0x1b, dmad[2].b.b3)
|
||||
r(0x1c, dmad[3].b.b0) r(0x1d, dmad[3].b.b1) r(0x1e, dmad[3].b.b2) r(0x1f, dmad[3].b.b3)
|
||||
r(0x20, dmam[0].b.b0) r(0x21, dmam[0].b.b1) r(0x22, dmam[0].b.b2) r(0x23, dmam[0].b.b3)
|
||||
r(0x24, dmam[1].b.b0) r(0x25, dmam[1].b.b1) r(0x26, dmam[1].b.b2) r(0x27, dmam[1].b.b3)
|
||||
r(0x28, dmam[2].b.b0) r(0x29, dmam[2].b.b1) r(0x2a, dmam[2].b.b2) r(0x2b, dmam[2].b.b3)
|
||||
r(0x2c, dmam[3].b.b0) r(0x2d, dmam[3].b.b1) r(0x2e, dmam[3].b.b3) r(0x2f, dmam[3].b.b3)
|
||||
r(0x3c, intnest.b.b0) r(0x3d, intnest.b.b1)
|
||||
#undef r
|
||||
}
|
||||
return nothing;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::map(ControlRegister<uint16> register) -> maybe<uint16&> {
|
||||
switch(register.id & ~1) {
|
||||
#define r(id, name) case id: return r.name;
|
||||
r(0x00, dmas[0].w.w0) r(0x02, dmas[0].w.w1)
|
||||
r(0x04, dmas[1].w.w0) r(0x06, dmas[1].w.w1)
|
||||
r(0x08, dmas[2].w.w0) r(0x0a, dmas[2].w.w1)
|
||||
r(0x0c, dmas[3].w.w0) r(0x0e, dmas[3].w.w1)
|
||||
r(0x10, dmad[0].w.w0) r(0x12, dmad[0].w.w1)
|
||||
r(0x14, dmad[1].w.w0) r(0x16, dmad[1].w.w1)
|
||||
r(0x18, dmad[2].w.w0) r(0x1a, dmad[2].w.w1)
|
||||
r(0x1c, dmad[3].w.w0) r(0x1e, dmad[3].w.w1)
|
||||
r(0x20, dmam[0].w.w0) r(0x22, dmam[0].w.w1)
|
||||
r(0x24, dmam[1].w.w0) r(0x26, dmam[1].w.w1)
|
||||
r(0x28, dmam[2].w.w0) r(0x2a, dmam[2].w.w1)
|
||||
r(0x2c, dmam[3].w.w0) r(0x2e, dmam[3].w.w1)
|
||||
r(0x3c, intnest.w.w0)
|
||||
#undef r
|
||||
}
|
||||
return nothing;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::map(ControlRegister<uint32> register) -> maybe<uint32&> {
|
||||
switch(register.id & ~1) {
|
||||
#define r(id, name) case id: return r.name;
|
||||
r(0x00, dmas[0].l.l0)
|
||||
r(0x04, dmas[1].l.l0)
|
||||
r(0x08, dmas[2].l.l0)
|
||||
r(0x0c, dmas[3].l.l0)
|
||||
r(0x10, dmad[0].l.l0)
|
||||
r(0x14, dmad[1].l.l0)
|
||||
r(0x18, dmad[2].l.l0)
|
||||
r(0x1c, dmad[3].l.l0)
|
||||
r(0x20, dmam[0].l.l0)
|
||||
r(0x24, dmam[1].l.l0)
|
||||
r(0x28, dmam[2].l.l0)
|
||||
r(0x2c, dmam[3].l.l0)
|
||||
r(0x3c, intnest.l.l0)
|
||||
#undef r
|
||||
}
|
||||
return nothing;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::load< uint8>(ControlRegister< uint8> register) -> uint8 { return map(register)(Undefined); }
|
||||
template<> auto TLCS900H::load<uint16>(ControlRegister<uint16> register) -> uint16 { return map(register)(Undefined); }
|
||||
template<> auto TLCS900H::load<uint32>(ControlRegister<uint32> register) -> uint32 { return map(register)(Undefined); }
|
||||
|
||||
template<> auto TLCS900H::store<uint8>(ControlRegister<uint8> register, uint32 data) -> void {
|
||||
if(auto r = map(register)) r() = data;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::store<uint16>(ControlRegister<uint16> register, uint32 data) -> void {
|
||||
if(auto r = map(register)) r() = data;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::store<uint32>(ControlRegister<uint32> register, uint32 data) -> void {
|
||||
//INTNEST is 16-bit: this isn't the nicest way to handle this, but ...
|
||||
if((register.id & ~3) == 0x3c) data = (uint16)data;
|
||||
if(auto r = map(register)) r() = data;
|
||||
}
|
|
@ -1,18 +1,27 @@
|
|||
template<> auto TLCS900H::registers< uint8>(uint3 code) const -> Register< uint8> {
|
||||
template<> auto TLCS900H::toRegister3<uint8>(uint3 code) const -> Register<uint8> {
|
||||
static const Register< uint8> lookup[] = {W, A, B, C, D, E, H, L};
|
||||
return lookup[code];
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::registers<uint16>(uint3 code) const -> Register<uint16> {
|
||||
template<> auto TLCS900H::toRegister3<uint16>(uint3 code) const -> Register<uint16> {
|
||||
static const Register<uint16> lookup[] = {WA, BC, DE, HL, IX, IY, IZ, SP};
|
||||
return lookup[code];
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::registers<uint32>(uint3 code) const -> Register<uint32> {
|
||||
template<> auto TLCS900H::toRegister3<uint32>(uint3 code) const -> Register<uint32> {
|
||||
static const Register<uint32> lookup[] = {XWA, XBC, XDE, XHL, XIX, XIY, XIZ, XSP};
|
||||
return lookup[code];
|
||||
}
|
||||
|
||||
template<typename T> auto TLCS900H::toRegister8(uint8 code) const -> Register<T> { return {code}; }
|
||||
template<typename T> auto TLCS900H::toControlRegister(uint8 code) const -> ControlRegister<T> { return {code}; }
|
||||
template<typename T> auto TLCS900H::toMemory(uint32 address) const -> Memory<T> { return {address}; }
|
||||
template<typename T> auto TLCS900H::toImmediate(uint32 constant) const -> Immediate<T> { return {constant}; }
|
||||
template<typename T> auto TLCS900H::toImmediate3(uint3 constant) const -> Immediate<T> { return {constant ? (uint)constant : 8u}; }
|
||||
|
||||
//note: much of this code is split to multiple statements due to C++ not guaranteeing
|
||||
//the order of evaluations of function arguments. fetch() ordering is critical.
|
||||
|
||||
auto TLCS900H::instruction() -> void {
|
||||
auto data = fetch();
|
||||
|
||||
|
@ -23,197 +32,211 @@ auto TLCS900H::instruction() -> void {
|
|||
case 0x03: return instructionPop(SR);
|
||||
case 0x04: return (void)Undefined;
|
||||
case 0x05: return instructionHalt();
|
||||
case 0x06: return instructionSetInterruptFlags((uint3)fetch());
|
||||
case 0x06: return instructionSetInterruptFlipFlop((uint3)fetch());
|
||||
case 0x07: return instructionReturnInterrupt();
|
||||
case 0x09: return instructionPush(Immediate< uint8>{fetch< uint8>()});
|
||||
case 0x0b: return instructionPush(Immediate<uint16>{fetch<uint16>()});
|
||||
case 0x12: return instructionComplementCarry();
|
||||
case 0x08: {
|
||||
auto memory = fetchMemory<uint8, uint8>();
|
||||
return instructionLoad(memory, fetchImmediate<uint16>()); }
|
||||
case 0x09: return instructionPush(fetchImmediate<uint8>());
|
||||
case 0x0a: {
|
||||
auto memory = fetchMemory<uint16, uint8>();
|
||||
return instructionLoad(memory, fetchImmediate<uint16>()); }
|
||||
case 0x0b: return instructionPush(fetchImmediate<uint16>());
|
||||
case 0x0c: return instructionSetRegisterFilePointer(RFP + 1);
|
||||
case 0x0d: return instructionSetRegisterFilePointer(RFP - 1);
|
||||
case 0x0e: return instructionReturn(True);
|
||||
case 0x0f: return instructionReturnDeallocate(fetchImmediate<int16>());
|
||||
case 0x10: return instructionSetFlag(CF, 0);
|
||||
case 0x11: return instructionSetFlag(CF, 1);
|
||||
case 0x12: return instructionSetFlag(CF, !CF);
|
||||
case 0x13: return instructionSetFlag(CF, ZF);
|
||||
case 0x14: return instructionPush(A);
|
||||
case 0x15: return instructionPop(A);
|
||||
case 0x16: return instructionExchange(F, FP);
|
||||
case 0x17: return instructionSetRegisterFilePointer((uint2)fetch());
|
||||
case 0x18: return instructionPush(F);
|
||||
case 0x19: return instructionPop(F);
|
||||
case 0x1a: return instructionJump(True, Immediate<uint16>{fetch<uint16>()});
|
||||
case 0x1b: return instructionJump(True, Immediate<uint24>{fetch<uint24>()});
|
||||
case 0x1c: return instructionCall(True, Immediate<uint16>{fetch<uint16>()});
|
||||
case 0x1d: return instructionCall(True, Immediate<uint24>{fetch<uint24>()});
|
||||
case 0x1a: return instructionJump(True, fetchImmediate<uint16>());
|
||||
case 0x1b: return instructionJump(True, fetchImmediate<uint24>());
|
||||
case 0x1c: return instructionCall(True, fetchImmediate<uint16>());
|
||||
case 0x1d: return instructionCall(True, fetchImmediate<uint24>());
|
||||
case 0x1e: return instructionCallRelative(fetchImmediate<int16>());
|
||||
case 0x1f: return (void)Undefined;
|
||||
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
|
||||
return instructionLoad(registers<uint8>(data), Immediate<uint8>{fetch<uint8>()});
|
||||
return instructionLoad(toRegister3<uint8>(data), fetchImmediate<uint8>());
|
||||
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
|
||||
return instructionPush(registers<uint16>(data));
|
||||
return instructionPush(toRegister3<uint16>(data));
|
||||
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
|
||||
return instructionLoad(registers<uint16>(data), Immediate<uint16>{fetch<uint16>()});
|
||||
return instructionLoad(toRegister3<uint16>(data), fetchImmediate<uint16>());
|
||||
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
|
||||
return instructionPush(registers<uint32>(data));
|
||||
return instructionPush(toRegister3<uint32>(data));
|
||||
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
|
||||
return instructionLoad(registers<uint32>(data), Immediate<uint32>{fetch<uint32>()});
|
||||
return instructionLoad(toRegister3<uint32>(data), fetchImmediate<uint32>());
|
||||
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
||||
return instructionPop(registers<uint16>(data));
|
||||
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
|
||||
return (void)Undefined;
|
||||
return instructionPop(toRegister3<uint16>(data));
|
||||
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: return (void)Undefined;
|
||||
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
|
||||
return instructionPop(registers<uint32>(data));
|
||||
return instructionPop(toRegister3<uint32>(data));
|
||||
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
|
||||
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
|
||||
return instructionJumpRelative((uint4)data, Immediate<int8>{fetch<int8>()});
|
||||
return instructionJumpRelative((uint4)data, fetchImmediate<int8>());
|
||||
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
|
||||
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
|
||||
return instructionJumpRelative((uint4)data, Immediate<int16>{fetch<int16>()});
|
||||
return instructionJumpRelative((uint4)data, fetchImmediate<int16>());
|
||||
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
|
||||
return instructionSourceMemory(Memory<uint8>{load(registers<uint32>(data))});
|
||||
return instructionSourceMemory(toMemory<uint8>(load(toRegister3<uint32>(data))));
|
||||
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
|
||||
return instructionSourceMemory(Memory<uint8>{load(registers<uint32>(data)) + fetch<int8>()});
|
||||
return instructionSourceMemory(toMemory<uint8>(load(toRegister3<uint32>(data)) + fetch<int8>()));
|
||||
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
|
||||
return instructionSourceMemory(Memory<uint16>{load(registers<uint32>(data))});
|
||||
return instructionSourceMemory(toMemory<uint16>(load(toRegister3<uint32>(data))));
|
||||
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
|
||||
return instructionSourceMemory(Memory<uint16>{load(registers<uint32>(data)) + fetch<int8>()});
|
||||
return instructionSourceMemory(toMemory<uint16>(load(toRegister3<uint32>(data)) + fetch<int8>()));
|
||||
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
|
||||
return instructionSourceMemory(Memory<uint32>{load(registers<uint32>(data))});
|
||||
return instructionSourceMemory(toMemory<uint32>(load(toRegister3<uint32>(data))));
|
||||
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
|
||||
return instructionSourceMemory(Memory<uint32>{load(registers<uint32>(data)) + fetch<int8>()});
|
||||
return instructionSourceMemory(toMemory<uint32>(load(toRegister3<uint32>(data)) + fetch<int8>()));
|
||||
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
|
||||
return instructionTargetMemory(load(registers<uint32>(data)));
|
||||
return instructionTargetMemory(load(toRegister3<uint32>(data)));
|
||||
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
|
||||
return instructionTargetMemory(load(registers<uint32>(data)) + fetch<int8>());
|
||||
case 0xc0: return instructionSourceMemory(Memory<uint8>{fetch< uint8>()});
|
||||
case 0xc1: return instructionSourceMemory(Memory<uint8>{fetch<uint16>()});
|
||||
case 0xc2: return instructionSourceMemory(Memory<uint8>{fetch<uint24>()});
|
||||
return instructionTargetMemory(load(toRegister3<uint32>(data)) + fetch<int8>());
|
||||
case 0xc0: return instructionSourceMemory(fetchMemory<uint8, uint8>());
|
||||
case 0xc1: return instructionSourceMemory(fetchMemory<uint8, uint16>());
|
||||
case 0xc2: return instructionSourceMemory(fetchMemory<uint8, uint24>());
|
||||
case 0xc3: {
|
||||
data = fetch();
|
||||
if((data & 3) == 0) return instructionSourceMemory(Memory<uint8>{load(Register<uint32>{data})});
|
||||
if((data & 3) == 1) return instructionSourceMemory(Memory<uint8>{load(Register<uint32>{data}) + fetch<int16>()});
|
||||
if((data & 3) == 0) return instructionSourceMemory(toMemory<uint8>(load(toRegister8<uint32>(data))));
|
||||
if((data & 3) == 1) return instructionSourceMemory(toMemory<uint8>(load(toRegister8<uint32>(data)) + fetch<int16>()));
|
||||
if(data == 0x03) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r8 = load(Register< uint8>{fetch()});
|
||||
auto r32 = load(fetchRegister<uint32>());
|
||||
auto r8 = load(fetchRegister< uint8>());
|
||||
return instructionSourceMemory(Memory<uint8>{r32 + (int8)r8});
|
||||
}
|
||||
if(data == 0x07) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r16 = load(Register<uint16>{fetch()});
|
||||
auto r32 = load(fetchRegister<uint32>());
|
||||
auto r16 = load(fetchRegister<uint16>());
|
||||
return instructionSourceMemory(Memory<uint8>{r32 + (int16)r16});
|
||||
}
|
||||
return (void)Undefined; }
|
||||
case 0xc4: {
|
||||
data = fetch();
|
||||
auto register = Register<uint32>{data};
|
||||
auto register = toRegister8<uint32>(data);
|
||||
if((data & 3) == 0) store(register, load(register) - 1);
|
||||
if((data & 3) == 1) store(register, load(register) - 2);
|
||||
if((data & 3) == 2) store(register, load(register) - 4);
|
||||
if((data & 3) == 3) Undefined;
|
||||
return instructionSourceMemory(Memory<uint8>{load(register)}); }
|
||||
return instructionSourceMemory(toMemory<uint8>(load(register))); }
|
||||
case 0xc5: {
|
||||
data = fetch();
|
||||
auto register = Register<uint32>{data};
|
||||
instructionSourceMemory(Memory<uint8>{load(register)});
|
||||
auto register = toRegister8<uint32>(data);
|
||||
instructionSourceMemory(toMemory<uint8>(load(register)));
|
||||
if((data & 3) == 0) store(register, load(register) + 1);
|
||||
if((data & 3) == 1) store(register, load(register) + 2);
|
||||
if((data & 3) == 2) store(register, load(register) + 4);
|
||||
if((data & 3) == 3) Undefined;
|
||||
return; }
|
||||
case 0xc6: return (void)Undefined;
|
||||
case 0xc7: return instructionRegister(Register<uint8>{fetch()});
|
||||
case 0xc7: return instructionRegister(fetchRegister<uint8>());
|
||||
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
|
||||
return instructionRegister(registers<uint8>(data));
|
||||
case 0xd0: return instructionSourceMemory(Memory<uint16>{fetch< uint8>()});
|
||||
case 0xd1: return instructionSourceMemory(Memory<uint16>{fetch<uint16>()});
|
||||
case 0xd2: return instructionSourceMemory(Memory<uint16>{fetch<uint24>()});
|
||||
return instructionRegister(toRegister3<uint8>(data));
|
||||
case 0xd0: return instructionSourceMemory(fetchMemory<uint16, uint8>());
|
||||
case 0xd1: return instructionSourceMemory(fetchMemory<uint16, uint16>());
|
||||
case 0xd2: return instructionSourceMemory(fetchMemory<uint16, uint24>());
|
||||
case 0xd3: {
|
||||
data = fetch();
|
||||
if((data & 3) == 0) return instructionSourceMemory(Memory<uint16>{load(Register<uint32>{data})});
|
||||
if((data & 3) == 1) return instructionSourceMemory(Memory<uint16>{load(Register<uint32>{data}) + fetch<int16>()});
|
||||
if((data & 3) == 0) return instructionSourceMemory(toMemory<uint16>(load(toRegister8<uint32>(data))));
|
||||
if((data & 3) == 1) return instructionSourceMemory(toMemory<uint16>(load(toRegister8<uint32>(data)) + fetch<int16>()));
|
||||
if(data == 0x03) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r8 = load(Register< uint8>{fetch()});
|
||||
return instructionSourceMemory(Memory<uint16>{r32 + (int8)r8});
|
||||
auto r32 = load(fetchRegister<uint32>());
|
||||
auto r8 = load(fetchRegister< uint8>());
|
||||
return instructionSourceMemory(toMemory<uint16>(r32 + (int8)r8));
|
||||
}
|
||||
if(data == 0x07) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r16 = load(Register<uint16>{fetch()});
|
||||
return instructionSourceMemory(Memory<uint16>{r32 + (int16)r16});
|
||||
auto r32 = load(fetchRegister<uint32>());
|
||||
auto r16 = load(fetchRegister<uint16>());
|
||||
return instructionSourceMemory(toMemory<uint16>(r32 + (int16)r16));
|
||||
}
|
||||
return (void)Undefined; }
|
||||
case 0xd4: {
|
||||
data = fetch();
|
||||
auto register = Register<uint32>{data};
|
||||
auto register = toRegister8<uint32>(data);
|
||||
if((data & 3) == 0) store(register, load(register) - 1);
|
||||
if((data & 3) == 1) store(register, load(register) - 2);
|
||||
if((data & 3) == 2) store(register, load(register) - 4);
|
||||
if((data & 3) == 3) Undefined;
|
||||
return instructionSourceMemory(Memory<uint16>{load(register)}); }
|
||||
return instructionSourceMemory(toMemory<uint16>(load(register))); }
|
||||
case 0xd5: {
|
||||
data = fetch();
|
||||
auto register = Register<uint32>{data};
|
||||
instructionSourceMemory(Memory<uint16>{load(register)});
|
||||
auto register = toRegister8<uint32>(data);
|
||||
instructionSourceMemory(toMemory<uint16>(load(register)));
|
||||
if((data & 3) == 0) store(register, load(register) + 1);
|
||||
if((data & 3) == 1) store(register, load(register) + 2);
|
||||
if((data & 3) == 2) store(register, load(register) + 4);
|
||||
if((data & 3) == 3) Undefined;
|
||||
return; }
|
||||
case 0xd6: return (void)Undefined;
|
||||
case 0xd7: return instructionRegister(Register<uint16>{fetch()});
|
||||
case 0xd7: return instructionRegister(fetchRegister<uint16>());
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
return instructionRegister(registers<uint16>(data));
|
||||
case 0xe0: return instructionSourceMemory(Memory<uint32>{fetch<uint8>()});
|
||||
case 0xe1: return instructionSourceMemory(Memory<uint32>{fetch<uint16>()});
|
||||
case 0xe2: return instructionSourceMemory(Memory<uint32>{fetch<uint24>()});
|
||||
return instructionRegister(toRegister3<uint16>(data));
|
||||
case 0xe0: return instructionSourceMemory(fetchMemory<uint32, uint8>());
|
||||
case 0xe1: return instructionSourceMemory(fetchMemory<uint32, uint16>());
|
||||
case 0xe2: return instructionSourceMemory(fetchMemory<uint32, uint24>());
|
||||
case 0xe3: {
|
||||
data = fetch();
|
||||
if((data & 3) == 0) return instructionSourceMemory(Memory<uint32>{load(Register<uint32>{data})});
|
||||
if((data & 3) == 1) return instructionSourceMemory(Memory<uint32>{load(Register<uint32>{data}) + fetch<int16>()});
|
||||
if((data & 3) == 0) return instructionSourceMemory(toMemory<uint32>(load(toRegister8<uint32>(data))));
|
||||
if((data & 3) == 1) return instructionSourceMemory(toMemory<uint32>(load(toRegister8<uint32>(data)) + fetch<int16>()));
|
||||
if(data == 0x03) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r8 = load(Register< uint8>{fetch()});
|
||||
return instructionSourceMemory(Memory<uint32>{r32 + (int8)r8});
|
||||
auto r32 = load(fetchRegister<uint32>());
|
||||
auto r8 = load(fetchRegister< uint8>());
|
||||
return instructionSourceMemory(toMemory<uint32>(r32 + (int8)r8));
|
||||
}
|
||||
if(data == 0x07) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r16 = load(Register< uint8>{fetch()});
|
||||
return instructionSourceMemory(Memory<uint32>{r32 + (int16)r16});
|
||||
auto r32 = load(fetchRegister<uint32>());
|
||||
auto r16 = load(fetchRegister<uint16>());
|
||||
return instructionSourceMemory(toMemory<uint32>(r32 + (int16)r16));
|
||||
}
|
||||
return (void)Undefined; }
|
||||
case 0xe4: {
|
||||
data = fetch();
|
||||
auto register = Register<uint32>{data};
|
||||
auto register = toRegister8<uint32>(data);
|
||||
if((data & 3) == 0) store(register, load(register) - 1);
|
||||
if((data & 3) == 1) store(register, load(register) - 2);
|
||||
if((data & 3) == 2) store(register, load(register) - 4);
|
||||
if((data & 3) == 3) Undefined;
|
||||
return instructionSourceMemory(Memory<uint32>{load(register)}); }
|
||||
return instructionSourceMemory(toMemory<uint32>(load(register))); }
|
||||
case 0xe5: {
|
||||
data = fetch();
|
||||
auto register = Register<uint32>{data};
|
||||
instructionSourceMemory(Memory<uint32>{load(register)});
|
||||
auto register = toRegister8<uint32>(data);
|
||||
instructionSourceMemory(toMemory<uint32>(load(register)));
|
||||
if((data & 3) == 0) store(register, load(register) + 1);
|
||||
if((data & 3) == 1) store(register, load(register) + 2);
|
||||
if((data & 3) == 2) store(register, load(register) + 4);
|
||||
if((data & 3) == 3) Undefined;
|
||||
return; }
|
||||
case 0xe6: return (void)Undefined;
|
||||
case 0xe7: return instructionRegister(Register<uint32>{fetch()});
|
||||
case 0xe7: return instructionRegister(fetchRegister<uint32>());
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
|
||||
return instructionRegister(registers<uint32>(data));
|
||||
case 0xf0: return instructionTargetMemory(fetch<uint8>());
|
||||
return instructionRegister(toRegister3<uint32>(data));
|
||||
case 0xf0: return instructionTargetMemory(fetch< uint8>());
|
||||
case 0xf1: return instructionTargetMemory(fetch<uint16>());
|
||||
case 0xf2: return instructionTargetMemory(fetch<uint24>());
|
||||
case 0xf3: {
|
||||
data = fetch();
|
||||
if((data & 3) == 0) return instructionTargetMemory(load(Register<uint32>{data}));
|
||||
if((data & 3) == 1) return instructionTargetMemory(load(Register<uint32>{data}) + fetch<int16>());
|
||||
if((data & 3) == 0) return instructionTargetMemory(load(toRegister8<uint32>(data)));
|
||||
if((data & 3) == 1) return instructionTargetMemory(load(toRegister8<uint32>(data)) + fetch<int16>());
|
||||
if(data == 0x03) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r8 = load(Register< uint8>{fetch()});
|
||||
auto r32 = load(fetchRegister<uint32>());
|
||||
auto r8 = load(fetchRegister< uint8>());
|
||||
return instructionTargetMemory(r32 + (int8)r8);
|
||||
}
|
||||
if(data == 0x07) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r16 = load(Register<uint16>{fetch()});
|
||||
auto r32 = load(fetchRegister<uint32>());
|
||||
auto r16 = load(fetchRegister<uint16>());
|
||||
return instructionTargetMemory(r32 + (int16)r16);
|
||||
}
|
||||
return (void)Undefined; }
|
||||
case 0xf4: {
|
||||
data = fetch();
|
||||
auto register = Register<uint32>{data};
|
||||
auto register = toRegister8<uint32>(data);
|
||||
if((data & 3) == 0) store(register, load(register) - 1);
|
||||
if((data & 3) == 1) store(register, load(register) - 2);
|
||||
if((data & 3) == 2) store(register, load(register) - 4);
|
||||
|
@ -221,14 +244,21 @@ auto TLCS900H::instruction() -> void {
|
|||
return instructionTargetMemory(load(register)); }
|
||||
case 0xf5: {
|
||||
data = fetch();
|
||||
auto register = Register<uint32>{data};
|
||||
auto register = toRegister8<uint32>(data);
|
||||
instructionTargetMemory(load(register));
|
||||
if((data & 3) == 0) store(register, load(register) + 1);
|
||||
if((data & 3) == 1) store(register, load(register) + 2);
|
||||
if((data & 3) == 2) store(register, load(register) + 4);
|
||||
if((data & 3) == 3) Undefined;
|
||||
return; }
|
||||
case 0xf6: case 0xf7: return (void)Undefined;
|
||||
case 0xf6: return (void)Undefined;
|
||||
case 0xf7: {
|
||||
if(fetch()) Undefined;
|
||||
auto memory = fetchMemory<uint8, uint8>();
|
||||
if(fetch()) Undefined;
|
||||
auto immediate = fetchImmediate<uint8>();
|
||||
if(fetch()) Undefined;
|
||||
return instructionLoad(memory, immediate); }
|
||||
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
|
||||
return instructionSoftwareInterrupt((uint3)data);
|
||||
}
|
||||
|
@ -236,132 +266,206 @@ auto TLCS900H::instruction() -> void {
|
|||
|
||||
template<typename R>
|
||||
auto TLCS900H::instructionRegister(R register) -> void {
|
||||
using type = typename R::type;
|
||||
using T = typename R::type;
|
||||
enum : uint { bits = R::bits };
|
||||
auto data = fetch();
|
||||
|
||||
switch(data) {
|
||||
case 0x00: case 0x01: case 0x02: return (void)Undefined;
|
||||
case 0x03: return instructionLoad(register, fetchImmediate<T>());
|
||||
case 0x04: return instructionPush(register);
|
||||
case 0x05: return instructionPop(register);
|
||||
case 0x06:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionComplement(register);
|
||||
case 0x07:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionNegate(register);
|
||||
case 0x08:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionMultiply(register, fetchImmediate<T>());
|
||||
case 0x09:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionMultiplySigned(register, fetchImmediate<T>());
|
||||
case 0x0a:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionDivide(register, fetchImmediate<T>());
|
||||
case 0x0b:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionDivideSigned(register, fetchImmediate<T>());
|
||||
case 0x11: return (void)Undefined;
|
||||
case 0x15: return (void)Undefined;
|
||||
case 0x16:
|
||||
if constexpr(bits == 16) return instructionMirror(register);
|
||||
return (void)Undefined;
|
||||
case 0x17: case 0x18: return (void)Undefined;
|
||||
case 0x19:
|
||||
if constexpr(bits == 16) return instructionMultiplyAdd(register);
|
||||
return (void)Undefined;
|
||||
case 0x1a: case 0x1b: return (void)Undefined;
|
||||
case 0x1d: case 0x1e: case 0x1f: return (void)Undefined;
|
||||
case 0x25: case 0x26: case 0x27: return (void)Undefined;
|
||||
case 0x2d: return (void)Undefined;
|
||||
case 0x2e: return instructionLoad(toControlRegister<T>(data), register);
|
||||
case 0x2f: return instructionLoad(register, toControlRegister<T>(data));
|
||||
case 0x35: case 0x36: case 0x37: return (void)Undefined;
|
||||
case 0x3b: return (void)Undefined;
|
||||
case 0x3f: return (void)Undefined;
|
||||
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionMultiply(toRegister3<T>(data), register);
|
||||
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionMultiplySigned(toRegister3<T>(data), register);
|
||||
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionDivide(toRegister3<T>(data), register);
|
||||
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionDivideSigned(toRegister3<T>(data), register);
|
||||
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
|
||||
return instructionAdd(register, toImmediate3<T>(data));
|
||||
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
|
||||
return instructionSubtract(register, toImmediate3<T>(data));
|
||||
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
|
||||
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
|
||||
if constexpr(R::bits == 32) return (void)Undefined;
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionSetConditionCode((uint4)data, register);
|
||||
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
|
||||
return instructionAdd(registers<type>(data), register);
|
||||
return instructionAdd(toRegister3<T>(data), register);
|
||||
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
|
||||
return instructionLoad(registers<type>(data), register);
|
||||
return instructionLoad(toRegister3<T>(data), register);
|
||||
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
|
||||
return instructionAddCarry(registers<type>(data), register);
|
||||
return instructionAddCarry(toRegister3<T>(data), register);
|
||||
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
|
||||
return instructionLoad(register, registers<type>(data));
|
||||
return instructionLoad(register, toRegister3<T>(data));
|
||||
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
|
||||
return instructionSubtract(registers<type>(data), register);
|
||||
return instructionSubtract(toRegister3<T>(data), register);
|
||||
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
|
||||
return instructionLoad(register, Immediate<type>{(uint3)data});
|
||||
return instructionLoad(register, toImmediate<T>((uint3)data));
|
||||
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
|
||||
return instructionSubtractCarry(registers<type>(data), register);
|
||||
return instructionSubtractCarry(toRegister3<T>(data), register);
|
||||
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
|
||||
if constexpr(R::bits == 32) return (void)Undefined;
|
||||
return instructionExchange(registers<type>(data), register);
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionExchange(toRegister3<T>(data), register);
|
||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
|
||||
return instructionAnd(registers<type>(data), register);
|
||||
case 0xc8: return instructionAdd(register, Immediate<type>{fetch<type>()});
|
||||
case 0xc9: return instructionAddCarry(register, Immediate<type>{fetch<type>()});
|
||||
case 0xca: return instructionSubtract(register, Immediate<type>{fetch<type>()});
|
||||
case 0xcb: return instructionSubtractCarry(register, Immediate<type>{fetch<type>()});
|
||||
case 0xcc: return instructionAnd(register, Immediate<type>{fetch<type>()});
|
||||
case 0xcd: return instructionXor(register, Immediate<type>{fetch<type>()});
|
||||
case 0xce: return instructionOr(register, Immediate<type>{fetch<type>()});
|
||||
case 0xcf: return instructionCompare(register, Immediate<type>{fetch<type>()});
|
||||
return instructionAnd(toRegister3<T>(data), register);
|
||||
case 0xc8: return instructionAdd(register, fetchImmediate<T>());
|
||||
case 0xc9: return instructionAddCarry(register, fetchImmediate<T>());
|
||||
case 0xca: return instructionSubtract(register, fetchImmediate<T>());
|
||||
case 0xcb: return instructionSubtractCarry(register, fetchImmediate<T>());
|
||||
case 0xcc: return instructionAnd(register, fetchImmediate<T>());
|
||||
case 0xcd: return instructionXor(register, fetchImmediate<T>());
|
||||
case 0xce: return instructionOr(register, fetchImmediate<T>());
|
||||
case 0xcf: return instructionCompare(register, fetchImmediate<T>());
|
||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||
return instructionXor(registers<type>(data), register);
|
||||
return instructionXor(toRegister3<T>(data), register);
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
return instructionCompare(register, Immediate<type>{(uint3)data});
|
||||
return instructionCompare(register, toImmediate<T>((uint3)data));
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
return instructionOr(registers<type>(data), register);
|
||||
return instructionOr(toRegister3<T>(data), register);
|
||||
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
|
||||
return instructionCompare(registers<type>(data), register);
|
||||
return instructionCompare(toRegister3<T>(data), register);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||
using type = typename M::type;
|
||||
using T = typename M::type;
|
||||
enum : uint { bits = M::bits };
|
||||
auto data = fetch();
|
||||
|
||||
switch(data) {
|
||||
case 0x00: case 0x01: case 0x02: case 0x03: return (void)Undefined;
|
||||
case 0x04:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionPush(memory);
|
||||
case 0x05: return (void)Undefined;
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: return (void)Undefined;
|
||||
case 0x18: return (void)Undefined;
|
||||
case 0x19:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
return instructionLoad(Memory<type>{fetch<type>()}, memory);
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionLoad(fetchMemory<T, T>(), memory);
|
||||
case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: return (void)Undefined;
|
||||
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
|
||||
return instructionLoad(registers<type>(data), memory);
|
||||
return instructionLoad(toRegister3<T>(data), memory);
|
||||
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: return (void)Undefined;
|
||||
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
return instructionExchange(memory, registers<type>(data));
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionExchange(memory, toRegister3<T>(data));
|
||||
case 0x38:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
return instructionAdd(memory, Immediate<type>{fetch<type>()});
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionAdd(memory, fetchImmediate<T>());
|
||||
case 0x39:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
return instructionAddCarry(memory, Immediate<type>{fetch<type>()});
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionAddCarry(memory, fetchImmediate<T>());
|
||||
case 0x3a:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
return instructionSubtract(memory, Immediate<type>{fetch<type>()});
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionSubtract(memory, fetchImmediate<T>());
|
||||
case 0x3b:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
return instructionSubtractCarry(memory, Immediate<type>{fetch<type>()});
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionSubtractCarry(memory, fetchImmediate<T>());
|
||||
case 0x3c:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionAnd(memory, fetchImmediate<T>());
|
||||
case 0x3d:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionXor(memory, fetchImmediate<T>());
|
||||
case 0x3e:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionOr(memory, fetchImmediate<T>());
|
||||
case 0x3f:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionCompare(memory, fetchImmediate<T>());
|
||||
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionMultiply(toRegister3<T>(data), memory);
|
||||
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionMultiplySigned(toRegister3<T>(data), memory);
|
||||
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionDivide(toRegister3<T>(data), memory);
|
||||
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
|
||||
if constexpr(bits == 32) return (void)Undefined;
|
||||
return instructionDivideSigned(toRegister3<T>(data), memory);
|
||||
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
|
||||
return instructionAdd(memory, toImmediate3<T>(data));
|
||||
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
|
||||
return instructionSubtract(memory, toImmediate3<T>(data));
|
||||
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: return (void)Undefined;
|
||||
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
|
||||
return instructionAdd(registers<type>(data), memory);
|
||||
return instructionAdd(toRegister3<T>(data), memory);
|
||||
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
|
||||
return instructionAdd(memory, registers<type>(data));
|
||||
return instructionAdd(memory, toRegister3<T>(data));
|
||||
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
|
||||
return instructionAddCarry(registers<type>(data), memory);
|
||||
return instructionAddCarry(toRegister3<T>(data), memory);
|
||||
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
|
||||
return instructionAddCarry(memory, registers<type>(data));
|
||||
return instructionAddCarry(memory, toRegister3<T>(data));
|
||||
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
|
||||
return instructionSubtract(registers<type>(data), memory);
|
||||
return instructionSubtract(toRegister3<T>(data), memory);
|
||||
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
|
||||
return instructionSubtract(memory, registers<type>(data));
|
||||
return instructionSubtract(memory, toRegister3<T>(data));
|
||||
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
|
||||
return instructionSubtractCarry(registers<type>(data), memory);
|
||||
return instructionSubtractCarry(toRegister3<T>(data), memory);
|
||||
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
|
||||
return instructionSubtractCarry(memory, registers<type>(data));
|
||||
return instructionSubtractCarry(memory, toRegister3<T>(data));
|
||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
|
||||
return instructionAnd(registers<type>(data), memory);
|
||||
return instructionAnd(toRegister3<T>(data), memory);
|
||||
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
|
||||
return instructionAnd(memory, registers<type>(data));
|
||||
return instructionAnd(memory, toRegister3<T>(data));
|
||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||
return instructionXor(registers<type>(data), memory);
|
||||
return instructionXor(toRegister3<T>(data), memory);
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
return instructionXor(memory, registers<type>(data));
|
||||
return instructionXor(memory, toRegister3<T>(data));
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
return instructionOr(registers<type>(data), memory);
|
||||
return instructionOr(toRegister3<T>(data), memory);
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
|
||||
return instructionOr(memory, registers<type>(data));
|
||||
return instructionOr(memory, toRegister3<T>(data));
|
||||
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
|
||||
return instructionCompare(registers<type>(data), memory);
|
||||
return instructionCompare(toRegister3<T>(data), memory);
|
||||
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
|
||||
return instructionCompare(memory, registers<type>(data));
|
||||
return instructionCompare(memory, toRegister3<T>(data));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,39 +473,46 @@ auto TLCS900H::instructionTargetMemory(uint32 address) -> void {
|
|||
auto data = fetch();
|
||||
|
||||
switch(data) {
|
||||
case 0x00: return instructionLoad(toMemory<uint8>(address), fetchImmediate<uint8>());
|
||||
case 0x01: return (void)Undefined;
|
||||
case 0x02: return instructionLoad(toMemory<uint16>(address), fetchImmediate<uint16>());
|
||||
case 0x03: return (void)Undefined;
|
||||
case 0x04: return instructionPop(Memory<uint8>{address});
|
||||
case 0x04: return instructionPop(toMemory<uint8>(address));
|
||||
case 0x05: return (void)Undefined;
|
||||
case 0x06: return instructionPop(Memory<uint16>{address});
|
||||
case 0x06: return instructionPop(toMemory<uint16>(address));
|
||||
case 0x07: return (void)Undefined;
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: return (void)Undefined;
|
||||
case 0x10: case 0x11: case 0x12: case 0x13: return (void)Undefined;
|
||||
case 0x14: return instructionLoad(toMemory<uint8>(address), fetchMemory<uint8, uint16>());
|
||||
case 0x15: return (void)Undefined;
|
||||
case 0x16: return instructionLoad(toMemory<uint16>(address), fetchMemory<uint16, uint16>());
|
||||
case 0x17: return (void)Undefined;
|
||||
case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: return (void)Undefined;
|
||||
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
|
||||
return instructionLoad(registers<uint16>(data), Memory<uint16>{address});
|
||||
return instructionLoad(toRegister3<uint16>(data), toMemory<uint16>(address));
|
||||
case 0x2d: case 0x2e: case 0x2f: return (void)Undefined;
|
||||
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
|
||||
return instructionLoad(registers<uint32>(data), Memory<uint32>{address});
|
||||
return instructionLoad(toRegister3<uint32>(data), toMemory<uint32>(address));
|
||||
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: return (void)Undefined;
|
||||
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
|
||||
return instructionLoad(Memory<uint8>{address}, registers<uint8>(data));
|
||||
return instructionLoad(toMemory<uint8>(address), toRegister3<uint8>(data));
|
||||
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: return (void)Undefined;
|
||||
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
|
||||
return instructionLoad(Memory<uint16>{address}, registers<uint16>(data));
|
||||
return instructionLoad(toMemory<uint16>(address), toRegister3<uint16>(data));
|
||||
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: return (void)Undefined;
|
||||
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
|
||||
return instructionLoad(Memory<uint32>{address}, registers<uint32>(data));
|
||||
return instructionLoad(toMemory<uint32>(address), toRegister3<uint32>(data));
|
||||
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: return (void)Undefined;
|
||||
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: return (void)Undefined;
|
||||
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: return (void)Undefined;
|
||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
return instructionJump((uint4)data, Memory<uint32>{address});
|
||||
return instructionJump((uint4)data, toMemory<uint32>(address));
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
|
||||
return instructionCall((uint4)data, Memory<uint32>{address});
|
||||
return instructionCall((uint4)data, toMemory<uint32>(address));
|
||||
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
|
||||
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
|
||||
return instructionReturn((uint4)data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
template<typename Target>
|
||||
auto TLCS900H::toSigned(Target target) -> int32 {
|
||||
if constexpr(Target::bits() == 8) return (int8)target;
|
||||
if constexpr(Target::bits() == 16) return (int16)target;
|
||||
if constexpr(Target::bits() == 32) return (int32)target;
|
||||
return Undefined;
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionAdd(Target target, Source source) -> void {
|
||||
store(target, algorithmAdd(load(target), load(source)));
|
||||
|
@ -5,7 +13,7 @@ auto TLCS900H::instructionAdd(Target target, Source source) -> void {
|
|||
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionAddCarry(Target target, Source source) -> void {
|
||||
store(target, algorithmAdd(load(target), load(source), carry()));
|
||||
store(target, algorithmAdd(load(target), load(source), CF));
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
|
@ -19,13 +27,34 @@ auto TLCS900H::instructionCall(uint4 code, Source source) -> void {
|
|||
if(condition(code)) push(PC), store(PC, address);
|
||||
}
|
||||
|
||||
template<typename Source>
|
||||
auto TLCS900H::instructionCallRelative(Source displacement) -> void {
|
||||
push(PC);
|
||||
store(PC, load(PC) + load(displacement));
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionCompare(Target target, Source source) -> void {
|
||||
algorithmSubtract(load(target), load(source));
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionComplementCarry() -> void {
|
||||
setCarry(!carry());
|
||||
template<typename Target>
|
||||
auto TLCS900H::instructionComplement(Target target) -> void {
|
||||
store(target, ~load(target));
|
||||
NF = 1;
|
||||
HF = 1;
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionDivide(Target target, Source source) -> void {
|
||||
//TODO: division by zero
|
||||
store(expand(target), load(target) / load(source));
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionDivideSigned(Target target, Source source) -> void {
|
||||
//TODO: division by zero
|
||||
store(expand(target), toSigned(load(target)) / toSigned(load(source)));
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
|
@ -55,6 +84,44 @@ auto TLCS900H::instructionLoad(Target target, Source source) -> void {
|
|||
store(target, load(source));
|
||||
}
|
||||
|
||||
//reverse all bits in a 16-bit register
|
||||
auto TLCS900H::instructionMirror(Register<uint16> register) -> void {
|
||||
auto data = load(register);
|
||||
uint8 lo = (data.byte(0) * 0x80200802ull & 0x884422110ull) * 0x101010101ull >> 32;
|
||||
uint8 hi = (data.byte(1) * 0x80200802ull & 0x884422110ull) * 0x101010101ull >> 32;
|
||||
store(register, lo << 8 | hi << 0);
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionMultiply(Target target, Source source) -> void {
|
||||
store(expand(target), load(target) * load(source));
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionMultiplyAdd(Register<uint16> register) -> void {
|
||||
auto xde = toMemory<int16>(load(XDE));
|
||||
auto xhl = toMemory<int16>(load(XHL));
|
||||
|
||||
auto source = load(expand(register));
|
||||
auto target = load(xde) * load(xhl);
|
||||
store(expand(register), source + target);
|
||||
store(XHL, load(XHL) - 2);
|
||||
|
||||
auto result = load(expand(register));
|
||||
VF = uint32(~(target ^ source) & (target ^ result)).negative();
|
||||
ZF = result.zero();
|
||||
SF = result.negative();
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionMultiplySigned(Target target, Source source) -> void {
|
||||
store(expand(target), toSigned(load(target)) * toSigned(load(source)));
|
||||
}
|
||||
|
||||
template<typename Target>
|
||||
auto TLCS900H::instructionNegate(Target target) -> void {
|
||||
store(target, algorithmSubtract(typename Target::type{0}, load(target)));
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionNoOperation() -> void {
|
||||
}
|
||||
|
||||
|
@ -73,10 +140,20 @@ auto TLCS900H::instructionPush(Source source) -> void {
|
|||
push(source);
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionReturn(uint4 code) -> void {
|
||||
if(condition(code)) pop(PC);
|
||||
}
|
||||
|
||||
template<typename Source>
|
||||
auto TLCS900H::instructionReturnDeallocate(Source displacement) -> void {
|
||||
pop(PC);
|
||||
store(XSP, load(XSP) + load(displacement));
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionReturnInterrupt() -> void {
|
||||
pop(SR);
|
||||
pop(PC);
|
||||
//TODO: decrement INTNEST here
|
||||
store(INTNEST, load(INTNEST) - 1);
|
||||
}
|
||||
|
||||
template<typename Target>
|
||||
|
@ -84,8 +161,16 @@ auto TLCS900H::instructionSetConditionCode(uint4 code, Target target) -> void {
|
|||
store(target, condition(code));
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionSetInterruptFlags(uint3 flags) -> void {
|
||||
setIFF(flags);
|
||||
auto TLCS900H::instructionSetFlag(uint1& flag, uint1 value) -> void {
|
||||
flag = value;
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionSetInterruptFlipFlop(uint3 value) -> void {
|
||||
IFF = value;
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionSetRegisterFilePointer(uint2 value) -> void {
|
||||
RFP = value;
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionSoftwareInterrupt(uint3 interrupt) -> void {
|
||||
|
@ -99,7 +184,7 @@ auto TLCS900H::instructionSubtract(Target target, Source source) -> void {
|
|||
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionSubtractCarry(Target target, Source source) -> void {
|
||||
store(target, algorithmSubtract(load(target), load(source), carry()));
|
||||
store(target, algorithmSubtract(load(target), load(source), CF));
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
|
|
|
@ -25,6 +25,10 @@ template<> auto TLCS900H::fetch<int16>() -> int16 { return (int16)fetch<uint16>(
|
|||
template<> auto TLCS900H::fetch<int24>() -> int24 { return (int24)fetch<uint24>(); }
|
||||
template<> auto TLCS900H::fetch<int32>() -> int32 { return (int32)fetch<uint32>(); }
|
||||
|
||||
template<typename T> auto TLCS900H::fetchRegister() -> Register<T> { return Register<T>{fetch<uint8>()}; }
|
||||
template<typename T, typename U> auto TLCS900H::fetchMemory() -> Memory<T> { return Memory<T>{fetch<U>()}; }
|
||||
template<typename T> auto TLCS900H::fetchImmediate() -> Immediate<T> { return Immediate<T>{fetch<T>()}; }
|
||||
|
||||
//
|
||||
|
||||
#define XSP r.xsp.l.l0
|
||||
|
@ -66,6 +70,10 @@ template<> auto TLCS900H::load(Memory<uint32> memory) -> uint32 {
|
|||
return data |= read(memory.address + 3) << 24;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::load(Memory< int8> memory) -> int8 { return (int8)load< uint8>(Memory< uint8>{memory.address}); }
|
||||
template<> auto TLCS900H::load(Memory<int16> memory) -> int16 { return (int16)load<uint16>(Memory<uint16>{memory.address}); }
|
||||
template<> auto TLCS900H::load(Memory<int32> memory) -> int32 { return (int32)load<uint32>(Memory<uint32>{memory.address}); }
|
||||
|
||||
template<> auto TLCS900H::store(Memory< uint8> memory, uint32 data) -> void {
|
||||
write(memory.address, data);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#define a r.rfp
|
||||
#define p r.rfpp
|
||||
#define a RFP
|
||||
#define p RFP - 1 & 3
|
||||
|
||||
template<> auto TLCS900H::map(Register<uint8> register) -> maybe<uint8&> {
|
||||
switch(register.id) {
|
||||
|
@ -85,6 +85,10 @@ template<> auto TLCS900H::store< uint8>(Register< uint8> register, uint32 data)
|
|||
template<> auto TLCS900H::store<uint16>(Register<uint16> register, uint32 data) -> void { if(auto r = map(register)) r() = data; }
|
||||
template<> auto TLCS900H::store<uint32>(Register<uint32> register, uint32 data) -> void { if(auto r = map(register)) r() = data; }
|
||||
|
||||
auto TLCS900H::expand(Register< uint8> register) const -> Register<uint16> { return {register.id & ~1}; }
|
||||
auto TLCS900H::expand(Register<uint16> register) const -> Register<uint32> { return {register.id & ~3}; }
|
||||
auto TLCS900H::expand(Register<uint32> register) const -> Register<uint32> { return {Undefined}; }
|
||||
|
||||
auto TLCS900H::load(FlagRegister f) -> uint8 {
|
||||
switch(f.id) {
|
||||
case 0: return r.c << 0 | r.n << 1 | r.v << 2 | r.h << 4 | r.z << 6 | r.s << 7;
|
||||
|
@ -107,7 +111,6 @@ auto TLCS900H::store(StatusRegister, uint16 data) -> void {
|
|||
store(F, data);
|
||||
r.rfp = data.bits( 8, 9);
|
||||
r.iff = data.bits(12,14);
|
||||
r.rfpp = r.rfp - 1;
|
||||
}
|
||||
|
||||
auto TLCS900H::load(ProgramCounter) -> uint32 { return r.pc.l.l0; }
|
||||
|
|
|
@ -3,7 +3,19 @@
|
|||
|
||||
namespace Processor {
|
||||
|
||||
#define CF r.c
|
||||
#define NF r.n
|
||||
#define VF r.v
|
||||
#define PF r.v
|
||||
#define HF r.h
|
||||
#define ZF r.z
|
||||
#define SF r.s
|
||||
|
||||
#define RFP r.rfp
|
||||
#define IFF r.iff
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "control-registers.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "conditions.cpp"
|
||||
#include "algorithms.cpp"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* what happens when a prohibited instruction operand size is used? (eg adc.l (memory),#immediate)
|
||||
* what happens when %11 is used for pre-decrement and post-increment addressing?
|
||||
* what happens when using 8-bit register indexing and d0 is set (Word) or d1/d0 is set (Long)?
|
||||
* what happens during an LDX instruction when the three padding bytes aren't all 0x00?
|
||||
* what value is read back from a non-existent 8-bit register ID? (eg 0x40-0xcf)
|
||||
* many instructions are undefined, some are marked as dummy instructions ... what do each do?
|
||||
*/
|
||||
|
@ -14,18 +15,50 @@
|
|||
namespace Processor {
|
||||
|
||||
struct TLCS900H {
|
||||
virtual auto read(uint32 address) -> uint8 { return 0; }
|
||||
virtual auto write(uint32 address, uint8 data) -> void {};
|
||||
virtual auto read(uint24 address) -> uint8 { return 0; }
|
||||
virtual auto write(uint24 address, uint8 data) -> void {};
|
||||
|
||||
TLCS900H();
|
||||
|
||||
struct FlagRegister { using type = uint8; enum : uint { bits = 8 }; uint1 id; };
|
||||
struct StatusRegister { using type = uint16; enum : uint { bits = 16 }; };
|
||||
struct ProgramCounter { using type = uint32; enum : uint { bits = 32 }; };
|
||||
struct FlagRegister {
|
||||
using type = uint8;
|
||||
enum : uint { bits = 8 };
|
||||
uint1 id;
|
||||
};
|
||||
|
||||
template<typename T> struct Register { using type = T; enum : uint { bits = 8 * sizeof(T) }; uint8 id; };
|
||||
template<typename T> struct Memory { using type = T; enum : uint { bits = 8 * sizeof(T) }; T address; };
|
||||
template<typename T> struct Immediate { using type = T; enum : uint { bits = 8 * sizeof(T) }; T constant; };
|
||||
struct StatusRegister {
|
||||
using type = uint16;
|
||||
enum : uint { bits = 16 };
|
||||
};
|
||||
|
||||
struct ProgramCounter {
|
||||
using type = uint32;
|
||||
enum : uint { bits = 32 };
|
||||
};
|
||||
|
||||
template<typename T> struct ControlRegister {
|
||||
using type = T;
|
||||
enum : uint { bits = 8 * sizeof(T) };
|
||||
uint8 id;
|
||||
};
|
||||
|
||||
template<typename T> struct Register {
|
||||
using type = T;
|
||||
enum : uint { bits = 8 * sizeof(T) };
|
||||
uint8 id;
|
||||
};
|
||||
|
||||
template<typename T> struct Memory {
|
||||
using type = T;
|
||||
enum : uint { bits = 8 * sizeof(T) };
|
||||
T address;
|
||||
};
|
||||
|
||||
template<typename T> struct Immediate {
|
||||
using type = T;
|
||||
enum : uint { bits = 8 * sizeof(T) };
|
||||
T constant;
|
||||
};
|
||||
|
||||
template<typename T> auto load(Immediate<T> immediate) const -> T { return immediate.constant; }
|
||||
|
||||
|
@ -36,6 +69,9 @@ struct TLCS900H {
|
|||
template<typename T> auto map(Register<T>) -> maybe<T&>;
|
||||
template<typename T> auto load(Register<T>) -> T;
|
||||
template<typename T> auto store(Register<T>, uint32) -> void;
|
||||
auto expand(Register< uint8>) const -> Register<uint16>;
|
||||
auto expand(Register<uint16>) const -> Register<uint32>;
|
||||
auto expand(Register<uint32>) const -> Register<uint32>;
|
||||
auto load(FlagRegister) -> uint8;
|
||||
auto store(FlagRegister, uint8) -> void;
|
||||
auto load(StatusRegister) -> uint16;
|
||||
|
@ -43,8 +79,16 @@ struct TLCS900H {
|
|||
auto load(ProgramCounter) -> uint32;
|
||||
auto store(ProgramCounter, uint32) -> void;
|
||||
|
||||
//control-registers.cpp
|
||||
template<typename T> auto map(ControlRegister<T>) -> maybe<T&>;
|
||||
template<typename T> auto load(ControlRegister<T>) -> T;
|
||||
template<typename T> auto store(ControlRegister<T>, uint32) -> void;
|
||||
|
||||
//memory.cpp
|
||||
template<typename T = uint8> auto fetch() -> T;
|
||||
template<typename T> auto fetchRegister() -> Register<T>;
|
||||
template<typename T, typename U> auto fetchMemory() -> Memory<T>;
|
||||
template<typename T> auto fetchImmediate() -> Immediate<T>;
|
||||
template<typename T> auto push(T) -> void;
|
||||
template<typename T> auto pop(T) -> void;
|
||||
template<typename T> auto load(Memory<T>) -> T;
|
||||
|
@ -62,35 +106,54 @@ struct TLCS900H {
|
|||
template<typename T> auto algorithmXor(T target, T source) -> T;
|
||||
|
||||
//instruction.cpp
|
||||
template<typename T> auto registers(uint3) const -> Register<T>;
|
||||
template<typename T> auto toRegister3(uint3) const -> Register<T>;
|
||||
template<typename T> auto toRegister8(uint8) const -> Register<T>;
|
||||
template<typename T> auto toControlRegister(uint8) const -> ControlRegister<T>;
|
||||
template<typename T> auto toMemory(uint32 address) const -> Memory<T>;
|
||||
template<typename T> auto toImmediate(uint32 constant) const -> Immediate<T>;
|
||||
template<typename T> auto toImmediate3(uint3 constant) const -> Immediate<T>;
|
||||
auto instruction() -> void;
|
||||
template<typename Register> auto instructionRegister(Register) -> void;
|
||||
template<typename Memory> auto instructionSourceMemory(Memory) -> void;
|
||||
auto instructionTargetMemory(uint32 address) -> void;
|
||||
|
||||
//instructions.cpp
|
||||
template<typename Target, typename Source> auto instructionAdd(Target target, Source source) -> void;
|
||||
template<typename Target, typename Source> auto instructionAddCarry(Target target, Source source) -> void;
|
||||
template<typename Target, typename Source> auto instructionAnd(Target target, Source source) -> void;
|
||||
template<typename Target> auto toSigned(Target) -> int32;
|
||||
|
||||
template<typename Target, typename Source> auto instructionAdd(Target, Source) -> void;
|
||||
template<typename Target, typename Source> auto instructionAddCarry(Target, Source) -> void;
|
||||
template<typename Target, typename Source> auto instructionAnd(Target, Source) -> void;
|
||||
template<typename Source> auto instructionCall(uint4 code, Source) -> void;
|
||||
template<typename Target, typename Source> auto instructionCompare(Target target, Source source) -> void;
|
||||
auto instructionComplementCarry() -> void;
|
||||
template<typename Target, typename Source> auto instructionExchange(Target target, Source source) -> void;
|
||||
template<typename Source> auto instructionCallRelative(Source) -> void;
|
||||
template<typename Target, typename Source> auto instructionCompare(Target, Source) -> void;
|
||||
template<typename Target> auto instructionComplement(Target) -> void;
|
||||
template<typename Target, typename Source> auto instructionDivide(Target, Source) -> void;
|
||||
template<typename Target, typename Source> auto instructionDivideSigned(Target, Source) -> void;
|
||||
template<typename Target, typename Source> auto instructionExchange(Target, Source) -> void;
|
||||
auto instructionHalt() -> void;
|
||||
template<typename Source> auto instructionJump(uint4 code, Source) -> void;
|
||||
template<typename Source> auto instructionJumpRelative(uint4 code, Source) -> void;
|
||||
template<typename Target, typename Source> auto instructionLoad(Target target, Source source) -> void;
|
||||
template<typename Target, typename Source> auto instructionLoad(Target, Source) -> void;
|
||||
auto instructionMirror(Register<uint16>) -> void;
|
||||
template<typename Target, typename Source> auto instructionMultiply(Target, Source) -> void;
|
||||
auto instructionMultiplyAdd(Register<uint16>) -> void;
|
||||
template<typename Target, typename Source> auto instructionMultiplySigned(Target, Source) -> void;
|
||||
template<typename Target> auto instructionNegate(Target) -> void;
|
||||
auto instructionNoOperation() -> void;
|
||||
template<typename Target, typename Source> auto instructionOr(Target target, Source source) -> void;
|
||||
template<typename Target> auto instructionPop(Target target) -> void;
|
||||
template<typename Source> auto instructionPush(Source source) -> void;
|
||||
template<typename Target, typename Source> auto instructionOr(Target, Source) -> void;
|
||||
template<typename Target> auto instructionPop(Target) -> void;
|
||||
template<typename Source> auto instructionPush(Source) -> void;
|
||||
auto instructionReturn(uint4 code) -> void;
|
||||
template<typename Source> auto instructionReturnDeallocate(Source) -> void;
|
||||
auto instructionReturnInterrupt() -> void;
|
||||
template<typename Target> auto instructionSetConditionCode(uint4 code, Target) -> void;
|
||||
auto instructionSetInterruptFlags(uint3 flags) -> void;
|
||||
auto instructionSetFlag(uint1& flag, uint1 value) -> void;
|
||||
auto instructionSetInterruptFlipFlop(uint3 value) -> void;
|
||||
auto instructionSetRegisterFilePointer(uint2 value) -> void;
|
||||
auto instructionSoftwareInterrupt(uint3 interrupt) -> void;
|
||||
template<typename Target, typename Source> auto instructionSubtract(Target target, Source source) -> void;
|
||||
template<typename Target, typename Source> auto instructionSubtractCarry(Target target, Source source) -> void;
|
||||
template<typename Target, typename Source> auto instructionXor(Target target, Source source) -> void;
|
||||
template<typename Target, typename Source> auto instructionSubtract(Target, Source) -> void;
|
||||
template<typename Target, typename Source> auto instructionSubtractCarry(Target, Source) -> void;
|
||||
template<typename Target, typename Source> auto instructionXor(Target, Source) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
@ -113,40 +176,23 @@ struct TLCS900H {
|
|||
DataRegister xsp;
|
||||
DataRegister pc;
|
||||
|
||||
uint1 c, cp; //carry
|
||||
uint1 n, np; //negative
|
||||
uint1 v, vp; //overflow or parity
|
||||
uint1 h, hp; //half carry
|
||||
uint1 z, zp; //zero
|
||||
uint1 s, sp; //sign
|
||||
uint2 rfp, rfpp = 3; //register file pointer
|
||||
DataRegister dmas[4];
|
||||
DataRegister dmad[4];
|
||||
DataRegister dmam[4];
|
||||
DataRegister intnest; //16-bit
|
||||
|
||||
uint1 c, cp; //carry
|
||||
uint1 n, np; //negative
|
||||
uint1 v, vp; //overflow or parity
|
||||
uint1 h, hp; //half carry
|
||||
uint1 z, zp; //zero
|
||||
uint1 s, sp; //sign
|
||||
uint2 rfp; //register file pointer
|
||||
uint3 iff = 7; //interrupt mask flip-flop
|
||||
|
||||
uint1 halted;
|
||||
} r;
|
||||
|
||||
auto carry() const -> bool { return r.c; }
|
||||
auto negative() const -> bool { return r.n; }
|
||||
auto overflow() const -> bool { return r.v; }
|
||||
auto parity() const -> bool { return r.v; }
|
||||
auto halfCarry() const -> bool { return r.h; }
|
||||
auto zero() const -> bool { return r.z; }
|
||||
auto sign() const -> bool { return r.s; }
|
||||
|
||||
auto setCarry(bool value) -> void { r.c = value; }
|
||||
auto setNegative(bool value) -> void { r.n = value; }
|
||||
auto setOverflow(bool value) -> void { r.v = value; }
|
||||
auto setParity(bool value) -> void { r.v = value; }
|
||||
auto setHalfCarry(bool value) -> void { r.h = value; }
|
||||
auto setZero(bool value) -> void { r.z = value; }
|
||||
auto setSign(bool value) -> void { r.s = value; }
|
||||
|
||||
auto rfp() const -> uint2 { return r.rfp; }
|
||||
auto setRFP(uint2 value) -> void { r.rfp = value; }
|
||||
|
||||
auto iff() const -> uint3 { return r.iff; }
|
||||
auto setIFF(uint3 value) -> void { r.iff = value; }
|
||||
|
||||
auto halted() const -> bool { return r.halted; }
|
||||
auto setHalted(bool value) -> void { r.halted = value; }
|
||||
|
||||
|
@ -183,6 +229,25 @@ struct TLCS900H {
|
|||
static inline const StatusRegister SR{};
|
||||
static inline const ProgramCounter PC{};
|
||||
|
||||
static inline const ControlRegister<uint32> DMAS0{0x00};
|
||||
static inline const ControlRegister<uint32> DMAS1{0x04};
|
||||
static inline const ControlRegister<uint32> DMAS2{0x08};
|
||||
static inline const ControlRegister<uint32> DMAS3{0x0c};
|
||||
static inline const ControlRegister<uint32> DMAD0{0x10};
|
||||
static inline const ControlRegister<uint32> DMAD1{0x14};
|
||||
static inline const ControlRegister<uint32> DMAD2{0x18};
|
||||
static inline const ControlRegister<uint32> DMAD3{0x1c};
|
||||
static inline const ControlRegister<uint32> DMAM0{0x20};
|
||||
static inline const ControlRegister<uint32> DMAM1{0x24};
|
||||
static inline const ControlRegister<uint32> DMAM2{0x28};
|
||||
static inline const ControlRegister<uint32> DMAM3{0x2c};
|
||||
|
||||
static inline const ControlRegister<uint16> DMAC0{0x20};
|
||||
static inline const ControlRegister<uint16> DMAC1{0x24};
|
||||
static inline const ControlRegister<uint16> DMAC2{0x28};
|
||||
static inline const ControlRegister<uint16> DMAC3{0x2c};
|
||||
static inline const ControlRegister<uint16> INTNEST{0x3c};
|
||||
|
||||
static inline const uint4 False{0x00};
|
||||
static inline const uint4 True {0x08};
|
||||
|
||||
|
|
Loading…
Reference in New Issue