Commit 25145f59 authored by Tim Allen's avatar Tim Allen

Update to v106r80 release.

byuu says:

Any usage of natural and integer cast to 64-bit math operations now.
Hopefully this will be the last of the major changes for a bit on
nall/primitives, at least until serious work begins on removing implicit
conversion to primitive types.

I also completed the initial TLCS900H core, sans SWI (kind of a ways off
from support interrupts.) I really shouldn't say completed, though. The
micro DMA unit is missing, interrupt priority handling is missing,
there's no debugger, and, of course, there's surely dozens of absolutely
critical CPU bugs that are going to be an absolute hellscape nightmare
to track down.

It was a damn shame, right up until the very last eight instructions,
[CP|LD][I|D](R), the instruction encoding was consistent. Of course,
there could be other inconsistencies that I missed. In fact, that's
somewhat likely ... sigh.
parent 17fc6d8d
Pipeline #43417798 passed with stage
in 13 minutes and 19 seconds
......@@ -30,7 +30,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "106.79";
static const string Version = "106.80";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org/";
......
......@@ -90,7 +90,7 @@ struct M68K {
//effective-address.cpp
struct EffectiveAddress {
explicit EffectiveAddress(uint mode_, uint reg_) : mode(mode_), reg(reg_) {
explicit EffectiveAddress(uint4 mode_, uint3 reg_) : mode(mode_), reg(reg_) {
if(mode == 7) mode += reg; //optimization: convert modes {7; 0-4} to {8-11}
}
......
......@@ -25,7 +25,7 @@ template<typename T> auto TLCS900H::toImmediate3(uint3 constant) const -> Immedi
auto TLCS900H::instruction() -> void {
auto data = fetch();
switch(data) {
switch(r.prefix = data) {
case 0x00: return instructionNoOperation();
case 0x01: return (void)Undefined;
case 0x02: return instructionPush(SR);
......@@ -293,8 +293,12 @@ auto TLCS900H::instructionRegister(R register) -> void {
case 0x0b:
if constexpr(bits != 32) return instructionDivideSigned(register, fetchImmediate<T>());
return (void)Undefined;
//case 0x0c: LINK r,dd
//case 0x0d: UNLK r
case 0x0c:
if constexpr(bits == 32) return instructionLink(register, fetchImmediate<int16>());
return (void)Undefined;
case 0x0d:
if constexpr(bits == 32) return instructionUnlink(register);
return (void)Undefined;
case 0x0e:
if constexpr(bits == 16) return instructionBitSearch1Forward(register);
return (void)Undefined;
......@@ -311,7 +315,9 @@ auto TLCS900H::instructionRegister(R register) -> void {
case 0x13:
if constexpr(bits != 8) return instructionExtendSign(register);
return (void)Undefined;
//case 0x14: PAA r
case 0x14:
if constexpr(bits != 8) return instructionPointerAdjustAccumulator(register);
return (void)Undefined;
case 0x15: return (void)Undefined;
case 0x16:
if constexpr(bits == 16) return instructionMirror(register);
......@@ -321,7 +327,9 @@ auto TLCS900H::instructionRegister(R register) -> void {
if constexpr(bits == 16) return instructionMultiplyAdd(register);
return (void)Undefined;
case 0x1a: case 0x1b: return (void)Undefined;
//case 0x1c: DJNZ r,d
case 0x1c:
if constexpr(bits != 32) return instructionDecrementJumpNotZero(register, fetchImmediate<int8>());
return (void)Undefined;
case 0x1d: case 0x1e: case 0x1f: return (void)Undefined;
case 0x20:
if constexpr(bits != 32) return instructionAndCarry(register, fetchImmediate<uint8>());
......@@ -373,13 +381,25 @@ auto TLCS900H::instructionRegister(R register) -> void {
if constexpr(bits != 32) return instructionTestSet(register, fetchImmediate<uint8>());
return (void)Undefined;
case 0x35: case 0x36: case 0x37: return (void)Undefined;
//case 0x38: MINC1 #,r
//case 0x39: MINC2 #,r
//case 0x3a: MINC4 #,r
case 0x38:
if constexpr(bits == 16) return instructionModuloIncrement<1>(register, fetchImmediate<int16>());
return (void)Undefined;
case 0x39:
if constexpr(bits == 16) return instructionModuloIncrement<2>(register, fetchImmediate<int16>());
return (void)Undefined;
case 0x3a:
if constexpr(bits == 16) return instructionModuloIncrement<4>(register, fetchImmediate<int16>());
return (void)Undefined;
case 0x3b: return (void)Undefined;
//case 0x3c: MDEC1 #,r
//case 0x3d: MDEC2 #,r
//case 0x3e: MDEC4 #,r
case 0x3c:
if constexpr(bits == 16) return instructionModuloDecrement<1>(register, fetchImmediate<int16>());
return (void)Undefined;
case 0x3d:
if constexpr(bits == 16) return instructionModuloDecrement<2>(register, fetchImmediate<int16>());
return (void)Undefined;
case 0x3e:
if constexpr(bits == 16) return instructionModuloDecrement<4>(register, fetchImmediate<int16>());
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 instructionMultiply(toRegister3<T>(data), register);
......@@ -467,17 +487,45 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
if constexpr(bits == 32) return (void)Undefined;
return instructionPush(memory);
case 0x05: return (void)Undefined;
//case 0x06: RLD A,(mem)
//case 0x07: RRD A,(mem)
case 0x06:
if constexpr(bits == 8) return instructionRotateLeftDigit(A, memory);
return (void)Undefined;
case 0x07:
if constexpr(bits == 8) return instructionRotateRightDigit(A, memory);
return (void)Undefined;
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: return (void)Undefined;
//case 0x10: LDI
//case 0x11: LDIR
//case 0x12: LDIR
//case 0x13: LDDR
//case 0x14: CPI
//case 0x15: CPIR
//case 0x16: CPD
//case 0x17: CPDR
case 0x10:
if constexpr(bits == 8) return instructionLoad<T, +1>();
if constexpr(bits == 16) return instructionLoad<T, +2>();
return (void)Undefined;
case 0x11:
if constexpr(bits == 8) return instructionLoadRepeat<T, +1>();
if constexpr(bits == 16) return instructionLoadRepeat<T, +2>();
return (void)Undefined;
case 0x12:
if constexpr(bits == 8) return instructionLoad<T, -1>();
if constexpr(bits == 16) return instructionLoad<T, -2>();
return (void)Undefined;
case 0x13:
if constexpr(bits == 8) return instructionLoadRepeat<T, -1>();
if constexpr(bits == 16) return instructionLoadRepeat<T, -2>();
return (void)Undefined;
case 0x14:
if constexpr(bits == 8) return instructionCompare<T, +1>(A);
if constexpr(bits == 16) return instructionCompare<T, +2>(WA);
return (void)Undefined;
case 0x15:
if constexpr(bits == 8) return instructionCompareRepeat<T, +1>(A);
if constexpr(bits == 16) return instructionCompareRepeat<T, +2>(WA);
return (void)Undefined;
case 0x16:
if constexpr(bits == 8) return instructionCompare<T, -1>(A);
if constexpr(bits == 16) return instructionCompare<T, -2>(WA);
return (void)Undefined;
case 0x17:
if constexpr(bits == 8) return instructionCompareRepeat<T, -1>(A);
if constexpr(bits == 16) return instructionCompareRepeat<T, -2>(WA);
return (void)Undefined;
case 0x18: return (void)Undefined;
case 0x19:
if constexpr(bits == 32) return (void)Undefined;
......
......@@ -63,6 +63,22 @@ auto TLCS900H::instructionChange(Target target, Offset offset) -> void {
store(target, result);
}
template<typename Size, int Adjust, typename Target>
auto TLCS900H::instructionCompare(Target target) -> void {
auto source = toRegister3<uint32>(r.prefix);
auto cf = CF; //CF is not modified; but algorithmSubtract will modify it
algorithmSubtract(load(target), load(toMemory<Size>(load(source))));
store(source, load(source) + Adjust);
store(BC, load(BC) - 1);
CF = cf;
VF = load(BC) == 0;
}
template<typename Size, int Adjust, typename Target>
auto TLCS900H::instructionCompareRepeat(Target target) -> void {
do { instructionCompare<Size, Adjust>(target); } while(VF && !ZF);
}
template<typename Target, typename Source>
auto TLCS900H::instructionCompare(Target target, Source source) -> void {
algorithmSubtract(load(target), load(source));
......@@ -93,6 +109,13 @@ auto TLCS900H::instructionDecrement(Target target, Source source) -> void {
store(target, algorithmDecrement(load(target), immediate));
}
template<typename Target, typename Offset>
auto TLCS900H::instructionDecrementJumpNotZero(Target target, Offset offset) -> void {
auto result = load(target);
store(target, --result);
if(result) store(PC, load(PC) + load(offset));
}
template<typename Target, typename Source>
auto TLCS900H::instructionDivide(Target target, Source source) -> void {
using T = typename Target::type;
......@@ -156,6 +179,13 @@ auto TLCS900H::instructionJumpRelative(uint4 code, Source displacement) -> void
if(condition(code)) store(PC, load(PC) + load(displacement));
}
template<typename Target, typename Offset>
auto TLCS900H::instructionLink(Target target, Offset offset) -> void {
push(target);
store(target, load(XSP));
store(XSP, load(XSP) + load(offset));
}
template<typename Target, typename Source>
auto TLCS900H::instructionLoad(Target target, Source source) -> void {
store(target, load(source));
......@@ -167,6 +197,22 @@ auto TLCS900H::instructionLoadCarry(Source source, Offset offset) -> void {
CF = load(source).bit(load(offset) & Source::bits - 1);
}
template<typename Size, int Adjust> auto TLCS900H::instructionLoad() -> void {
auto target = (uint3)r.prefix == 5 ? XIX : XDE;
auto source = (uint3)r.prefix == 5 ? XIY : XHL;
store(toMemory<Size>(load(target)), load(toMemory<Size>(load(source))));
store(target, load(target) + Adjust);
store(source, load(source) + Adjust);
store(BC, load(BC) - 1);
NF = 0;
VF = load(BC) == 0;
HF = 0;
}
template<typename Size, int Adjust> auto TLCS900H::instructionLoadRepeat() -> void {
do { instructionLoad<Size, Adjust>(); } while(VF);
}
//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 {
......@@ -177,6 +223,28 @@ auto TLCS900H::instructionMirror(Register<uint16> register) -> void {
store(register, data << 8 | data >> 8);
}
template<uint Modulo, typename Target, typename Source>
auto TLCS900H::instructionModuloDecrement(Target target, Source source) -> void {
auto result = load(target);
auto number = load(source);
if(result % number == 0) {
store(target, result + (number - Modulo));
} else {
store(target, result - Modulo);
}
}
template<uint Modulo, typename Target, typename Source>
auto TLCS900H::instructionModuloIncrement(Target target, Source source) -> void {
auto result = load(target);
auto number = load(source);
if(result % number == number - Modulo) {
store(target, result - (number - Modulo));
} else {
store(target, result + Modulo);
}
}
template<typename Target, typename Source>
auto TLCS900H::instructionMultiply(Target target, Source source) -> void {
store(expand(target), load(target) * load(source));
......@@ -221,6 +289,13 @@ auto TLCS900H::instructionOrCarry(Source source, Offset offset) -> void {
CF |= load(source).bit(load(offset) & Source::bits - 1);
}
//increments odd addresses only to ensure they are even (16-bit aligned)
template<typename Target>
auto TLCS900H::instructionPointerAdjustAccumulator(Target target) -> void {
auto result = load(target);
store(target, result + result.bit(0));
}
template<typename Target>
auto TLCS900H::instructionPop(Target target) -> void {
pop(target);
......@@ -254,6 +329,23 @@ auto TLCS900H::instructionReturnInterrupt() -> void {
store(INTNEST, load(INTNEST) - 1);
}
template<typename LHS, typename RHS>
auto TLCS900H::instructionRotateLeftDigit(LHS lhs, RHS rhs) -> void {
auto lvalue = load(lhs);
auto rvalue = load(rhs);
auto Lvalue = lvalue;
lvalue.bits(0,3) = rvalue.bits(4,7);
rvalue.bits(4,7) = rvalue.bits(0,3);
rvalue.bits(0,3) = Lvalue.bits(0,3);
store(lhs, lvalue);
store(rhs, rvalue);
NF = 0;
PF = parity(lvalue);
HF = 0;
ZF = lvalue == 0;
SF = lvalue.bit(-1);
}
template<typename Target, typename Amount>
auto TLCS900H::instructionRotateLeft(Target target, Amount amount) -> void {
auto result = load(target);
......@@ -277,6 +369,23 @@ auto TLCS900H::instructionRotateLeftWithoutCarry(Target target, Amount amount) -
store(target, algorithmRotated(result));
}
template<typename LHS, typename RHS>
auto TLCS900H::instructionRotateRightDigit(LHS lhs, RHS rhs) -> void {
auto lvalue = load(lhs);
auto rvalue = load(rhs);
auto Rvalue = rvalue;
rvalue.bits(0,3) = rvalue.bits(4,7);
rvalue.bits(4,7) = lvalue.bits(0,3);
lvalue.bits(0,3) = Rvalue.bits(0,3);
store(lhs, lvalue);
store(rhs, rvalue);
NF = 0;
PF = parity(lvalue);
HF = 0;
ZF = lvalue == 0;
SF = lvalue.bit(-1);
}
template<typename Target, typename Amount>
auto TLCS900H::instructionRotateRight(Target target, Amount amount) -> void {
auto result = load(target);
......@@ -404,6 +513,12 @@ auto TLCS900H::instructionTestSet(Target target, Offset offset) -> void {
store(target, result);
}
template<typename Target>
auto TLCS900H::instructionUnlink(Target target) -> void {
store(XSP, load(target));
pop(target);
}
template<typename Target, typename Source>
auto TLCS900H::instructionXor(Target target, Source source) -> void {
store(target, algorithmXor(load(target), load(source)));
......
......@@ -102,10 +102,13 @@ struct TLCS900H {
template<typename Source> auto instructionCall(uint4 code, Source) -> void;
template<typename Source> auto instructionCallRelative(Source) -> void;
template<typename Target, typename Offset> auto instructionChange(Target, Offset) -> void;
template<typename Size, int Adjust, typename Target> auto instructionCompare(Target) -> void;
template<typename Size, int Adjust, typename Target> auto instructionCompareRepeat(Target) -> void;
template<typename Target, typename Source> auto instructionCompare(Target, Source) -> 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 Offset> auto instructionDecrementJumpNotZero(Target, Offset) -> void;
template<typename Target, typename Source> auto instructionDivide(Target, Source) -> void;
template<typename Target, typename Source> auto instructionDivideSigned(Target, Source) -> void;
template<typename Target, typename Source> auto instructionExchange(Target, Source) -> void;
......@@ -115,8 +118,13 @@ struct TLCS900H {
template<typename Target, typename Source> auto instructionIncrement(Target, Source) -> void;
template<typename Source> auto instructionJump(uint4 code, Source) -> void;
template<typename Source> auto instructionJumpRelative(uint4 code, Source) -> void;
template<typename Target, typename Offset> auto instructionLink(Target, Offset) -> void;
template<typename Target, typename Source> auto instructionLoad(Target, Source) -> void;
template<typename Source, typename Offset> auto instructionLoadCarry(Source, Offset) -> void;
template<typename Size, int Adjust> auto instructionLoad() -> void;
template<typename Size, int Adjust> auto instructionLoadRepeat() -> void;
template<uint Modulo, typename Target, typename Source> auto instructionModuloDecrement(Target, Source) -> void;
template<uint Modulo, typename Target, typename Source> auto instructionModuloIncrement(Target, Source) -> void;
auto instructionMirror(Register<uint16>) -> void;
template<typename Target, typename Source> auto instructionMultiply(Target, Source) -> void;
auto instructionMultiplyAdd(Register<uint16>) -> void;
......@@ -125,14 +133,17 @@ struct TLCS900H {
auto instructionNoOperation() -> void;
template<typename Target, typename Source> auto instructionOr(Target, Source) -> void;
template<typename Source, typename Offset> auto instructionOrCarry(Source, Offset) -> void;
template<typename Target> auto instructionPointerAdjustAccumulator(Target) -> void;
template<typename Target> auto instructionPop(Target) -> void;
template<typename Source> auto instructionPush(Source) -> void;
template<typename Target, typename Offset> auto instructionReset(Target, Offset) -> void;
auto instructionReturn(uint4 code) -> void;
template<typename Source> auto instructionReturnDeallocate(Source) -> void;
auto instructionReturnInterrupt() -> void;
template<typename LHS, typename RHS> auto instructionRotateLeftDigit(LHS, RHS) -> void;
template<typename Target, typename Amount> auto instructionRotateLeft(Target, Amount) -> void;
template<typename Target, typename Amount> auto instructionRotateLeftWithoutCarry(Target, Amount) -> void;
template<typename LHS, typename RHS> auto instructionRotateRightDigit(LHS, RHS) -> void;
template<typename Target, typename Amount> auto instructionRotateRight(Target, Amount) -> void;
template<typename Target, typename Amount> auto instructionRotateRightWithoutCarry(Target, Amount) -> void;
template<typename Target, typename Offset> auto instructionSet(Target, Offset) -> void;
......@@ -149,6 +160,7 @@ struct TLCS900H {
template<typename Target, typename Source> auto instructionSubtract(Target, Source) -> void;
template<typename Target, typename Source> auto instructionSubtractBorrow(Target, Source) -> void;
template<typename Target, typename Offset> auto instructionTestSet(Target, Offset) -> void;
template<typename Target> auto instructionUnlink(Target) -> void;
template<typename Target, typename Source> auto instructionXor(Target, Source) -> void;
template<typename Source, typename Offset> auto instructionXorCarry(Source, Offset) -> void;
......@@ -188,6 +200,7 @@ struct TLCS900H {
uint3 iff = 7; //interrupt mask flip-flop
uint1 halted;
uint8 prefix; //first opcode byte; needed for [CP|LD][ID](R) instructions
} r;
auto halted() const -> bool { return r.halted; }
......
......@@ -223,9 +223,9 @@ public:
};
struct Pixel {
uint source;
uint priority;
uint color;
uint source;
uint priority;
uint15 color;
};
//io.cpp
......
......@@ -2,16 +2,16 @@
namespace nall {
template<int Requested> struct Integer {
enum : uint { Precision = Requested < 1 ? 1 : Requested > 64 ? 64 : Requested };
template<int Precision> struct Integer {
static_assert(Precision >= 1 && Precision <= 64);
static inline constexpr auto bits() -> uint { return Precision; }
using type =
using stype =
typename conditional<bits() <= 8, int8_t,
typename conditional<bits() <= 16, int16_t,
typename conditional<bits() <= 32, int32_t,
typename conditional<bits() <= 64, int64_t,
void>::type>::type>::type>::type;
using utype = typename Natural<Requested>::type;
using utype = typename Natural<Precision>::utype;
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - bits(); }
static inline constexpr auto sign() -> utype { return 1ull << Precision - 1; }
......@@ -20,7 +20,7 @@ template<int Requested> struct Integer {
template<typename T> inline Integer(const T& value) { data = mask(value); }
explicit inline operator bool() const { return data; }
inline operator type() const { return data; }
inline operator int64_t() const { return data; }
inline auto operator++(int) { auto value = *this; data = mask(data + 1); return value; }
inline auto operator--(int) { auto value = *this; data = mask(data - 1); return value; }
......@@ -49,59 +49,54 @@ template<int Requested> struct Integer {
#undef lhs
#undef rhs
inline auto bits(int lo, int hi) -> BitRange<Requested> { return {(utype&)data, lo, hi}; }
inline auto bit(int index) -> BitRange<Requested> { return {(utype&)data, index, index}; }
inline auto byte(int index) -> BitRange<Requested> { return {(utype&)data, index * 8 + 0, index * 8 + 7}; }
#define lhs (int64_t)data
#define rhs value
#undef lhs
#undef rhs
inline auto bits(int lo, int hi) -> BitRange<Precision> { return {(utype&)data, lo, hi}; }
inline auto bit(int index) -> BitRange<Precision> { return {(utype&)data, index, index}; }
inline auto byte(int index) -> BitRange<Precision> { return {(utype&)data, index * 8 + 0, index * 8 + 7}; }
inline auto bits(int lo, int hi) const -> const BitRange<Requested> { return {(utype&)*this, lo, lo}; }
inline auto bit(int index) const -> const BitRange<Requested> { return {(utype&)*this, index, index}; }
inline auto byte(int index) const -> const BitRange<Requested> { return {(utype&)*this, index * 8 + 0, index * 8 + 7}; }
inline auto bits(int lo, int hi) const -> const BitRange<Precision> { return {(utype&)*this, lo, lo}; }
  • Just to double-check: Is it normal to have return {(utype&)*this, lo, lo}; instead of return {(utype&)*this, lo, hi};?

  • I checked with byuu and he said:

    Ah, good catch, thanks. I'll get that fixed. I don't think higan ever used .bits on signed types, but, definitely a serious bug.

    Thanks for the report!

Please register or sign in to reply
inline auto bit(int index) const -> const BitRange<Precision> { return {(utype&)*this, index, index}; }
inline auto byte(int index) const -> const BitRange<Precision> { return {(utype&)*this, index * 8 + 0, index * 8 + 7}; }
inline auto clamp(uint bits) -> type {
inline auto clamp(uint bits) {
const intmax b = 1ull << (bits - 1);
const intmax m = b - 1;
return data > m ? m : data < -b ? -b : data;
return Integer<64>{data > m ? m : data < -b ? -b : data};
}
inline auto clip(uint bits) -> type {
inline auto clip(uint bits) {
const uintmax b = 1ull << (bits - 1);
const uintmax m = b * 2 - 1;
return ((data & m) ^ b) - b;
return Integer<64>{(data & m ^ b) - b};
}
inline auto serialize(serializer& s) { s(data); }
inline auto natural() const -> Natural<Requested>;
inline auto natural() const -> Natural<Precision>;
private:
inline auto mask(type value) const -> type {
inline auto mask(stype value) const -> stype {
return (value & mask() ^ sign()) - sign();
}
type data;
stype data;
};
#define ALL 64
#define ADD 64 //LHS + RHS
#define INC 64 //1 + (LHS >= RHS ? LHS : RHS)
#define MAX 64 //LHS >= RHS ? LHS : RHS
#define MIN 64 //LHS <= RHS ? LHS : RHS
#define lhs (int64_t)(typename Integer<LHS>::type)l
#define rhs (typename Integer<RHS>::type)r
template<int LHS, int RHS> inline auto operator *(Integer<LHS> l, Integer<RHS> r) { return Integer<ADD>{lhs * rhs}; }
template<int LHS, int RHS> inline auto operator /(Integer<LHS> l, Integer<RHS> r) { return Integer<LHS>{lhs / rhs}; }
template<int LHS, int RHS> inline auto operator %(Integer<LHS> l, Integer<RHS> r) { return Integer<LHS>{lhs % rhs}; }
template<int LHS, int RHS> inline auto operator +(Integer<LHS> l, Integer<RHS> r) { return Integer<INC>{lhs + rhs}; }
template<int LHS, int RHS> inline auto operator -(Integer<LHS> l, Integer<RHS> r) { return Integer<INC>{lhs - rhs}; }
template<int LHS, int RHS> inline auto operator<<(Integer<LHS> l, Integer<RHS> r) { return Integer<ALL>{lhs << rhs}; }
template<int LHS, int RHS> inline auto operator>>(Integer<LHS> l, Integer<RHS> r) { return Integer<LHS>{lhs >> rhs}; }
template<int LHS, int RHS> inline auto operator &(Integer<LHS> l, Integer<RHS> r) { return Integer<MAX>{lhs & rhs}; }
template<int LHS, int RHS> inline auto operator ^(Integer<LHS> l, Integer<RHS> r) { return Integer<MAX>{lhs ^ rhs}; }
template<int LHS, int RHS> inline auto operator |(Integer<LHS> l, Integer<RHS> r) { return Integer<MAX>{lhs | rhs}; }
#undef ALL
#undef ADD
#undef INC
#undef MAX
#undef MIN
#define lhs (int64_t)l
#define rhs r
template<int LHS, int RHS> inline auto operator *(Integer<LHS> l, Integer<RHS> r) { return Integer<64>{lhs * rhs}; }
template<int LHS, int RHS> inline auto operator /(Integer<LHS> l, Integer<RHS> r) { return Integer<64>{lhs / rhs}; }
template<int LHS, int RHS> inline auto operator %(Integer<LHS> l, Integer<RHS> r) { return Integer<64>{lhs % rhs}; }
template<int LHS, int RHS> inline auto operator +(Integer<LHS> l, Integer<RHS> r) { return Integer<64>{lhs + rhs}; }
template<int LHS, int RHS> inline auto operator -(Integer<LHS> l, Integer<RHS> r) { return Integer<64>{lhs - rhs}; }
template<int LHS, int RHS> inline auto operator<<(Integer<LHS> l, Integer<RHS> r) { return Integer<64>{lhs << rhs}; }
template<int LHS, int RHS> inline auto operator>>(Integer<LHS> l, Integer<RHS> r) { return Integer<64>{lhs >> rhs}; }
template<int LHS, int RHS> inline auto operator &(Integer<LHS> l, Integer<RHS> r) { return Integer<64>{lhs & rhs}; }
template<int LHS, int RHS> inline auto operator ^(Integer<LHS> l, Integer<RHS> r) { return Integer<64>{lhs ^ rhs}; }
template<int LHS, int RHS> inline auto operator |(Integer<LHS> l, Integer<RHS> r) { return Integer<64>{lhs | rhs}; }
#undef lhs
#undef rhs
......
......@@ -2,23 +2,23 @@
namespace nall {
template<int Requested> struct Natural {
enum : uint { Precision = Requested < 1 ? 1 : Requested > 64 ? 64 : Requested };
template<int Precision> struct Natural {
static_assert(Precision >= 1 && Precision <= 64);
static inline constexpr auto bits() -> uint { return Precision; }
using type =
using utype =
typename conditional<bits() <= 8, uint8_t,
typename conditional<bits() <= 16, uint16_t,
typename conditional<bits() <= 32, uint32_t,
typename conditional<bits() <= 64, uint64_t,
void>::type>::type>::type>::type;
static inline constexpr auto mask() -> type { return ~0ull >> 64 - bits(); }
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - bits(); }
inline Natural() : data(0) {}
template<int Bits> inline Natural(Natural<Bits> value) { data = mask(value); }
template<typename T> inline Natural(const T& value) { data = mask(value); }
explicit inline operator bool() const { return data; }
inline operator type() const { return data; }
inline operator uint64_t() const { return data; }
inline auto operator++(int) { auto value = *this; data = mask(data + 1); return value; }
inline auto operator--(int) { auto value = *this; data = mask(data - 1); return value; }
......@@ -47,59 +47,84 @@ template<int Requested> struct Natural {
#undef lhs
#undef rhs
inline auto bits(int lo, int hi) <