#include "baremetal_protocol.hpp"

#include <poplar/Vertex.hpp>

volatile unsigned bareImageInput = 0x6badc0de;

class BareImageInputCheck : public poplar::SupervisorVertex {
public:
  __attribute__((target("supervisor"))) bool compute() {
#if defined(__IPU__) && defined(__POPC__)
    asm volatile("setzi $m6, 0x13579\n\t"
                 "setzi $m6, 0x2468a\n\t"
                 ".long 0x41800003\n\t"
                 :
                 :
                 : "memory");
    if (bareImageInput != __builtin_ipu_get_tile_id() + 0x123)
      while (true)
        asm volatile("nop");
    asm volatile(".long 0x41800007\n\t"
                 "1: bri 1b\n\t"
                 :
                 :
                 : "memory");
    __builtin_unreachable();
#endif
    return true;
  }
};

class BareImageConstantCheck : public poplar::SupervisorVertex {
public:
  __attribute__((target("supervisor"))) bool compute() {
#if defined(__IPU__) && defined(__POPC__)
    asm volatile("setzi $m6, 0x3579b\n\t"
                 "setzi $m6, 0x468ac\n\t"
                 ".long 0x41800003\n\t"
                 :
                 :
                 : "memory");
    if (bareImageInput != 0x56789)
      while (true)
        asm volatile("nop");
    asm volatile(".long 0x41800007\n\t"
                 "1: bri 1b\n\t"
                 :
                 :
                 : "memory");
    __builtin_unreachable();
#endif
    return true;
  }
};

class BareSignal : public poplar::SupervisorVertex {
public:
  __attribute__((target("supervisor"))) bool compute() {
#if defined(__IPU__) && defined(__POPC__)
    asm volatile("setzi $m6, 0x34567\n\t"
                 "setzi $m6, 0x45678\n\t"
                 ".long 0x41800003\n\t"
                 "1: bri 1b\n\t"
                 :
                 :
                 : "memory");
    __builtin_unreachable();
#endif
    return true;
  }
};

class BareResult : public poplar::SupervisorVertex {
public:
  __attribute__((target("supervisor"))) bool compute() {
#if defined(__IPU__) && defined(__POPC__)
    asm volatile("setzi $m6, 0x89abc\n\t"
                 "setzi $m6, 0x9abcd\n\t"
                 ".long 0x41800003\n\t"
                 "setzi $m1, 0x52000\n\t"
                 "setzi $m2, 1234\n\t"
                 "add $m2, $m2, 5678\n\t"
                 "st32 $m2, $m1, $m15, 0\n\t"
                 "1: bri 1b\n\t"
                 :
                 :
                 : "memory");
    __builtin_unreachable();
#endif
    return true;
  }
};

class BareResultAlternate : public poplar::SupervisorVertex {
public:
  __attribute__((target("supervisor"))) bool compute() {
#if defined(__IPU__) && defined(__POPC__)
    asm volatile("setzi $m6, 0xabcde\n\t"
                 "setzi $m6, 0xbcdef\n\t"
                 ".long 0x41800003\n\t"
                 "setzi $m1, 0x52000\n\t"
                 "setzi $m2, 1111\n\t"
                 "add $m2, $m2, 2222\n\t"
                 "st32 $m2, $m1, $m15, 0\n\t"
                 "1: bri 1b\n\t"
                 :
                 :
                 : "memory");
    __builtin_unreachable();
#endif
    return true;
  }
};

