Files
P3DS-test/third_party/teakra/include/teakra/impl/register.h
wheremyfoodat 78002be334 Vendor Teakra, make emulator own DSP RAM and add DSP RAM to fastmem (#806)
* DSP: Own DSP RAM and add it to fastmem

* Vendor Teakra

* Add MacOS support to fastmem

* Fix MacOS fastmem paths

* Fix iOS build
2025-08-22 02:12:21 +03:00

688 lines
22 KiB
C++

#pragma once
#include <algorithm>
#include <array>
#include <memory>
#include <vector>
#include "../../../src/common_types.h"
#include "../../../src/crash.h"
#include "../../../src/operand.h"
namespace Teakra {
struct RegisterState {
void Reset() {
*this = RegisterState();
}
/** Program control unit **/
u32 pc = 0; // 18-bit, program counter
u16 prpage = 0; // 4-bit, program page
u16 cpc = 1; // 1-bit, change word order when push/pop pc
u16 repc = 0; // 16-bit rep loop counter
u16 repcs = 0; // repc shadow
bool rep = false; // true when in rep loop
u16 crep = 1; // 1-bit. If clear, store/restore repc to shadows on context switch
u16 bcn = 0; // 3-bit, nest loop counter
u16 lp = 0; // 1-bit, set when in a loop
struct BlockRepeatFrame {
u32 start = 0;
u32 end = 0;
u16 lc = 0;
};
std::array<BlockRepeatFrame, 4> bkrep_stack;
u16& Lc() {
if (lp)
return bkrep_stack[bcn - 1].lc;
return bkrep_stack[0].lc;
}
/** Computation unit **/
// 40-bit 2's comp accumulators.
// Use 64-bit 2's comp here. The upper 24 bits are always sign extension
std::array<u64, 2> a{};
std::array<u64, 2> b{};
u64 a1s = 0, b1s = 0; // shadows for a1 and b1
u16 ccnta = 1; // 1-bit. If clear, store/restore a1/b1 to shadows on context switch
u16 sat = 0; // 1-bit, disable saturation when moving from acc
u16 sata = 1; // 1-bit, disable saturation when moving to acc
u16 s = 0; // 1-bit, shift mode. 0 - arithmetic, 1 - logic
u16 sv = 0; // 16-bit two's complement shift value
// 1-bit flags
u16 fz = 0; // zero flag
u16 fm = 0; // negative flag
u16 fn = 0; // normalized flag
u16 fv = 0; // overflow flag
u16 fe = 0; // extension flag
u16 fc0 = 0; // carry flag
u16 fc1 = 0; // another carry flag
u16 flm = 0; // set on saturation
u16 fvl = 0; // latching fv
u16 fr = 0; // Rn zero flag
// Viterbi
u16 vtr0 = 0;
u16 vtr1 = 0;
/** Multiplication unit **/
std::array<u16, 2> x{}; // factor
std::array<u16, 2> y{}; // factor
u16 hwm = 0; // 2-bit, half word mode, modify y on multiplication
std::array<u32, 2> p{}; // product
std::array<u16, 2> pe{}; // 1-bit product extension
std::array<u16, 2> ps{}; // 2-bit, product shift mode
u16 p0h_cbs = 0; // 16-bit hidden state for codebook search (CBS) opcode
/** Address unit **/
std::array<u16, 8> r{}; // 16-bit general and address registers
u16 mixp = 0; // 16-bit, stores result of min/max instructions
u16 sp = 0; // 16-bit stack pointer
u16 page = 0; // 8-bit, higher part of MemImm8 address
u16 pcmhi = 0; // 2-bit, higher part of program address for movp/movd
// shadows for bank exchange;
u16 r0b = 0, r1b = 0, r4b = 0, r7b = 0;
/** Address step/mod unit **/
// step/modulo
u16 stepi = 0, stepj = 0; // 7-bit step
u16 modi = 0, modj = 0; // 9-bit mod
u16 stepi0 = 0, stepj0 = 0; // 16-bit step
// shadows for bank exchange
u16 stepib = 0, stepjb = 0;
u16 modib = 0, modjb = 0;
u16 stepi0b = 0, stepj0b = 0;
std::array<u16, 8> m{}; // 1-bit each, enable modulo arithmetic for Rn
std::array<u16, 8> br{}; // 1-bit each, use bit-reversed value from Rn as address
u16 stp16 = 0; // 1 bit. If set, stepi0/j0 will be exchanged along with cfgi/j in banke, and use
// stepi0/j0 for steping
u16 cmd = 1; // 1-bit, step/mod method. 0 - Teak; 1 - TeakLite
u16 epi = 0; // 1-bit. If set, cause r3 = 0 when steping r3
u16 epj = 0; // 1-bit. If set, cause r7 = 0 when steping r7
/** Indirect address unit **/
// 3 bits each
// 0: +0
// 1: +1
// 2: -1
// 3: +s
// 4: +2
// 5: -2
// 6: +2*
// 7: -2*
std::array<u16, 4> arstep{{1, 4, 5, 3}}, arpstepi{{1, 4, 5, 3}}, arpstepj{{1, 4, 5, 3}};
// 2 bits each
// 0: +0
// 1: +1
// 2: -1
// 3: -1*
std::array<u16, 4> aroffset{{0, 1, 2, 0}}, arpoffseti{{0, 1, 2, 0}}, arpoffsetj{{0, 1, 2, 0}};
// 3 bits each, represent r0~r7
std::array<u16, 4> arrn{{0, 4, 2, 6}};
// 2 bits each. for i represent r0~r3, for j represents r4~r7
std::array<u16, 4> arprni{{0, 1, 2, 3}}, arprnj{{0, 1, 2, 3}};
/** Interrupt unit **/
// interrupt pending bit
std::array<u16, 3> ip{};
u16 ipv = 0;
// interrupt enable bit
std::array<u16, 3> im{};
u16 imv = 0;
// interrupt context switching bit
std::array<u16, 3> ic{};
u16 nimc = 0;
// interrupt enable master bit
u16 ie = 0;
/** Extension unit **/
std::array<u16, 5> ou{}; // user output pins
std::array<u16, 2> iu{}; // user input pins
std::array<u16, 4> ext{};
u16 mod0_unk_const = 1; // 3-bit
/** Shadow registers **/
template <u16 RegisterState::* origin>
class ShadowRegister {
public:
void Store(RegisterState* self) {
shadow = self->*origin;
}
void Restore(RegisterState* self) {
self->*origin = shadow;
}
private:
u16 shadow = 0;
};
template <std::size_t size, std::array<u16, size> RegisterState::* origin>
class ShadowArrayRegister {
public:
void Store(RegisterState* self) {
shadow = self->*origin;
}
void Restore(RegisterState* self) {
self->*origin = shadow;
}
private:
std::array<u16, size> shadow{};
};
template <typename... ShadowRegisters>
class ShadowRegisterList : private ShadowRegisters... {
public:
void Store(RegisterState* self) {
(ShadowRegisters::Store(self), ...);
}
void Restore(RegisterState* self) {
(ShadowRegisters::Restore(self), ...);
}
};
template <u16 RegisterState::* origin>
class ShadowSwapRegister {
public:
void Swap(RegisterState* self) {
std::swap(self->*origin, shadow);
}
private:
u16 shadow = 0;
};
template <std::size_t size, std::array<u16, size> RegisterState::* origin>
class ShadowSwapArrayRegister {
public:
void Swap(RegisterState* self) {
std::swap(self->*origin, shadow);
}
private:
std::array<u16, size> shadow{};
};
template <typename... ShadowSwapRegisters>
class ShadowSwapRegisterList : private ShadowSwapRegisters... {
public:
void Swap(RegisterState* self) {
(ShadowSwapRegisters::Swap(self), ...);
}
};
// clang-format off
ShadowRegisterList<
ShadowRegister<&RegisterState::flm>,
ShadowRegister<&RegisterState::fvl>,
ShadowRegister<&RegisterState::fe>,
ShadowRegister<&RegisterState::fc0>,
ShadowRegister<&RegisterState::fc1>,
ShadowRegister<&RegisterState::fv>,
ShadowRegister<&RegisterState::fn>,
ShadowRegister<&RegisterState::fm>,
ShadowRegister<&RegisterState::fz>,
ShadowRegister<&RegisterState::fr>
> shadow_registers;
ShadowSwapRegisterList<
ShadowSwapRegister<&RegisterState::pcmhi>,
ShadowSwapRegister<&RegisterState::sat>,
ShadowSwapRegister<&RegisterState::sata>,
ShadowSwapRegister<&RegisterState::hwm>,
ShadowSwapRegister<&RegisterState::s>,
ShadowSwapArrayRegister<2, &RegisterState::ps>,
ShadowSwapRegister<&RegisterState::page>,
ShadowSwapRegister<&RegisterState::stp16>,
ShadowSwapRegister<&RegisterState::cmd>,
ShadowSwapArrayRegister<8, &RegisterState::m>,
ShadowSwapArrayRegister<8, &RegisterState::br>,
ShadowSwapArrayRegister<3, &RegisterState::im>, // ?
ShadowSwapRegister<&RegisterState::imv>, // ?
ShadowSwapRegister<&RegisterState::epi>,
ShadowSwapRegister<&RegisterState::epj>
> shadow_swap_registers;
// clang-format on
template <unsigned index>
class ShadowSwapAr {
public:
void Swap(RegisterState* self) {
std::swap(self->arrn[index * 2], rni);
std::swap(self->arrn[index * 2 + 1], rnj);
std::swap(self->arstep[index * 2], stepi);
std::swap(self->arstep[index * 2 + 1], stepj);
std::swap(self->aroffset[index * 2], offseti);
std::swap(self->aroffset[index * 2 + 1], offsetj);
}
private:
u16 rni, rnj, stepi, stepj, offseti, offsetj;
};
template <unsigned index>
class ShadowSwapArp {
public:
void Swap(RegisterState* self) {
std::swap(self->arprni[index], rni);
std::swap(self->arprnj[index], rnj);
std::swap(self->arpstepi[index], stepi);
std::swap(self->arpstepj[index], stepj);
std::swap(self->arpoffseti[index], offseti);
std::swap(self->arpoffsetj[index], offsetj);
}
private:
u16 rni, rnj, stepi, stepj, offseti, offsetj;
};
ShadowSwapAr<0> shadow_swap_ar0;
ShadowSwapAr<1> shadow_swap_ar1;
ShadowSwapArp<0> shadow_swap_arp0;
ShadowSwapArp<1> shadow_swap_arp1;
ShadowSwapArp<2> shadow_swap_arp2;
ShadowSwapArp<3> shadow_swap_arp3;
void ShadowStore() {
shadow_registers.Store(this);
}
void ShadowRestore() {
shadow_registers.Restore(this);
}
void SwapAllArArp() {
shadow_swap_ar0.Swap(this);
shadow_swap_ar1.Swap(this);
shadow_swap_arp0.Swap(this);
shadow_swap_arp1.Swap(this);
shadow_swap_arp2.Swap(this);
shadow_swap_arp3.Swap(this);
}
void ShadowSwap() {
shadow_swap_registers.Swap(this);
SwapAllArArp();
}
void SwapAr(u16 index) {
switch (index) {
case 0:
shadow_swap_ar0.Swap(this);
break;
case 1:
shadow_swap_ar1.Swap(this);
break;
}
}
void SwapArp(u16 index) {
switch (index) {
case 0:
shadow_swap_arp0.Swap(this);
break;
case 1:
shadow_swap_arp1.Swap(this);
break;
case 2:
shadow_swap_arp2.Swap(this);
break;
case 3:
shadow_swap_arp3.Swap(this);
break;
}
}
bool ConditionPass(Cond cond) const {
switch (cond.GetName()) {
case CondValue::True:
return true;
case CondValue::Eq:
return fz == 1;
case CondValue::Neq:
return fz == 0;
case CondValue::Gt:
return fz == 0 && fm == 0;
case CondValue::Ge:
return fm == 0;
case CondValue::Lt:
return fm == 1;
case CondValue::Le:
return fm == 1 || fz == 1;
case CondValue::Nn:
return fn == 0;
case CondValue::C:
return fc0 == 1;
case CondValue::V:
return fv == 1;
case CondValue::E:
return fe == 1;
case CondValue::L:
return flm == 1 || fvl == 1;
case CondValue::Nr:
return fr == 0;
case CondValue::Niu0:
return iu[0] == 0;
case CondValue::Iu0:
return iu[0] == 1;
case CondValue::Iu1:
return iu[1] == 1;
default:
UNREACHABLE();
}
}
template <typename PseudoRegisterT>
u16 Get() const {
return PseudoRegisterT::Get(this);
}
template <typename PseudoRegisterT>
void Set(u16 value) {
PseudoRegisterT::Set(this, value);
}
};
template <u16 RegisterState::* target>
struct Redirector {
static u16 Get(const RegisterState* self) {
return self->*target;
}
static void Set(RegisterState* self, u16 value) {
self->*target = value;
}
};
template <std::size_t size, std::array<u16, size> RegisterState::* target, std::size_t index>
struct ArrayRedirector {
static u16 Get(const RegisterState* self) {
return (self->*target)[index];
}
static void Set(RegisterState* self, u16 value) {
(self->*target)[index] = value;
}
};
template <u16 RegisterState::* target0, u16 RegisterState::* target1>
struct DoubleRedirector {
static u16 Get(const RegisterState* self) {
return self->*target0 | self->*target1;
}
static void Set(RegisterState* self, u16 value) {
self->*target0 = self->*target1 = value;
}
};
template <u16 RegisterState::* target>
struct RORedirector {
static u16 Get(const RegisterState* self) {
return self->*target;
}
static void Set(RegisterState*, u16) {
// no
}
};
template <std::size_t size, std::array<u16, size> RegisterState::* target, std::size_t index>
struct ArrayRORedirector {
static u16 Get(const RegisterState* self) {
return (self->*target)[index];
}
static void Set(RegisterState*, u16) {
// no
}
};
template <unsigned index>
struct AccEProxy {
static u16 Get(const RegisterState* self) {
return (u16)((self->a[index] >> 32) & 0xF);
}
static void Set(RegisterState* self, u16 value) {
u32 value32 = SignExtend<4>((u32)value);
self->a[index] &= 0xFFFFFFFF;
self->a[index] |= (u64)value32 << 32;
}
};
struct LPRedirector {
static u16 Get(const RegisterState* self) {
return self->lp;
}
static void Set(RegisterState* self, u16 value) {
if (value != 0) {
self->lp = 0;
self->bcn = 0;
}
}
};
template <typename Proxy, unsigned position, unsigned length>
struct ProxySlot {
using proxy = Proxy;
static constexpr unsigned pos = position;
static constexpr unsigned len = length;
static_assert(length < 16, "Error");
static_assert(position + length <= 16, "Error");
static constexpr u16 mask = ((1 << length) - 1) << position;
};
template <typename... ProxySlots>
struct PseudoRegister {
static_assert(NoOverlap<u16, ProxySlots::mask...>, "Error");
static u16 Get(const RegisterState* self) {
return ((ProxySlots::proxy::Get(self) << ProxySlots::pos) | ...);
}
static void Set(RegisterState* self, u16 value) {
(ProxySlots::proxy::Set(self, (value >> ProxySlots::pos) & ((1 << ProxySlots::len) - 1)),
...);
}
};
// clang-format off
using cfgi = PseudoRegister<
ProxySlot<Redirector<&RegisterState::stepi>, 0, 7>,
ProxySlot<Redirector<&RegisterState::modi>, 7, 9>
>;
using cfgj = PseudoRegister<
ProxySlot<Redirector<&RegisterState::stepj>, 0, 7>,
ProxySlot<Redirector<&RegisterState::modj>, 7, 9>
>;
using stt0 = PseudoRegister<
ProxySlot<Redirector<&RegisterState::flm>, 0, 1>,
ProxySlot<Redirector<&RegisterState::fvl>, 1, 1>,
ProxySlot<Redirector<&RegisterState::fe>, 2, 1>,
ProxySlot<Redirector<&RegisterState::fc0>, 3, 1>,
ProxySlot<Redirector<&RegisterState::fv>, 4, 1>,
ProxySlot<Redirector<&RegisterState::fn>, 5, 1>,
ProxySlot<Redirector<&RegisterState::fm>, 6, 1>,
ProxySlot<Redirector<&RegisterState::fz>, 7, 1>,
ProxySlot<Redirector<&RegisterState::fc1>, 11, 1>
>;
using stt1 = PseudoRegister<
ProxySlot<Redirector<&RegisterState::fr>, 4, 1>,
ProxySlot<ArrayRORedirector<2, &RegisterState::iu, 0>, 10, 1>,
ProxySlot<ArrayRORedirector<2, &RegisterState::iu, 1>, 11, 1>,
ProxySlot<ArrayRedirector<2, &RegisterState::pe, 0>, 14, 1>,
ProxySlot<ArrayRedirector<2, &RegisterState::pe, 1>, 15, 1>
>;
using stt2 = PseudoRegister<
ProxySlot<ArrayRORedirector<3, &RegisterState::ip, 0>, 0, 1>,
ProxySlot<ArrayRORedirector<3, &RegisterState::ip, 1>, 1, 1>,
ProxySlot<ArrayRORedirector<3, &RegisterState::ip, 2>, 2, 1>,
ProxySlot<RORedirector<&RegisterState::ipv>, 3, 1>,
ProxySlot<Redirector<&RegisterState::pcmhi>, 6, 2>,
ProxySlot<RORedirector<&RegisterState::bcn>, 12, 3>,
ProxySlot<LPRedirector, 15, 1>
>;
using mod0 = PseudoRegister<
ProxySlot<Redirector<&RegisterState::sat>, 0, 1>,
ProxySlot<Redirector<&RegisterState::sata>, 1, 1>,
ProxySlot<RORedirector<&RegisterState::mod0_unk_const>, 2, 3>,
ProxySlot<Redirector<&RegisterState::hwm>, 5, 2>,
ProxySlot<Redirector<&RegisterState::s>, 7, 1>,
ProxySlot<ArrayRedirector<5, &RegisterState::ou, 0>, 8, 1>,
ProxySlot<ArrayRedirector<5, &RegisterState::ou, 1>, 9, 1>,
ProxySlot<ArrayRedirector<2, &RegisterState::ps, 0>, 10, 2>,
ProxySlot<ArrayRedirector<2, &RegisterState::ps, 1>, 13, 2>
>;
using mod1 = PseudoRegister<
ProxySlot<Redirector<&RegisterState::page>, 0, 8>,
ProxySlot<Redirector<&RegisterState::stp16>, 12, 1>,
ProxySlot<Redirector<&RegisterState::cmd>, 13, 1>,
ProxySlot<Redirector<&RegisterState::epi>, 14, 1>,
ProxySlot<Redirector<&RegisterState::epj>, 15, 1>
>;
using mod2 = PseudoRegister<
ProxySlot<ArrayRedirector<8, &RegisterState::m, 0>, 0, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 1>, 1, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 2>, 2, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 3>, 3, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 4>, 4, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 5>, 5, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 6>, 6, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 7>, 7, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::br, 0>, 8, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::br, 1>, 9, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::br, 2>, 10, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::br, 3>, 11, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::br, 4>, 12, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::br, 5>, 13, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::br, 6>, 14, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::br, 7>, 15, 1>
>;
using mod3 = PseudoRegister<
ProxySlot<Redirector<&RegisterState::nimc>, 0, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::ic, 0>, 1, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::ic, 1>, 2, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::ic, 2>, 3, 1>,
ProxySlot<ArrayRedirector<5, &RegisterState::ou, 2>, 4, 1>,
ProxySlot<ArrayRedirector<5, &RegisterState::ou, 3>, 5, 1>,
ProxySlot<ArrayRedirector<5, &RegisterState::ou, 4>, 6, 1>,
ProxySlot<Redirector<&RegisterState::ie>, 7, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::im, 0>, 8, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::im, 1>, 9, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::im, 2>, 10, 1>,
ProxySlot<Redirector<&RegisterState::imv>, 11, 1>,
ProxySlot<Redirector<&RegisterState::ccnta>, 13, 1>,
ProxySlot<Redirector<&RegisterState::cpc>, 14, 1>,
ProxySlot<Redirector<&RegisterState::crep>, 15, 1>
>;
using st0 = PseudoRegister<
ProxySlot<Redirector<&RegisterState::sat>, 0, 1>,
ProxySlot<Redirector<&RegisterState::ie>, 1, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::im, 0>, 2, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::im, 1>, 3, 1>,
ProxySlot<Redirector<&RegisterState::fr>, 4, 1>,
ProxySlot<DoubleRedirector<&RegisterState::flm, &RegisterState::fvl>, 5, 1>,
ProxySlot<Redirector<&RegisterState::fe>, 6, 1>,
ProxySlot<Redirector<&RegisterState::fc0>, 7, 1>,
ProxySlot<Redirector<&RegisterState::fv>, 8, 1>,
ProxySlot<Redirector<&RegisterState::fn>, 9, 1>,
ProxySlot<Redirector<&RegisterState::fm>, 10, 1>,
ProxySlot<Redirector<&RegisterState::fz>, 11, 1>,
ProxySlot<AccEProxy<0>, 12, 4>
>;
using st1 = PseudoRegister<
ProxySlot<Redirector<&RegisterState::page>, 0, 8>,
// 8, 9: reserved
ProxySlot<ArrayRedirector<2, &RegisterState::ps, 0>, 10, 2>,
ProxySlot<AccEProxy<1>, 12, 4>
>;
using st2 = PseudoRegister<
ProxySlot<ArrayRedirector<8, &RegisterState::m, 0>, 0, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 1>, 1, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 2>, 2, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 3>, 3, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 4>, 4, 1>,
ProxySlot<ArrayRedirector<8, &RegisterState::m, 5>, 5, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::im, 2>, 6, 1>,
ProxySlot<Redirector<&RegisterState::s>, 7, 1>,
ProxySlot<ArrayRedirector<5, &RegisterState::ou, 0>, 8, 1>,
ProxySlot<ArrayRedirector<5, &RegisterState::ou, 1>, 9, 1>,
ProxySlot<ArrayRORedirector<2, &RegisterState::iu, 0>, 10, 1>,
ProxySlot<ArrayRORedirector<2, &RegisterState::iu, 1>, 11, 1>,
// 12: reserved
ProxySlot<ArrayRORedirector<3, &RegisterState::ip, 2>, 13, 1>, // Note the index order!
ProxySlot<ArrayRORedirector<3, &RegisterState::ip, 0>, 14, 1>,
ProxySlot<ArrayRORedirector<3, &RegisterState::ip, 1>, 15, 1>
>;
using icr = PseudoRegister<
ProxySlot<Redirector<&RegisterState::nimc>, 0, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::ic, 0>, 1, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::ic, 1>, 2, 1>,
ProxySlot<ArrayRedirector<3, &RegisterState::ic, 2>, 3, 1>,
ProxySlot<LPRedirector, 4, 1>,
ProxySlot<RORedirector<&RegisterState::bcn>, 5, 3>
>;
template<unsigned index>
using ar = PseudoRegister<
ProxySlot<ArrayRedirector<4, &RegisterState::arstep, index * 2 + 1>, 0, 3>,
ProxySlot<ArrayRedirector<4, &RegisterState::aroffset, index * 2 + 1>, 3, 2>,
ProxySlot<ArrayRedirector<4, &RegisterState::arstep, index * 2>, 5, 3>,
ProxySlot<ArrayRedirector<4, &RegisterState::aroffset, index * 2>, 8, 2>,
ProxySlot<ArrayRedirector<4, &RegisterState::arrn, index * 2 + 1>, 10, 3>,
ProxySlot<ArrayRedirector<4, &RegisterState::arrn, index * 2>, 13, 3>
>;
using ar0 = ar<0>;
using ar1 = ar<1>;
template<unsigned index>
using arp = PseudoRegister<
ProxySlot<ArrayRedirector<4, &RegisterState::arpstepi, index>, 0, 3>,
ProxySlot<ArrayRedirector<4, &RegisterState::arpoffseti, index>, 3, 2>,
ProxySlot<ArrayRedirector<4, &RegisterState::arpstepj, index>, 5, 3>,
ProxySlot<ArrayRedirector<4, &RegisterState::arpoffsetj, index>, 8, 2>,
ProxySlot<ArrayRedirector<4, &RegisterState::arprni, index>, 10, 2>,
// bit 12 reserved
ProxySlot<ArrayRedirector<4, &RegisterState::arprnj, index>, 13, 2>
// bit 15 reserved
>;
using arp0 = arp<0>;
using arp1 = arp<1>;
using arp2 = arp<2>;
using arp3 = arp<3>;
// clang-format on
} // namespace Teakra