diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index da17fb40..da82ee62 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -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/"; diff --git a/higan/processor/tlcs900h/algorithms.cpp b/higan/processor/tlcs900h/algorithms.cpp index b3475fc3..47c5d0b7 100644 --- a/higan/processor/tlcs900h/algorithms.cpp +++ b/higan/processor/tlcs900h/algorithms.cpp @@ -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 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 data) const -> bool { return Undefined; } // -template auto TLCS900H::algorithmAdd(Size target, Size source, uint1 carry) -> Size { +template 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()) 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::value) setHalfCarry(Undefined); + setZero(T(result).zero()); + setSign(result.negative()); return result; } -template 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 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 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 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 auto TLCS900H::algorithmSubtract(Size target, Size source, uint1 carry) -> Size { +template 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()) 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::value) setHalfCarry(Undefined); + setZero(T(result).zero()); + setSign(result.negative()); return result; } -template 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 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; } diff --git a/higan/processor/tlcs900h/conditions.cpp b/higan/processor/tlcs900h/conditions.cpp index 1785cdaf..00740043 100644 --- a/higan/processor/tlcs900h/conditions.cpp +++ b/higan/processor/tlcs900h/conditions.cpp @@ -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; } diff --git a/higan/processor/tlcs900h/instruction.cpp b/higan/processor/tlcs900h/instruction.cpp index 8bca259b..9d3fd3ff 100644 --- a/higan/processor/tlcs900h/instruction.cpp +++ b/higan/processor/tlcs900h/instruction.cpp @@ -1,387 +1,379 @@ -template<> auto TLCS900H::registerLookup(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(uint3 code) -> Register { - return {0xe0 | code << 2}; //WA, BC, DE, HL, IX, IY, IZ, SP +template<> auto TLCS900H::registers(uint3 code) const -> Register { + static const Register lookup[] = {WA, BC, DE, HL, IX, IY, IZ, SP}; + return lookup[code]; } -template<> auto TLCS900H::registerLookup(uint3 code) -> Register { - return {0xe0 | code << 2}; //XWA, XBC, XDE, XHL, XIX, XIY, XIZ, XSP +template<> auto TLCS900H::registers(uint3 code) const -> Register { + static const Register 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(r.sr); - case 0x03: return instructionPop(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(Immediate{fetch()}); - case 0x0b: return instructionPush(Immediate{fetch()}); + 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{fetch()}); case 0x12: return instructionComplementCarry(); - case 0x14: return instructionPush(A); - case 0x15: return instructionPop(A); - case 0x18: return instructionPush(r.sr.f); - case 0x19: return instructionPop(r.sr.f); - case 0x1a: return instructionJump(Immediate{fetch()}); - case 0x1b: return instructionJump(Immediate{fetch()}); + 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{fetch()}); + case 0x1b: return instructionJump(True, Immediate{fetch()}); + case 0x1c: return instructionCall(True, Immediate{fetch()}); + case 0x1d: return instructionCall(True, Immediate{fetch()}); case 0x1f: return (void)Undefined; - case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: - return instructionLoad(registerLookup(data), Immediate{fetch()}); - + return instructionLoad(registers(data), Immediate{fetch()}); case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: - return instructionPush(registerLookup(data)); - + return instructionPush(registers(data)); case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: - return instructionLoad(registerLookup(data), Immediate{fetch()}); - + return instructionLoad(registers(data), Immediate{fetch()}); case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: - return instructionPush(registerLookup(data)); - + return instructionPush(registers(data)); case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: - return instructionLoad(registerLookup(data), Immediate{fetch()}); - + return instructionLoad(registers(data), Immediate{fetch()}); case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: - return instructionPop(registerLookup(data)); - + return instructionPop(registers(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(registerLookup(data)); - + return instructionPop(registers(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{fetch()}); 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()); - + return instructionJumpRelative((uint4)data, Immediate{fetch()}); case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: - memory = {read(register)}; - return instructionSourceMemory(memory); - + return instructionSourceMemory(Memory{load(registers(data))}); case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: - memory = {read(register) + (int8)fetch()}; - return instructionSourceMemory(memory); - + return instructionSourceMemory(Memory{load(registers(data)) + fetch()}); case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: - memory = {read(register)}; - return instructionSourceMemory(memory); - + return instructionSourceMemory(Memory{load(registers(data))}); case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: - memory = {read(register) + (int8)fetch()}; - return instructionSourceMemory(memory); - + return instructionSourceMemory(Memory{load(registers(data)) + fetch()}); case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: - memory = {read(register)}; - return instructionSourceMemory(memory); - + return instructionSourceMemory(Memory{load(registers(data))}); case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: - memory = {read(register) + (int8)fetch()}; - return instructionSourceMemory(memory); - + return instructionSourceMemory(Memory{load(registers(data)) + fetch()}); case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: - memory = {read(register)}; - return instructionTargetMemory(memory); - + return instructionTargetMemory(load(registers(data))); case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: - memory = {read(register) + (int8)fetch()}; - return instructionTargetMemory(memory); - - case 0xc0: - memory = {fetch< uint8>()}; - return instructionSourceMemory(memory); - case 0xc1: - memory = {fetch()}; - return instructionSourceMemory(memory); - case 0xc2: - memory = {fetch()}; - return instructionSourceMemory(memory); - case 0xc3: + return instructionTargetMemory(load(registers(data)) + fetch()); + case 0xc0: return instructionSourceMemory(Memory{fetch< uint8>()}); + case 0xc1: return instructionSourceMemory(Memory{fetch()}); + case 0xc2: return instructionSourceMemory(Memory{fetch()}); + case 0xc3: { data = fetch(); - memory = {read(Register{data})}; - if((data & 3) == 1) memory.value += (int16)fetch(); - if((data & 3) == 2) memory.value += (int8)read(Register{fetch()}); - if((data & 3) == 3) memory.value += (int16)read(Register{fetch()}); - return instructionSourceMemory(memory); - case 0xc4: + if((data & 3) == 0) return instructionSourceMemory(Memory{load(Register{data})}); + if((data & 3) == 1) return instructionSourceMemory(Memory{load(Register{data}) + fetch()}); + if(data == 0x03) { + auto r32 = load(Register{fetch()}); + auto r8 = load(Register< uint8>{fetch()}); + return instructionSourceMemory(Memory{r32 + (int8)r8}); + } + if(data == 0x07) { + auto r32 = load(Register{fetch()}); + auto r16 = load(Register{fetch()}); + return instructionSourceMemory(Memory{r32 + (int16)r16}); + } + return (void)Undefined; } + case 0xc4: { data = fetch(); - register = {data}; - if((data & 3) == 0) write(register, read(register) - 1); - if((data & 3) == 1) write(register, read(register) - 2); - if((data & 3) == 2) write(register, read(register) - 4); + auto register = Register{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(register)}; - return instructionSourceMemory(memory); - case 0xc5: + return instructionSourceMemory(Memory{load(register)}); } + case 0xc5: { data = fetch(); - register = {data}; - memory = {read(register)}; - instructionSourceMemory(memory); - if((data & 3) == 0) write(register, read(register) + 1); - if((data & 3) == 1) write(register, read(register) + 2); - if((data & 3) == 2) write(register, read(register) + 4); + auto register = Register{data}; + instructionSourceMemory(Memory{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(register); + return; } + case 0xc6: return (void)Undefined; + case 0xc7: return instructionRegister(Register{fetch()}); case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: - register = registerLookup(data); - return instructionRegister(register); - - case 0xd0: - memory = {fetch< uint8>()}; - return instructionSourceMemory(memory); - case 0xd1: - memory = {fetch()}; - return instructionSourceMemory(memory); - case 0xd2: - memory = {fetch()}; - return instructionSourceMemory(memory); - case 0xd3: + return instructionRegister(registers(data)); + case 0xd0: return instructionSourceMemory(Memory{fetch< uint8>()}); + case 0xd1: return instructionSourceMemory(Memory{fetch()}); + case 0xd2: return instructionSourceMemory(Memory{fetch()}); + case 0xd3: { data = fetch(); - memory = {read(Register{data})}; - if((data & 3) == 1) memory.value += (int16)fetch(); - if((data & 3) == 2) memory.value += (int8)read(Register{fetch()}); - if((data & 3) == 3) memory.value += (int16)read(Register{fetch()}); - return instructionSourceMemory(memory); - case 0xd4: + if((data & 3) == 0) return instructionSourceMemory(Memory{load(Register{data})}); + if((data & 3) == 1) return instructionSourceMemory(Memory{load(Register{data}) + fetch()}); + if(data == 0x03) { + auto r32 = load(Register{fetch()}); + auto r8 = load(Register< uint8>{fetch()}); + return instructionSourceMemory(Memory{r32 + (int8)r8}); + } + if(data == 0x07) { + auto r32 = load(Register{fetch()}); + auto r16 = load(Register{fetch()}); + return instructionSourceMemory(Memory{r32 + (int16)r16}); + } + return (void)Undefined; } + case 0xd4: { data = fetch(); - register = {data}; - if((data & 3) == 0) write(register, read(register) - 1); - if((data & 3) == 1) write(register, read(register) - 2); - if((data & 3) == 2) write(register, read(register) - 4); + auto register = Register{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(register)}; - return instructionSourceMemory(memory); - case 0xd5: + return instructionSourceMemory(Memory{load(register)}); } + case 0xd5: { data = fetch(); - register = {data}; - memory = {read(register)}; - instructionSourceMemory(memory); - if((data & 3) == 0) write(register, read(register) + 1); - if((data & 3) == 1) write(register, read(register) + 2); - if((data & 3) == 2) write(register, read(register) + 4); + auto register = Register{data}; + instructionSourceMemory(Memory{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(register); + return; } + case 0xd6: return (void)Undefined; + case 0xd7: return instructionRegister(Register{fetch()}); case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: - register = registerLookup(data); - return instructionRegister(register); - - case 0xe0: - memory = {fetch< uint8>()}; - return instructionSourceMemory(memory); - case 0xe1: - memory = {fetch()}; - return instructionSourceMemory(memory); - case 0xe2: - memory = {fetch()}; - return instructionSourceMemory(memory); - case 0xe3: + return instructionRegister(registers(data)); + case 0xe0: return instructionSourceMemory(Memory{fetch()}); + case 0xe1: return instructionSourceMemory(Memory{fetch()}); + case 0xe2: return instructionSourceMemory(Memory{fetch()}); + case 0xe3: { data = fetch(); - memory = {read(Register{data})}; - if((data & 3) == 1) memory.value += (int16)fetch(); - if((data & 3) == 2) memory.value += (int8)read(Register{fetch()}); - if((data & 3) == 3) memory.value += (int16)read(Register{fetch()}); - return instructionSourceMemory(memory); - case 0xe4: + if((data & 3) == 0) return instructionSourceMemory(Memory{load(Register{data})}); + if((data & 3) == 1) return instructionSourceMemory(Memory{load(Register{data}) + fetch()}); + if(data == 0x03) { + auto r32 = load(Register{fetch()}); + auto r8 = load(Register< uint8>{fetch()}); + return instructionSourceMemory(Memory{r32 + (int8)r8}); + } + if(data == 0x07) { + auto r32 = load(Register{fetch()}); + auto r16 = load(Register< uint8>{fetch()}); + return instructionSourceMemory(Memory{r32 + (int16)r16}); + } + return (void)Undefined; } + case 0xe4: { data = fetch(); - register = {data}; - if((data & 3) == 0) write(register, read(register) - 1); - if((data & 3) == 1) write(register, read(register) - 2); - if((data & 3) == 2) write(register, read(register) - 4); + auto register = Register{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(register)}; - return instructionSourceMemory(memory); - case 0xe5: + return instructionSourceMemory(Memory{load(register)}); } + case 0xe5: { data = fetch(); - register = {data}; - memory = {read(register)}; - instructionSourceMemory(memory); - if((data & 3) == 0) write(register, read(register) + 1); - if((data & 3) == 1) write(register, read(register) + 2); - if((data & 3) == 2) write(register, read(register) + 4); + auto register = Register{data}; + instructionSourceMemory(Memory{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(register); + return; } + case 0xe6: return (void)Undefined; + case 0xe7: return instructionRegister(Register{fetch()}); case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: - register = registerLookup(data); - return instructionRegister(register); - - case 0xf0: - memory = {fetch< uint8>()}; - return instructionTargetMemory(memory); - case 0xf1: - memory = {fetch()}; - return instructionTargetMemory(memory); - case 0xf2: - memory = {fetch()}; - return instructionTargetMemory(memory); - case 0xf3: + return instructionRegister(registers(data)); + case 0xf0: return instructionTargetMemory(fetch()); + case 0xf1: return instructionTargetMemory(fetch()); + case 0xf2: return instructionTargetMemory(fetch()); + case 0xf3: { data = fetch(); - memory = {read(Register{data})}; - if((data & 3) == 1) memory.value += (int16)fetch(); - if((data & 3) == 2) memory.value += (int8)read(Register{fetch()}); - if((data & 3) == 3) memory.value += (int16)read(Register{fetch()}); - return instructionTargetMemory(memory); - case 0xf4: + if((data & 3) == 0) return instructionTargetMemory(load(Register{data})); + if((data & 3) == 1) return instructionTargetMemory(load(Register{data}) + fetch()); + if(data == 0x03) { + auto r32 = load(Register{fetch()}); + auto r8 = load(Register< uint8>{fetch()}); + return instructionTargetMemory(r32 + (int8)r8); + } + if(data == 0x07) { + auto r32 = load(Register{fetch()}); + auto r16 = load(Register{fetch()}); + return instructionTargetMemory(r32 + (int16)r16); + } + return (void)Undefined; } + case 0xf4: { data = fetch(); - register = {data}; - if((data & 3) == 0) write(register, read(register) - 1); - if((data & 3) == 1) write(register, read(register) - 2); - if((data & 3) == 2) write(register, read(register) - 4); + auto register = Register{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(register)}; - return instructionTargetMemory(memory); - case 0xf5: + return instructionTargetMemory(load(register)); } + case 0xf5: { data = fetch(); - register = {data}; - memory = {read(register)}; - instructionTargetMemory(memory); - if((data & 3) == 0) write(register, read(register) + 1); - if((data & 3) == 1) write(register, read(register) + 2); - if((data & 3) == 2) write(register, read(register) + 4); + auto register = Register{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 -auto TLCS900H::instructionRegister(Register register) -> void { +template +auto TLCS900H::instructionRegister(R register) -> void { + using type = typename R::type; auto data = fetch(); switch(data) { - case 0x04: return instructionPush(register); - case 0x05: return instructionPop(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(registerLookup(data), register); + return instructionAdd(registers(data), register); case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: - return instructionLoad(registerLookup(data), register); + return instructionLoad(registers(data), register); case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: - return instructionAddCarry(registerLookup(data), register); + return instructionAddCarry(registers(data), register); case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: - return instructionLoad(register, registerLookup(data)); + return instructionLoad(register, registers(data)); case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: - return instructionSubtract(registerLookup(data), register); + return instructionSubtract(registers(data), register); case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: - return instructionLoad(register, Immediate{data.bits(0,2)}); + return instructionLoad(register, Immediate{(uint3)data}); case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: - return instructionSubtractCarry(registerLookup(data), register); + return instructionSubtractCarry(registers(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(data), register); case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: - return instructionAnd(registerLookup(data), register); - case 0xc8: return instructionAdd(register, Immediate{fetch()}); - case 0xc9: return instructionAddCarry(register, Immediate{fetch()}); - case 0xca: return instructionSubtract(register, Immediate{fetch()}); - case 0xcb: return instructionSubtractCarry(register, Immediate{fetch()}); - case 0xcc: return instructionAnd(register, Immediate{fetch()}); - case 0xcd: return instructionXor(register, Immediate{fetch()}); - case 0xce: return instructionOr(register, Immediate{fetch()}); - case 0xcf: return instructionCompare(register, Immediate{fetch()}); + return instructionAnd(registers(data), register); + case 0xc8: return instructionAdd(register, Immediate{fetch()}); + case 0xc9: return instructionAddCarry(register, Immediate{fetch()}); + case 0xca: return instructionSubtract(register, Immediate{fetch()}); + case 0xcb: return instructionSubtractCarry(register, Immediate{fetch()}); + case 0xcc: return instructionAnd(register, Immediate{fetch()}); + case 0xcd: return instructionXor(register, Immediate{fetch()}); + case 0xce: return instructionOr(register, Immediate{fetch()}); + case 0xcf: return instructionCompare(register, Immediate{fetch()}); case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: - return instructionXor(registerLookup(data), register); + return instructionXor(registers(data), register); case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: - return instructionCompare(register, Immediate{data.bits(0,2)}); + return instructionCompare(register, Immediate{(uint3)data}); case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: - return instructionOr(registerLookup(data), register); + return instructionOr(registers(data), register); case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: - return instructionCompare(registerLookup(data), register); + return instructionCompare(registers(data), register); } } -template -auto TLCS900H::instructionSourceMemory(Memory memory) -> void { +template +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()) return (void)Undefined; - return instructionPush(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()) return (void)Undefined; - return instructionLoad(Memory{fetch()}, memory); + case 0x19: + if constexpr(M::bits == 32) return (void)Undefined; + return instructionLoad(Memory{fetch()}, 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(registerLookup(data), memory); + return instructionLoad(registers(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()) return (void)Undefined; - return instructionAdd(memory, Immediate{fetch()}); - case 0x39: if constexpr(isLong()) return (void)Undefined; - return instructionAddCarry(memory, Immediate{fetch()}); - case 0x3a: if constexpr(isLong()) return (void)Undefined; - return instructionSubtract(memory, Immediate{fetch()}); - case 0x3b: if constexpr(isLong()) return (void)Undefined; - return instructionSubtractCarry(memory, Immediate{fetch()}); + 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(data)); + case 0x38: + if constexpr(M::bits == 32) return (void)Undefined; + return instructionAdd(memory, Immediate{fetch()}); + case 0x39: + if constexpr(M::bits == 32) return (void)Undefined; + return instructionAddCarry(memory, Immediate{fetch()}); + case 0x3a: + if constexpr(M::bits == 32) return (void)Undefined; + return instructionSubtract(memory, Immediate{fetch()}); + case 0x3b: + if constexpr(M::bits == 32) return (void)Undefined; + return instructionSubtractCarry(memory, Immediate{fetch()}); case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: - return instructionAdd(registerLookup(data), memory); + return instructionAdd(registers(data), memory); case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: - return instructionAdd(memory, registerLookup(data)); + return instructionAdd(memory, registers(data)); case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: - return instructionAddCarry(registerLookup(data), memory); + return instructionAddCarry(registers(data), memory); case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: - return instructionAddCarry(memory, registerLookup(data)); + return instructionAddCarry(memory, registers(data)); case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: - return instructionSubtract(registerLookup(data), memory); + return instructionSubtract(registers(data), memory); case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: - return instructionSubtract(memory, registerLookup(data)); + return instructionSubtract(memory, registers(data)); case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: - return instructionSubtractCarry(registerLookup(data), memory); + return instructionSubtractCarry(registers(data), memory); case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: - return instructionSubtractCarry(memory, registerLookup(data)); + return instructionSubtractCarry(memory, registers(data)); case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: - return instructionAnd(registerLookup(data), memory); + return instructionAnd(registers(data), memory); case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: - return instructionAnd(memory, registerLookup(data)); + return instructionAnd(memory, registers(data)); case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: - return instructionXor(registerLookup(data), memory); + return instructionXor(registers(data), memory); case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: - return instructionXor(memory, registerLookup(data)); + return instructionXor(memory, registers(data)); case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: - return instructionOr(registerLookup(data), memory); + return instructionOr(registers(data), memory); case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: - return instructionOr(memory, registerLookup(data)); + return instructionOr(memory, registers(data)); case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: - return instructionCompare(registerLookup(data), memory); + return instructionCompare(registers(data), memory); case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: - return instructionCompare(memory, registerLookup(data)); + return instructionCompare(memory, registers(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(memory); + case 0x04: return instructionPop(Memory{address}); case 0x05: return (void)Undefined; - case 0x06: return instructionPop(memory); + case 0x06: return instructionPop(Memory{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(registerLookup(data), memory); + return instructionLoad(registers(data), Memory{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(registerLookup(data), memory); + return instructionLoad(registers(data), Memory{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, registerLookup(data)); + return instructionLoad(Memory{address}, registers(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, registerLookup(data)); + return instructionLoad(Memory{address}, registers(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, registerLookup(data)); + return instructionLoad(Memory{address}, registers(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(data.bits(0,3), memory); + return instructionJump((uint4)data, Memory{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{address}); } } diff --git a/higan/processor/tlcs900h/instructions.cpp b/higan/processor/tlcs900h/instructions.cpp index a5b01cff..b29dfaac 100644 --- a/higan/processor/tlcs900h/instructions.cpp +++ b/higan/processor/tlcs900h/instructions.cpp @@ -1,90 +1,108 @@ -#define read read -#define write write -#define push push -#define pop pop -#define algorithm(name, ...) algorithm##name(__VA_ARGS__) - -template +template auto TLCS900H::instructionAdd(Target target, Source source) -> void { - write(target, algorithm(Add, read(target), read(source))); + store(target, algorithmAdd(load(target), load(source))); } -template +template 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 +template auto TLCS900H::instructionAnd(Target target, Source source) -> void { - write(target, algorithm(And, read(target), read(source))); + store(target, algorithmAnd(load(target), load(source))); } -template +template +auto TLCS900H::instructionCall(uint4 code, Source source) -> void { + auto address = load(source); + if(condition(code)) push(PC), store(PC, address); +} + +template 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 auto TLCS900H::instructionJump(Source source) -> void { - PC = read(source); +template +auto TLCS900H::instructionExchange(Target target, Source source) -> void { + auto data = load(target); + store(target, load(source)); + store(source, data); } -template auto TLCS900H::instructionJump(uint4 code, Source source) -> void { - auto address = read(source); - if(condition(code)) PC = address; +auto TLCS900H::instructionHalt() -> void { + setHalted(true); } -template auto TLCS900H::instructionJumpRelative(uint4 code, Size displacement) -> void { - if(condition(code)) PC += displacement; +template +auto TLCS900H::instructionJump(uint4 code, Source source) -> void { + auto address = load(source); + if(condition(code)) store(PC, address); } -template +template +auto TLCS900H::instructionJumpRelative(uint4 code, Source displacement) -> void { + if(condition(code)) store(PC, load(PC) + load(displacement)); +} + +template auto TLCS900H::instructionLoad(Target target, Source source) -> void { - write(target, read(source)); + store(target, load(source)); } auto TLCS900H::instructionNoOperation() -> void { } -template +template auto TLCS900H::instructionOr(Target target, Source source) -> void { - write(target, algorithm(Or, read(target), read(source))); + store(target, algorithmOr(load(target), load(source))); } -template +template auto TLCS900H::instructionPop(Target target) -> void { - write(target, pop()); + pop(target); } -template +template auto TLCS900H::instructionPush(Source source) -> void { - push(read(source)); + push(source); +} + +auto TLCS900H::instructionReturnInterrupt() -> void { + pop(SR); + pop(PC); + //TODO: decrement INTNEST here +} + +template +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 +template auto TLCS900H::instructionSubtract(Target target, Source source) -> void { - write(target, algorithm(Subtract, read(target), read(source))); + store(target, algorithmSubtract(load(target), load(source))); } -template +template 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 +template 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 diff --git a/higan/processor/tlcs900h/memory.cpp b/higan/processor/tlcs900h/memory.cpp index 97cadf95..ae24c82f 100644 --- a/higan/processor/tlcs900h/memory.cpp +++ b/higan/processor/tlcs900h/memory.cpp @@ -1,23 +1,23 @@ -template<> auto TLCS900H::fetch() -> Byte { - return 0x00; +template<> auto TLCS900H::fetch< uint8>() -> uint8 { + return rand(); } -template<> auto TLCS900H::fetch() -> Word { - uint16 data = fetch(); - return data | fetch() << 8; +template<> auto TLCS900H::fetch() -> uint16 { + uint16 data = fetch(); + return data | fetch() << 8; } template<> auto TLCS900H::fetch() -> uint24 { - uint24 data = fetch(); - data |= fetch() << 8; - return data |= fetch() << 16; + uint24 data = fetch(); + data |= fetch() << 8; + return data |= fetch() << 16; } -template<> auto TLCS900H::fetch() -> Long { - uint32 data = fetch(); - data |= fetch() << 8; - data |= fetch() << 16; - return data |= fetch() << 24; +template<> auto TLCS900H::fetch() -> uint32 { + uint32 data = fetch(); + data |= fetch() << 8; + data |= fetch() << 16; + return data |= fetch() << 24; } template<> auto TLCS900H::fetch< int8>() -> int8 { return ( int8)fetch< uint8>(); } @@ -29,78 +29,55 @@ template<> auto TLCS900H::fetch() -> int32 { return (int32)fetch( #define XSP r.xsp.l.l0 -template<> auto TLCS900H::push(Byte data) -> void { - write(--XSP, data); +template 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 data) -> void { - write(--XSP, data >> 0); - write(--XSP, data >> 8); -} - -template<> auto TLCS900H::push(Long data) -> void { - write(--XSP, data >> 0); - write(--XSP, data >> 8); - write(--XSP, data >> 16); - write(--XSP, data >> 24); -} - -// - -template<> auto TLCS900H::pop() -> Byte { - return read(XSP++); -} - -template<> auto TLCS900H::pop() -> Word { - uint16 data = read(XSP++) << 0; - return data | read(XSP++) << 8; -} - -template<> auto TLCS900H::pop() -> Long { - uint32 data = read(XSP++) << 0; - data |= read(XSP++) << 8; - data |= read(XSP++) << 16; - return data |= read(XSP++) << 24; +template 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(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(Memory memory) -> uint16 { - uint32 address = memory.value; - uint16 data = read(address + 0) << 0; - return data | read(address + 1) << 8; +template<> auto TLCS900H::load(Memory memory) -> uint16 { + uint16 data = read(memory.address + 0) << 0; + return data | read(memory.address + 1) << 8; } -template<> auto TLCS900H::read(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 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(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(Memory memory, uint16 data) -> void { - uint32 address = memory.value; - write(address + 0, data >> 0); - write(address + 1, data >> 8); +template<> auto TLCS900H::store(Memory memory, uint32 data) -> void { + write(memory.address + 0, data >> 0); + write(memory.address + 1, data >> 8); } -template<> auto TLCS900H::write(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 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); } diff --git a/higan/processor/tlcs900h/registers.cpp b/higan/processor/tlcs900h/registers.cpp index a042df74..32637483 100644 --- a/higan/processor/tlcs900h/registers.cpp +++ b/higan/processor/tlcs900h/registers.cpp @@ -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(Register register) -> maybe { - switch(register.value) { +template<> auto TLCS900H::map(Register register) -> maybe { + 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(Register register) -> maybe { return nothing; } -template<> auto TLCS900H::map(Register register) -> maybe { - switch(register.value & ~1) { +template<> auto TLCS900H::map(Register register) -> maybe { + 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(Register register) -> maybe { return nothing; } -template<> auto TLCS900H::map(Register register) -> maybe { - switch(register.value & ~3) { +template<> auto TLCS900H::map(Register register) -> maybe { + 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(Register register) -> maybe { #undef a #undef p -template<> auto TLCS900H::read(Register register) -> Byte { - return map(register)(0); +template<> auto TLCS900H::load< uint8>(Register< uint8> register) -> uint8 { return map(register)(Undefined); } +template<> auto TLCS900H::load(Register register) -> uint16 { return map(register)(Undefined); } +template<> auto TLCS900H::load(Register 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(Register register, uint32 data) -> void { if(auto r = map(register)) r() = data; } +template<> auto TLCS900H::store(Register 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(Register register) -> Word { - return map(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(Register register) -> Long { - return map(register)(0); +auto TLCS900H::load(StatusRegister) -> uint16 { + return load(F) | r.rfp << 8 | 1 << 11 | r.iff << 12 | 1 << 15; } -template<> auto TLCS900H::write(Register register, Byte data) -> void { - if(auto r = map(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(Register register, Word data) -> void { - if(auto r = map(register)) r() = data; -} - -template<> auto TLCS900H::write(Register register, Long data) -> void { - if(auto r = map(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(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(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(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(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; } diff --git a/higan/processor/tlcs900h/tlcs900h.cpp b/higan/processor/tlcs900h/tlcs900h.cpp index f4425c3a..b09b5502 100644 --- a/higan/processor/tlcs900h/tlcs900h.cpp +++ b/higan/processor/tlcs900h/tlcs900h.cpp @@ -3,14 +3,6 @@ namespace Processor { -using Byte = uint8; -using Word = uint16; -using Long = uint32; - -template static constexpr auto isByte() -> bool { return is_same::value; } -template static constexpr auto isWord() -> bool { return is_same::value; } -template static constexpr auto isLong() -> bool { return is_same::value; } - #include "registers.cpp" #include "memory.cpp" #include "conditions.cpp" @@ -19,8 +11,13 @@ template static constexpr auto isLong() -> bool { return is_same< #include "instructions.cpp" #include "serialization.cpp" +TLCS900H tlcs900h; + auto TLCS900H::power() -> void { r = {}; } +TLCS900H::TLCS900H() { +} + } diff --git a/higan/processor/tlcs900h/tlcs900h.hpp b/higan/processor/tlcs900h/tlcs900h.hpp index 96e2578f..509d026b 100644 --- a/higan/processor/tlcs900h/tlcs900h.hpp +++ b/higan/processor/tlcs900h/tlcs900h.hpp @@ -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 struct Register { using type = T; enum : uint { bits = 8 * sizeof(T) }; uint8 id; }; + template struct Memory { using type = T; enum : uint { bits = 8 * sizeof(T) }; T address; }; + template 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 auto read(Immediate immediate) -> Size { return immediate.value; } + template auto load(Immediate immediate) const -> T { return immediate.constant; } //tlcs900h.cpp auto power() -> void; //registers.cpp - template auto map(Register register) -> maybe; - template auto read(Register) -> Size; - template auto write(Register, Size data) -> void; - template auto read(StatusRegister) -> Size; - template auto write(StatusRegister, Size) -> void; - template auto read(FlagRegister) -> Size; - template auto write(FlagRegister, Size) -> void; + template auto map(Register) -> maybe; + template auto load(Register) -> T; + template auto store(Register, 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 auto fetch() -> Size; - template auto push(Size) -> void; - template auto pop() -> Size; - template auto read(Memory memory) -> Size; - template auto write(Memory memory, Size data) -> void; + template auto fetch() -> T; + template auto push(T) -> void; + template auto pop(T) -> void; + template auto load(Memory) -> T; + template auto store(Memory, uint32) -> void; //conditions.cpp auto condition(uint4 code) -> bool; //algorithms.cpp - template auto parity(Size) const -> bool; - template auto algorithmAdd(Size target, Size source, uint1 carry = 0) -> Size; - template auto algorithmAnd(Size target, Size source) -> Size; - template auto algorithmOr(Size target, Size source) -> Size; - template auto algorithmSubtract(Size target, Size source, uint1 carry = 0) -> Size; - template auto algorithmXor(Size target, Size source) -> Size; + template auto parity(T) const -> bool; + template auto algorithmAdd(T target, T source, uint1 carry = 0) -> T; + template auto algorithmAnd(T target, T source) -> T; + template auto algorithmOr(T target, T source) -> T; + template auto algorithmSubtract(T target, T source, uint1 carry = 0) -> T; + template auto algorithmXor(T target, T source) -> T; //instruction.cpp - template auto registerLookup(uint3 code) -> Register; - + template auto registers(uint3) const -> Register; auto instruction() -> void; - template auto instructionRegister(Register) -> void; - template auto instructionSourceMemory(Memory) -> void; - auto instructionTargetMemory(Memory) -> void; + template auto instructionRegister(Register) -> void; + template auto instructionSourceMemory(Memory) -> void; + auto instructionTargetMemory(uint32 address) -> void; //instructions.cpp - template auto instructionAdd(Target target, Source source) -> void; - template auto instructionAddCarry(Target target, Source source) -> void; - template auto instructionAnd(Target target, Source source) -> void; - template auto instructionCompare(Target target, Source source) -> void; + template auto instructionAdd(Target target, Source source) -> void; + template auto instructionAddCarry(Target target, Source source) -> void; + template auto instructionAnd(Target target, Source source) -> void; + template auto instructionCall(uint4 code, Source) -> void; + template auto instructionCompare(Target target, Source source) -> void; auto instructionComplementCarry() -> void; - template auto instructionJump(Source) -> void; - template auto instructionJump(uint4 code, Source) -> void; - template auto instructionJumpRelative(uint4 code, Size displacement) -> void; - template auto instructionLoad(Target target, Source source) -> void; + template auto instructionExchange(Target target, Source source) -> void; + auto instructionHalt() -> void; + template auto instructionJump(uint4 code, Source) -> void; + template auto instructionJumpRelative(uint4 code, Source) -> void; + template auto instructionLoad(Target target, Source source) -> void; auto instructionNoOperation() -> void; - template auto instructionOr(Target target, Source source) -> void; - template auto instructionPop(Target target) -> void; - template auto instructionPush(Source source) -> void; + template auto instructionOr(Target target, Source source) -> void; + template auto instructionPop(Target target) -> void; + template auto instructionPush(Source source) -> void; + auto instructionReturnInterrupt() -> void; + template auto instructionSetConditionCode(uint4 code, Target) -> void; + auto instructionSetInterruptFlags(uint3 flags) -> void; auto instructionSoftwareInterrupt(uint3 interrupt) -> void; - template auto instructionSubtract(Target target, Source source) -> void; - template auto instructionSubtractCarry(Target target, Source source) -> void; - template auto instructionXor(Target target, Source source) -> void; + template auto instructionSubtract(Target target, Source source) -> void; + template auto instructionSubtractCarry(Target target, Source source) -> void; + template 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 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}; + + 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}; + + 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; };