mirror of https://github.com/bsnes-emu/bsnes.git
Update to v106r76 release.
byuu says: I added some useful new functions to nall/primitives: auto Natural<T>::integer() const -> Integer<T>; auto Integer<T>::natural() const -> Natural<T>; These let you cast between signed and unsigned representation without having to care about the value of T (eg if you take a Natural<T> as a template parameter.) So for instance when you're given an unsigned type but it's supposed to be a sign-extended type (example: signed multiplication), eg Natural<T> → Integer<T>, you can just say: x = y.integer() * z.integer(); The TLCS900H core gained some more pesky instructions such as DAA, BS1F, BS1B. I stole an optimization from RACE for calculating the overflow flag on addition. Assuming: z = x + y + c; Before: ~(x ^ y) & (x ^ z) & signBit; After: (x ^ z) & (y ^ z) & signBit; Subtraction stays the same. Assuming: z = x - y - c; Same: (x ^ y) & (x ^ z) & signBit; However, taking a speed penalty, I've implemented the carry computation in a way that doesn't require an extra bit. Adding before: uint9 z = x + y + c; c = z & 0x100; Subtracting before: uint9 z = x - y - c; c = z & 0x100; Adding after: uint8 z = x + y + c; c = z < x || z == x && c; Subtracting after: uint8 z = x - y - c; c = z > x || z == x && c; I haven't been able to code golf the new carry computation to be any shorter, unless I include an extra bit, eg for adding: c = z < x + c; But that defeats the entire point of the change. I want the computation to work even when T is uintmax_t. If anyone can come up with a faster method, please let me know. Anyway ... I also had to split off INC and DEC because they compute flags differently (word and long modes don't set flags at all, byte mode doesn't set carry at all.) I also added division by zero support, although I don't know if it's actually hardware accurate. It's what other emulators do, though.
This commit is contained in:
parent
95d0020297
commit
c9f7c6c4be
|
@ -30,7 +30,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "106.75";
|
static const string Version = "106.76";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "https://byuu.org/";
|
static const string Website = "https://byuu.org/";
|
||||||
|
|
|
@ -20,13 +20,13 @@ template<> auto TLCS900H::parity<uint32>(uint32 data) const -> bool {
|
||||||
//
|
//
|
||||||
|
|
||||||
template<typename T> auto TLCS900H::algorithmAdd(T target, T source, uint1 carry) -> T {
|
template<typename T> auto TLCS900H::algorithmAdd(T target, T source, uint1 carry) -> T {
|
||||||
uint64 result = target + source + carry;
|
T result = target + source + carry;
|
||||||
CF = result.bit(T::bits());
|
CF = result < target || result == target && carry;
|
||||||
NF = 0;
|
NF = 0;
|
||||||
VF = T(~(target ^ source) & (target ^ result)).negative();
|
VF = T((target ^ result) & (source ^ result)).negative();
|
||||||
HF = T(target ^ source ^ result).bit(4);
|
HF = T(target ^ source ^ result).bit(4);
|
||||||
if constexpr(is_same<T, uint32>::value) HF = Undefined;
|
if constexpr(T::bits() == 32) HF = Undefined;
|
||||||
ZF = T(result).zero();
|
ZF = result.zero();
|
||||||
SF = result.negative();
|
SF = result.negative();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,30 @@ template<typename T> auto TLCS900H::algorithmAnd(T target, T source) -> T {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T> auto TLCS900H::algorithmDecrement(T target, T source) -> T {
|
||||||
|
T result = target - source;
|
||||||
|
if constexpr(T::bits() == 8) {
|
||||||
|
NF = 1;
|
||||||
|
VF = T((target ^ source) & (target ^ result)).negative();
|
||||||
|
HF = T(target ^ source ^ result).bit(4);
|
||||||
|
ZF = result.zero();
|
||||||
|
SF = result.negative();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> auto TLCS900H::algorithmIncrement(T target, T source) -> T {
|
||||||
|
T result = target + source;
|
||||||
|
if constexpr(T::bits() == 8) {
|
||||||
|
NF = 0;
|
||||||
|
VF = T((target ^ result) & (source ^ result)).negative();
|
||||||
|
HF = T(target ^ source ^ result).bit(4);
|
||||||
|
ZF = result.zero();
|
||||||
|
SF = result.negative();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T> auto TLCS900H::algorithmOr(T target, T source) -> T {
|
template<typename T> auto TLCS900H::algorithmOr(T target, T source) -> T {
|
||||||
T result = target | source;
|
T result = target | source;
|
||||||
CF = 0;
|
CF = 0;
|
||||||
|
@ -54,13 +78,13 @@ template<typename T> auto TLCS900H::algorithmOr(T target, T source) -> T {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto TLCS900H::algorithmSubtract(T target, T source, uint1 carry) -> T {
|
template<typename T> auto TLCS900H::algorithmSubtract(T target, T source, uint1 carry) -> T {
|
||||||
uint64 result = target - source - carry;
|
T result = target - source - carry;
|
||||||
CF = result.bit(T::bits());
|
CF = result > target || result == target && carry;
|
||||||
NF = 1;
|
NF = 1;
|
||||||
VF = T((target ^ source) & (target ^ result)).negative();
|
VF = T((target ^ source) & (target ^ result)).negative();
|
||||||
HF = T(target ^ source ^ result).bit(4);
|
HF = T(target ^ source ^ result).bit(4);
|
||||||
if constexpr(is_same<T, uint32>::value) HF = Undefined;
|
if constexpr(T::bits() == 32) HF = Undefined;
|
||||||
ZF = T(result).zero();
|
ZF = result.zero();
|
||||||
SF = result.negative();
|
SF = result.negative();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
template<> auto TLCS900H::map(ControlRegister<uint8> register) -> maybe<uint8&> {
|
template<> auto TLCS900H::map(ControlRegister<uint8> register) const -> maybe<uint8&> {
|
||||||
switch(register.id) {
|
switch(register.id) {
|
||||||
#define r(id, name) case id: return r.name;
|
#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(0x00, dmas[0].b.b0) r(0x01, dmas[0].b.b1) r(0x02, dmas[0].b.b2) r(0x03, dmas[0].b.b3)
|
||||||
|
@ -19,7 +19,7 @@ template<> auto TLCS900H::map(ControlRegister<uint8> register) -> maybe<uint8&>
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto TLCS900H::map(ControlRegister<uint16> register) -> maybe<uint16&> {
|
template<> auto TLCS900H::map(ControlRegister<uint16> register) const -> maybe<uint16&> {
|
||||||
switch(register.id & ~1) {
|
switch(register.id & ~1) {
|
||||||
#define r(id, name) case id: return r.name;
|
#define r(id, name) case id: return r.name;
|
||||||
r(0x00, dmas[0].w.w0) r(0x02, dmas[0].w.w1)
|
r(0x00, dmas[0].w.w0) r(0x02, dmas[0].w.w1)
|
||||||
|
@ -40,7 +40,7 @@ template<> auto TLCS900H::map(ControlRegister<uint16> register) -> maybe<uint16&
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto TLCS900H::map(ControlRegister<uint32> register) -> maybe<uint32&> {
|
template<> auto TLCS900H::map(ControlRegister<uint32> register) const -> maybe<uint32&> {
|
||||||
switch(register.id & ~1) {
|
switch(register.id & ~1) {
|
||||||
#define r(id, name) case id: return r.name;
|
#define r(id, name) case id: return r.name;
|
||||||
r(0x00, dmas[0].l.l0)
|
r(0x00, dmas[0].l.l0)
|
||||||
|
@ -61,9 +61,9 @@ template<> auto TLCS900H::map(ControlRegister<uint32> register) -> maybe<uint32&
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto TLCS900H::load< uint8>(ControlRegister< uint8> register) -> uint8 { return map(register)(Undefined); }
|
template<> auto TLCS900H::load< uint8>(ControlRegister< uint8> register) const -> uint8 { return map(register)(Undefined); }
|
||||||
template<> auto TLCS900H::load<uint16>(ControlRegister<uint16> register) -> uint16 { return map(register)(Undefined); }
|
template<> auto TLCS900H::load<uint16>(ControlRegister<uint16> register) const -> uint16 { return map(register)(Undefined); }
|
||||||
template<> auto TLCS900H::load<uint32>(ControlRegister<uint32> register) -> uint32 { return map(register)(Undefined); }
|
template<> auto TLCS900H::load<uint32>(ControlRegister<uint32> register) const -> uint32 { return map(register)(Undefined); }
|
||||||
|
|
||||||
template<> auto TLCS900H::store<uint8>(ControlRegister<uint8> register, uint32 data) -> void {
|
template<> auto TLCS900H::store<uint8>(ControlRegister<uint8> register, uint32 data) -> void {
|
||||||
if(auto r = map(register)) r() = data;
|
if(auto r = map(register)) r() = data;
|
||||||
|
|
|
@ -282,18 +282,36 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits == 32) return (void)Undefined;
|
||||||
return instructionNegate(register);
|
return instructionNegate(register);
|
||||||
case 0x08:
|
case 0x08:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionMultiply(register, fetchImmediate<T>());
|
||||||
return instructionMultiply(register, fetchImmediate<T>());
|
return (void)Undefined;
|
||||||
case 0x09:
|
case 0x09:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionMultiplySigned(register, fetchImmediate<T>());
|
||||||
return instructionMultiplySigned(register, fetchImmediate<T>());
|
return (void)Undefined;
|
||||||
case 0x0a:
|
case 0x0a:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionDivide(register, fetchImmediate<T>());
|
||||||
return instructionDivide(register, fetchImmediate<T>());
|
return (void)Undefined;
|
||||||
case 0x0b:
|
case 0x0b:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionDivideSigned(register, fetchImmediate<T>());
|
||||||
return instructionDivideSigned(register, fetchImmediate<T>());
|
return (void)Undefined;
|
||||||
|
//case 0x0c: LINK r,dd
|
||||||
|
//case 0x0d: UNLK r
|
||||||
|
case 0x0e:
|
||||||
|
if constexpr(bits == 16) return instructionBitSearch1Forward(register);
|
||||||
|
return (void)Undefined;
|
||||||
|
case 0x0f:
|
||||||
|
if constexpr(bits == 16) return instructionBitSearch1Backward(register);
|
||||||
|
return (void)Undefined;
|
||||||
|
case 0x10:
|
||||||
|
if constexpr(bits == 8) return instructionDecimalAdjustAccumulator(register);
|
||||||
|
return (void)Undefined;
|
||||||
case 0x11: return (void)Undefined;
|
case 0x11: return (void)Undefined;
|
||||||
|
case 0x12:
|
||||||
|
if constexpr(bits != 8) return instructionExtendZero(register);
|
||||||
|
return (void)Undefined;
|
||||||
|
case 0x13:
|
||||||
|
if constexpr(bits != 8) return instructionExtendSign(register);
|
||||||
|
return (void)Undefined;
|
||||||
|
//case 0x14: PAA r
|
||||||
case 0x15: return (void)Undefined;
|
case 0x15: return (void)Undefined;
|
||||||
case 0x16:
|
case 0x16:
|
||||||
if constexpr(bits == 16) return instructionMirror(register);
|
if constexpr(bits == 16) return instructionMirror(register);
|
||||||
|
@ -303,6 +321,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||||
if constexpr(bits == 16) return instructionMultiplyAdd(register);
|
if constexpr(bits == 16) return instructionMultiplyAdd(register);
|
||||||
return (void)Undefined;
|
return (void)Undefined;
|
||||||
case 0x1a: case 0x1b: return (void)Undefined;
|
case 0x1a: case 0x1b: return (void)Undefined;
|
||||||
|
//case 0x1c: DJNZ r,d
|
||||||
case 0x1d: case 0x1e: case 0x1f: return (void)Undefined;
|
case 0x1d: case 0x1e: case 0x1f: return (void)Undefined;
|
||||||
case 0x25: case 0x26: case 0x27: return (void)Undefined;
|
case 0x25: case 0x26: case 0x27: return (void)Undefined;
|
||||||
case 0x2d: return (void)Undefined;
|
case 0x2d: return (void)Undefined;
|
||||||
|
@ -312,21 +331,21 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||||
case 0x3b: return (void)Undefined;
|
case 0x3b: return (void)Undefined;
|
||||||
case 0x3f: return (void)Undefined;
|
case 0x3f: return (void)Undefined;
|
||||||
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
|
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionMultiply(toRegister3<T>(data), register);
|
||||||
return instructionMultiply(toRegister3<T>(data), register);
|
return (void)Undefined;
|
||||||
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionMultiplySigned(toRegister3<T>(data), register);
|
||||||
return instructionMultiplySigned(toRegister3<T>(data), register);
|
return (void)Undefined;
|
||||||
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
|
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionDivide(toRegister3<T>(data), register);
|
||||||
return instructionDivide(toRegister3<T>(data), register);
|
return (void)Undefined;
|
||||||
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
|
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionDivideSigned(toRegister3<T>(data), register);
|
||||||
return instructionDivideSigned(toRegister3<T>(data), register);
|
return (void)Undefined;
|
||||||
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
|
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
|
||||||
return instructionAdd(register, toImmediate3<T>(data));
|
return instructionIncrement(register, toImmediate<T>((uint3)data));
|
||||||
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
|
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
|
||||||
return instructionSubtract(register, toImmediate3<T>(data));
|
return instructionDecrement(register, toImmediate<T>((uint3)data));
|
||||||
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
|
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:
|
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits == 32) return (void)Undefined;
|
||||||
|
@ -418,21 +437,21 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits == 32) return (void)Undefined;
|
||||||
return instructionCompare(memory, fetchImmediate<T>());
|
return instructionCompare(memory, fetchImmediate<T>());
|
||||||
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
|
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionMultiply(toRegister3<T>(data), memory);
|
||||||
return instructionMultiply(toRegister3<T>(data), memory);
|
return (void)Undefined;
|
||||||
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionMultiplySigned(toRegister3<T>(data), memory);
|
||||||
return instructionMultiplySigned(toRegister3<T>(data), memory);
|
return (void)Undefined;
|
||||||
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
|
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionDivide(toRegister3<T>(data), memory);
|
||||||
return instructionDivide(toRegister3<T>(data), memory);
|
return (void)Undefined;
|
||||||
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
|
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
|
||||||
if constexpr(bits == 32) return (void)Undefined;
|
if constexpr(bits != 32) return instructionDivideSigned(toRegister3<T>(data), memory);
|
||||||
return instructionDivideSigned(toRegister3<T>(data), memory);
|
return (void)Undefined;
|
||||||
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
|
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
|
||||||
return instructionAdd(memory, toImmediate3<T>(data));
|
return instructionIncrement(memory, toImmediate<T>((uint3)data));
|
||||||
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
|
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
|
||||||
return instructionSubtract(memory, toImmediate3<T>(data));
|
return instructionDecrement(memory, toImmediate<T>((uint3)data));
|
||||||
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: return (void)Undefined;
|
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:
|
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
|
||||||
return instructionAdd(toRegister3<T>(data), memory);
|
return instructionAdd(toRegister3<T>(data), memory);
|
||||||
|
|
|
@ -1,11 +1,3 @@
|
||||||
template<typename Target>
|
|
||||||
auto TLCS900H::toSigned(Target target) -> int32 {
|
|
||||||
if constexpr(Target::bits() == 8) return (int8)target;
|
|
||||||
if constexpr(Target::bits() == 16) return (int16)target;
|
|
||||||
if constexpr(Target::bits() == 32) return (int32)target;
|
|
||||||
return Undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Target, typename Source>
|
template<typename Target, typename Source>
|
||||||
auto TLCS900H::instructionAdd(Target target, Source source) -> void {
|
auto TLCS900H::instructionAdd(Target target, Source source) -> void {
|
||||||
store(target, algorithmAdd(load(target), load(source)));
|
store(target, algorithmAdd(load(target), load(source)));
|
||||||
|
@ -21,6 +13,22 @@ auto TLCS900H::instructionAnd(Target target, Source source) -> void {
|
||||||
store(target, algorithmAnd(load(target), load(source)));
|
store(target, algorithmAnd(load(target), load(source)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto TLCS900H::instructionBitSearch1Backward(Register<uint16> register) -> void {
|
||||||
|
auto value = load(register);
|
||||||
|
for(uint index : reverse(range(16))) {
|
||||||
|
if(value.bit(index)) return VF = 1, store(A, index);
|
||||||
|
}
|
||||||
|
VF = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto TLCS900H::instructionBitSearch1Forward(Register<uint16> register) -> void {
|
||||||
|
auto value = load(register);
|
||||||
|
for(uint index : range(16)) {
|
||||||
|
if(value.bit(index)) return VF = 1, store(A, index);
|
||||||
|
}
|
||||||
|
VF = 0;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Source>
|
template<typename Source>
|
||||||
auto TLCS900H::instructionCall(uint4 code, Source source) -> void {
|
auto TLCS900H::instructionCall(uint4 code, Source source) -> void {
|
||||||
auto address = load(source);
|
auto address = load(source);
|
||||||
|
@ -45,16 +53,46 @@ auto TLCS900H::instructionComplement(Target target) -> void {
|
||||||
HF = 1;
|
HF = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto TLCS900H::instructionDecimalAdjustAccumulator(Register<uint8> register) -> void {
|
||||||
|
auto value = load(register);
|
||||||
|
if(CF || (uint8)value > 0x99) value += NF ? -0x60 : 0x60, CF = 1;
|
||||||
|
if(HF || (uint4)value > 0x09) value += NF ? -0x06 : 0x06;
|
||||||
|
PF = parity(value);
|
||||||
|
HF = uint8(value ^ load(register)).bit(4);
|
||||||
|
ZF = value.zero();
|
||||||
|
SF = value.negative();
|
||||||
|
store(register, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Target, typename Source>
|
||||||
|
auto TLCS900H::instructionDecrement(Target target, Source source) -> void {
|
||||||
|
auto immediate = load(source);
|
||||||
|
if(!immediate) immediate = 8;
|
||||||
|
store(target, algorithmDecrement(load(target), immediate));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Target, typename Source>
|
template<typename Target, typename Source>
|
||||||
auto TLCS900H::instructionDivide(Target target, Source source) -> void {
|
auto TLCS900H::instructionDivide(Target target, Source source) -> void {
|
||||||
//TODO: division by zero
|
using T = typename Target::type;
|
||||||
store(expand(target), load(target) / load(source));
|
using E = Natural<2 * T::bits()>;
|
||||||
|
auto dividend = load(expand(target));
|
||||||
|
auto divisor = load(source);
|
||||||
|
auto quotient = divisor ? E(dividend / divisor) : E(T(~(dividend >> T::bits())));
|
||||||
|
auto remainder = divisor ? E(dividend % divisor) : E(T(dividend));
|
||||||
|
store(expand(target), T(remainder) << T::bits() | T(quotient));
|
||||||
|
VF = !divisor || remainder >> T::bits();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Target, typename Source>
|
template<typename Target, typename Source>
|
||||||
auto TLCS900H::instructionDivideSigned(Target target, Source source) -> void {
|
auto TLCS900H::instructionDivideSigned(Target target, Source source) -> void {
|
||||||
//TODO: division by zero
|
using T = typename Target::type;
|
||||||
store(expand(target), toSigned(load(target)) / toSigned(load(source)));
|
using E = Natural<2 * T::bits()>;
|
||||||
|
auto dividend = load(expand(target)).integer();
|
||||||
|
auto divisor = load(source).integer();
|
||||||
|
auto quotient = divisor ? E(dividend / divisor) : E(T(~(dividend >> T::bits())));
|
||||||
|
auto remainder = divisor ? E(dividend % divisor) : E(T(dividend));
|
||||||
|
store(expand(target), T(remainder) << T::bits() | T(quotient));
|
||||||
|
VF = !divisor || remainder >> T::bits();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Target, typename Source>
|
template<typename Target, typename Source>
|
||||||
|
@ -64,10 +102,27 @@ auto TLCS900H::instructionExchange(Target target, Source source) -> void {
|
||||||
store(source, data);
|
store(source, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Target>
|
||||||
|
auto TLCS900H::instructionExtendSign(Target target) -> void {
|
||||||
|
store(target, load(shrink(target)).integer());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Target>
|
||||||
|
auto TLCS900H::instructionExtendZero(Target target) -> void {
|
||||||
|
store(target, load(shrink(target)));
|
||||||
|
}
|
||||||
|
|
||||||
auto TLCS900H::instructionHalt() -> void {
|
auto TLCS900H::instructionHalt() -> void {
|
||||||
setHalted(true);
|
setHalted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Target, typename Source>
|
||||||
|
auto TLCS900H::instructionIncrement(Target target, Source source) -> void {
|
||||||
|
auto immediate = load(source);
|
||||||
|
if(!immediate) immediate = 8;
|
||||||
|
store(target, algorithmIncrement(load(target), immediate));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Source>
|
template<typename Source>
|
||||||
auto TLCS900H::instructionJump(uint4 code, Source source) -> void {
|
auto TLCS900H::instructionJump(uint4 code, Source source) -> void {
|
||||||
auto address = load(source);
|
auto address = load(source);
|
||||||
|
@ -85,6 +140,7 @@ auto TLCS900H::instructionLoad(Target target, Source source) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
//reverse all bits in a 16-bit register
|
//reverse all bits in a 16-bit register
|
||||||
|
//note: an 8-bit lookup table is faster (when in L1/L2 cache), but much more code
|
||||||
auto TLCS900H::instructionMirror(Register<uint16> register) -> void {
|
auto TLCS900H::instructionMirror(Register<uint16> register) -> void {
|
||||||
auto data = load(register);
|
auto data = load(register);
|
||||||
uint8 lo = (data.byte(0) * 0x80200802ull & 0x884422110ull) * 0x101010101ull >> 32;
|
uint8 lo = (data.byte(0) * 0x80200802ull & 0x884422110ull) * 0x101010101ull >> 32;
|
||||||
|
@ -114,7 +170,7 @@ auto TLCS900H::instructionMultiplyAdd(Register<uint16> register) -> void {
|
||||||
|
|
||||||
template<typename Target, typename Source>
|
template<typename Target, typename Source>
|
||||||
auto TLCS900H::instructionMultiplySigned(Target target, Source source) -> void {
|
auto TLCS900H::instructionMultiplySigned(Target target, Source source) -> void {
|
||||||
store(expand(target), toSigned(load(target)) * toSigned(load(source)));
|
store(expand(target), load(target).integer() * load(source).integer());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Target>
|
template<typename Target>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#define a RFP
|
#define a RFP
|
||||||
#define p RFP - 1 & 3
|
#define p RFP - 1 & 3
|
||||||
|
|
||||||
template<> auto TLCS900H::map(Register<uint8> register) -> maybe<uint8&> {
|
template<> auto TLCS900H::map(Register<uint8> register) const -> maybe<uint8&> {
|
||||||
switch(register.id) {
|
switch(register.id) {
|
||||||
#define r(id, name) case id: return r.name;
|
#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(0x00, xwa[0].b.b0) r(0x01, xwa[0].b.b1) r(0x02, xwa[0].b.b2) r(0x03, xwa[0].b.b3)
|
||||||
|
@ -37,7 +37,7 @@ template<> auto TLCS900H::map(Register<uint8> register) -> maybe<uint8&> {
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto TLCS900H::map(Register<uint16> register) -> maybe<uint16&> {
|
template<> auto TLCS900H::map(Register<uint16> register) const -> maybe<uint16&> {
|
||||||
switch(register.id & ~1) {
|
switch(register.id & ~1) {
|
||||||
#define r(id, name) case id: return r.name;
|
#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(0x00, xwa[0].w.w0) r(0x02, xwa[0].w.w1) r(0x04, xbc[0].w.w0) r(0x06, xbc[0].w.w1)
|
||||||
|
@ -59,7 +59,7 @@ template<> auto TLCS900H::map(Register<uint16> register) -> maybe<uint16&> {
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto TLCS900H::map(Register<uint32> register) -> maybe<uint32&> {
|
template<> auto TLCS900H::map(Register<uint32> register) const -> maybe<uint32&> {
|
||||||
switch(register.id & ~3) {
|
switch(register.id & ~3) {
|
||||||
#define r(id, name) case id: return r.name;
|
#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(0x00, xwa[0].l.l0) r(0x04, xbc[0].l.l0) r(0x08, xde[0].l.l0) r(0x0c, xhl[0].l.l0)
|
||||||
|
@ -77,9 +77,9 @@ template<> auto TLCS900H::map(Register<uint32> register) -> maybe<uint32&> {
|
||||||
#undef a
|
#undef a
|
||||||
#undef p
|
#undef p
|
||||||
|
|
||||||
template<> auto TLCS900H::load< uint8>(Register< uint8> register) -> uint8 { return map(register)(Undefined); }
|
template<> auto TLCS900H::load< uint8>(Register< uint8> register) const -> uint8 { return map(register)(Undefined); }
|
||||||
template<> auto TLCS900H::load<uint16>(Register<uint16> register) -> uint16 { return map(register)(Undefined); }
|
template<> auto TLCS900H::load<uint16>(Register<uint16> register) const -> uint16 { return map(register)(Undefined); }
|
||||||
template<> auto TLCS900H::load<uint32>(Register<uint32> register) -> uint32 { return map(register)(Undefined); }
|
template<> auto TLCS900H::load<uint32>(Register<uint32> register) const -> 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< uint8>(Register< uint8> register, uint32 data) -> void { if(auto r = map(register)) r() = data; }
|
||||||
template<> auto TLCS900H::store<uint16>(Register<uint16> register, uint32 data) -> void { if(auto r = map(register)) r() = data; }
|
template<> auto TLCS900H::store<uint16>(Register<uint16> register, uint32 data) -> void { if(auto r = map(register)) r() = data; }
|
||||||
|
@ -87,9 +87,11 @@ template<> auto TLCS900H::store<uint32>(Register<uint32> register, uint32 data)
|
||||||
|
|
||||||
auto TLCS900H::expand(Register< uint8> register) const -> Register<uint16> { return {register.id & ~1}; }
|
auto TLCS900H::expand(Register< uint8> register) const -> Register<uint16> { return {register.id & ~1}; }
|
||||||
auto TLCS900H::expand(Register<uint16> register) const -> Register<uint32> { return {register.id & ~3}; }
|
auto TLCS900H::expand(Register<uint16> register) const -> Register<uint32> { return {register.id & ~3}; }
|
||||||
auto TLCS900H::expand(Register<uint32> register) const -> Register<uint32> { return {Undefined}; }
|
|
||||||
|
|
||||||
auto TLCS900H::load(FlagRegister f) -> uint8 {
|
auto TLCS900H::shrink(Register<uint32> register) const -> Register<uint16> { return {register.id}; }
|
||||||
|
auto TLCS900H::shrink(Register<uint16> register) const -> Register< uint8> { return {register.id}; }
|
||||||
|
|
||||||
|
auto TLCS900H::load(FlagRegister f) const -> uint8 {
|
||||||
switch(f.id) {
|
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 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;
|
case 1: return r.cp << 0 | r.np << 1 | r.vp << 2 | r.hp << 4 | r.zp << 6 | r.sp << 7;
|
||||||
|
@ -103,7 +105,7 @@ auto TLCS900H::store(FlagRegister f, uint8 data) -> void {
|
||||||
} unreachable;
|
} unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto TLCS900H::load(StatusRegister) -> uint16 {
|
auto TLCS900H::load(StatusRegister) const -> uint16 {
|
||||||
return load(F) | r.rfp << 8 | 1 << 11 | r.iff << 12 | 1 << 15;
|
return load(F) | r.rfp << 8 | 1 << 11 | r.iff << 12 | 1 << 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,5 +115,5 @@ auto TLCS900H::store(StatusRegister, uint16 data) -> void {
|
||||||
r.iff = data.bits(12,14);
|
r.iff = data.bits(12,14);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto TLCS900H::load(ProgramCounter) -> uint32 { return r.pc.l.l0; }
|
auto TLCS900H::load(ProgramCounter) const -> uint32 { return r.pc.l.l0; }
|
||||||
auto TLCS900H::store(ProgramCounter, uint32 data) -> void { r.pc.l.l0 = data; }
|
auto TLCS900H::store(ProgramCounter, uint32 data) -> void { r.pc.l.l0 = data; }
|
||||||
|
|
|
@ -20,45 +20,13 @@ struct TLCS900H {
|
||||||
|
|
||||||
TLCS900H();
|
TLCS900H();
|
||||||
|
|
||||||
struct FlagRegister {
|
struct FlagRegister { using type = uint8; enum : uint { bits = 8 }; uint1 id; };
|
||||||
using type = uint8;
|
struct StatusRegister { using type = uint16; enum : uint { bits = 16 }; };
|
||||||
enum : uint { bits = 8 };
|
struct ProgramCounter { using type = uint32; enum : uint { bits = 32 }; };
|
||||||
uint1 id;
|
template<typename T> struct ControlRegister { using type = T; enum : uint { bits = 8 * sizeof(T) }; uint8 id; };
|
||||||
};
|
template<typename T> struct Register { using type = T; enum : uint { bits = 8 * sizeof(T) }; uint8 id; };
|
||||||
|
template<typename T> struct Memory { using type = T; enum : uint { bits = 8 * sizeof(T) }; T address; };
|
||||||
struct StatusRegister {
|
template<typename T> struct Immediate { using type = T; enum : uint { bits = 8 * sizeof(T) }; T constant; };
|
||||||
using type = uint16;
|
|
||||||
enum : uint { bits = 16 };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ProgramCounter {
|
|
||||||
using type = uint32;
|
|
||||||
enum : uint { bits = 32 };
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct ControlRegister {
|
|
||||||
using type = T;
|
|
||||||
enum : uint { bits = 8 * sizeof(T) };
|
|
||||||
uint8 id;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct Register {
|
|
||||||
using type = T;
|
|
||||||
enum : uint { bits = 8 * sizeof(T) };
|
|
||||||
uint8 id;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct Memory {
|
|
||||||
using type = T;
|
|
||||||
enum : uint { bits = 8 * sizeof(T) };
|
|
||||||
T address;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct Immediate {
|
|
||||||
using type = T;
|
|
||||||
enum : uint { bits = 8 * sizeof(T) };
|
|
||||||
T constant;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> auto load(Immediate<T> immediate) const -> T { return immediate.constant; }
|
template<typename T> auto load(Immediate<T> immediate) const -> T { return immediate.constant; }
|
||||||
|
|
||||||
|
@ -66,22 +34,23 @@ struct TLCS900H {
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
//registers.cpp
|
//registers.cpp
|
||||||
template<typename T> auto map(Register<T>) -> maybe<T&>;
|
template<typename T> auto map(Register<T>) const -> maybe<T&>;
|
||||||
template<typename T> auto load(Register<T>) -> T;
|
template<typename T> auto load(Register<T>) const -> T;
|
||||||
template<typename T> auto store(Register<T>, uint32) -> void;
|
template<typename T> auto store(Register<T>, uint32) -> void;
|
||||||
auto expand(Register< uint8>) const -> Register<uint16>;
|
auto expand(Register< uint8>) const -> Register<uint16>;
|
||||||
auto expand(Register<uint16>) const -> Register<uint32>;
|
auto expand(Register<uint16>) const -> Register<uint32>;
|
||||||
auto expand(Register<uint32>) const -> Register<uint32>;
|
auto shrink(Register<uint32>) const -> Register<uint16>;
|
||||||
auto load(FlagRegister) -> uint8;
|
auto shrink(Register<uint16>) const -> Register< uint8>;
|
||||||
|
auto load(FlagRegister) const -> uint8;
|
||||||
auto store(FlagRegister, uint8) -> void;
|
auto store(FlagRegister, uint8) -> void;
|
||||||
auto load(StatusRegister) -> uint16;
|
auto load(StatusRegister) const -> uint16;
|
||||||
auto store(StatusRegister, uint16) -> void;
|
auto store(StatusRegister, uint16) -> void;
|
||||||
auto load(ProgramCounter) -> uint32;
|
auto load(ProgramCounter) const -> uint32;
|
||||||
auto store(ProgramCounter, uint32) -> void;
|
auto store(ProgramCounter, uint32) -> void;
|
||||||
|
|
||||||
//control-registers.cpp
|
//control-registers.cpp
|
||||||
template<typename T> auto map(ControlRegister<T>) -> maybe<T&>;
|
template<typename T> auto map(ControlRegister<T>) const -> maybe<T&>;
|
||||||
template<typename T> auto load(ControlRegister<T>) -> T;
|
template<typename T> auto load(ControlRegister<T>) const -> T;
|
||||||
template<typename T> auto store(ControlRegister<T>, uint32) -> void;
|
template<typename T> auto store(ControlRegister<T>, uint32) -> void;
|
||||||
|
|
||||||
//memory.cpp
|
//memory.cpp
|
||||||
|
@ -101,6 +70,8 @@ struct TLCS900H {
|
||||||
template<typename T> auto parity(T) const -> bool;
|
template<typename T> auto parity(T) const -> bool;
|
||||||
template<typename T> auto algorithmAdd(T target, T source, uint1 carry = 0) -> T;
|
template<typename T> auto algorithmAdd(T target, T source, uint1 carry = 0) -> T;
|
||||||
template<typename T> auto algorithmAnd(T target, T source) -> T;
|
template<typename T> auto algorithmAnd(T target, T source) -> T;
|
||||||
|
template<typename T> auto algorithmDecrement(T target, T source) -> T;
|
||||||
|
template<typename T> auto algorithmIncrement(T target, T source) -> T;
|
||||||
template<typename T> auto algorithmOr(T target, T source) -> T;
|
template<typename T> auto algorithmOr(T target, T source) -> T;
|
||||||
template<typename T> auto algorithmSubtract(T target, T source, uint1 carry = 0) -> T;
|
template<typename T> auto algorithmSubtract(T target, T source, uint1 carry = 0) -> T;
|
||||||
template<typename T> auto algorithmXor(T target, T source) -> T;
|
template<typename T> auto algorithmXor(T target, T source) -> T;
|
||||||
|
@ -118,19 +89,24 @@ struct TLCS900H {
|
||||||
auto instructionTargetMemory(uint32 address) -> void;
|
auto instructionTargetMemory(uint32 address) -> void;
|
||||||
|
|
||||||
//instructions.cpp
|
//instructions.cpp
|
||||||
template<typename Target> auto toSigned(Target) -> int32;
|
|
||||||
|
|
||||||
template<typename Target, typename Source> auto instructionAdd(Target, Source) -> void;
|
template<typename Target, typename Source> auto instructionAdd(Target, Source) -> void;
|
||||||
template<typename Target, typename Source> auto instructionAddCarry(Target, Source) -> void;
|
template<typename Target, typename Source> auto instructionAddCarry(Target, Source) -> void;
|
||||||
template<typename Target, typename Source> auto instructionAnd(Target, Source) -> void;
|
template<typename Target, typename Source> auto instructionAnd(Target, Source) -> void;
|
||||||
|
auto instructionBitSearch1Backward(Register<uint16>) -> void;
|
||||||
|
auto instructionBitSearch1Forward(Register<uint16>) -> void;
|
||||||
template<typename Source> auto instructionCall(uint4 code, Source) -> void;
|
template<typename Source> auto instructionCall(uint4 code, Source) -> void;
|
||||||
template<typename Source> auto instructionCallRelative(Source) -> void;
|
template<typename Source> auto instructionCallRelative(Source) -> void;
|
||||||
template<typename Target, typename Source> auto instructionCompare(Target, Source) -> void;
|
template<typename Target, typename Source> auto instructionCompare(Target, Source) -> void;
|
||||||
template<typename Target> auto instructionComplement(Target) -> void;
|
template<typename Target> auto instructionComplement(Target) -> void;
|
||||||
|
auto instructionDecimalAdjustAccumulator(Register<uint8>) -> void;
|
||||||
|
template<typename Target, typename Source> auto instructionDecrement(Target, Source) -> void;
|
||||||
template<typename Target, typename Source> auto instructionDivide(Target, Source) -> void;
|
template<typename Target, typename Source> auto instructionDivide(Target, Source) -> void;
|
||||||
template<typename Target, typename Source> auto instructionDivideSigned(Target, Source) -> void;
|
template<typename Target, typename Source> auto instructionDivideSigned(Target, Source) -> void;
|
||||||
template<typename Target, typename Source> auto instructionExchange(Target, Source) -> void;
|
template<typename Target, typename Source> auto instructionExchange(Target, Source) -> void;
|
||||||
|
template<typename Target> auto instructionExtendSign(Target) -> void;
|
||||||
|
template<typename Target> auto instructionExtendZero(Target) -> void;
|
||||||
auto instructionHalt() -> void;
|
auto instructionHalt() -> void;
|
||||||
|
template<typename Target, typename Source> auto instructionIncrement(Target, Source) -> void;
|
||||||
template<typename Source> auto instructionJump(uint4 code, Source) -> void;
|
template<typename Source> auto instructionJump(uint4 code, Source) -> void;
|
||||||
template<typename Source> auto instructionJumpRelative(uint4 code, Source) -> void;
|
template<typename Source> auto instructionJumpRelative(uint4 code, Source) -> void;
|
||||||
template<typename Target, typename Source> auto instructionLoad(Target, Source) -> void;
|
template<typename Target, typename Source> auto instructionLoad(Target, Source) -> void;
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
|
struct Boolean;
|
||||||
|
template<uint Bits> struct Natural;
|
||||||
|
template<uint Bits> struct Integer;
|
||||||
|
|
||||||
struct Boolean {
|
struct Boolean {
|
||||||
inline Boolean() : data(false) {}
|
inline Boolean() : data(false) {}
|
||||||
template<typename T> inline Boolean(const T& value) : data(value) {}
|
template<typename T> inline Boolean(const T& value) : data(value) {}
|
||||||
|
@ -127,6 +131,8 @@ template<uint Bits> struct Natural {
|
||||||
return data & m;
|
return data & m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline auto integer() const -> Integer<Bits>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto set(type value) -> void {
|
auto set(type value) -> void {
|
||||||
data = value & Mask;
|
data = value & Mask;
|
||||||
|
@ -237,6 +243,8 @@ template<uint Bits> struct Integer {
|
||||||
return ((data & m) ^ b) - b;
|
return ((data & m) ^ b) - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline auto natural() const -> Natural<Bits>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto set(type value) -> void {
|
auto set(type value) -> void {
|
||||||
data = ((value & Mask) ^ Sign) - Sign;
|
data = ((value & Mask) ^ Sign) - Sign;
|
||||||
|
@ -245,6 +253,16 @@ private:
|
||||||
type data;
|
type data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//cast an unsigned type to a signed type with the same number of bits
|
||||||
|
template<uint Bits> auto Natural<Bits>::integer() const -> Integer<Bits> {
|
||||||
|
return Integer<Bits>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//cast a signed type to an unsigned type with the same number of bits
|
||||||
|
template<uint Bits> auto Integer<Bits>::natural() const -> Natural<Bits> {
|
||||||
|
return Natural<Bits>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
template<uint Bits> struct Real {
|
template<uint Bits> struct Real {
|
||||||
using type =
|
using type =
|
||||||
typename conditional<Bits == 32, float32_t,
|
typename conditional<Bits == 32, float32_t,
|
||||||
|
|
Loading…
Reference in New Issue