#include <perms.h>
const int R0 = 0;
const int R1 = 1;
const int R2 = 2;
const int R3 = 3;
const int R4 = 4;
const int R5 = 5;
const int R6 = 6;
const int R7 = 7;
const int R8 = 8;
const int R9 = 9;
const int R10 = 10;
const int R11 = 11;
const int R12 = 12;
const int R13 = 13;
const int R14 = 14;
const int R15 = 15;
const int SB = R9;
const int FP = R10;
const int SP = R12;
const int PC = R15;
const int LINK = R14;
const int F0 = 16 + 0;
const int F1 = 16 + 1;
extern void CALLSIGNAL(void) /* See
                                https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html
                              */
    ;                        /*perm*/
void SIGNAL(void) {
  _imp_enter();
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void ASSTEST(void) {
  _imp_enter();
  asm("MOV _ R1, #8");
  asm("MOV _ R2, #1");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void RTMONITOR(void) {
  _imp_enter();
  asm("MOV _ R1, #4");
  asm("MOV _ R2, #0");
  asm("MOV _ R3, #7");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void SWJUMP(void) {
  _imp_enter();
  asm("BIC   _ Link, Link, #16_FC00 0000 {clear top bits}");
  asm("LDR   _ R2, [Link, #4]            {address of switch vector} {001}");
  asm("LDMIA _ R2!, <R4, R5>             {R4=UB, R5=LB}");
  asm("CMPS  _ R4, R1");
  asm("SUBGES_ R5, R1, R5");
  asm("MOVGE _ Pc, Link                  {return to LDR_Pc,[R2,R5,%LSL #2]}");
  asm("MOV   _ R3, R1        {index}");
  asm("MOV   _ R2, #4        {SUB}");
  asm("MOV   _ R1, #6        {EVENT, switch label error}");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void PRIMDIV(void) {
  _imp_enter();

  label... label... label... asm("CMPS   _ R2, #0");
  asm("BNE    _ L0");
  asm("MOV _ R1, #14;");
  asm("MOV _ R2, #2;");
  asm("MOV _ R3, #0");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
L0:;
  asm("MOV    _ R4, #1                {result sign}");
  asm("RSBLT  _ R2, R2, #0            {R2 = |R2|}");
  asm("RSBLT  _ R4, R4, #0            {invert result sign}");
  asm("ADDS   _ R5, R1, #0            {preserve Dividend & test sign}");
  asm("RSBLT  _ R1, R1, #0            {R1 = |R1|}");
  asm("RSBLT  _ R4, R4, #0            {invert result sign}");
  asm("MOV    _ R3, #1");

L1:;
  asm("CMPS   _ R2, #16_80000000");
  asm("CMPCCS _ R2, R1");
  asm("MOVCC  _ R2, R2, %LSL #1");
  asm("MOVCC  _ R3, R3, %LSL #1");
  asm("BCC    _ L1");
  asm("MOV    _ R0, #0");

L2:;
  asm("CMPS   _ R1, R2");
  asm("SUBCS  _ R1, R1, R2");
  asm("ADDCS  _ R0, R0, R3");
  asm("MOVS   _ R3, R3, %LSR #1");
  asm("MOVNE  _ R2, R2, %LSR #1");
  asm("BNE    _ L2");
  asm("CMPS   _ R4, #0");
  asm("RSBLT  _ R0, R0, #0         {negate quotient}");
  asm("CMPS   _ R5, #0");
  asm("RSBLT  _ R1, R1, #0         {negate remainder}");
  asm("MOV    _ Pc, Link");

  _imp_leave();
}
/*perm*/ void PRIMUDIV(void) {
  _imp_enter();

  label... label... label... asm("CMPS   _ R2, #0");
  asm("BNE    _ L0");
  asm("MOV _ R1, #14;");
  asm("MOV _ R2, #2;");
  asm("MOV _ R3, #0");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
L0:;
  asm("MOV    _ R3, #1");

L1:;
  asm("CMPS   _ R2, #16_80000000");
  asm("CMPCCS _ R2, R1");
  asm("MOVCC  _ R2, R2, %LSL #1");
  asm("MOVCC  _ R3, R3, %LSL #1");
  asm("BCC    _ L1");
  asm("MOV    _ R0, #0");

L2:;
  asm("CMPS   _ R1, R2");
  asm("SUBCS  _ R1, R1, R2");
  asm("ADDCS  _ R0, R0, R3");
  asm("MOVS   _ R3, R3, %LSR #1");
  asm("MOVNE  _ R2, R2, %LSR #1");
  asm("BNE    _ L2");
  asm("MOV    _ Pc, Link");

  _imp_leave();
}
/*perm*/ void SCONC(void) {
  _imp_enter();

  label... asm("LDRB   _ R4, [R3], #1         {length of new bit}");

L1:;
  asm("SUBS   _ R4, R4, #1");
  asm("LDRGEB _ R5, [R3], #1       {next character}");
  asm("STRGEB _ R5, [R2], #1       {plug it into destination}");
  asm("BGT    _ L1");
  asm("MOV    _ Pc, Link");

  _imp_leave();
}
/*perm*/ void SCOMP(void) {
  _imp_enter();

  label... label... asm("LDRB  _ R3, [R1], #1");
  asm("LDRB  _ R4, [R2], #1");
  asm("SUBS  _ R3, R3, R4");
  asm("ADDLT _ R4, R3, R4        {r4 is now the minimum length}");

S1:;
  asm("SUBS  _ R4, R4, #1");
  asm("BLT   _ S2                {common bits the same - use R3 for answer}");
  asm("LDRB  _ R5, [R1], #1");
  asm("LDRB  _ R6, [R2], #1");
  asm("CMPS  _ R5, R6");
  asm("BEQ   _ S1");
  asm("MOV   _ Pc, Link          {characters differ, return CC}");

S2:;
  asm("CMPS  _ R3, #0            {set CC on difference in lengths}");
  asm("MOV   _ Pc, Link          {return}");

  _imp_leave();
}
/*perm*/ void CSCOMP(void) {
  _imp_enter();

  label... asm("LDRB  _ R0, [R2]           {length of string}");
  asm("CMPS  _ R0, #1");
  asm("MOVLT _ Pc, Link           {compare against null - return LT}");
  asm("LDRB  _ R0, [R2, #1]       {first character}");
  asm("BEQ   _ L1");
  asm("CMPS  _ R0, R1");
  asm("MOVNE _ Pc, Link");
  asm("MOV   _ R0, #256           {to give >}");

L1:;
  asm("CMPS  _ R0, R1             {lengths the same}");
  asm("MOV   _ Pc, Link           {return}");

  _imp_leave();
}
/*perm*/ void SRES(void) {
  _imp_enter();

  label... label... label... asm(
      "LDRB  _ R7, [R1], #1         {length of source}");
  asm("LDRB  _ R3, [R2], #1         {length of pattern}");
  asm("MOVS  _ R6, R3               {test the length}");
  asm("MOVEQ _ Pc, Link             {null pattern -> success}");
  asm("LDRB  _ R0, [R2], #1         {first character of pattern}");
  asm("ADD   _ R4, R7, R1");
  asm("SUB   _ R4, R4, R3           {limit of search}");
  asm("MOV   _ R5, R1");

L1:;
  asm("CMPS  _ R5, R4               {check against limit}");
  asm("MOVGT _ Pc, R14              {greater implies failure}");
  asm("LDRB  _ R6, [R5], #1         {look for first character}");
  asm("CMPS  _ R6, R0");
  asm("BNE   _ L1");
  asm("SUBS  _ R7, R3, #2           {found}");
  asm("BLT   _ L3                   {only searching for a single character}");

L2:;
  asm("LDRB  _ R8, [R5, R7]         {compare the rest}");
  asm("LDRB  _ R6, [R2, R7]");
  asm("CMPS  _ R8, R6");
  asm("BNE   _ L1                   {no match, continue looking for first "
      "character}");
  asm("SUBS  _ R7, R7, #1");
  asm("BGT   _ L2");

L3:;
  asm("SUB   _ R5, R5, #1           {complete match}");
  asm("SUB   _ R7, R5, R1           {length of left fragment}");
  asm("SUB   _ R6, R4, R5           {length of right fragment}");
  asm("ADD   _ R3, R3, R5           {address of right fragment}");
  asm("CMPS  _ R3, R3               {set CC=EQ - success}");
  asm("MOV   _ Pc, Link             {return}");

  _imp_leave();
}
/*perm*/ void FRAG1(void) {
  _imp_enter();

  label... asm("STRB  _ R7, [R2],#1       {plug length}");

F1:;
  asm("SUBS  _ R7, R7, #1");
  asm("MOVLT _ Pc, Link          {all done}");
  asm("LDRB  _ R0, [R1], #1      {copy next character}");
  asm("STRB  _ R0, [R2], #1");
  asm("BR    _ F1");

  _imp_leave();
}
/*perm*/ void FRAG2(void) {
  _imp_enter();

  label... asm("STRB  _ R6, [R2],#1       {plug length}");

F1:;
  asm("SUBS  _ R6, R6, #1");
  asm("MOVLT _ Pc, Link          {all done}");
  asm("LDRB  _ R0, [R3], #1      {copy next character}");
  asm("STRB  _ R0, [R2], #1");
  asm("BR    _ F1");

  _imp_leave();
}
/*perm*/ void RESFLOP(void) {
  _imp_enter();
  asm("MOVEQ _ Pc, Link          {return if OK}");
  asm("MOV _ R1, #4");
  asm("MOV _ R2, #0");
  asm("MOV _ R3, #8");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void PRIMCOMP(void) {
  _imp_enter();

  label... asm("CMPS  _ R0, #0         {beware of null strings}");
  asm("MOVEQ _ Pc, Link       {return equal}");

L:;
  asm("LDRB  _ R3, [R1], #1");
  asm("LDRB  _ R4, [R2], #1");
  asm("CMPS  _ R3, R4");
  asm("MOVNE _ Pc, Link");
  asm("SUBS  _ R0, R0, #1");
  asm("BNE   _ L");
  asm("MOV   _ Pc, Link       {return equal}");

  _imp_leave();
}
/*perm*/ void SJAM(void) {
  _imp_enter();

  label... asm("LDRB   _ R3, [R1],#1      {actual length}");
  asm("CMPS   _ R0, R3           {compare with max+1}");
  asm("SUBLE  _ R3, R0, #1       {replace with max if nesc}");
  asm("STRB   _ R3, [R2], #1     {plug new length}");

L1:;
  asm("SUBS   _ R3, R3, #1");
  asm("MOVLT  _ Pc, Link");
  asm("LDRB   _ R0, [R1], #1");
  asm("STRB   _ R0, [R2], #1");
  asm("BR     _ L1");

  _imp_leave();
}
/*perm*/ void INTEXP(void) {
  _imp_enter();

  label... label... label... asm(
      "MOV    _ R0, R1         {preserve multiplier}");
  asm("MOV    _ R1, #1");
  asm("CMPS   _ R2, #0");
  asm("BLE    _ Ng");

L1:;
  asm("MOV    _ R3, R1         {Ra}");
  asm("MOV    _ R5, R0         {Rb}");
  asm("MOV    _ R1, #0");

L2:;
  asm("MOVS   _ R3, R3, %LSR #1");
  asm("ADDCS  _ R1, R1, R5");
  asm("ADD    _ R5, R5, R5");
  asm("BNE    _ L2");
  asm("SUBS   _ R2, R2, #1");
  asm("BNE    _ L1");

NG:;
  asm("MOVEQ  _ Pc, Link       {return 1 if zero}");
  asm("MOV _ R1, #4");
  asm("MOV _ R2, #0");
  asm("MOV _ R3, #20");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void DYNAMIC1(void) {
  _imp_enter();

  label... label... label... asm(
      "MOV   _ R2, #0      {calculate zero'th disp}");
  asm("MOV   _ R0, R5      {save multiplier}");
  asm("MOV   _ R6, R3      {save lower bound}");
  asm("MOV   _ R7, R4      {save upper bound}");
  asm("MOV   _ R8, R5      {save multiplier}");

M1:;
  asm("MOVS  _ R0, R0, %LSR #1");
  asm("ADDCS _ R2, R2, R6");
  asm("ADD   _ R6, R6, R6");
  asm("BNE   _ M1          {R2 = Lower*Item}");
  asm("RSB   _ R2, R2, #0  {R2 = -Lower*Item = Zero'th Disp}");
  asm("MOV   _ R1, #0      {calculate total size}");
  asm("ADD   _ R7, R7, #1");

M2:;
  asm("MOVS  _ R8, R8, %LSR #1");
  asm("ADDCS _ R1, R1, R7");
  asm("ADD   _ R7, R7, R7");
  asm("BNE   _ M2          {R1 = (Upper+1)*Item}");
  asm("ADDS  _ R1, R1, R2  {R1 = (Upper+1)*Item-Lower*Item = "
      "(Upper-Lower+1)*Item}");
  asm("BLT   _ No          {inside-out}");
  asm("ADD   _ R1, R1, #3");
  asm("BIC   _ R1, R1, #3  {round up}");
  asm("MOV   _ R0, #1      {dimension}");
  asm("STMDB _ Sp!, <R0,R1,R2,R3,R4,R5>");
  asm("MOV   _ R3, Sp      {address of dope vector}");
  asm("MOV   _ Pc, Link");

NO:;
  asm("MOV _ R1, #4");
  asm("MOV _ R2, #0");
  asm("MOV _ R3, #9");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void DYNAMIC2(void) {
  _imp_enter();

  label... label... label... label... label... asm("SUB   _ R5, R7, R6");
  asm("ADDS  _ R5, R5, #1  {number of elements in second dimension, M2}");
  asm("BLT   _ No          {inside out}");
  asm("STMDB _ Sp!, <R3,R4,R5,R6,R7,R8>  {half of dope vector}");
  asm("SUB   _ R4, R4, R3");
  asm("ADDS  _ R4, R4, #1        {elements in first dimension, M1}");
  asm("BLT   _ No");
  asm("MOV   _ R0, R8            {protect item size}");
  asm("MOV   _ R7, #0");

L1:;
  asm("MOVS  _ R0, R0, %LSR #1");
  asm("ADDCS _ R7, R7, R5");
  asm("ADD   _ R5, R5, R5");
  asm("BNE   _ L1                {R7 = M2*Item = T1}");
  asm("MOV   _ R0, R8");
  asm("MOV   _ R2, #0");

L2:;
  asm("MOVS  _ R0, R0, %LSR #1");
  asm("ADDCS _ R2, R2, R6");
  asm("ADD   _ R6, R6, R6");
  asm("BNE   _ L2                {R2 = L2*Item}");
  asm("MOV   _ R1, R7");
  asm("MOV   _ R0, #0");

L3:;
  asm("MOVS  _ R1, R1, %LSR #1");
  asm("ADDCS _ R0, R0, R3");
  asm("ADD   _ R3, R3, R3");
  asm("BNE   _ L3                {R0 = L1*T1}");
  asm("ADD   _ R2, R2, R0        {R2 = L2*item + L1*T1}");
  asm("RSB   _ R2, R2, #0        {R2 = -R2 = disp of A(0)}");
  asm("MOV   _ R1, #0");

L4:;
  asm("MOVS  _ R4, R4, %LSR #1");
  asm("ADDCS _ R1, R1, R7");
  asm("ADD   _ R7, R7, R7");
  asm("BNE   _ L4                {R1 = T1*M1 = total size}");
  asm("ADD   _ R1, R1, #3");
  asm("BIC   _ R1, R1, #3        {round up}");
  asm("MOV   _ R0, #2            {2 dimensions}");
  asm("STMDB _ Sp!, <R0,R1,R2>");
  asm("MOV   _ R3, Sp            {pointer to dope vector}");
  asm("MOV   _ Pc, Link");

NO:;
  asm("MOV _ R1, #4");
  asm("MOV _ R2, #0");
  asm("MOV _ R3, #1");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void DYNAMICN(void) {
  _imp_enter();
  asm("MOV _ R1, #4");
  asm("MOV _ R2, #0");
  asm("MOV _ R3, #1");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void SETADD(void) {
  _imp_enter();
  asm("LDMIA _ R8,   <R0,R1,R2,R3>");
  asm("LDMIA _ R11!, <R4,R5,R6,R7>");
  asm("ORR   _ R0, R0, R4");
  asm("ORR   _ R1, R1, R5");
  asm("ORR   _ R2, R2, R6");
  asm("ORR   _ R3, R3, R7");
  asm("STMIA _ R8!,  <R0,R1,R2,R3>");
  asm("LDMIA _ R8,   <R0,R1,R2,R3>");
  asm("LDMIA _ R11!, <R4,R5,R6,R7>");
  asm("ORR   _ R0, R0, R4");
  asm("ORR   _ R1, R1, R5");
  asm("ORR   _ R2, R2, R6");
  asm("ORR   _ R3, R3, R7");
  asm("STMIA _ R8!, <R0,R1,R2,R3>");
  asm("MOV   _ Pc, Link");

  _imp_leave();
}
/*perm*/ void SETSUB(void) {
  _imp_enter();
  asm("LDMIA _ R8,   <R0,R1,R2,R3>");
  asm("LDMIA _ R11!, <R4,R5,R6,R7>");
  asm("BIC   _ R0, R0, R4");
  asm("BIC   _ R1, R1, R5");
  asm("BIC   _ R2, R2, R6");
  asm("BIC   _ R3, R3, R7");
  asm("STMIA _ R8!,  <R0,R1,R2,R3>");
  asm("LDMIA _ R8,   <R0,R1,R2,R3>");
  asm("LDMIA _ R11!, <R4,R5,R6,R7>");
  asm("BIC   _ R0, R0, R4");
  asm("BIC   _ R1, R1, R5");
  asm("BIC   _ R2, R2, R6");
  asm("BIC   _ R3, R3, R7");
  asm("STMIA _ R8!, <R0,R1,R2,R3>");
  asm("MOV   _ Pc, Link");

  _imp_leave();
}
/*perm*/ void SETINTER(void) {
  _imp_enter();
  asm("LDMIA _ R8,   <R0,R1,R2,R3>");
  asm("LDMIA _ R11!, <R4,R5,R6,R7>");
  asm("AND   _ R0, R0, R4");
  asm("AND   _ R1, R1, R5");
  asm("AND   _ R2, R2, R6");
  asm("AND   _ R3, R3, R7");
  asm("STMIA _ R8!,  <R0,R1,R2,R3>");
  asm("LDMIA _ R8,   <R0,R1,R2,R3>");
  asm("LDMIA _ R11!, <R4,R5,R6,R7>");
  asm("AND   _ R0, R0, R4");
  asm("AND   _ R1, R1, R5");
  asm("AND   _ R2, R2, R6");
  asm("AND   _ R3, R3, R7");
  asm("STMIA _ R8!, <R0,R1,R2,R3>");
  asm("MOV   _ Pc, Link");

  _imp_leave();
}
/*perm*/ void SETGE(void) {
  _imp_enter();
  asm("LDMIA  _ R8! , <R0,R1,R2,R3>");
  asm("LDMIA  _ R11!, <R4,R5,R6,R7>");
  asm("BICS   _ R0, R4, R0");
  asm("BICEQS _ R1, R5, R1");
  asm("BICEQS _ R2, R6, R2");
  asm("BICEQS _ R3, R7, R3");
  asm("MOVNE  _ Pc, Link");
  asm("LDMIA  _ R8! , <R0,R1,R2,R3>");
  asm("LDMIA  _ R11!, <R4,R5,R6,R7>");
  asm("BICS   _ R0, R4, R0");
  asm("BICEQS _ R1, R5, R1");
  asm("BICEQS _ R2, R6, R2");
  asm("BICEQS _ R3, R7, R3");
  asm("MOV    _ Pc, Link");

  _imp_leave();
}
/*perm*/ void SETIN(void) {
  _imp_enter();

  label... asm("CMPS _ R1, #255");
  asm("BHI  _ No");
  asm("AND  _ R3, R1, #7            {bit index into byte}");
  asm("LDRB _ R0, [R2, R1, %LSR #3]");
  asm("MOV  _ R0, R0, %LSR R3       {get relevant bit to least significant "
      "end}");
  asm("TSTS _ R0, #1                {set CC}");
  asm("MOV  _ Pc, Link");

NO:;
  asm("CMPS _ R1, R1                {set EQ i.e. False}");
  asm("MOV  _ Pc, Link");

  _imp_leave();
}
/*perm*/ void SETBIT(void) {
  _imp_enter();

  label... asm("CMPS _ R1, #255");
  asm("BHI  _ No");
  asm("AND  _ R3, R1, #7           {bit index into byte}");
  asm("LDRB _ R0, [R8, R1, %LSR #3]");
  asm("MOV  _ R4, #1");
  asm("ORR  _ R0, R0, R4, %LSL R3");
  asm("STRB _ R0, [R8, R1, %LSR #3]");
  asm("MOV  _ Pc, Link");

NO:;
  asm("MOV  _ R3, R1");
  asm("MOV  _ R1, #14");
  asm("MOV  _ R2, #3");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void CLEARBIT(void) {
  _imp_enter();

  label... asm("CMPS _ R1, #255");
  asm("BHI  _ No");
  asm("AND  _ R3, R1, #7           {bit index into byte}");
  asm("LDRB _ R0, [R8, R1, %LSR #3]");
  asm("MOV  _ R4, #1");
  asm("BIC  _ R0, R0, R4, %LSL R3");
  asm("STRB _ R0, [R8, R1, %LSR #3]");
  asm("MOV  _ Pc, Link");

NO:;
  asm("MOV  _ R3, R1");
  asm("MOV  _ R1, #14");
  asm("MOV  _ R2, #3");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void SETBITS(void) {
  _imp_enter();

  label... label... label... asm("CMPS  _ R0, R1");
  asm("MOVGT _ Pc, Link       {return if inside-out}");
  asm("CMPS  _ R0, #255");
  asm("BHI   _ X1");
  asm("CMPS  _ R1, #255");
  asm("BHI   _ X2");
  asm("MOV   _ R4, #1");

L1:;
  asm("AND  _ R3, R1, #7           {bit index into word}");
  asm("LDRB _ R5, [R8, R1, %LSR #3]");
  asm("ORR  _ R5, R5, R4, %LSL R3");
  asm("STRB _ R5, [R8, R1, %LSR #3]");
  asm("SUB  _ R1, R1, #1");
  asm("CMPS _ R0, R1");
  asm("BLE  _ L1");
  asm("MOV  _ Pc, Link");

X1:;
  asm("MOV _ R1, R0");

X2:;
  asm("MOV _ R3, R1");
  asm("MOV _ R1, #14");
  asm("MOV _ R2, #3");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void CLEARBITS(void) {
  _imp_enter();

  label... label... label... asm("CMPS  _ R0, R1");
  asm("MOVGT _ Pc, Link       {return if inside-out}");
  asm("CMPS  _ R0, #255");
  asm("BHI   _ X1");
  asm("CMPS  _ R1, #255");
  asm("BHI   _ X2");
  asm("MOV   _ R4, #1");

L1:;
  asm("AND  _ R3, R1, #7           {bit index into word}");
  asm("LDRB _ R5, [R8, R1, %LSR #3]");
  asm("BIC  _ R5, R5, R4, %LSL R3");
  asm("STRB _ R5, [R8, R1, %LSR #3]");
  asm("SUB  _ R1, R1, #1");
  asm("CMPS _ R0, R1");
  asm("BLE  _ L1");
  asm("MOV  _ Pc, Link");

X1:;
  asm("MOV _ R1, R0");

X2:;
  asm("MOV _ R3, R1");
  asm("MOV _ R1, #14");
  asm("MOV _ R2, #3");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void SETZERO(void) {
  _imp_enter();
  asm("LDMIA  _ R0, <R1,R2,R3,R4,R5,R6,R7,R8>");
  asm("ORRS   _ R1, R1, R2");
  asm("ORREQS _ R1, R3, R4");
  asm("ORREQS _ R1, R5, R6");
  asm("ORREQS _ R1, R7, R8");
  asm("MOV    _ Pc, Link");

  _imp_leave();
}
/*perm*/ void SETEQUAL(void) {
  _imp_enter();
  asm("LDMIA   _ R0!, <R2,R3,R4,R5>");
  asm("LDMIA   _ R1!, <R6,R7,R8,R11>");
  asm("CMPS    _ R2, R6");
  asm("CMPEQS  _ R3, R7");
  asm("CMPEQS  _ R4, R8");
  asm("CMPEQS  _ R5, R11");
  asm("MOVNE   _ Pc, Link");
  asm("LDMIA   _ R0!, <R2,R3,R4,R5>");
  asm("LDMIA   _ R1!, <R6,R7,R8,R11>");
  asm("CMPEQS  _ R2, R6");
  asm("CMPEQS  _ R3, R7");
  asm("CMPEQS  _ R4, R8");
  asm("CMPEQS  _ R5, R11");
  asm("MOV     _ Pc, Link");

  _imp_leave();
}
/*perm*/ void PSYM(void) {
  _imp_enter();
  extern int CURRENTOUT /* See
                           https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html
                         */
      ;
  asm("LDR     _ R1, Current Out          {address of IMP_CUR_OUT}");
  asm("LDMIA   _ R1, <R2, R3, R4, R5, R6> {next, limit, handler, Break, "
      "Bhandler}");
  asm("CMPS    _ R0, R5                   {break character?}");
  asm("MOVLE   _ Pc, R6                   {yes, use caller's return address}");
  asm("CMPS    _ R2, R3                   {empty?}");
  asm("MOVGE   _ Pc, R4                   {flush & add next character}");
  asm("STRB    _ R0, [R2], #1             {store & increment}");
  asm("STR     _ R2, [R1]                 {update the pointer}");
  asm("MOV     _ Pc, Link                 {return}");

  _imp_leave();
}
/*perm*/ void REALRND(void) {
  _imp_enter();
  asm("CMF    _ F0, #0");
  asm("ADFGTE _ F0, F0, #1/2 {really 0.5}");
  asm("SUFLTE _ F0, F0, #1/2 {really 0.5}");
  asm("FIXEZ  _ R0, F0");
  asm("MOV    _ Pc, Link");

  _imp_leave();
}
/*perm*/ void REALINT(void) {
  _imp_enter();
  asm("ADFE  _ F0, F0, #1/2 {really 0.5}");
  asm("FIXEM  _ R0, F0");
  asm("MOV   _ Pc, Link");

  _imp_leave();
}
/*perm*/ void REALEXP(void) {
  _imp_enter();

  label... label... asm("MVFE _ F1, F0");
  asm("MVFE _ F0, #1");
  asm("CMPS _ R0, #0     {test sign of exponent}");
  asm("BLT _ Nl");

PL:;
  asm("MUFGTE _ F0, F0, F1   {beware of ^0}");
  asm("SUBS _ R0, R0, #1");
  asm("BGT  _ Pl");
  asm("MOV  _ Pc, Link");

NL:;
  asm("DVFE _ F0, F0, F1");
  asm("ADDS _ R0, R0, #1");
  asm("BNE  _ Nl");
  asm("MOV  _ Pc, Link");

  _imp_leave();
}
/*perm*/ void SETRANGE(void) {
  _imp_enter();

  label... label... label... asm("MOV  _ R3, R1, %lsr #5");
  asm("MOV  _ R3, R3, %lsl #2");
  asm("AND  _ R4, R1, #31");
  asm("MVN  _ R5, #0              {R5=-1}");
  asm("MOV  _ R5, R5, %lsl R4");

L1:;
  asm("LDR  _ R4, [R0, R3]");
  asm("BICS _ R4, R4, R5");
  asm("BNE  _ No");
  asm("MOV  _ R5, #0              {R5 = 0}");
  asm("SUBS _ R3, R3, #4");
  asm("BGE  _ L1");
  asm("ADD  _ R2, R2, #1          {onto first free bit}");
  asm("MOV  _ R3, R2, %lsr #5");
  asm("MOV  _ R3, R3, %lsl #2");
  asm("AND  _ R4, R2, #31");
  asm("MVN  _ R5, #0");
  asm("MOV  _ R5, R5, %lsl R4");

L2:;
  asm("CMPS _ R3, #32");
  asm("MOVGE_ Pc, Link            {success}");
  asm("LDR  _ R4, [R0, R3]");
  asm("ANDS _ R4, R4, R5");
  asm("MVNEQ_ R5, #0              {R5 = -1}");
  asm("ADDEQ_ R3, R3, #4");
  asm("BEQ  _ L2");

NO:;
  asm("MOV _ R3, #16_80000000");
  asm("MOV _ R2, #3");
  asm("MOV _ R1, #14");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void RANGE(void) {
  _imp_enter();
  asm("CMPS _ R1, R3");
  asm("MOVLS_ Pc, Link         {ok if 0 <= R1 <= R3}");
  asm("MOV _ R3, R1");
  asm("MOV _ R1, #14");
  asm("MOV _ R2, #4");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void TESTNIL(void) {
  _imp_enter();
  asm("CMPS  _ R1, #0");
  asm("MOVGT _ Pc, Link");
  asm("MOV _ R1, #14");
  asm("MOV _ R2, #5");
  asm("MOV _ R3, #0");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void TESTVAR(void) {
  _imp_enter();
  asm("CMPS   _ R3, R1");
  asm("CMPNES _ R3, #0");
  asm("MOVEQ  _ Pc, Link");
  asm("MOV _ R1, #14");
  asm("MOV _ R2, #6");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void DYNRANGE(void) {
  _imp_enter();
  asm("CMPS   _ R2, R1");
  asm("CMPLES _ R1, R3");
  asm("MOVLE  _ Pc, Link");
  asm("MOV _ R3, R1");
  asm("MOV _ R1, #14");
  asm("MOV _ R2, #4");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void MAKELOCAL(void) {
  _imp_enter();

  label... asm("SUB _ Sp, Sp, R0     {claim space}");
  asm("BIC _ Sp, Sp, #3     {keep it word aligned}");
  asm("LDR _ R3, [R2]       {pointer to source}");
  asm("ADD _ R3, R3, R1     {onto first element}");
  asm("SUB _ R1, Sp, R1     {onto zero'th address}");
  asm("STR _ R1, [R2]       {update pointer}");
  asm("MOV _ R1, Sp         {pointer for copying}");

L:;
  asm("LDRB_ R2, [R3], #1");
  asm("STRB_ R2, [R1], #1");
  asm("SUBS_ R0, R0, #1");
  asm("BNE _ L");
  asm("MOV _ Pc, Link");

  _imp_leave();
}
/*perm*/ void MODULUS(void) {
  _imp_enter();

  label... label... label... label... asm(
      "ADDS _ R4, R2, #0              {preserve divisor & test it}");
  asm("BLE  _ No");

L0:;
  asm("ADDS   _ R5, R1, #0            {preserve Dividend & test sign}");
  asm("RSBLT  _ R1, R1, #0            {R1 = |R1|}");
  asm("MOV    _ R3, #1");

L1:;
  asm("CMPS   _ R2, #16_80000000");
  asm("CMPCCS _ R2, R1");
  asm("MOVCC  _ R2, R2, %LSL #1");
  asm("MOVCC  _ R3, R3, %LSL #1");
  asm("BCC    _ L1");

L2:;
  asm("CMPS   _ R1, R2");
  asm("SUBCS  _ R1, R1, R2");
  asm("MOVS   _ R3, R3, %LSR #1");
  asm("MOVNE  _ R2, R2, %LSR #1");
  asm("BNE    _ L2");
  asm("CMPS   _ R5, #0");
  asm("MOVGE  _ Pc, Link");
  asm("RSBS   _ R1, R1, #0         {negate remainder}");
  asm("ADDNE  _ R1, R1, R4         {and add in divisor}");
  asm("MOV    _ Pc, Link");

NO:;
  asm("MOV _ R1, #14");
  asm("MOV _ R2, #7");
  asm("MOV _ R3, R4");
  asm("STMDB _ Sp!, <R1, R2, R3, Fp, Sb, Link>");
  CALLSIGNAL();
  _imp_leave();
}
/*perm*/ void GENMOVE(void) {
  _imp_enter();

  label... label... label... label... asm("ADDS   _ R3, R3, #0");
  asm("ADDEQS _ R3, R4, #0     {Tlen=0 implies Tlen=Flen}");
  asm("MOVLE  _ Pc, Link       {return if Tlen <= 0}");
  asm("SUBS   _ R6, R3, R4     {R6 = Tlen - Flen}");
  asm("BGT    _ L3             {Tlen > Flen}");

L1:;
  asm("LDRB _ R0, [R2], #1");
  asm("STRB _ R0, [R1], #1");
  asm("SUBS _ R3, R3, #1");
  asm("BNE  _ L1");
  asm("MOV  _ Pc, Link");

L2:;
  asm("LDRB _ R0, [R2], #1");
  asm("STRB _ R0, [R1], #1");

L3:;
  asm("SUBS _ R4, R4, #1");
  asm("BGE  _ L2");
  asm("MOV  _ R0, #32       {space}");

L4:;
  asm("STRB _ R0, [R1], #1");
  asm("SUBS _ R6, R6, #1");
  asm("BNE  _ L4");
  asm("MOV  _ Pc, Link");

  _imp_leave();
}
/*perm*/ void CALLP(void) {
  _imp_enter();
  asm("LDMIA _ R4, <R8, Pc>");

  _imp_leave();
}
/*perm*/ void ENTERP(void) {
  _imp_enter();
  asm("MOV _ Pc, R4");

  _imp_leave();
}
/*perm*/ void DALLOC(void) {
  _imp_enter();

  label... asm("LDR _ R11, [Sb]");

L1:;
  asm("STR _ R11, [Sp, #-4]!");
  asm("SUBS_ R4, R4, #4");
  asm("BGT _ L1");
  asm("MOV _ Pc, Link");

  _imp_leave();
}
