diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index da82ee62..c477d834 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.74"; + static const string Version = "106.75"; 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 47c5d0b7..10fa24e7 100644 --- a/higan/processor/tlcs900h/algorithms.cpp +++ b/higan/processor/tlcs900h/algorithms.cpp @@ -21,57 +21,57 @@ template<> auto TLCS900H::parity(uint32 data) const -> bool { template auto TLCS900H::algorithmAdd(T target, T source, uint1 carry) -> T { uint64 result = target + source + carry; - setCarry(result.bit(T::bits())); - setNegative(0); - setOverflow(T(~(target ^ source) & (target ^ result)).negative()); - setHalfCarry(T(target ^ source ^ result).bit(4)); - if constexpr(is_same::value) setHalfCarry(Undefined); - setZero(T(result).zero()); - setSign(result.negative()); + CF = result.bit(T::bits()); + NF = 0; + VF = T(~(target ^ source) & (target ^ result)).negative(); + HF = T(target ^ source ^ result).bit(4); + if constexpr(is_same::value) HF = Undefined; + ZF = T(result).zero(); + SF = result.negative(); return result; } 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()); + CF = 0; + NF = 0; + PF = parity(result); + HF = 1; + ZF = result.zero(); + SF = result.negative(); return result; } 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()); + CF = 0; + NF = 0; + PF = parity(result); + HF = 0; + ZF = result.zero(); + SF = result.negative(); return result; } template auto TLCS900H::algorithmSubtract(T target, T source, uint1 carry) -> T { uint64 result = target - source - carry; - setCarry(result.bit(T::bits())); - setNegative(1); - setOverflow(T((target ^ source) & (target ^ result)).negative()); - setHalfCarry(T(target ^ source ^ result).bit(4)); - if constexpr(is_same::value) setHalfCarry(Undefined); - setZero(T(result).zero()); - setSign(result.negative()); + CF = result.bit(T::bits()); + NF = 1; + VF = T((target ^ source) & (target ^ result)).negative(); + HF = T(target ^ source ^ result).bit(4); + if constexpr(is_same::value) HF = Undefined; + ZF = T(result).zero(); + SF = result.negative(); return result; } 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()); + CF = 0; + NF = 0; + PF = parity(result); + HF = 0; + ZF = result.zero(); + SF = result.negative(); return result; } diff --git a/higan/processor/tlcs900h/conditions.cpp b/higan/processor/tlcs900h/conditions.cpp index 00740043..1785cdaf 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 (sign() ^ overflow()) == 1; //LT (signed less than) - case 2: return (zero() | (sign() ^ overflow())) == 1; //LE (signed less than or equal) - case 3: return (carry() | zero()) == 1; //ULE (unsigned less than or equal) - case 4: return overflow() == 1; //OV (overflow) - case 5: return sign() == 1; //MI (minus) - case 6: return zero() == 1; //EQ (equal) - case 7: return carry() == 1; //ULT (unsigned less than) - case 8: return 0 == 0; //T (true) - case 9: return (sign() ^ overflow()) == 0; //GE (signed greater than or equal) - case 10: return (zero() | (sign() ^ overflow())) == 0; //GT (signed greater than) - case 11: return (carry() | zero()) == 0; //UGT (unsigned greater than) - case 12: return overflow() == 0; //NOV (no overflow) - case 13: return sign() == 0; //PL (plus) - case 14: return zero() == 0; //NE (not equal) - case 15: return carry() == 0; //UGE (unsigned greater than or equal) + case 0: return 0 == 1; //F (false) + case 1: return (SF ^ VF) == 1; //LT (signed less than) + case 2: return (ZF | (SF ^ VF)) == 1; //LE (signed less than or equal) + case 3: return (CF | ZF) == 1; //ULE (unsigned less than or equal) + case 4: return VF == 1; //OV (overflow) + case 5: return SF == 1; //MI (minus) + case 6: return ZF == 1; //EQ (equal) + case 7: return CF == 1; //ULT (unsigned less than) + case 8: return 0 == 0; //T (true) + case 9: return (SF ^ VF) == 0; //GE (signed greater than or equal) + case 10: return (ZF | (SF ^ VF)) == 0; //GT (signed greater than) + case 11: return (CF | ZF) == 0; //UGT (unsigned greater than) + case 12: return VF == 0; //NOV (no overflow) + case 13: return SF == 0; //PL (plus) + case 14: return ZF == 0; //NE (not equal) + case 15: return CF == 0; //UGE (unsigned greater than or equal) } unreachable; } diff --git a/higan/processor/tlcs900h/control-registers.cpp b/higan/processor/tlcs900h/control-registers.cpp new file mode 100644 index 00000000..58270507 --- /dev/null +++ b/higan/processor/tlcs900h/control-registers.cpp @@ -0,0 +1,80 @@ +template<> auto TLCS900H::map(ControlRegister register) -> maybe { + switch(register.id) { + #define r(id, name) case id: return r.name; + r(0x00, dmas[0].b.b0) r(0x01, dmas[0].b.b1) r(0x02, dmas[0].b.b2) r(0x03, dmas[0].b.b3) + r(0x04, dmas[1].b.b0) r(0x05, dmas[1].b.b1) r(0x06, dmas[1].b.b2) r(0x07, dmas[1].b.b3) + r(0x08, dmas[2].b.b0) r(0x09, dmas[2].b.b1) r(0x0a, dmas[2].b.b2) r(0x0b, dmas[2].b.b3) + r(0x0c, dmas[3].b.b0) r(0x0d, dmas[3].b.b1) r(0x0e, dmas[3].b.b2) r(0x0f, dmas[3].b.b3) + r(0x10, dmad[0].b.b0) r(0x11, dmad[0].b.b1) r(0x12, dmad[0].b.b2) r(0x13, dmad[0].b.b3) + r(0x14, dmad[1].b.b0) r(0x15, dmad[1].b.b1) r(0x16, dmad[1].b.b2) r(0x17, dmad[1].b.b3) + r(0x18, dmad[2].b.b0) r(0x19, dmad[2].b.b1) r(0x1a, dmad[2].b.b2) r(0x1b, dmad[2].b.b3) + r(0x1c, dmad[3].b.b0) r(0x1d, dmad[3].b.b1) r(0x1e, dmad[3].b.b2) r(0x1f, dmad[3].b.b3) + r(0x20, dmam[0].b.b0) r(0x21, dmam[0].b.b1) r(0x22, dmam[0].b.b2) r(0x23, dmam[0].b.b3) + r(0x24, dmam[1].b.b0) r(0x25, dmam[1].b.b1) r(0x26, dmam[1].b.b2) r(0x27, dmam[1].b.b3) + r(0x28, dmam[2].b.b0) r(0x29, dmam[2].b.b1) r(0x2a, dmam[2].b.b2) r(0x2b, dmam[2].b.b3) + r(0x2c, dmam[3].b.b0) r(0x2d, dmam[3].b.b1) r(0x2e, dmam[3].b.b3) r(0x2f, dmam[3].b.b3) + r(0x3c, intnest.b.b0) r(0x3d, intnest.b.b1) + #undef r + } + return nothing; +} + +template<> auto TLCS900H::map(ControlRegister register) -> maybe { + switch(register.id & ~1) { + #define r(id, name) case id: return r.name; + r(0x00, dmas[0].w.w0) r(0x02, dmas[0].w.w1) + r(0x04, dmas[1].w.w0) r(0x06, dmas[1].w.w1) + r(0x08, dmas[2].w.w0) r(0x0a, dmas[2].w.w1) + r(0x0c, dmas[3].w.w0) r(0x0e, dmas[3].w.w1) + r(0x10, dmad[0].w.w0) r(0x12, dmad[0].w.w1) + r(0x14, dmad[1].w.w0) r(0x16, dmad[1].w.w1) + r(0x18, dmad[2].w.w0) r(0x1a, dmad[2].w.w1) + r(0x1c, dmad[3].w.w0) r(0x1e, dmad[3].w.w1) + r(0x20, dmam[0].w.w0) r(0x22, dmam[0].w.w1) + r(0x24, dmam[1].w.w0) r(0x26, dmam[1].w.w1) + r(0x28, dmam[2].w.w0) r(0x2a, dmam[2].w.w1) + r(0x2c, dmam[3].w.w0) r(0x2e, dmam[3].w.w1) + r(0x3c, intnest.w.w0) + #undef r + } + return nothing; +} + +template<> auto TLCS900H::map(ControlRegister register) -> maybe { + switch(register.id & ~1) { + #define r(id, name) case id: return r.name; + r(0x00, dmas[0].l.l0) + r(0x04, dmas[1].l.l0) + r(0x08, dmas[2].l.l0) + r(0x0c, dmas[3].l.l0) + r(0x10, dmad[0].l.l0) + r(0x14, dmad[1].l.l0) + r(0x18, dmad[2].l.l0) + r(0x1c, dmad[3].l.l0) + r(0x20, dmam[0].l.l0) + r(0x24, dmam[1].l.l0) + r(0x28, dmam[2].l.l0) + r(0x2c, dmam[3].l.l0) + r(0x3c, intnest.l.l0) + #undef r + } + return nothing; +} + +template<> auto TLCS900H::load< uint8>(ControlRegister< uint8> register) -> uint8 { return map(register)(Undefined); } +template<> auto TLCS900H::load(ControlRegister register) -> uint16 { return map(register)(Undefined); } +template<> auto TLCS900H::load(ControlRegister register) -> uint32 { return map(register)(Undefined); } + +template<> auto TLCS900H::store(ControlRegister register, uint32 data) -> void { + if(auto r = map(register)) r() = data; +} + +template<> auto TLCS900H::store(ControlRegister register, uint32 data) -> void { + if(auto r = map(register)) r() = data; +} + +template<> auto TLCS900H::store(ControlRegister register, uint32 data) -> void { + //INTNEST is 16-bit: this isn't the nicest way to handle this, but ... + if((register.id & ~3) == 0x3c) data = (uint16)data; + if(auto r = map(register)) r() = data; +} diff --git a/higan/processor/tlcs900h/instruction.cpp b/higan/processor/tlcs900h/instruction.cpp index 9d3fd3ff..597f2f46 100644 --- a/higan/processor/tlcs900h/instruction.cpp +++ b/higan/processor/tlcs900h/instruction.cpp @@ -1,18 +1,27 @@ -template<> auto TLCS900H::registers< uint8>(uint3 code) const -> Register< uint8> { +template<> auto TLCS900H::toRegister3(uint3 code) const -> Register { static const Register< uint8> lookup[] = {W, A, B, C, D, E, H, L}; return lookup[code]; } -template<> auto TLCS900H::registers(uint3 code) const -> Register { +template<> auto TLCS900H::toRegister3(uint3 code) const -> Register { static const Register lookup[] = {WA, BC, DE, HL, IX, IY, IZ, SP}; return lookup[code]; } -template<> auto TLCS900H::registers(uint3 code) const -> Register { +template<> auto TLCS900H::toRegister3(uint3 code) const -> Register { static const Register lookup[] = {XWA, XBC, XDE, XHL, XIX, XIY, XIZ, XSP}; return lookup[code]; } +template auto TLCS900H::toRegister8(uint8 code) const -> Register { return {code}; } +template auto TLCS900H::toControlRegister(uint8 code) const -> ControlRegister { return {code}; } +template auto TLCS900H::toMemory(uint32 address) const -> Memory { return {address}; } +template auto TLCS900H::toImmediate(uint32 constant) const -> Immediate { return {constant}; } +template auto TLCS900H::toImmediate3(uint3 constant) const -> Immediate { return {constant ? (uint)constant : 8u}; } + +//note: much of this code is split to multiple statements due to C++ not guaranteeing +//the order of evaluations of function arguments. fetch() ordering is critical. + auto TLCS900H::instruction() -> void { auto data = fetch(); @@ -23,197 +32,211 @@ auto TLCS900H::instruction() -> void { case 0x03: return instructionPop(SR); case 0x04: return (void)Undefined; case 0x05: return instructionHalt(); - case 0x06: return instructionSetInterruptFlags((uint3)fetch()); + case 0x06: return instructionSetInterruptFlipFlop((uint3)fetch()); case 0x07: return instructionReturnInterrupt(); - case 0x09: return instructionPush(Immediate< uint8>{fetch< uint8>()}); - case 0x0b: return instructionPush(Immediate{fetch()}); - case 0x12: return instructionComplementCarry(); + case 0x08: { + auto memory = fetchMemory(); + return instructionLoad(memory, fetchImmediate()); } + case 0x09: return instructionPush(fetchImmediate()); + case 0x0a: { + auto memory = fetchMemory(); + return instructionLoad(memory, fetchImmediate()); } + case 0x0b: return instructionPush(fetchImmediate()); + case 0x0c: return instructionSetRegisterFilePointer(RFP + 1); + case 0x0d: return instructionSetRegisterFilePointer(RFP - 1); + case 0x0e: return instructionReturn(True); + case 0x0f: return instructionReturnDeallocate(fetchImmediate()); + case 0x10: return instructionSetFlag(CF, 0); + case 0x11: return instructionSetFlag(CF, 1); + case 0x12: return instructionSetFlag(CF, !CF); + case 0x13: return instructionSetFlag(CF, ZF); case 0x14: return instructionPush(A); case 0x15: return instructionPop(A); case 0x16: return instructionExchange(F, FP); + case 0x17: return instructionSetRegisterFilePointer((uint2)fetch()); case 0x18: return instructionPush(F); case 0x19: return instructionPop(F); - case 0x1a: return instructionJump(True, Immediate{fetch()}); - case 0x1b: return instructionJump(True, Immediate{fetch()}); - case 0x1c: return instructionCall(True, Immediate{fetch()}); - case 0x1d: return instructionCall(True, Immediate{fetch()}); + case 0x1a: return instructionJump(True, fetchImmediate()); + case 0x1b: return instructionJump(True, fetchImmediate()); + case 0x1c: return instructionCall(True, fetchImmediate()); + case 0x1d: return instructionCall(True, fetchImmediate()); + case 0x1e: return instructionCallRelative(fetchImmediate()); case 0x1f: return (void)Undefined; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: - return instructionLoad(registers(data), Immediate{fetch()}); + return instructionLoad(toRegister3(data), fetchImmediate()); case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: - return instructionPush(registers(data)); + return instructionPush(toRegister3(data)); case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: - return instructionLoad(registers(data), Immediate{fetch()}); + return instructionLoad(toRegister3(data), fetchImmediate()); case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: - return instructionPush(registers(data)); + return instructionPush(toRegister3(data)); case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: - return instructionLoad(registers(data), Immediate{fetch()}); + return instructionLoad(toRegister3(data), fetchImmediate()); case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: - return instructionPop(registers(data)); - case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: - return (void)Undefined; + return instructionPop(toRegister3(data)); + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: return (void)Undefined; case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: - return instructionPop(registers(data)); + return instructionPop(toRegister3(data)); case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: - return instructionJumpRelative((uint4)data, Immediate{fetch()}); + return instructionJumpRelative((uint4)data, fetchImmediate()); case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: - return instructionJumpRelative((uint4)data, Immediate{fetch()}); + return instructionJumpRelative((uint4)data, fetchImmediate()); case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: - return instructionSourceMemory(Memory{load(registers(data))}); + return instructionSourceMemory(toMemory(load(toRegister3(data)))); case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: - return instructionSourceMemory(Memory{load(registers(data)) + fetch()}); + return instructionSourceMemory(toMemory(load(toRegister3(data)) + fetch())); case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: - return instructionSourceMemory(Memory{load(registers(data))}); + return instructionSourceMemory(toMemory(load(toRegister3(data)))); case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: - return instructionSourceMemory(Memory{load(registers(data)) + fetch()}); + return instructionSourceMemory(toMemory(load(toRegister3(data)) + fetch())); case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: - return instructionSourceMemory(Memory{load(registers(data))}); + return instructionSourceMemory(toMemory(load(toRegister3(data)))); case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: - return instructionSourceMemory(Memory{load(registers(data)) + fetch()}); + return instructionSourceMemory(toMemory(load(toRegister3(data)) + fetch())); case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: - return instructionTargetMemory(load(registers(data))); + return instructionTargetMemory(load(toRegister3(data))); case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: - 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()}); + return instructionTargetMemory(load(toRegister3(data)) + fetch()); + case 0xc0: return instructionSourceMemory(fetchMemory()); + case 0xc1: return instructionSourceMemory(fetchMemory()); + case 0xc2: return instructionSourceMemory(fetchMemory()); case 0xc3: { data = fetch(); - if((data & 3) == 0) return instructionSourceMemory(Memory{load(Register{data})}); - if((data & 3) == 1) return instructionSourceMemory(Memory{load(Register{data}) + fetch()}); + if((data & 3) == 0) return instructionSourceMemory(toMemory(load(toRegister8(data)))); + if((data & 3) == 1) return instructionSourceMemory(toMemory(load(toRegister8(data)) + fetch())); if(data == 0x03) { - auto r32 = load(Register{fetch()}); - auto r8 = load(Register< uint8>{fetch()}); + auto r32 = load(fetchRegister()); + auto r8 = load(fetchRegister< uint8>()); return instructionSourceMemory(Memory{r32 + (int8)r8}); } if(data == 0x07) { - auto r32 = load(Register{fetch()}); - auto r16 = load(Register{fetch()}); + auto r32 = load(fetchRegister()); + auto r16 = load(fetchRegister()); return instructionSourceMemory(Memory{r32 + (int16)r16}); } return (void)Undefined; } case 0xc4: { data = fetch(); - auto register = Register{data}; + auto register = toRegister8(data); if((data & 3) == 0) store(register, load(register) - 1); if((data & 3) == 1) store(register, load(register) - 2); if((data & 3) == 2) store(register, load(register) - 4); if((data & 3) == 3) Undefined; - return instructionSourceMemory(Memory{load(register)}); } + return instructionSourceMemory(toMemory(load(register))); } case 0xc5: { data = fetch(); - auto register = Register{data}; - instructionSourceMemory(Memory{load(register)}); + auto register = toRegister8(data); + instructionSourceMemory(toMemory(load(register))); if((data & 3) == 0) store(register, load(register) + 1); if((data & 3) == 1) store(register, load(register) + 2); if((data & 3) == 2) store(register, load(register) + 4); if((data & 3) == 3) Undefined; return; } case 0xc6: return (void)Undefined; - case 0xc7: return instructionRegister(Register{fetch()}); + case 0xc7: return instructionRegister(fetchRegister()); case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: - return instructionRegister(registers(data)); - case 0xd0: return instructionSourceMemory(Memory{fetch< uint8>()}); - case 0xd1: return instructionSourceMemory(Memory{fetch()}); - case 0xd2: return instructionSourceMemory(Memory{fetch()}); + return instructionRegister(toRegister3(data)); + case 0xd0: return instructionSourceMemory(fetchMemory()); + case 0xd1: return instructionSourceMemory(fetchMemory()); + case 0xd2: return instructionSourceMemory(fetchMemory()); case 0xd3: { data = fetch(); - if((data & 3) == 0) return instructionSourceMemory(Memory{load(Register{data})}); - if((data & 3) == 1) return instructionSourceMemory(Memory{load(Register{data}) + fetch()}); + if((data & 3) == 0) return instructionSourceMemory(toMemory(load(toRegister8(data)))); + if((data & 3) == 1) return instructionSourceMemory(toMemory(load(toRegister8(data)) + fetch())); if(data == 0x03) { - auto r32 = load(Register{fetch()}); - auto r8 = load(Register< uint8>{fetch()}); - return instructionSourceMemory(Memory{r32 + (int8)r8}); + auto r32 = load(fetchRegister()); + auto r8 = load(fetchRegister< uint8>()); + return instructionSourceMemory(toMemory(r32 + (int8)r8)); } if(data == 0x07) { - auto r32 = load(Register{fetch()}); - auto r16 = load(Register{fetch()}); - return instructionSourceMemory(Memory{r32 + (int16)r16}); + auto r32 = load(fetchRegister()); + auto r16 = load(fetchRegister()); + return instructionSourceMemory(toMemory(r32 + (int16)r16)); } return (void)Undefined; } case 0xd4: { data = fetch(); - auto register = Register{data}; + auto register = toRegister8(data); if((data & 3) == 0) store(register, load(register) - 1); if((data & 3) == 1) store(register, load(register) - 2); if((data & 3) == 2) store(register, load(register) - 4); if((data & 3) == 3) Undefined; - return instructionSourceMemory(Memory{load(register)}); } + return instructionSourceMemory(toMemory(load(register))); } case 0xd5: { data = fetch(); - auto register = Register{data}; - instructionSourceMemory(Memory{load(register)}); + auto register = toRegister8(data); + instructionSourceMemory(toMemory(load(register))); if((data & 3) == 0) store(register, load(register) + 1); if((data & 3) == 1) store(register, load(register) + 2); if((data & 3) == 2) store(register, load(register) + 4); if((data & 3) == 3) Undefined; return; } case 0xd6: return (void)Undefined; - case 0xd7: return instructionRegister(Register{fetch()}); + case 0xd7: return instructionRegister(fetchRegister()); case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: - return instructionRegister(registers(data)); - case 0xe0: return instructionSourceMemory(Memory{fetch()}); - case 0xe1: return instructionSourceMemory(Memory{fetch()}); - case 0xe2: return instructionSourceMemory(Memory{fetch()}); + return instructionRegister(toRegister3(data)); + case 0xe0: return instructionSourceMemory(fetchMemory()); + case 0xe1: return instructionSourceMemory(fetchMemory()); + case 0xe2: return instructionSourceMemory(fetchMemory()); case 0xe3: { data = fetch(); - if((data & 3) == 0) return instructionSourceMemory(Memory{load(Register{data})}); - if((data & 3) == 1) return instructionSourceMemory(Memory{load(Register{data}) + fetch()}); + if((data & 3) == 0) return instructionSourceMemory(toMemory(load(toRegister8(data)))); + if((data & 3) == 1) return instructionSourceMemory(toMemory(load(toRegister8(data)) + fetch())); if(data == 0x03) { - auto r32 = load(Register{fetch()}); - auto r8 = load(Register< uint8>{fetch()}); - return instructionSourceMemory(Memory{r32 + (int8)r8}); + auto r32 = load(fetchRegister()); + auto r8 = load(fetchRegister< uint8>()); + return instructionSourceMemory(toMemory(r32 + (int8)r8)); } if(data == 0x07) { - auto r32 = load(Register{fetch()}); - auto r16 = load(Register< uint8>{fetch()}); - return instructionSourceMemory(Memory{r32 + (int16)r16}); + auto r32 = load(fetchRegister()); + auto r16 = load(fetchRegister()); + return instructionSourceMemory(toMemory(r32 + (int16)r16)); } return (void)Undefined; } case 0xe4: { data = fetch(); - auto register = Register{data}; + auto register = toRegister8(data); if((data & 3) == 0) store(register, load(register) - 1); if((data & 3) == 1) store(register, load(register) - 2); if((data & 3) == 2) store(register, load(register) - 4); if((data & 3) == 3) Undefined; - return instructionSourceMemory(Memory{load(register)}); } + return instructionSourceMemory(toMemory(load(register))); } case 0xe5: { data = fetch(); - auto register = Register{data}; - instructionSourceMemory(Memory{load(register)}); + auto register = toRegister8(data); + instructionSourceMemory(toMemory(load(register))); if((data & 3) == 0) store(register, load(register) + 1); if((data & 3) == 1) store(register, load(register) + 2); if((data & 3) == 2) store(register, load(register) + 4); if((data & 3) == 3) Undefined; return; } case 0xe6: return (void)Undefined; - case 0xe7: return instructionRegister(Register{fetch()}); + case 0xe7: return instructionRegister(fetchRegister()); case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: - return instructionRegister(registers(data)); - case 0xf0: return instructionTargetMemory(fetch()); + return instructionRegister(toRegister3(data)); + case 0xf0: return instructionTargetMemory(fetch< uint8>()); case 0xf1: return instructionTargetMemory(fetch()); case 0xf2: return instructionTargetMemory(fetch()); case 0xf3: { data = fetch(); - if((data & 3) == 0) return instructionTargetMemory(load(Register{data})); - if((data & 3) == 1) return instructionTargetMemory(load(Register{data}) + fetch()); + if((data & 3) == 0) return instructionTargetMemory(load(toRegister8(data))); + if((data & 3) == 1) return instructionTargetMemory(load(toRegister8(data)) + fetch()); if(data == 0x03) { - auto r32 = load(Register{fetch()}); - auto r8 = load(Register< uint8>{fetch()}); + auto r32 = load(fetchRegister()); + auto r8 = load(fetchRegister< uint8>()); return instructionTargetMemory(r32 + (int8)r8); } if(data == 0x07) { - auto r32 = load(Register{fetch()}); - auto r16 = load(Register{fetch()}); + auto r32 = load(fetchRegister()); + auto r16 = load(fetchRegister()); return instructionTargetMemory(r32 + (int16)r16); } return (void)Undefined; } case 0xf4: { data = fetch(); - auto register = Register{data}; + auto register = toRegister8(data); if((data & 3) == 0) store(register, load(register) - 1); if((data & 3) == 1) store(register, load(register) - 2); if((data & 3) == 2) store(register, load(register) - 4); @@ -221,14 +244,21 @@ auto TLCS900H::instruction() -> void { return instructionTargetMemory(load(register)); } case 0xf5: { data = fetch(); - auto register = Register{data}; + auto register = toRegister8(data); instructionTargetMemory(load(register)); if((data & 3) == 0) store(register, load(register) + 1); if((data & 3) == 1) store(register, load(register) + 2); if((data & 3) == 2) store(register, load(register) + 4); if((data & 3) == 3) Undefined; return; } - case 0xf6: case 0xf7: return (void)Undefined; + case 0xf6: return (void)Undefined; + case 0xf7: { + if(fetch()) Undefined; + auto memory = fetchMemory(); + if(fetch()) Undefined; + auto immediate = fetchImmediate(); + if(fetch()) Undefined; + return instructionLoad(memory, immediate); } case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: return instructionSoftwareInterrupt((uint3)data); } @@ -236,132 +266,206 @@ auto TLCS900H::instruction() -> void { template auto TLCS900H::instructionRegister(R register) -> void { - using type = typename R::type; + using T = typename R::type; + enum : uint { bits = R::bits }; auto data = fetch(); switch(data) { case 0x00: case 0x01: case 0x02: return (void)Undefined; + case 0x03: return instructionLoad(register, fetchImmediate()); case 0x04: return instructionPush(register); case 0x05: return instructionPop(register); + case 0x06: + if constexpr(bits == 32) return (void)Undefined; + return instructionComplement(register); + case 0x07: + if constexpr(bits == 32) return (void)Undefined; + return instructionNegate(register); + case 0x08: + if constexpr(bits == 32) return (void)Undefined; + return instructionMultiply(register, fetchImmediate()); + case 0x09: + if constexpr(bits == 32) return (void)Undefined; + return instructionMultiplySigned(register, fetchImmediate()); + case 0x0a: + if constexpr(bits == 32) return (void)Undefined; + return instructionDivide(register, fetchImmediate()); + case 0x0b: + if constexpr(bits == 32) return (void)Undefined; + return instructionDivideSigned(register, fetchImmediate()); case 0x11: return (void)Undefined; case 0x15: return (void)Undefined; + case 0x16: + if constexpr(bits == 16) return instructionMirror(register); + return (void)Undefined; case 0x17: case 0x18: return (void)Undefined; + case 0x19: + if constexpr(bits == 16) return instructionMultiplyAdd(register); + return (void)Undefined; case 0x1a: case 0x1b: return (void)Undefined; case 0x1d: case 0x1e: case 0x1f: return (void)Undefined; case 0x25: case 0x26: case 0x27: return (void)Undefined; case 0x2d: return (void)Undefined; + case 0x2e: return instructionLoad(toControlRegister(data), register); + case 0x2f: return instructionLoad(register, toControlRegister(data)); case 0x35: case 0x36: case 0x37: return (void)Undefined; case 0x3b: return (void)Undefined; case 0x3f: return (void)Undefined; + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + if constexpr(bits == 32) return (void)Undefined; + return instructionMultiply(toRegister3(data), register); + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + if constexpr(bits == 32) return (void)Undefined; + return instructionMultiplySigned(toRegister3(data), register); + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + if constexpr(bits == 32) return (void)Undefined; + return instructionDivide(toRegister3(data), register); + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + if constexpr(bits == 32) return (void)Undefined; + return instructionDivideSigned(toRegister3(data), register); + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + return instructionAdd(register, toImmediate3(data)); + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + return instructionSubtract(register, toImmediate3(data)); case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: - if constexpr(R::bits == 32) return (void)Undefined; + if constexpr(bits == 32) return (void)Undefined; return instructionSetConditionCode((uint4)data, register); case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: - return instructionAdd(registers(data), register); + return instructionAdd(toRegister3(data), register); case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: - return instructionLoad(registers(data), register); + return instructionLoad(toRegister3(data), register); case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: - return instructionAddCarry(registers(data), register); + return instructionAddCarry(toRegister3(data), register); case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: - return instructionLoad(register, registers(data)); + return instructionLoad(register, toRegister3(data)); case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: - return instructionSubtract(registers(data), register); + return instructionSubtract(toRegister3(data), register); case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: - return instructionLoad(register, Immediate{(uint3)data}); + return instructionLoad(register, toImmediate((uint3)data)); case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: - return instructionSubtractCarry(registers(data), register); + return instructionSubtractCarry(toRegister3(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); + if constexpr(bits == 32) return (void)Undefined; + return instructionExchange(toRegister3(data), register); case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: - 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()}); + return instructionAnd(toRegister3(data), register); + case 0xc8: return instructionAdd(register, fetchImmediate()); + case 0xc9: return instructionAddCarry(register, fetchImmediate()); + case 0xca: return instructionSubtract(register, fetchImmediate()); + case 0xcb: return instructionSubtractCarry(register, fetchImmediate()); + case 0xcc: return instructionAnd(register, fetchImmediate()); + case 0xcd: return instructionXor(register, fetchImmediate()); + case 0xce: return instructionOr(register, fetchImmediate()); + case 0xcf: return instructionCompare(register, fetchImmediate()); case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: - return instructionXor(registers(data), register); + return instructionXor(toRegister3(data), register); case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: - return instructionCompare(register, Immediate{(uint3)data}); + return instructionCompare(register, toImmediate((uint3)data)); case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: - return instructionOr(registers(data), register); + return instructionOr(toRegister3(data), register); case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: - return instructionCompare(registers(data), register); + return instructionCompare(toRegister3(data), register); } } template auto TLCS900H::instructionSourceMemory(M memory) -> void { - using type = typename M::type; + using T = typename M::type; + enum : uint { bits = M::bits }; auto data = fetch(); switch(data) { case 0x00: case 0x01: case 0x02: case 0x03: return (void)Undefined; case 0x04: - if constexpr(M::bits == 32) return (void)Undefined; + if constexpr(bits == 32) return (void)Undefined; return instructionPush(memory); case 0x05: return (void)Undefined; case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: return (void)Undefined; case 0x18: return (void)Undefined; case 0x19: - if constexpr(M::bits == 32) return (void)Undefined; - return instructionLoad(Memory{fetch()}, memory); + if constexpr(bits == 32) return (void)Undefined; + return instructionLoad(fetchMemory(), memory); case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: return (void)Undefined; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: - return instructionLoad(registers(data), memory); + return instructionLoad(toRegister3(data), memory); case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: return (void)Undefined; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: - if constexpr(M::bits == 32) return (void)Undefined; - return instructionExchange(memory, registers(data)); + if constexpr(bits == 32) return (void)Undefined; + return instructionExchange(memory, toRegister3(data)); case 0x38: - if constexpr(M::bits == 32) return (void)Undefined; - return instructionAdd(memory, Immediate{fetch()}); + if constexpr(bits == 32) return (void)Undefined; + return instructionAdd(memory, fetchImmediate()); case 0x39: - if constexpr(M::bits == 32) return (void)Undefined; - return instructionAddCarry(memory, Immediate{fetch()}); + if constexpr(bits == 32) return (void)Undefined; + return instructionAddCarry(memory, fetchImmediate()); case 0x3a: - if constexpr(M::bits == 32) return (void)Undefined; - return instructionSubtract(memory, Immediate{fetch()}); + if constexpr(bits == 32) return (void)Undefined; + return instructionSubtract(memory, fetchImmediate()); case 0x3b: - if constexpr(M::bits == 32) return (void)Undefined; - return instructionSubtractCarry(memory, Immediate{fetch()}); + if constexpr(bits == 32) return (void)Undefined; + return instructionSubtractCarry(memory, fetchImmediate()); + case 0x3c: + if constexpr(bits == 32) return (void)Undefined; + return instructionAnd(memory, fetchImmediate()); + case 0x3d: + if constexpr(bits == 32) return (void)Undefined; + return instructionXor(memory, fetchImmediate()); + case 0x3e: + if constexpr(bits == 32) return (void)Undefined; + return instructionOr(memory, fetchImmediate()); + case 0x3f: + if constexpr(bits == 32) return (void)Undefined; + return instructionCompare(memory, fetchImmediate()); + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + if constexpr(bits == 32) return (void)Undefined; + return instructionMultiply(toRegister3(data), memory); + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + if constexpr(bits == 32) return (void)Undefined; + return instructionMultiplySigned(toRegister3(data), memory); + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + if constexpr(bits == 32) return (void)Undefined; + return instructionDivide(toRegister3(data), memory); + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + if constexpr(bits == 32) return (void)Undefined; + return instructionDivideSigned(toRegister3(data), memory); + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + return instructionAdd(memory, toImmediate3(data)); + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + return instructionSubtract(memory, toImmediate3(data)); + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: return (void)Undefined; case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: - return instructionAdd(registers(data), memory); + return instructionAdd(toRegister3(data), memory); case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: - return instructionAdd(memory, registers(data)); + return instructionAdd(memory, toRegister3(data)); case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: - return instructionAddCarry(registers(data), memory); + return instructionAddCarry(toRegister3(data), memory); case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: - return instructionAddCarry(memory, registers(data)); + return instructionAddCarry(memory, toRegister3(data)); case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: - return instructionSubtract(registers(data), memory); + return instructionSubtract(toRegister3(data), memory); case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: - return instructionSubtract(memory, registers(data)); + return instructionSubtract(memory, toRegister3(data)); case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: - return instructionSubtractCarry(registers(data), memory); + return instructionSubtractCarry(toRegister3(data), memory); case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: - return instructionSubtractCarry(memory, registers(data)); + return instructionSubtractCarry(memory, toRegister3(data)); case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: - return instructionAnd(registers(data), memory); + return instructionAnd(toRegister3(data), memory); case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: - return instructionAnd(memory, registers(data)); + return instructionAnd(memory, toRegister3(data)); case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: - return instructionXor(registers(data), memory); + return instructionXor(toRegister3(data), memory); case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: - return instructionXor(memory, registers(data)); + return instructionXor(memory, toRegister3(data)); case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: - return instructionOr(registers(data), memory); + return instructionOr(toRegister3(data), memory); case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: - return instructionOr(memory, registers(data)); + return instructionOr(memory, toRegister3(data)); case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: - return instructionCompare(registers(data), memory); + return instructionCompare(toRegister3(data), memory); case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: - return instructionCompare(memory, registers(data)); + return instructionCompare(memory, toRegister3(data)); } } @@ -369,39 +473,46 @@ auto TLCS900H::instructionTargetMemory(uint32 address) -> void { auto data = fetch(); switch(data) { + case 0x00: return instructionLoad(toMemory(address), fetchImmediate()); case 0x01: return (void)Undefined; + case 0x02: return instructionLoad(toMemory(address), fetchImmediate()); case 0x03: return (void)Undefined; - case 0x04: return instructionPop(Memory{address}); + case 0x04: return instructionPop(toMemory(address)); case 0x05: return (void)Undefined; - case 0x06: return instructionPop(Memory{address}); + case 0x06: return instructionPop(toMemory(address)); case 0x07: return (void)Undefined; case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: return (void)Undefined; case 0x10: case 0x11: case 0x12: case 0x13: return (void)Undefined; + case 0x14: return instructionLoad(toMemory(address), fetchMemory()); case 0x15: return (void)Undefined; + case 0x16: return instructionLoad(toMemory(address), fetchMemory()); case 0x17: return (void)Undefined; case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: return (void)Undefined; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: - return instructionLoad(registers(data), Memory{address}); + return instructionLoad(toRegister3(data), toMemory(address)); case 0x2d: case 0x2e: case 0x2f: return (void)Undefined; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: - return instructionLoad(registers(data), Memory{address}); + return instructionLoad(toRegister3(data), toMemory(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{address}, registers(data)); + return instructionLoad(toMemory(address), toRegister3(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{address}, registers(data)); + return instructionLoad(toMemory(address), toRegister3(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{address}, registers(data)); + return instructionLoad(toMemory(address), toRegister3(data)); case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: return (void)Undefined; case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: return (void)Undefined; case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: return (void)Undefined; case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: - return instructionJump((uint4)data, Memory{address}); + return instructionJump((uint4)data, toMemory(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}); + return instructionCall((uint4)data, toMemory(address)); + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: + return instructionReturn((uint4)data); } } diff --git a/higan/processor/tlcs900h/instructions.cpp b/higan/processor/tlcs900h/instructions.cpp index b29dfaac..4772320e 100644 --- a/higan/processor/tlcs900h/instructions.cpp +++ b/higan/processor/tlcs900h/instructions.cpp @@ -1,3 +1,11 @@ +template +auto TLCS900H::toSigned(Target target) -> int32 { + if constexpr(Target::bits() == 8) return (int8)target; + if constexpr(Target::bits() == 16) return (int16)target; + if constexpr(Target::bits() == 32) return (int32)target; + return Undefined; +} + template auto TLCS900H::instructionAdd(Target target, Source source) -> void { store(target, algorithmAdd(load(target), load(source))); @@ -5,7 +13,7 @@ auto TLCS900H::instructionAdd(Target target, Source source) -> void { template auto TLCS900H::instructionAddCarry(Target target, Source source) -> void { - store(target, algorithmAdd(load(target), load(source), carry())); + store(target, algorithmAdd(load(target), load(source), CF)); } template @@ -19,13 +27,34 @@ auto TLCS900H::instructionCall(uint4 code, Source source) -> void { if(condition(code)) push(PC), store(PC, address); } +template +auto TLCS900H::instructionCallRelative(Source displacement) -> void { + push(PC); + store(PC, load(PC) + load(displacement)); +} + template auto TLCS900H::instructionCompare(Target target, Source source) -> void { algorithmSubtract(load(target), load(source)); } -auto TLCS900H::instructionComplementCarry() -> void { - setCarry(!carry()); +template +auto TLCS900H::instructionComplement(Target target) -> void { + store(target, ~load(target)); + NF = 1; + HF = 1; +} + +template +auto TLCS900H::instructionDivide(Target target, Source source) -> void { + //TODO: division by zero + store(expand(target), load(target) / load(source)); +} + +template +auto TLCS900H::instructionDivideSigned(Target target, Source source) -> void { + //TODO: division by zero + store(expand(target), toSigned(load(target)) / toSigned(load(source))); } template @@ -55,6 +84,44 @@ auto TLCS900H::instructionLoad(Target target, Source source) -> void { store(target, load(source)); } +//reverse all bits in a 16-bit register +auto TLCS900H::instructionMirror(Register register) -> void { + auto data = load(register); + uint8 lo = (data.byte(0) * 0x80200802ull & 0x884422110ull) * 0x101010101ull >> 32; + uint8 hi = (data.byte(1) * 0x80200802ull & 0x884422110ull) * 0x101010101ull >> 32; + store(register, lo << 8 | hi << 0); +} + +template +auto TLCS900H::instructionMultiply(Target target, Source source) -> void { + store(expand(target), load(target) * load(source)); +} + +auto TLCS900H::instructionMultiplyAdd(Register register) -> void { + auto xde = toMemory(load(XDE)); + auto xhl = toMemory(load(XHL)); + + auto source = load(expand(register)); + auto target = load(xde) * load(xhl); + store(expand(register), source + target); + store(XHL, load(XHL) - 2); + + auto result = load(expand(register)); + VF = uint32(~(target ^ source) & (target ^ result)).negative(); + ZF = result.zero(); + SF = result.negative(); +} + +template +auto TLCS900H::instructionMultiplySigned(Target target, Source source) -> void { + store(expand(target), toSigned(load(target)) * toSigned(load(source))); +} + +template +auto TLCS900H::instructionNegate(Target target) -> void { + store(target, algorithmSubtract(typename Target::type{0}, load(target))); +} + auto TLCS900H::instructionNoOperation() -> void { } @@ -73,10 +140,20 @@ auto TLCS900H::instructionPush(Source source) -> void { push(source); } +auto TLCS900H::instructionReturn(uint4 code) -> void { + if(condition(code)) pop(PC); +} + +template +auto TLCS900H::instructionReturnDeallocate(Source displacement) -> void { + pop(PC); + store(XSP, load(XSP) + load(displacement)); +} + auto TLCS900H::instructionReturnInterrupt() -> void { pop(SR); pop(PC); - //TODO: decrement INTNEST here + store(INTNEST, load(INTNEST) - 1); } template @@ -84,8 +161,16 @@ auto TLCS900H::instructionSetConditionCode(uint4 code, Target target) -> void { store(target, condition(code)); } -auto TLCS900H::instructionSetInterruptFlags(uint3 flags) -> void { - setIFF(flags); +auto TLCS900H::instructionSetFlag(uint1& flag, uint1 value) -> void { + flag = value; +} + +auto TLCS900H::instructionSetInterruptFlipFlop(uint3 value) -> void { + IFF = value; +} + +auto TLCS900H::instructionSetRegisterFilePointer(uint2 value) -> void { + RFP = value; } auto TLCS900H::instructionSoftwareInterrupt(uint3 interrupt) -> void { @@ -99,7 +184,7 @@ auto TLCS900H::instructionSubtract(Target target, Source source) -> void { template auto TLCS900H::instructionSubtractCarry(Target target, Source source) -> void { - store(target, algorithmSubtract(load(target), load(source), carry())); + store(target, algorithmSubtract(load(target), load(source), CF)); } template diff --git a/higan/processor/tlcs900h/memory.cpp b/higan/processor/tlcs900h/memory.cpp index ae24c82f..4db6f5ec 100644 --- a/higan/processor/tlcs900h/memory.cpp +++ b/higan/processor/tlcs900h/memory.cpp @@ -25,6 +25,10 @@ template<> auto TLCS900H::fetch() -> int16 { return (int16)fetch( template<> auto TLCS900H::fetch() -> int24 { return (int24)fetch(); } template<> auto TLCS900H::fetch() -> int32 { return (int32)fetch(); } +template auto TLCS900H::fetchRegister() -> Register { return Register{fetch()}; } +template auto TLCS900H::fetchMemory() -> Memory { return Memory{fetch()}; } +template auto TLCS900H::fetchImmediate() -> Immediate { return Immediate{fetch()}; } + // #define XSP r.xsp.l.l0 @@ -66,6 +70,10 @@ template<> auto TLCS900H::load(Memory memory) -> uint32 { return data |= read(memory.address + 3) << 24; } +template<> auto TLCS900H::load(Memory< int8> memory) -> int8 { return (int8)load< uint8>(Memory< uint8>{memory.address}); } +template<> auto TLCS900H::load(Memory memory) -> int16 { return (int16)load(Memory{memory.address}); } +template<> auto TLCS900H::load(Memory memory) -> int32 { return (int32)load(Memory{memory.address}); } + template<> auto TLCS900H::store(Memory< uint8> memory, uint32 data) -> void { write(memory.address, data); } diff --git a/higan/processor/tlcs900h/registers.cpp b/higan/processor/tlcs900h/registers.cpp index 32637483..5e2bb59a 100644 --- a/higan/processor/tlcs900h/registers.cpp +++ b/higan/processor/tlcs900h/registers.cpp @@ -1,5 +1,5 @@ -#define a r.rfp -#define p r.rfpp +#define a RFP +#define p RFP - 1 & 3 template<> auto TLCS900H::map(Register register) -> maybe { switch(register.id) { @@ -85,6 +85,10 @@ template<> auto TLCS900H::store< uint8>(Register< uint8> register, uint32 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::expand(Register< uint8> register) const -> Register { return {register.id & ~1}; } +auto TLCS900H::expand(Register register) const -> Register { return {register.id & ~3}; } +auto TLCS900H::expand(Register register) const -> Register { return {Undefined}; } + auto TLCS900H::load(FlagRegister f) -> uint8 { switch(f.id) { case 0: return r.c << 0 | r.n << 1 | r.v << 2 | r.h << 4 | r.z << 6 | r.s << 7; @@ -107,7 +111,6 @@ auto TLCS900H::store(StatusRegister, uint16 data) -> void { store(F, data); r.rfp = data.bits( 8, 9); r.iff = data.bits(12,14); - r.rfpp = r.rfp - 1; } auto TLCS900H::load(ProgramCounter) -> uint32 { return r.pc.l.l0; } diff --git a/higan/processor/tlcs900h/tlcs900h.cpp b/higan/processor/tlcs900h/tlcs900h.cpp index b09b5502..a6dff50b 100644 --- a/higan/processor/tlcs900h/tlcs900h.cpp +++ b/higan/processor/tlcs900h/tlcs900h.cpp @@ -3,7 +3,19 @@ namespace Processor { +#define CF r.c +#define NF r.n +#define VF r.v +#define PF r.v +#define HF r.h +#define ZF r.z +#define SF r.s + +#define RFP r.rfp +#define IFF r.iff + #include "registers.cpp" +#include "control-registers.cpp" #include "memory.cpp" #include "conditions.cpp" #include "algorithms.cpp" diff --git a/higan/processor/tlcs900h/tlcs900h.hpp b/higan/processor/tlcs900h/tlcs900h.hpp index 509d026b..063cc6f7 100644 --- a/higan/processor/tlcs900h/tlcs900h.hpp +++ b/higan/processor/tlcs900h/tlcs900h.hpp @@ -5,6 +5,7 @@ * what happens when a prohibited instruction operand size is used? (eg adc.l (memory),#immediate) * what happens when %11 is used for pre-decrement and post-increment addressing? * what happens when using 8-bit register indexing and d0 is set (Word) or d1/d0 is set (Long)? + * what happens during an LDX instruction when the three padding bytes aren't all 0x00? * what value is read back from a non-existent 8-bit register ID? (eg 0x40-0xcf) * many instructions are undefined, some are marked as dummy instructions ... what do each do? */ @@ -14,18 +15,50 @@ namespace Processor { struct TLCS900H { - virtual auto read(uint32 address) -> uint8 { return 0; } - virtual auto write(uint32 address, uint8 data) -> void {}; + virtual auto read(uint24 address) -> uint8 { return 0; } + virtual auto write(uint24 address, uint8 data) -> void {}; TLCS900H(); - struct FlagRegister { using type = uint8; enum : uint { bits = 8 }; uint1 id; }; - struct StatusRegister { using type = uint16; enum : uint { bits = 16 }; }; - struct ProgramCounter { using type = uint32; enum : uint { bits = 32 }; }; + struct FlagRegister { + using type = uint8; + enum : uint { bits = 8 }; + uint1 id; + }; - template 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 { + using type = uint16; + enum : uint { bits = 16 }; + }; + + struct ProgramCounter { + using type = uint32; + enum : uint { bits = 32 }; + }; + + template struct ControlRegister { + using type = T; + enum : uint { bits = 8 * sizeof(T) }; + uint8 id; + }; + + 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; + }; template auto load(Immediate immediate) const -> T { return immediate.constant; } @@ -36,6 +69,9 @@ struct TLCS900H { template auto map(Register) -> maybe; template auto load(Register) -> T; template auto store(Register, uint32) -> void; + auto expand(Register< uint8>) const -> Register; + auto expand(Register) const -> Register; + auto expand(Register) const -> Register; auto load(FlagRegister) -> uint8; auto store(FlagRegister, uint8) -> void; auto load(StatusRegister) -> uint16; @@ -43,8 +79,16 @@ struct TLCS900H { auto load(ProgramCounter) -> uint32; auto store(ProgramCounter, uint32) -> void; + //control-registers.cpp + template auto map(ControlRegister) -> maybe; + template auto load(ControlRegister) -> T; + template auto store(ControlRegister, uint32) -> void; + //memory.cpp template auto fetch() -> T; + template auto fetchRegister() -> Register; + template auto fetchMemory() -> Memory; + template auto fetchImmediate() -> Immediate; template auto push(T) -> void; template auto pop(T) -> void; template auto load(Memory) -> T; @@ -62,35 +106,54 @@ struct TLCS900H { template auto algorithmXor(T target, T source) -> T; //instruction.cpp - template auto registers(uint3) const -> Register; + template auto toRegister3(uint3) const -> Register; + template auto toRegister8(uint8) const -> Register; + template auto toControlRegister(uint8) const -> ControlRegister; + template auto toMemory(uint32 address) const -> Memory; + template auto toImmediate(uint32 constant) const -> Immediate; + template auto toImmediate3(uint3 constant) const -> Immediate; auto instruction() -> 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 toSigned(Target) -> int32; + + template auto instructionAdd(Target, Source) -> void; + template auto instructionAddCarry(Target, Source) -> void; + template auto instructionAnd(Target, Source) -> void; template auto instructionCall(uint4 code, Source) -> void; - template auto instructionCompare(Target target, Source source) -> void; - auto instructionComplementCarry() -> void; - template auto instructionExchange(Target target, Source source) -> void; + template auto instructionCallRelative(Source) -> void; + template auto instructionCompare(Target, Source) -> void; + template auto instructionComplement(Target) -> void; + template auto instructionDivide(Target, Source) -> void; + template auto instructionDivideSigned(Target, Source) -> void; + template auto instructionExchange(Target, 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; + template auto instructionLoad(Target, Source) -> void; + auto instructionMirror(Register) -> void; + template auto instructionMultiply(Target, Source) -> void; + auto instructionMultiplyAdd(Register) -> void; + template auto instructionMultiplySigned(Target, Source) -> void; + template auto instructionNegate(Target) -> 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, Source) -> void; + template auto instructionPop(Target) -> void; + template auto instructionPush(Source) -> void; + auto instructionReturn(uint4 code) -> void; + template auto instructionReturnDeallocate(Source) -> void; auto instructionReturnInterrupt() -> void; template auto instructionSetConditionCode(uint4 code, Target) -> void; - auto instructionSetInterruptFlags(uint3 flags) -> void; + auto instructionSetFlag(uint1& flag, uint1 value) -> void; + auto instructionSetInterruptFlipFlop(uint3 value) -> void; + auto instructionSetRegisterFilePointer(uint2 value) -> void; auto instructionSoftwareInterrupt(uint3 interrupt) -> void; - template 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, Source) -> void; + template auto instructionSubtractCarry(Target, Source) -> void; + template auto instructionXor(Target, Source) -> void; //serialization.cpp auto serialize(serializer&) -> void; @@ -113,40 +176,23 @@ struct TLCS900H { DataRegister xsp; DataRegister pc; - uint1 c, cp; //carry - uint1 n, np; //negative - uint1 v, vp; //overflow or parity - uint1 h, hp; //half carry - uint1 z, zp; //zero - uint1 s, sp; //sign - uint2 rfp, rfpp = 3; //register file pointer + DataRegister dmas[4]; + DataRegister dmad[4]; + DataRegister dmam[4]; + DataRegister intnest; //16-bit + + uint1 c, cp; //carry + uint1 n, np; //negative + uint1 v, vp; //overflow or parity + uint1 h, hp; //half carry + uint1 z, zp; //zero + uint1 s, sp; //sign + uint2 rfp; //register file pointer uint3 iff = 7; //interrupt mask flip-flop uint1 halted; } r; - auto carry() const -> bool { return r.c; } - auto negative() const -> bool { return r.n; } - auto overflow() const -> bool { return r.v; } - auto parity() const -> bool { return r.v; } - auto halfCarry() const -> bool { return r.h; } - auto zero() const -> bool { return r.z; } - auto sign() const -> bool { return r.s; } - - auto setCarry(bool value) -> void { r.c = value; } - auto setNegative(bool value) -> void { r.n = value; } - auto setOverflow(bool value) -> void { r.v = value; } - auto setParity(bool value) -> void { r.v = value; } - auto setHalfCarry(bool value) -> void { r.h = value; } - auto setZero(bool value) -> void { r.z = value; } - auto setSign(bool value) -> void { r.s = value; } - - auto rfp() const -> uint2 { return r.rfp; } - auto setRFP(uint2 value) -> void { r.rfp = value; } - - auto iff() const -> uint3 { return r.iff; } - auto setIFF(uint3 value) -> void { r.iff = value; } - auto halted() const -> bool { return r.halted; } auto setHalted(bool value) -> void { r.halted = value; } @@ -183,6 +229,25 @@ struct TLCS900H { static inline const StatusRegister SR{}; static inline const ProgramCounter PC{}; + static inline const ControlRegister DMAS0{0x00}; + static inline const ControlRegister DMAS1{0x04}; + static inline const ControlRegister DMAS2{0x08}; + static inline const ControlRegister DMAS3{0x0c}; + static inline const ControlRegister DMAD0{0x10}; + static inline const ControlRegister DMAD1{0x14}; + static inline const ControlRegister DMAD2{0x18}; + static inline const ControlRegister DMAD3{0x1c}; + static inline const ControlRegister DMAM0{0x20}; + static inline const ControlRegister DMAM1{0x24}; + static inline const ControlRegister DMAM2{0x28}; + static inline const ControlRegister DMAM3{0x2c}; + + static inline const ControlRegister DMAC0{0x20}; + static inline const ControlRegister DMAC1{0x24}; + static inline const ControlRegister DMAC2{0x28}; + static inline const ControlRegister DMAC3{0x2c}; + static inline const ControlRegister INTNEST{0x3c}; + static inline const uint4 False{0x00}; static inline const uint4 True {0x08};