class BareHostExchange : public poplar::SupervisorVertex {
public:
  __attribute__((target("supervisor"))) bool compute() {
#if defined(__IPU__) && defined(__POPC__)
    asm volatile("setzi $m6, 0xcdef0\n\t"
                 "setzi $m6, 0xdef01\n\t"
                 ".long 0x41800003\n\t"
                 ".p2align 3\n\t"
                 "setzi $m1, 95f\n\t"
                 "ld32 $m0, $m15, $m1, 0\n\t"
                 "setzi $m5, 0x52000\n\t"
                 "st32 $m0, $m5, $m15, 0\n\t"
                 ".long 0x0face000\n\t"
                 "cmpeq $m4, $m3, 2\n\t"
                 "brnz $m4, 20f\n\t"
                 "cmpeq $m4, $m3, 0\n\t"
                 "brnz $m4, 30f\n\t"
                 "bri 90f\n\t"
                 ".p2align 3\n\t"
                 "20:\n\t"
                 "put 0xa7, $m5\n\t"
                 "setzi $m10, 22f\n\t"
                 "setzi $m2, 21f\n\t"
                 "br $m2\n\t"
                 ".p2align 3\n\t"
                 "21:\n\t"
                 ".long 0x0bad0000, 0x0bad0001, 0x0bad0002\n\t"
                 ".long 0x0bad0003, 0x0bad0004, 0x0bad0005\n\t"
                 ".long 0x0bad0006, 0x0bad0007, 0x0bad0008\n\t"
                 ".p2align 3\n\t"
                 "22:\n\t"
                 "bri 90f\n\t"
                 ".p2align 3\n\t"
                 "30:\n\t"
                 "setzi $m4, 999999\n\t"
                 ".p2align 3\n\t"
                 "31:\n\t"
                 "zero $m15\n\t"
                 "brnzdec $m4, 31b\n\t"
                 "setzi $m5, 0x52008\n\t"
                 "put 0xa4, $m5\n\t"
                 "setzi $m10, 33f\n\t"
                 "setzi $m2, 32f\n\t"
                 "br $m2\n\t"
                 ".p2align 3\n\t"
                 "32:\n\t"
                 ".long 0x0bad0000, 0x0bad0001, 0x0bad0002\n\t"
                 ".long 0x0bad0003, 0x0bad0004, 0x0bad0005\n\t"
                 ".long 0x0bad0006, 0x0bad0007, 0x0bad0008\n\t"
                 ".p2align 3\n\t"
                 "33:\n\t"
                 "setzi $m5, 0x52000\n\t"
                 "ld32 $m0, $m5, $m15, 0\n\t"
                 "setzi $m5, 0x52008\n\t"
                 "ld32 $m1, $m5, $m15, 0\n\t"
                 "add $m0, $m0, $m1\n\t"
                 "setzi $m5, 0x5200c\n\t"
                 "st32 $m0, $m5, $m15, 0\n\t"
                 ".p2align 3\n\t"
                 "90:\n\t"
                 ".long 0x41800007\n\t"
                 "add $m6, $m6, 1\n\t"
                 "bri 90b\n\t"
                 ".p2align 3\n\t"
                 "95:\n\t"
                 ".long 0xdec0adde\n\t"
                 :
                 :
                 : "$m0", "$m1", "$m2", "$m3", "$m4", "$m5", "$m10", "memory");
    __builtin_unreachable();
#endif
    return true;
  }
};

class BareHostConstantCheck : public poplar::SupervisorVertex {
public:
  __attribute__((target("supervisor"))) bool compute() {
#if defined(__IPU__) && defined(__POPC__)
    asm volatile("setzi $m6, 0x6789a\n\t"
                 "setzi $m6, 0x789ab\n\t"
                 ".long 0x41800003\n\t"
                 "setzi $m1, 0x52000\n\t"
                 "1:\n\t"
                 "ld32 $m2, $m1, $m15, 0\n\t"
                 "setzi $m0, 0x56789\n\t"
                 "cmpeq $m0, $m0, $m2\n\t"
                 "brz $m0, 1b\n\t"
                 ".long 0x41800007\n\t"
                 "2: bri 2b\n\t"
                 :
                 :
                 : "memory");
    __builtin_unreachable();
#endif
    return true;
  }
};

class BareHostWriteCheck : public poplar::SupervisorVertex {
public:
  __attribute__((target("supervisor"))) bool compute() {
#if defined(__IPU__) && defined(__POPC__)
    asm volatile("setzi $m6, 0x12345\n\t"
                 "setzi $m6, 0x23456\n\t"
                 ".long 0x41800003\n\t"
                 "setzi $m1, 0x52000\n\t"
                 "1:\n\t"
                 "get $m0, 3\n\t"
                 "ld32 $m2, $m1, $m15, 0\n\t"
                 "add $m0, $m0, 0x123\n\t"
                 "cmpeq $m0, $m0, $m2\n\t"
                 "brz $m0, 1b\n\t"
                 ".long 0x41800007\n\t"
                 "2: bri 2b\n\t"
                 :
                 :
                 : "memory");
    __builtin_unreachable();
#endif
    return true;
  }
};
