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:
Tim Allen 2019-01-11 12:51:18 +11:00
parent 95d0020297
commit c9f7c6c4be
8 changed files with 211 additions and 116 deletions

View File

@ -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/";

View File

@ -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;
} }

View File

@ -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;

View File

@ -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);

View File

@ -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>

View File

@ -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; }

View File

@ -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;

View File

@ -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,