mirror of https://github.com/bsnes-emu/bsnes.git
Update to v106r74 release.
byuu says: So I spent the better part of eight hours refactoring the TLCS900H core to be more flexible in light of new edge cases. I'm now including the size information inside of the types (eg Register<Byte>, Memory<Word>) rather than as parameters to the instruction handlers. This allows me to eg implement RETI without needing template arguments in all the instructions. pop(SR), pop(PC) can deduce how much to pop off of the stack. It's still highly templated, but not unrolling the 3-bit register indexes and instead going through the switch table to access registers is going to hurt the performance a good deal. A benefit of this is that Register{A} != Register{WA} != Register{XWA} anymore, despite them sharing IDs. I also renamed read/write to load/store for the CPU core, because implicit conversions are nasty. They all call the virtual read/write. I added more instructions, improved the memory addressing mode support, and some other things. I got rid of Byte, Word, Long because there's too many alternate sizes needed: int8, int16, uint24, etc. Ran into a really annoying C++ case ... struct TLCS900H { template<typename T> auto store(Register<T> target, T source) -> void; }; If you call store(Register<uint32>(x), uint16(y)); it errors out since the T types don't match. But you can't specialize it: template<typename T, typename U> auto store(Register<T>, U) -> void; template<typename U> auto TLCS900H::store<uint32, U>(Register<uint32>, U) -> void; Because somehow it's 2019 and we still can't do partial template specialization inside classes ... So as a result, I had to make T source be type uint32 even for Register<uint8> and Register<uint16>. Doesn't matter too much, just annoying.
This commit is contained in:
parent
dbee893408
commit
41148b1024
|
@ -30,7 +30,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "106.73";
|
||||
static const string Version = "106.74";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org/";
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
template<> auto TLCS900H::parity(Byte data) const -> bool {
|
||||
template<> auto TLCS900H::parity< uint8>( uint8 data) const -> bool {
|
||||
data ^= data >> 4;
|
||||
data ^= data >> 2;
|
||||
data ^= data >> 1;
|
||||
return !(data & 1);
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::parity(Word data) const -> bool {
|
||||
template<> auto TLCS900H::parity<uint16>(uint16 data) const -> bool {
|
||||
data ^= data >> 8;
|
||||
data ^= data >> 4;
|
||||
data ^= data >> 2;
|
||||
|
@ -13,65 +13,65 @@ template<> auto TLCS900H::parity(Word data) const -> bool {
|
|||
return !(data & 1);
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::parity(Long data) const -> bool {
|
||||
template<> auto TLCS900H::parity<uint32>(uint32 data) const -> bool {
|
||||
return Undefined;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
template<typename Size> auto TLCS900H::algorithmAdd(Size target, Size source, uint1 carry) -> Size {
|
||||
template<typename T> auto TLCS900H::algorithmAdd(T target, T source, uint1 carry) -> T {
|
||||
uint64 result = target + source + carry;
|
||||
CF = result.bit(Size::bits());
|
||||
NF = 0;
|
||||
VF = Size(~(target ^ source) & (target ^ result)).negative();
|
||||
HF = Size(target ^ source ^ result).bit(4);
|
||||
if constexpr(isLong<Size>()) HF = Undefined;
|
||||
ZF = Size(result).zero();
|
||||
SF = result.negative();
|
||||
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());
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Size> auto TLCS900H::algorithmAnd(Size target, Size source) -> Size {
|
||||
Size result = target & source;
|
||||
CF = 0;
|
||||
NF = 0;
|
||||
VF = parity(result);
|
||||
HF = 1;
|
||||
ZF = result.zero();
|
||||
SF = result.negative();
|
||||
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());
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Size> auto TLCS900H::algorithmOr(Size target, Size source) -> Size {
|
||||
Size result = target | source;
|
||||
CF = 0;
|
||||
NF = 0;
|
||||
VF = parity(result);
|
||||
HF = 0;
|
||||
ZF = result.zero();
|
||||
SF = result.negative();
|
||||
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());
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Size> auto TLCS900H::algorithmSubtract(Size target, Size source, uint1 carry) -> Size {
|
||||
template<typename T> auto TLCS900H::algorithmSubtract(T target, T source, uint1 carry) -> T {
|
||||
uint64 result = target - source - carry;
|
||||
CF = result.bit(Size::bits());
|
||||
NF = 1;
|
||||
VF = Size((target ^ source) & (target ^ result)).negative();
|
||||
HF = Size(target ^ source ^ result).bit(4);
|
||||
if constexpr(isLong<Size>()) HF = Undefined;
|
||||
ZF = Size(result).zero();
|
||||
SF = result.negative();
|
||||
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());
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Size> auto TLCS900H::algorithmXor(Size target, Size source) -> Size {
|
||||
Size result = target ^ source;
|
||||
CF = 0;
|
||||
NF = 0;
|
||||
VF = parity(result);
|
||||
HF = 0;
|
||||
ZF = result.zero();
|
||||
SF = result.negative();
|
||||
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());
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
auto TLCS900H::condition(uint4 code) -> bool {
|
||||
switch(code) {
|
||||
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)
|
||||
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)
|
||||
} unreachable;
|
||||
}
|
||||
|
|
|
@ -1,387 +1,379 @@
|
|||
template<> auto TLCS900H::registerLookup<Byte>(uint3 code) -> Register {
|
||||
return {0xe0 | code >> 1 << 2 | code & 1 ^ 1}; //W, A, B, C, D, E, H, L
|
||||
template<> auto TLCS900H::registers< 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::registerLookup<Word>(uint3 code) -> Register {
|
||||
return {0xe0 | code << 2}; //WA, BC, DE, HL, IX, IY, IZ, SP
|
||||
template<> auto TLCS900H::registers<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::registerLookup<Long>(uint3 code) -> Register {
|
||||
return {0xe0 | code << 2}; //XWA, XBC, XDE, XHL, XIX, XIY, XIZ, XSP
|
||||
template<> auto TLCS900H::registers<uint32>(uint3 code) const -> Register<uint32> {
|
||||
static const Register<uint32> lookup[] = {XWA, XBC, XDE, XHL, XIX, XIY, XIZ, XSP};
|
||||
return lookup[code];
|
||||
}
|
||||
|
||||
auto TLCS900H::instruction() -> void {
|
||||
auto data = fetch();
|
||||
Register register;
|
||||
Memory memory;
|
||||
|
||||
switch(data) {
|
||||
case 0x00: return instructionNoOperation();
|
||||
case 0x02: return instructionPush<Word>(r.sr);
|
||||
case 0x03: return instructionPop<Word>(r.sr);
|
||||
case 0x01: return (void)Undefined;
|
||||
case 0x02: return instructionPush(SR);
|
||||
case 0x03: return instructionPop(SR);
|
||||
case 0x04: return (void)Undefined;
|
||||
case 0x09: return instructionPush<Byte>(Immediate{fetch<Byte>()});
|
||||
case 0x0b: return instructionPush<Word>(Immediate{fetch<Word>()});
|
||||
case 0x05: return instructionHalt();
|
||||
case 0x06: return instructionSetInterruptFlags((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 0x14: return instructionPush<Byte>(A);
|
||||
case 0x15: return instructionPop<Byte>(A);
|
||||
case 0x18: return instructionPush<Byte>(r.sr.f);
|
||||
case 0x19: return instructionPop<Byte>(r.sr.f);
|
||||
case 0x1a: return instructionJump<Word>(Immediate{fetch<uint16>()});
|
||||
case 0x1b: return instructionJump<Long>(Immediate{fetch<uint24>()});
|
||||
case 0x14: return instructionPush(A);
|
||||
case 0x15: return instructionPop(A);
|
||||
case 0x16: return instructionExchange(F, FP);
|
||||
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 0x1f: return (void)Undefined;
|
||||
|
||||
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
|
||||
return instructionLoad<Byte>(registerLookup<Byte>(data), Immediate{fetch<Byte>()});
|
||||
|
||||
return instructionLoad(registers<uint8>(data), Immediate<uint8>{fetch<uint8>()});
|
||||
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
|
||||
return instructionPush<Word>(registerLookup<Word>(data));
|
||||
|
||||
return instructionPush(registers<uint16>(data));
|
||||
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
|
||||
return instructionLoad<Word>(registerLookup<Word>(data), Immediate{fetch<Word>()});
|
||||
|
||||
return instructionLoad(registers<uint16>(data), Immediate<uint16>{fetch<uint16>()});
|
||||
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
|
||||
return instructionPush<Long>(registerLookup<Long>(data));
|
||||
|
||||
return instructionPush(registers<uint32>(data));
|
||||
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
|
||||
return instructionLoad<Long>(registerLookup<Long>(data), Immediate{fetch<Long>()});
|
||||
|
||||
return instructionLoad(registers<uint32>(data), Immediate<uint32>{fetch<uint32>()});
|
||||
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
||||
return instructionPop<Word>(registerLookup<Word>(data));
|
||||
|
||||
return instructionPop(registers<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<Long>(registerLookup<Long>(data));
|
||||
|
||||
return instructionPop(registers<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(data & 15, fetch< int8>());
|
||||
|
||||
return instructionJumpRelative((uint4)data, Immediate<int8>{fetch<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(data & 15, fetch<int16>());
|
||||
|
||||
return instructionJumpRelative((uint4)data, Immediate<int16>{fetch<int16>()});
|
||||
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
|
||||
memory = {read<Long>(register)};
|
||||
return instructionSourceMemory<Byte>(memory);
|
||||
|
||||
return instructionSourceMemory(Memory<uint8>{load(registers<uint32>(data))});
|
||||
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
|
||||
memory = {read<Long>(register) + (int8)fetch()};
|
||||
return instructionSourceMemory<Byte>(memory);
|
||||
|
||||
return instructionSourceMemory(Memory<uint8>{load(registers<uint32>(data)) + fetch<int8>()});
|
||||
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
|
||||
memory = {read<Long>(register)};
|
||||
return instructionSourceMemory<Word>(memory);
|
||||
|
||||
return instructionSourceMemory(Memory<uint16>{load(registers<uint32>(data))});
|
||||
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
|
||||
memory = {read<Long>(register) + (int8)fetch()};
|
||||
return instructionSourceMemory<Word>(memory);
|
||||
|
||||
return instructionSourceMemory(Memory<uint16>{load(registers<uint32>(data)) + fetch<int8>()});
|
||||
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
|
||||
memory = {read<Long>(register)};
|
||||
return instructionSourceMemory<Long>(memory);
|
||||
|
||||
return instructionSourceMemory(Memory<uint32>{load(registers<uint32>(data))});
|
||||
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
|
||||
memory = {read<Long>(register) + (int8)fetch()};
|
||||
return instructionSourceMemory<Long>(memory);
|
||||
|
||||
return instructionSourceMemory(Memory<uint32>{load(registers<uint32>(data)) + fetch<int8>()});
|
||||
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
|
||||
memory = {read<Long>(register)};
|
||||
return instructionTargetMemory(memory);
|
||||
|
||||
return instructionTargetMemory(load(registers<uint32>(data)));
|
||||
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
|
||||
memory = {read<Long>(register) + (int8)fetch()};
|
||||
return instructionTargetMemory(memory);
|
||||
|
||||
case 0xc0:
|
||||
memory = {fetch< uint8>()};
|
||||
return instructionSourceMemory<Byte>(memory);
|
||||
case 0xc1:
|
||||
memory = {fetch<uint16>()};
|
||||
return instructionSourceMemory<Byte>(memory);
|
||||
case 0xc2:
|
||||
memory = {fetch<uint24>()};
|
||||
return instructionSourceMemory<Byte>(memory);
|
||||
case 0xc3:
|
||||
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>()});
|
||||
case 0xc3: {
|
||||
data = fetch();
|
||||
memory = {read<Long>(Register{data})};
|
||||
if((data & 3) == 1) memory.value += (int16)fetch<uint16>();
|
||||
if((data & 3) == 2) memory.value += (int8)read<Byte>(Register{fetch()});
|
||||
if((data & 3) == 3) memory.value += (int16)read<Word>(Register{fetch()});
|
||||
return instructionSourceMemory<Byte>(memory);
|
||||
case 0xc4:
|
||||
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 == 0x03) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r8 = load(Register< uint8>{fetch()});
|
||||
return instructionSourceMemory(Memory<uint8>{r32 + (int8)r8});
|
||||
}
|
||||
if(data == 0x07) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r16 = load(Register<uint16>{fetch()});
|
||||
return instructionSourceMemory(Memory<uint8>{r32 + (int16)r16});
|
||||
}
|
||||
return (void)Undefined; }
|
||||
case 0xc4: {
|
||||
data = fetch();
|
||||
register = {data};
|
||||
if((data & 3) == 0) write<Long>(register, read<Long>(register) - 1);
|
||||
if((data & 3) == 1) write<Long>(register, read<Long>(register) - 2);
|
||||
if((data & 3) == 2) write<Long>(register, read<Long>(register) - 4);
|
||||
auto register = Register<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;
|
||||
memory = {read<Long>(register)};
|
||||
return instructionSourceMemory<Byte>(memory);
|
||||
case 0xc5:
|
||||
return instructionSourceMemory(Memory<uint8>{load(register)}); }
|
||||
case 0xc5: {
|
||||
data = fetch();
|
||||
register = {data};
|
||||
memory = {read<Long>(register)};
|
||||
instructionSourceMemory<Byte>(memory);
|
||||
if((data & 3) == 0) write<Long>(register, read<Long>(register) + 1);
|
||||
if((data & 3) == 1) write<Long>(register, read<Long>(register) + 2);
|
||||
if((data & 3) == 2) write<Long>(register, read<Long>(register) + 4);
|
||||
auto register = Register<uint32>{data};
|
||||
instructionSourceMemory(Memory<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:
|
||||
register = {fetch()};
|
||||
return instructionRegister<Byte>(register);
|
||||
return; }
|
||||
case 0xc6: return (void)Undefined;
|
||||
case 0xc7: return instructionRegister(Register<uint8>{fetch()});
|
||||
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
|
||||
register = registerLookup<Byte>(data);
|
||||
return instructionRegister<Byte>(register);
|
||||
|
||||
case 0xd0:
|
||||
memory = {fetch< uint8>()};
|
||||
return instructionSourceMemory<Word>(memory);
|
||||
case 0xd1:
|
||||
memory = {fetch<uint16>()};
|
||||
return instructionSourceMemory<Word>(memory);
|
||||
case 0xd2:
|
||||
memory = {fetch<uint24>()};
|
||||
return instructionSourceMemory<Word>(memory);
|
||||
case 0xd3:
|
||||
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>()});
|
||||
case 0xd3: {
|
||||
data = fetch();
|
||||
memory = {read<Long>(Register{data})};
|
||||
if((data & 3) == 1) memory.value += (int16)fetch<uint16>();
|
||||
if((data & 3) == 2) memory.value += (int8)read<Byte>(Register{fetch()});
|
||||
if((data & 3) == 3) memory.value += (int16)read<Word>(Register{fetch()});
|
||||
return instructionSourceMemory<Word>(memory);
|
||||
case 0xd4:
|
||||
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 == 0x03) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r8 = load(Register< uint8>{fetch()});
|
||||
return instructionSourceMemory(Memory<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});
|
||||
}
|
||||
return (void)Undefined; }
|
||||
case 0xd4: {
|
||||
data = fetch();
|
||||
register = {data};
|
||||
if((data & 3) == 0) write<Long>(register, read<Long>(register) - 1);
|
||||
if((data & 3) == 1) write<Long>(register, read<Long>(register) - 2);
|
||||
if((data & 3) == 2) write<Long>(register, read<Long>(register) - 4);
|
||||
auto register = Register<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;
|
||||
memory = {read<Long>(register)};
|
||||
return instructionSourceMemory<Word>(memory);
|
||||
case 0xd5:
|
||||
return instructionSourceMemory(Memory<uint16>{load(register)}); }
|
||||
case 0xd5: {
|
||||
data = fetch();
|
||||
register = {data};
|
||||
memory = {read<Long>(register)};
|
||||
instructionSourceMemory<Word>(memory);
|
||||
if((data & 3) == 0) write<Long>(register, read<Long>(register) + 1);
|
||||
if((data & 3) == 1) write<Long>(register, read<Long>(register) + 2);
|
||||
if((data & 3) == 2) write<Long>(register, read<Long>(register) + 4);
|
||||
auto register = Register<uint32>{data};
|
||||
instructionSourceMemory(Memory<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:
|
||||
register = {fetch()};
|
||||
return instructionRegister<Word>(register);
|
||||
return; }
|
||||
case 0xd6: return (void)Undefined;
|
||||
case 0xd7: return instructionRegister(Register<uint16>{fetch()});
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
register = registerLookup<Word>(data);
|
||||
return instructionRegister<Word>(register);
|
||||
|
||||
case 0xe0:
|
||||
memory = {fetch< uint8>()};
|
||||
return instructionSourceMemory<Long>(memory);
|
||||
case 0xe1:
|
||||
memory = {fetch<uint16>()};
|
||||
return instructionSourceMemory<Long>(memory);
|
||||
case 0xe2:
|
||||
memory = {fetch<uint24>()};
|
||||
return instructionSourceMemory<Long>(memory);
|
||||
case 0xe3:
|
||||
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>()});
|
||||
case 0xe3: {
|
||||
data = fetch();
|
||||
memory = {read<Long>(Register{data})};
|
||||
if((data & 3) == 1) memory.value += (int16)fetch<uint16>();
|
||||
if((data & 3) == 2) memory.value += (int8)read<Byte>(Register{fetch()});
|
||||
if((data & 3) == 3) memory.value += (int16)read<Word>(Register{fetch()});
|
||||
return instructionSourceMemory<Long>(memory);
|
||||
case 0xe4:
|
||||
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 == 0x03) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r8 = load(Register< uint8>{fetch()});
|
||||
return instructionSourceMemory(Memory<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});
|
||||
}
|
||||
return (void)Undefined; }
|
||||
case 0xe4: {
|
||||
data = fetch();
|
||||
register = {data};
|
||||
if((data & 3) == 0) write<Long>(register, read<Long>(register) - 1);
|
||||
if((data & 3) == 1) write<Long>(register, read<Long>(register) - 2);
|
||||
if((data & 3) == 2) write<Long>(register, read<Long>(register) - 4);
|
||||
auto register = Register<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;
|
||||
memory = {read<Long>(register)};
|
||||
return instructionSourceMemory<Long>(memory);
|
||||
case 0xe5:
|
||||
return instructionSourceMemory(Memory<uint32>{load(register)}); }
|
||||
case 0xe5: {
|
||||
data = fetch();
|
||||
register = {data};
|
||||
memory = {read<Long>(register)};
|
||||
instructionSourceMemory<Long>(memory);
|
||||
if((data & 3) == 0) write<Long>(register, read<Long>(register) + 1);
|
||||
if((data & 3) == 1) write<Long>(register, read<Long>(register) + 2);
|
||||
if((data & 3) == 2) write<Long>(register, read<Long>(register) + 4);
|
||||
auto register = Register<uint32>{data};
|
||||
instructionSourceMemory(Memory<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:
|
||||
register = {fetch()};
|
||||
return instructionRegister<Long>(register);
|
||||
return; }
|
||||
case 0xe6: return (void)Undefined;
|
||||
case 0xe7: return instructionRegister(Register<uint32>{fetch()});
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
|
||||
register = registerLookup<Long>(data);
|
||||
return instructionRegister<Long>(register);
|
||||
|
||||
case 0xf0:
|
||||
memory = {fetch< uint8>()};
|
||||
return instructionTargetMemory(memory);
|
||||
case 0xf1:
|
||||
memory = {fetch<uint16>()};
|
||||
return instructionTargetMemory(memory);
|
||||
case 0xf2:
|
||||
memory = {fetch<uint24>()};
|
||||
return instructionTargetMemory(memory);
|
||||
case 0xf3:
|
||||
return instructionRegister(registers<uint32>(data));
|
||||
case 0xf0: return instructionTargetMemory(fetch<uint8>());
|
||||
case 0xf1: return instructionTargetMemory(fetch<uint16>());
|
||||
case 0xf2: return instructionTargetMemory(fetch<uint24>());
|
||||
case 0xf3: {
|
||||
data = fetch();
|
||||
memory = {read<Long>(Register{data})};
|
||||
if((data & 3) == 1) memory.value += (int16)fetch<uint16>();
|
||||
if((data & 3) == 2) memory.value += (int8)read<Byte>(Register{fetch()});
|
||||
if((data & 3) == 3) memory.value += (int16)read<Word>(Register{fetch()});
|
||||
return instructionTargetMemory(memory);
|
||||
case 0xf4:
|
||||
if((data & 3) == 0) return instructionTargetMemory(load(Register<uint32>{data}));
|
||||
if((data & 3) == 1) return instructionTargetMemory(load(Register<uint32>{data}) + fetch<int16>());
|
||||
if(data == 0x03) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r8 = load(Register< uint8>{fetch()});
|
||||
return instructionTargetMemory(r32 + (int8)r8);
|
||||
}
|
||||
if(data == 0x07) {
|
||||
auto r32 = load(Register<uint32>{fetch()});
|
||||
auto r16 = load(Register<uint16>{fetch()});
|
||||
return instructionTargetMemory(r32 + (int16)r16);
|
||||
}
|
||||
return (void)Undefined; }
|
||||
case 0xf4: {
|
||||
data = fetch();
|
||||
register = {data};
|
||||
if((data & 3) == 0) write<Long>(register, read<Long>(register) - 1);
|
||||
if((data & 3) == 1) write<Long>(register, read<Long>(register) - 2);
|
||||
if((data & 3) == 2) write<Long>(register, read<Long>(register) - 4);
|
||||
auto register = Register<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;
|
||||
memory = {read<Long>(register)};
|
||||
return instructionTargetMemory(memory);
|
||||
case 0xf5:
|
||||
return instructionTargetMemory(load(register)); }
|
||||
case 0xf5: {
|
||||
data = fetch();
|
||||
register = {data};
|
||||
memory = {read<Long>(register)};
|
||||
instructionTargetMemory(memory);
|
||||
if((data & 3) == 0) write<Long>(register, read<Long>(register) + 1);
|
||||
if((data & 3) == 1) write<Long>(register, read<Long>(register) + 2);
|
||||
if((data & 3) == 2) write<Long>(register, read<Long>(register) + 4);
|
||||
auto register = Register<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;
|
||||
|
||||
return; }
|
||||
case 0xf6: case 0xf7: return (void)Undefined;
|
||||
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
|
||||
return instructionSoftwareInterrupt(data.bits(0,2));
|
||||
return instructionSoftwareInterrupt((uint3)data);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Size>
|
||||
auto TLCS900H::instructionRegister(Register register) -> void {
|
||||
template<typename R>
|
||||
auto TLCS900H::instructionRegister(R register) -> void {
|
||||
using type = typename R::type;
|
||||
auto data = fetch();
|
||||
|
||||
switch(data) {
|
||||
case 0x04: return instructionPush<Size>(register);
|
||||
case 0x05: return instructionPop<Size>(register);
|
||||
|
||||
case 0x00: case 0x01: case 0x02: return (void)Undefined;
|
||||
case 0x04: return instructionPush(register);
|
||||
case 0x05: return instructionPop(register);
|
||||
case 0x11: return (void)Undefined;
|
||||
case 0x15: return (void)Undefined;
|
||||
case 0x17: case 0x18: 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 0x35: case 0x36: case 0x37: return (void)Undefined;
|
||||
case 0x3b: return (void)Undefined;
|
||||
case 0x3f: return (void)Undefined;
|
||||
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;
|
||||
return instructionSetConditionCode((uint4)data, register);
|
||||
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
|
||||
return instructionAdd<Size>(registerLookup<Size>(data), register);
|
||||
return instructionAdd(registers<type>(data), register);
|
||||
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
|
||||
return instructionLoad<Size>(registerLookup<Size>(data), register);
|
||||
return instructionLoad(registers<type>(data), register);
|
||||
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
|
||||
return instructionAddCarry<Size>(registerLookup<Size>(data), register);
|
||||
return instructionAddCarry(registers<type>(data), register);
|
||||
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
|
||||
return instructionLoad<Size>(register, registerLookup<Size>(data));
|
||||
return instructionLoad(register, registers<type>(data));
|
||||
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
|
||||
return instructionSubtract<Size>(registerLookup<Size>(data), register);
|
||||
return instructionSubtract(registers<type>(data), register);
|
||||
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
|
||||
return instructionLoad<Size>(register, Immediate{data.bits(0,2)});
|
||||
return instructionLoad(register, Immediate<type>{(uint3)data});
|
||||
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
|
||||
return instructionSubtractCarry<Size>(registerLookup<Size>(data), register);
|
||||
return instructionSubtractCarry(registers<type>(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);
|
||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
|
||||
return instructionAnd<Size>(registerLookup<Size>(data), register);
|
||||
case 0xc8: return instructionAdd<Size>(register, Immediate{fetch<Size>()});
|
||||
case 0xc9: return instructionAddCarry<Size>(register, Immediate{fetch<Size>()});
|
||||
case 0xca: return instructionSubtract<Size>(register, Immediate{fetch<Size>()});
|
||||
case 0xcb: return instructionSubtractCarry<Size>(register, Immediate{fetch<Size>()});
|
||||
case 0xcc: return instructionAnd<Size>(register, Immediate{fetch<Size>()});
|
||||
case 0xcd: return instructionXor<Size>(register, Immediate{fetch<Size>()});
|
||||
case 0xce: return instructionOr<Size>(register, Immediate{fetch<Size>()});
|
||||
case 0xcf: return instructionCompare<Size>(register, Immediate{fetch<Size>()});
|
||||
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>()});
|
||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||
return instructionXor<Size>(registerLookup<Size>(data), register);
|
||||
return instructionXor(registers<type>(data), register);
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
return instructionCompare<Size>(register, Immediate{data.bits(0,2)});
|
||||
return instructionCompare(register, Immediate<type>{(uint3)data});
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
return instructionOr<Size>(registerLookup<Size>(data), register);
|
||||
return instructionOr(registers<type>(data), register);
|
||||
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
|
||||
return instructionCompare<Size>(registerLookup<Size>(data), register);
|
||||
return instructionCompare(registers<type>(data), register);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Size>
|
||||
auto TLCS900H::instructionSourceMemory(Memory memory) -> void {
|
||||
template<typename M>
|
||||
auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||
using type = typename M::type;
|
||||
auto data = fetch();
|
||||
|
||||
switch(data) {
|
||||
case 0x00: case 0x01: case 0x02: case 0x03: return (void)Undefined;
|
||||
case 0x04: if constexpr(isLong<Size>()) return (void)Undefined;
|
||||
return instructionPush<Size>(memory);
|
||||
case 0x04:
|
||||
if constexpr(M::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(isLong<Size>()) return (void)Undefined;
|
||||
return instructionLoad<Size>(Memory{fetch<Size>()}, memory);
|
||||
case 0x19:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
return instructionLoad(Memory<type>{fetch<type>()}, 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<Size>(registerLookup<Size>(data), memory);
|
||||
return instructionLoad(registers<type>(data), memory);
|
||||
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: return (void)Undefined;
|
||||
case 0x38: if constexpr(isLong<Size>()) return (void)Undefined;
|
||||
return instructionAdd<Size>(memory, Immediate{fetch<Size>()});
|
||||
case 0x39: if constexpr(isLong<Size>()) return (void)Undefined;
|
||||
return instructionAddCarry<Size>(memory, Immediate{fetch<Size>()});
|
||||
case 0x3a: if constexpr(isLong<Size>()) return (void)Undefined;
|
||||
return instructionSubtract<Size>(memory, Immediate{fetch<Size>()});
|
||||
case 0x3b: if constexpr(isLong<Size>()) return (void)Undefined;
|
||||
return instructionSubtractCarry<Size>(memory, Immediate{fetch<Size>()});
|
||||
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));
|
||||
case 0x38:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
return instructionAdd(memory, Immediate<type>{fetch<type>()});
|
||||
case 0x39:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
return instructionAddCarry(memory, Immediate<type>{fetch<type>()});
|
||||
case 0x3a:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
return instructionSubtract(memory, Immediate<type>{fetch<type>()});
|
||||
case 0x3b:
|
||||
if constexpr(M::bits == 32) return (void)Undefined;
|
||||
return instructionSubtractCarry(memory, Immediate<type>{fetch<type>()});
|
||||
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
|
||||
return instructionAdd<Size>(registerLookup<Size>(data), memory);
|
||||
return instructionAdd(registers<type>(data), memory);
|
||||
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
|
||||
return instructionAdd<Size>(memory, registerLookup<Size>(data));
|
||||
return instructionAdd(memory, registers<type>(data));
|
||||
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
|
||||
return instructionAddCarry<Size>(registerLookup<Size>(data), memory);
|
||||
return instructionAddCarry(registers<type>(data), memory);
|
||||
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
|
||||
return instructionAddCarry<Size>(memory, registerLookup<Size>(data));
|
||||
return instructionAddCarry(memory, registers<type>(data));
|
||||
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
|
||||
return instructionSubtract<Size>(registerLookup<Size>(data), memory);
|
||||
return instructionSubtract(registers<type>(data), memory);
|
||||
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
|
||||
return instructionSubtract<Size>(memory, registerLookup<Size>(data));
|
||||
return instructionSubtract(memory, registers<type>(data));
|
||||
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
|
||||
return instructionSubtractCarry<Size>(registerLookup<Size>(data), memory);
|
||||
return instructionSubtractCarry(registers<type>(data), memory);
|
||||
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
|
||||
return instructionSubtractCarry<Size>(memory, registerLookup<Size>(data));
|
||||
return instructionSubtractCarry(memory, registers<type>(data));
|
||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
|
||||
return instructionAnd<Size>(registerLookup<Size>(data), memory);
|
||||
return instructionAnd(registers<type>(data), memory);
|
||||
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
|
||||
return instructionAnd<Size>(memory, registerLookup<Size>(data));
|
||||
return instructionAnd(memory, registers<type>(data));
|
||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||
return instructionXor<Size>(registerLookup<Size>(data), memory);
|
||||
return instructionXor(registers<type>(data), memory);
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
return instructionXor<Size>(memory, registerLookup<Size>(data));
|
||||
return instructionXor(memory, registers<type>(data));
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
return instructionOr<Size>(registerLookup<Size>(data), memory);
|
||||
return instructionOr(registers<type>(data), memory);
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
|
||||
return instructionOr<Size>(memory, registerLookup<Size>(data));
|
||||
return instructionOr(memory, registers<type>(data));
|
||||
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
|
||||
return instructionCompare<Size>(registerLookup<Size>(data), memory);
|
||||
return instructionCompare(registers<type>(data), memory);
|
||||
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
|
||||
return instructionCompare<Size>(memory, registerLookup<Size>(data));
|
||||
return instructionCompare(memory, registers<type>(data));
|
||||
}
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionTargetMemory(Memory memory) -> void {
|
||||
auto TLCS900H::instructionTargetMemory(uint32 address) -> void {
|
||||
auto data = fetch();
|
||||
|
||||
switch(data) {
|
||||
case 0x01: return (void)Undefined;
|
||||
case 0x03: return (void)Undefined;
|
||||
case 0x04: return instructionPop<Byte>(memory);
|
||||
case 0x04: return instructionPop(Memory<uint8>{address});
|
||||
case 0x05: return (void)Undefined;
|
||||
case 0x06: return instructionPop<Word>(memory);
|
||||
case 0x06: return instructionPop(Memory<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;
|
||||
|
@ -389,24 +381,27 @@ auto TLCS900H::instructionTargetMemory(Memory memory) -> void {
|
|||
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<Word>(registerLookup<Word>(data), memory);
|
||||
return instructionLoad(registers<uint16>(data), Memory<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<Long>(registerLookup<Long>(data), memory);
|
||||
return instructionLoad(registers<uint32>(data), Memory<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<Byte>(memory, registerLookup<Byte>(data));
|
||||
return instructionLoad(Memory<uint8>{address}, registers<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<Word>(memory, registerLookup<Word>(data));
|
||||
return instructionLoad(Memory<uint16>{address}, registers<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<Long>(memory, registerLookup<Long>(data));
|
||||
return instructionLoad(Memory<uint32>{address}, registers<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<Long>(data.bits(0,3), memory);
|
||||
return instructionJump((uint4)data, Memory<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});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,90 +1,108 @@
|
|||
#define read read<Size>
|
||||
#define write write<Size>
|
||||
#define push push<Size>
|
||||
#define pop pop<Size>
|
||||
#define algorithm(name, ...) algorithm##name<Size>(__VA_ARGS__)
|
||||
|
||||
template<typename Size, typename Target, typename Source>
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionAdd(Target target, Source source) -> void {
|
||||
write(target, algorithm(Add, read(target), read(source)));
|
||||
store(target, algorithmAdd(load(target), load(source)));
|
||||
}
|
||||
|
||||
template<typename Size, typename Target, typename Source>
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionAddCarry(Target target, Source source) -> void {
|
||||
write(target, algorithm(Add, read(target), read(source), CF));
|
||||
store(target, algorithmAdd(load(target), load(source), carry()));
|
||||
}
|
||||
|
||||
template<typename Size, typename Target, typename Source>
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionAnd(Target target, Source source) -> void {
|
||||
write(target, algorithm(And, read(target), read(source)));
|
||||
store(target, algorithmAnd(load(target), load(source)));
|
||||
}
|
||||
|
||||
template<typename Size, typename Target, typename Source>
|
||||
template<typename Source>
|
||||
auto TLCS900H::instructionCall(uint4 code, Source source) -> void {
|
||||
auto address = load(source);
|
||||
if(condition(code)) push(PC), store(PC, address);
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionCompare(Target target, Source source) -> void {
|
||||
algorithm(Subtract, read(target), read(source));
|
||||
algorithmSubtract(load(target), load(source));
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionComplementCarry() -> void {
|
||||
CF = !CF;
|
||||
setCarry(!carry());
|
||||
}
|
||||
|
||||
template<typename Size, typename Source> auto TLCS900H::instructionJump(Source source) -> void {
|
||||
PC = read(source);
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionExchange(Target target, Source source) -> void {
|
||||
auto data = load(target);
|
||||
store(target, load(source));
|
||||
store(source, data);
|
||||
}
|
||||
|
||||
template<typename Size, typename Source> auto TLCS900H::instructionJump(uint4 code, Source source) -> void {
|
||||
auto address = read(source);
|
||||
if(condition(code)) PC = address;
|
||||
auto TLCS900H::instructionHalt() -> void {
|
||||
setHalted(true);
|
||||
}
|
||||
|
||||
template<typename Size> auto TLCS900H::instructionJumpRelative(uint4 code, Size displacement) -> void {
|
||||
if(condition(code)) PC += displacement;
|
||||
template<typename Source>
|
||||
auto TLCS900H::instructionJump(uint4 code, Source source) -> void {
|
||||
auto address = load(source);
|
||||
if(condition(code)) store(PC, address);
|
||||
}
|
||||
|
||||
template<typename Size, typename Target, typename Source>
|
||||
template<typename Source>
|
||||
auto TLCS900H::instructionJumpRelative(uint4 code, Source displacement) -> void {
|
||||
if(condition(code)) store(PC, load(PC) + load(displacement));
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionLoad(Target target, Source source) -> void {
|
||||
write(target, read(source));
|
||||
store(target, load(source));
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionNoOperation() -> void {
|
||||
}
|
||||
|
||||
template<typename Size, typename Target, typename Source>
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionOr(Target target, Source source) -> void {
|
||||
write(target, algorithm(Or, read(target), read(source)));
|
||||
store(target, algorithmOr(load(target), load(source)));
|
||||
}
|
||||
|
||||
template<typename Size, typename Target>
|
||||
template<typename Target>
|
||||
auto TLCS900H::instructionPop(Target target) -> void {
|
||||
write(target, pop());
|
||||
pop(target);
|
||||
}
|
||||
|
||||
template<typename Size, typename Source>
|
||||
template<typename Source>
|
||||
auto TLCS900H::instructionPush(Source source) -> void {
|
||||
push(read(source));
|
||||
push(source);
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionReturnInterrupt() -> void {
|
||||
pop(SR);
|
||||
pop(PC);
|
||||
//TODO: decrement INTNEST here
|
||||
}
|
||||
|
||||
template<typename Target>
|
||||
auto TLCS900H::instructionSetConditionCode(uint4 code, Target target) -> void {
|
||||
store(target, condition(code));
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionSetInterruptFlags(uint3 flags) -> void {
|
||||
setIFF(flags);
|
||||
}
|
||||
|
||||
auto TLCS900H::instructionSoftwareInterrupt(uint3 interrupt) -> void {
|
||||
//TODO
|
||||
}
|
||||
|
||||
template<typename Size, typename Target, typename Source>
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionSubtract(Target target, Source source) -> void {
|
||||
write(target, algorithm(Subtract, read(target), read(source)));
|
||||
store(target, algorithmSubtract(load(target), load(source)));
|
||||
}
|
||||
|
||||
template<typename Size, typename Target, typename Source>
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionSubtractCarry(Target target, Source source) -> void {
|
||||
write(target, algorithm(Subtract, read(target), read(source), CF));
|
||||
store(target, algorithmSubtract(load(target), load(source), carry()));
|
||||
}
|
||||
|
||||
template<typename Size, typename Target, typename Source>
|
||||
template<typename Target, typename Source>
|
||||
auto TLCS900H::instructionXor(Target target, Source source) -> void {
|
||||
write(target, algorithm(Xor, read(target), read(source)));
|
||||
store(target, algorithmXor(load(target), load(source)));
|
||||
}
|
||||
|
||||
#undef read
|
||||
#undef write
|
||||
#undef push
|
||||
#undef pop
|
||||
#undef algorithm
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
template<> auto TLCS900H::fetch<Byte>() -> Byte {
|
||||
return 0x00;
|
||||
template<> auto TLCS900H::fetch< uint8>() -> uint8 {
|
||||
return rand();
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::fetch<Word>() -> Word {
|
||||
uint16 data = fetch<Byte>();
|
||||
return data | fetch<Byte>() << 8;
|
||||
template<> auto TLCS900H::fetch<uint16>() -> uint16 {
|
||||
uint16 data = fetch<uint8>();
|
||||
return data | fetch<uint8>() << 8;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::fetch<uint24>() -> uint24 {
|
||||
uint24 data = fetch<Byte>();
|
||||
data |= fetch<Byte>() << 8;
|
||||
return data |= fetch<Byte>() << 16;
|
||||
uint24 data = fetch<uint8>();
|
||||
data |= fetch<uint8>() << 8;
|
||||
return data |= fetch<uint8>() << 16;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::fetch<Long>() -> Long {
|
||||
uint32 data = fetch<Byte>();
|
||||
data |= fetch<Byte>() << 8;
|
||||
data |= fetch<Byte>() << 16;
|
||||
return data |= fetch<Byte>() << 24;
|
||||
template<> auto TLCS900H::fetch<uint32>() -> uint32 {
|
||||
uint32 data = fetch<uint8>();
|
||||
data |= fetch<uint8>() << 8;
|
||||
data |= fetch<uint8>() << 16;
|
||||
return data |= fetch<uint8>() << 24;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::fetch< int8>() -> int8 { return ( int8)fetch< uint8>(); }
|
||||
|
@ -29,78 +29,55 @@ template<> auto TLCS900H::fetch<int32>() -> int32 { return (int32)fetch<uint32>(
|
|||
|
||||
#define XSP r.xsp.l.l0
|
||||
|
||||
template<> auto TLCS900H::push<Byte>(Byte data) -> void {
|
||||
write(--XSP, data);
|
||||
template<typename T> auto TLCS900H::pop(T data) -> void {
|
||||
auto value = typename T::type();
|
||||
if constexpr(T::bits >= 8) value.byte(0) = read(XSP++);
|
||||
if constexpr(T::bits >= 16) value.byte(1) = read(XSP++);
|
||||
if constexpr(T::bits >= 24) value.byte(2) = read(XSP++);
|
||||
if constexpr(T::bits >= 32) value.byte(3) = read(XSP++);
|
||||
store(data, value);
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::push<Word>(Word data) -> void {
|
||||
write(--XSP, data >> 0);
|
||||
write(--XSP, data >> 8);
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::push<Long>(Long data) -> void {
|
||||
write(--XSP, data >> 0);
|
||||
write(--XSP, data >> 8);
|
||||
write(--XSP, data >> 16);
|
||||
write(--XSP, data >> 24);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
template<> auto TLCS900H::pop<Byte>() -> Byte {
|
||||
return read(XSP++);
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::pop<Word>() -> Word {
|
||||
uint16 data = read(XSP++) << 0;
|
||||
return data | read(XSP++) << 8;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::pop<Long>() -> Long {
|
||||
uint32 data = read(XSP++) << 0;
|
||||
data |= read(XSP++) << 8;
|
||||
data |= read(XSP++) << 16;
|
||||
return data |= read(XSP++) << 24;
|
||||
template<typename T> auto TLCS900H::push(T data) -> void {
|
||||
auto value = load(data);
|
||||
if constexpr(T::bits >= 8) write(--XSP, value >> 0);
|
||||
if constexpr(T::bits >= 16) write(--XSP, value >> 8);
|
||||
if constexpr(T::bits >= 24) write(--XSP, value >> 16);
|
||||
if constexpr(T::bits >= 32) write(--XSP, value >> 24);
|
||||
}
|
||||
|
||||
#undef XSP
|
||||
|
||||
//
|
||||
|
||||
template<> auto TLCS900H::read<Byte>(Memory memory) -> uint8 {
|
||||
uint32 address = memory.value;
|
||||
return read(address);
|
||||
template<> auto TLCS900H::load(Memory< uint8> memory) -> uint8 {
|
||||
return read(memory.address);
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::read<Word>(Memory memory) -> uint16 {
|
||||
uint32 address = memory.value;
|
||||
uint16 data = read(address + 0) << 0;
|
||||
return data | read(address + 1) << 8;
|
||||
template<> auto TLCS900H::load(Memory<uint16> memory) -> uint16 {
|
||||
uint16 data = read(memory.address + 0) << 0;
|
||||
return data | read(memory.address + 1) << 8;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::read<Long>(Memory memory) -> uint32 {
|
||||
uint32 address = memory.value;
|
||||
uint32 data = read(address + 0) << 0;
|
||||
data |= read(address + 1) << 8;
|
||||
data |= read(address + 2) << 16;
|
||||
return data |= read(address + 3) << 24;
|
||||
template<> auto TLCS900H::load(Memory<uint32> memory) -> uint32 {
|
||||
uint32 data = read(memory.address + 0) << 0;
|
||||
data |= read(memory.address + 1) << 8;
|
||||
data |= read(memory.address + 2) << 16;
|
||||
return data |= read(memory.address + 3) << 24;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::write<Byte>(Memory memory, uint8 data) -> void {
|
||||
uint32 address = memory.value;
|
||||
write(address + 0, data >> 0);
|
||||
template<> auto TLCS900H::store(Memory< uint8> memory, uint32 data) -> void {
|
||||
write(memory.address, data);
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::write<Word>(Memory memory, uint16 data) -> void {
|
||||
uint32 address = memory.value;
|
||||
write(address + 0, data >> 0);
|
||||
write(address + 1, data >> 8);
|
||||
template<> auto TLCS900H::store(Memory<uint16> memory, uint32 data) -> void {
|
||||
write(memory.address + 0, data >> 0);
|
||||
write(memory.address + 1, data >> 8);
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::write<Long>(Memory memory, uint32 data) -> void {
|
||||
uint32 address = memory.value;
|
||||
write(address + 0, data >> 0);
|
||||
write(address + 1, data >> 8);
|
||||
write(address + 2, data >> 16);
|
||||
write(address + 3, data >> 24);
|
||||
template<> auto TLCS900H::store(Memory<uint32> memory, uint32 data) -> void {
|
||||
write(memory.address + 0, data >> 0);
|
||||
write(memory.address + 1, data >> 8);
|
||||
write(memory.address + 2, data >> 16);
|
||||
write(memory.address + 3, data >> 24);
|
||||
}
|
||||
|
|
|
@ -1,21 +1,8 @@
|
|||
#define PC r.pc.l.l0
|
||||
#define a r.rfp
|
||||
#define p r.rfpp
|
||||
|
||||
#define CF r.sr.f.c
|
||||
#define NF r.sr.f.n
|
||||
#define VF r.sr.f.v
|
||||
#define HF r.sr.f.h
|
||||
#define ZF r.sr.f.z
|
||||
#define SF r.sr.f.s
|
||||
|
||||
#define RFP r.sr.rfp
|
||||
#define RFPP r.sr.rfpp
|
||||
#define IFF r.sr.iff
|
||||
|
||||
#define a RFP
|
||||
#define p RFPP
|
||||
|
||||
template<> auto TLCS900H::map<Byte>(Register register) -> maybe<Byte&> {
|
||||
switch(register.value) {
|
||||
template<> auto TLCS900H::map(Register<uint8> register) -> maybe<uint8&> {
|
||||
switch(register.id) {
|
||||
#define r(id, name) case id: return r.name;
|
||||
r(0x00, xwa[0].b.b0) r(0x01, xwa[0].b.b1) r(0x02, xwa[0].b.b2) r(0x03, xwa[0].b.b3)
|
||||
r(0x04, xbc[0].b.b0) r(0x05, xbc[0].b.b1) r(0x06, xbc[0].b.b2) r(0x07, xbc[0].b.b3)
|
||||
|
@ -50,8 +37,8 @@ template<> auto TLCS900H::map<Byte>(Register register) -> maybe<Byte&> {
|
|||
return nothing;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::map<Word>(Register register) -> maybe<Word&> {
|
||||
switch(register.value & ~1) {
|
||||
template<> auto TLCS900H::map(Register<uint16> register) -> maybe<uint16&> {
|
||||
switch(register.id & ~1) {
|
||||
#define r(id, name) case id: return r.name;
|
||||
r(0x00, xwa[0].w.w0) r(0x02, xwa[0].w.w1) r(0x04, xbc[0].w.w0) r(0x06, xbc[0].w.w1)
|
||||
r(0x08, xde[0].w.w0) r(0x0a, xde[0].w.w1) r(0x0c, xhl[0].w.w0) r(0x0e, xhl[0].w.w1)
|
||||
|
@ -72,8 +59,8 @@ template<> auto TLCS900H::map<Word>(Register register) -> maybe<Word&> {
|
|||
return nothing;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::map<Long>(Register register) -> maybe<Long&> {
|
||||
switch(register.value & ~3) {
|
||||
template<> auto TLCS900H::map(Register<uint32> register) -> maybe<uint32&> {
|
||||
switch(register.id & ~3) {
|
||||
#define r(id, name) case id: return r.name;
|
||||
r(0x00, xwa[0].l.l0) r(0x04, xbc[0].l.l0) r(0x08, xde[0].l.l0) r(0x0c, xhl[0].l.l0)
|
||||
r(0x10, xwa[1].l.l0) r(0x14, xbc[1].l.l0) r(0x18, xde[1].l.l0) r(0x1c, xhl[1].l.l0)
|
||||
|
@ -90,64 +77,38 @@ template<> auto TLCS900H::map<Long>(Register register) -> maybe<Long&> {
|
|||
#undef a
|
||||
#undef p
|
||||
|
||||
template<> auto TLCS900H::read<Byte>(Register register) -> Byte {
|
||||
return map<Byte>(register)(0);
|
||||
template<> auto TLCS900H::load< uint8>(Register< uint8> register) -> uint8 { return map(register)(Undefined); }
|
||||
template<> auto TLCS900H::load<uint16>(Register<uint16> register) -> uint16 { return map(register)(Undefined); }
|
||||
template<> auto TLCS900H::load<uint32>(Register<uint32> register) -> uint32 { return map(register)(Undefined); }
|
||||
|
||||
template<> auto TLCS900H::store< uint8>(Register< uint8> register, uint32 data) -> void { if(auto r = map(register)) r() = 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::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;
|
||||
case 1: return r.cp << 0 | r.np << 1 | r.vp << 2 | r.hp << 4 | r.zp << 6 | r.sp << 7;
|
||||
} unreachable;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::read<Word>(Register register) -> Word {
|
||||
return map<Word>(register)(0);
|
||||
auto TLCS900H::store(FlagRegister f, uint8 data) -> void {
|
||||
switch(f.id) {
|
||||
case 0: r.c = data.bit(0); r.n = data.bit(1); r.v = data.bit(2); r.h = data.bit(4); r.z = data.bit(6); r.s = data.bit(7); return;
|
||||
case 1: r.cp = data.bit(0); r.np = data.bit(1); r.vp = data.bit(2); r.hp = data.bit(4); r.zp = data.bit(6); r.sp = data.bit(7); return;
|
||||
} unreachable;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::read<Long>(Register register) -> Long {
|
||||
return map<Long>(register)(0);
|
||||
auto TLCS900H::load(StatusRegister) -> uint16 {
|
||||
return load(F) | r.rfp << 8 | 1 << 11 | r.iff << 12 | 1 << 15;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::write<Byte>(Register register, Byte data) -> void {
|
||||
if(auto r = map<Byte>(register)) r() = data;
|
||||
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;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::write<Word>(Register register, Word data) -> void {
|
||||
if(auto r = map<Word>(register)) r() = data;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::write<Long>(Register register, Long data) -> void {
|
||||
if(auto r = map<Long>(register)) r() = data;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
//todo: this is pretty hacky ... the templates pass by-value, but we need to modify the status register
|
||||
//since there's only one, we ignore the parameter and access the underlying register directly instead
|
||||
|
||||
template<> auto TLCS900H::read<Word>(StatusRegister) -> Word {
|
||||
return r.sr.f.c << 0 | r.sr.f.n << 1 | r.sr.f.v << 2 | r.sr.f.h << 4 | r.sr.f.z << 6 | r.sr.f.s << 7
|
||||
| r.sr.rfp << 8 | 1 << 11 | r.sr.iff << 12 | 1 << 15;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::write<Word>(StatusRegister, Word data) -> void {
|
||||
r.sr.f.c = data.bit(0);
|
||||
r.sr.f.n = data.bit(1);
|
||||
r.sr.f.v = data.bit(2);
|
||||
r.sr.f.h = data.bit(4);
|
||||
r.sr.f.z = data.bit(6);
|
||||
r.sr.f.s = data.bit(7);
|
||||
r.sr.rfp = data.bits(8,9);
|
||||
r.sr.iff = data.bits(12,14);
|
||||
|
||||
r.sr.rfpp = r.sr.rfp - 1;
|
||||
}
|
||||
|
||||
//todo: the same thing for the flag register
|
||||
|
||||
template<> auto TLCS900H::read<Byte>(FlagRegister) -> Byte {
|
||||
return r.sr.f.c << 0 | r.sr.f.n << 1 | r.sr.f.v << 2 | r.sr.f.h << 4 | r.sr.f.z << 6 | r.sr.f.s << 7;
|
||||
}
|
||||
|
||||
template<> auto TLCS900H::write<Byte>(FlagRegister, Byte data) -> void {
|
||||
r.sr.f.c = data.bit(0);
|
||||
r.sr.f.n = data.bit(1);
|
||||
r.sr.f.v = data.bit(2);
|
||||
r.sr.f.h = data.bit(4);
|
||||
r.sr.f.z = data.bit(6);
|
||||
r.sr.f.s = data.bit(7);
|
||||
}
|
||||
auto TLCS900H::load(ProgramCounter) -> uint32 { return r.pc.l.l0; }
|
||||
auto TLCS900H::store(ProgramCounter, uint32 data) -> void { r.pc.l.l0 = data; }
|
||||
|
|
|
@ -3,14 +3,6 @@
|
|||
|
||||
namespace Processor {
|
||||
|
||||
using Byte = uint8;
|
||||
using Word = uint16;
|
||||
using Long = uint32;
|
||||
|
||||
template<typename Size> static constexpr auto isByte() -> bool { return is_same<Size, Byte>::value; }
|
||||
template<typename Size> static constexpr auto isWord() -> bool { return is_same<Size, Word>::value; }
|
||||
template<typename Size> static constexpr auto isLong() -> bool { return is_same<Size, Long>::value; }
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "conditions.cpp"
|
||||
|
@ -19,8 +11,13 @@ template<typename Size> static constexpr auto isLong() -> bool { return is_same<
|
|||
#include "instructions.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
TLCS900H tlcs900h;
|
||||
|
||||
auto TLCS900H::power() -> void {
|
||||
r = {};
|
||||
}
|
||||
|
||||
TLCS900H::TLCS900H() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 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 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?
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
@ -12,104 +14,94 @@
|
|||
namespace Processor {
|
||||
|
||||
struct TLCS900H {
|
||||
using Byte = uint8;
|
||||
using Word = uint16;
|
||||
using Long = uint32;
|
||||
virtual auto read(uint32 address) -> uint8 { return 0; }
|
||||
virtual auto write(uint32 address, uint8 data) -> void {};
|
||||
|
||||
struct Register { Byte value; };
|
||||
struct Memory { Long value; };
|
||||
struct Immediate { Long value; };
|
||||
TLCS900H();
|
||||
|
||||
struct DataRegister {
|
||||
union {
|
||||
struct { Long order_lsb1(l0); } l;
|
||||
struct { Word order_lsb2(w0, w1); } w;
|
||||
struct { Byte order_lsb4(b0, b1, b2, b3); } b;
|
||||
};
|
||||
};
|
||||
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 {
|
||||
uint1 c; //carry
|
||||
uint1 n; //negative
|
||||
uint1 v; //overflow / parity
|
||||
uint1 h; //half carry
|
||||
uint1 z; //zero
|
||||
uint1 s; //sign
|
||||
};
|
||||
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 {
|
||||
uint2 rfp; //register file pointer
|
||||
uint2 rfpp; //register file pointer - 1
|
||||
uint3 iff = 7; //interrupt mask flip-flop
|
||||
FlagRegister f;
|
||||
FlagRegister fp;
|
||||
};
|
||||
|
||||
virtual auto read(uint32 address) -> uint8 = 0;
|
||||
virtual auto write(uint32 address, uint8 data) -> void = 0;
|
||||
|
||||
template<typename Size> auto read(Immediate immediate) -> Size { return immediate.value; }
|
||||
template<typename T> auto load(Immediate<T> immediate) const -> T { return immediate.constant; }
|
||||
|
||||
//tlcs900h.cpp
|
||||
auto power() -> void;
|
||||
|
||||
//registers.cpp
|
||||
template<typename Size> auto map(Register register) -> maybe<Size&>;
|
||||
template<typename Size> auto read(Register) -> Size;
|
||||
template<typename Size> auto write(Register, Size data) -> void;
|
||||
template<typename Size> auto read(StatusRegister) -> Size;
|
||||
template<typename Size> auto write(StatusRegister, Size) -> void;
|
||||
template<typename Size> auto read(FlagRegister) -> Size;
|
||||
template<typename Size> auto write(FlagRegister, Size) -> void;
|
||||
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 load(FlagRegister) -> uint8;
|
||||
auto store(FlagRegister, uint8) -> void;
|
||||
auto load(StatusRegister) -> uint16;
|
||||
auto store(StatusRegister, uint16) -> void;
|
||||
auto load(ProgramCounter) -> uint32;
|
||||
auto store(ProgramCounter, uint32) -> void;
|
||||
|
||||
//memory.cpp
|
||||
template<typename Size = Byte> auto fetch() -> Size;
|
||||
template<typename Size> auto push(Size) -> void;
|
||||
template<typename Size> auto pop() -> Size;
|
||||
template<typename Size> auto read(Memory memory) -> Size;
|
||||
template<typename Size> auto write(Memory memory, Size data) -> void;
|
||||
template<typename T = uint8> auto fetch() -> T;
|
||||
template<typename T> auto push(T) -> void;
|
||||
template<typename T> auto pop(T) -> void;
|
||||
template<typename T> auto load(Memory<T>) -> T;
|
||||
template<typename T> auto store(Memory<T>, uint32) -> void;
|
||||
|
||||
//conditions.cpp
|
||||
auto condition(uint4 code) -> bool;
|
||||
|
||||
//algorithms.cpp
|
||||
template<typename Size> auto parity(Size) const -> bool;
|
||||
template<typename Size> auto algorithmAdd(Size target, Size source, uint1 carry = 0) -> Size;
|
||||
template<typename Size> auto algorithmAnd(Size target, Size source) -> Size;
|
||||
template<typename Size> auto algorithmOr(Size target, Size source) -> Size;
|
||||
template<typename Size> auto algorithmSubtract(Size target, Size source, uint1 carry = 0) -> Size;
|
||||
template<typename Size> auto algorithmXor(Size target, Size source) -> Size;
|
||||
template<typename T> auto parity(T) const -> bool;
|
||||
template<typename T> auto algorithmAdd(T target, T source, uint1 carry = 0) -> T;
|
||||
template<typename T> auto algorithmAnd(T target, T source) -> T;
|
||||
template<typename T> auto algorithmOr(T target, T source) -> T;
|
||||
template<typename T> auto algorithmSubtract(T target, T source, uint1 carry = 0) -> T;
|
||||
template<typename T> auto algorithmXor(T target, T source) -> T;
|
||||
|
||||
//instruction.cpp
|
||||
template<typename Size> auto registerLookup(uint3 code) -> Register;
|
||||
|
||||
template<typename T> auto registers(uint3) const -> Register<T>;
|
||||
auto instruction() -> void;
|
||||
template<typename Size> auto instructionRegister(Register) -> void;
|
||||
template<typename Size> auto instructionSourceMemory(Memory) -> void;
|
||||
auto instructionTargetMemory(Memory) -> void;
|
||||
template<typename Register> auto instructionRegister(Register) -> void;
|
||||
template<typename Memory> auto instructionSourceMemory(Memory) -> void;
|
||||
auto instructionTargetMemory(uint32 address) -> void;
|
||||
|
||||
//instructions.cpp
|
||||
template<typename Size, typename Target, typename Source> auto instructionAdd(Target target, Source source) -> void;
|
||||
template<typename Size, typename Target, typename Source> auto instructionAddCarry(Target target, Source source) -> void;
|
||||
template<typename Size, typename Target, typename Source> auto instructionAnd(Target target, Source source) -> void;
|
||||
template<typename Size, typename Target, typename Source> auto instructionCompare(Target target, Source source) -> void;
|
||||
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 Source> auto instructionCall(uint4 code, Source) -> void;
|
||||
template<typename Target, typename Source> auto instructionCompare(Target target, Source source) -> void;
|
||||
auto instructionComplementCarry() -> void;
|
||||
template<typename Size, typename Source> auto instructionJump(Source) -> void;
|
||||
template<typename Size, typename Source> auto instructionJump(uint4 code, Source) -> void;
|
||||
template<typename Size> auto instructionJumpRelative(uint4 code, Size displacement) -> void;
|
||||
template<typename Size, typename Target, typename Source> auto instructionLoad(Target target, Source source) -> void;
|
||||
template<typename Target, typename Source> auto instructionExchange(Target target, Source 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;
|
||||
auto instructionNoOperation() -> void;
|
||||
template<typename Size, typename Target, typename Source> auto instructionOr(Target target, Source source) -> void;
|
||||
template<typename Size, typename Target> auto instructionPop(Target target) -> void;
|
||||
template<typename Size, typename Source> auto instructionPush(Source source) -> 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;
|
||||
auto instructionReturnInterrupt() -> void;
|
||||
template<typename Target> auto instructionSetConditionCode(uint4 code, Target) -> void;
|
||||
auto instructionSetInterruptFlags(uint3 flags) -> void;
|
||||
auto instructionSoftwareInterrupt(uint3 interrupt) -> void;
|
||||
template<typename Size, typename Target, typename Source> auto instructionSubtract(Target target, Source source) -> void;
|
||||
template<typename Size, typename Target, typename Source> auto instructionSubtractCarry(Target target, Source source) -> void;
|
||||
template<typename Size, typename Target, typename Source> auto instructionXor(Target target, Source source) -> 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;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
union DataRegister {
|
||||
DataRegister() {}
|
||||
struct { uint32 order_lsb1(l0); } l;
|
||||
struct { uint16 order_lsb2(w0, w1); } w;
|
||||
struct { uint8 order_lsb4(b0, b1, b2, b3); } b;
|
||||
};
|
||||
|
||||
struct Registers {
|
||||
DataRegister xwa[4];
|
||||
DataRegister xbc[4];
|
||||
|
@ -120,35 +112,79 @@ struct TLCS900H {
|
|||
DataRegister xiz;
|
||||
DataRegister xsp;
|
||||
DataRegister pc;
|
||||
StatusRegister sr;
|
||||
|
||||
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
|
||||
uint3 iff = 7; //interrupt mask flip-flop
|
||||
|
||||
uint1 halted;
|
||||
} r;
|
||||
|
||||
static inline const Register A{0xe0};
|
||||
static inline const Register W{0xe1};
|
||||
static inline const Register C{0xe4};
|
||||
static inline const Register B{0xe5};
|
||||
static inline const Register E{0xe8};
|
||||
static inline const Register D{0xe9};
|
||||
static inline const Register L{0xec};
|
||||
static inline const Register H{0xed};
|
||||
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; }
|
||||
|
||||
static inline const Register WA{0xe0};
|
||||
static inline const Register BC{0xe4};
|
||||
static inline const Register DE{0xe8};
|
||||
static inline const Register HL{0xec};
|
||||
static inline const Register IX{0xf0};
|
||||
static inline const Register IY{0xf4};
|
||||
static inline const Register IZ{0xf8};
|
||||
static inline const Register SP{0xfc};
|
||||
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; }
|
||||
|
||||
static inline const Register XWA{0xe0};
|
||||
static inline const Register XBC{0xe4};
|
||||
static inline const Register XDE{0xe8};
|
||||
static inline const Register XHL{0xec};
|
||||
static inline const Register XIX{0xf0};
|
||||
static inline const Register XIY{0xf4};
|
||||
static inline const Register XIZ{0xf8};
|
||||
static inline const Register XSP{0xfc};
|
||||
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; }
|
||||
|
||||
static inline const Register< uint8> A{0xe0};
|
||||
static inline const Register< uint8> W{0xe1};
|
||||
static inline const Register< uint8> C{0xe4};
|
||||
static inline const Register< uint8> B{0xe5};
|
||||
static inline const Register< uint8> E{0xe8};
|
||||
static inline const Register< uint8> D{0xe9};
|
||||
static inline const Register< uint8> L{0xec};
|
||||
static inline const Register< uint8> H{0xed};
|
||||
|
||||
static inline const Register<uint16> WA{0xe0};
|
||||
static inline const Register<uint16> BC{0xe4};
|
||||
static inline const Register<uint16> DE{0xe8};
|
||||
static inline const Register<uint16> HL{0xec};
|
||||
static inline const Register<uint16> IX{0xf0};
|
||||
static inline const Register<uint16> IY{0xf4};
|
||||
static inline const Register<uint16> IZ{0xf8};
|
||||
static inline const Register<uint16> SP{0xfc};
|
||||
|
||||
static inline const Register<uint32> XWA{0xe0};
|
||||
static inline const Register<uint32> XBC{0xe4};
|
||||
static inline const Register<uint32> XDE{0xe8};
|
||||
static inline const Register<uint32> XHL{0xec};
|
||||
static inline const Register<uint32> XIX{0xf0};
|
||||
static inline const Register<uint32> XIY{0xf4};
|
||||
static inline const Register<uint32> XIZ{0xf8};
|
||||
static inline const Register<uint32> XSP{0xfc};
|
||||
|
||||
static inline const FlagRegister F {0};
|
||||
static inline const FlagRegister FP{1};
|
||||
|
||||
static inline const StatusRegister SR{};
|
||||
static inline const ProgramCounter PC{};
|
||||
|
||||
static inline const uint4 False{0x00};
|
||||
static inline const uint4 True {0x08};
|
||||
|
||||
static inline const uint1 Undefined = 0;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue