#include <perms.h>

static int Short_Integer(int addr) {
  return (int) (*((short *)addr));
}

static const unsigned char Xsym[16] = {
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};

static void HexP(int N, int P) {
  int J;
  for (J = 0; J < 4; J++) {
    putchar(Xsym[((unsigned)N >> (4*P - 4)) & 15]);
    N = N << 4;
  }
}
static inline void Hex8(int N) {  HexP(N, 8);}
static inline void Hex(int N)  {  HexP(N, 4);}

static void Put(int Sp, int Syms) {
  int I;
  for (I = 0; I < Sp; I++) putchar(' ');;
  for (I = 1; I <= 4; I++) {
    putchar((unsigned)Syms >> 24 & 127);
    Syms = Syms << 8;
  }
}

void Recode(int S, int To, int Base) {
  static const int Opcodes[256] = {
    [0 ... 3] = 0,
    'SPM ',    'BALR',    'BCTR',    'BCR ',    'SSK ',    'ISK ',    'SVC ',
    [11 ... 15] = 0,
    'LPR ',    'LNR ',    'LTR ',    'LCR ',    'NR  ',    'CLR ',    'OR  ',
    'XR  ',    'LR  ',    'CR  ',    'AR  ',    'SR  ',    'MR  ',    'DR  ',
    'ALR ',    'SLR ',    'LPDR',    'LNDR',    'LTDR',    'LCDR',    'HDR ',
    'LRDR',    'MXR ',    'MXDR',    'LDR ',    'CDR ',    'ADR ',    'SDR ',
    'MDR ',    'DDR ',    'AWR ',    'SWR ',    'LPER',    'LNER',    'LTER',
    'LCER',    'HER ',    'LRER',    'AXR ',    'SXR ',    'LER ',    'CER ',
    'AER ',    'SER ',    'MER ',    'DER ',    'AUR ',    'SUR ',    'STH ',
    'LA  ',    'STC ',    'IC  ',    'EX  ',    'BAL ',    'BCT ',    'BC  ',
    'LH  ',    'CH  ',    'AH  ',    'SH  ',    'MH  ',
    0,
    'CVD ',    'CVB ',    'ST  ',
    [81 ... 83] = 0,
    'N   ',    'CL  ',    'O   ',    'X   ',    'L   ',    'C   ',    'A   ',
    'S   ',    'M   ',    'D   ',    'AL  ',    'SL  ',    'STD ',
    [97 ... 102] = 0,
    'MXD ',    'LD  ',    'CD  ',    'AD  ',    'SD  ',    'MD  ',    'DD  ',
    'AW  ',    'SW  ',    'STE ',
    [113 ... 119] = 0,
    'LE  ',    'CE  ',    'AE  ',    'SE  ',    'ME  ',    'DE  ',    'AU  ',
    'SU  ',    'SSM',
    0,
    'LPSW',    'DIAG',    'WRD ',    'RDD ',    'BXH ',    'BXLE',    'SRL ',
    'SLL ',    'SRA ',    'SLA ',    'SRDL',    'SLDL',    'SRDA',    'SLDA',
    'STM ',    'TM  ',    'MVI ',    'TS  ',    'NI  ',    'CLI ',    'OI  ',
    'XI  ',    'LM  ',
    [153 ... 155] = 0,
    'SIO ',    'TIO ',    'HIO ',    'TCH ',
    [160 ... 208] = 0,
    'MVN ',    'MVC ',    'MVZ ',    'NC  ',    'CLC ',    'OC  ',    'XC  ',
    [216 ... 219] = 0,
    'TR  ',    'TRT ',    'ED  ',    'EDMK',
    [224 ... 240] = 0,
    'MVO ',    'PACK',    'UNPK',
    [244 ... 247] = 0,
    'ZAP ',    'CP  ',    'AP  ',    'SP  ',    'MP  ',    'DP  ',
    0,
    0
  };
  int J, K, L, M, T;

  S = S & (~1);
  Base -= S;

  for (;;) {
    printf("\n"); if (S >= To) { printf("\n"); return; }

    printf("C "); Hex8(Base + S); printf("    ");

    J = Short_Integer(S); S += 2;
    M = ((unsigned)J >> 8) & 255;
    T = Opcodes[M];
    Hex(J);
    if (!T) continue;

    if (((unsigned)M >> 6) == 0) {
      Put(12, T);
      printf("%4d,%2d",
             ((unsigned)J >> 4) & 15,
             J & 15);
      continue;
    }

    K = Short_Integer(S); S += 2;
    Hex(K);

    if ((unsigned)M >> 6 == 1) {
      Put(8, T);
      printf("%4d,%4d(%2d,%2d)",
             ((unsigned)J >> 4) & 15,
             K & 0xFFF,
             J & 15,
             ((unsigned)K >> 12) & 15);
      continue;
    }

    if ((M & 0xF8) == 0x88) {
      Put(8, T);
      printf("%4d,%4d(%2d)",
             ((unsigned)J >> 4) & 15,
             K & 0xFFF,
             ((unsigned)K >> 12) & 15);
      continue;
    }
    
    if (M > 192) {
      L = Short_Integer(S);
      S += 2;
      Hex(L);
      Put(4, T);

      printf("%5d(", K & 0xFFF);
      if ((((unsigned)M >> 4) & 15) != 15)
        printf("%2d", (J & 255) + 1);
      else
        printf("%2d", ((unsigned)J >> 4) & 15);
      printf(",%2d),%4d(",
             ((unsigned)K >> 12) & 15,
             L & 0xFFF);
      if ((((unsigned)M >> 4) & 15) == 15) {
        printf("%2d,", J & 15);
      }
      printf("%2d)", ((unsigned)L >> 12) & 15);
      continue;
    }
    
    if (M == 134 || M == 135 || M == 144 || M == 152) {
      Put(8, T);
      printf("%4d,%2d,%4d(%2d)",
             ((unsigned)J >> 4) & 15,
             J & 15,
             K & 0xFFF,
             ((unsigned)K >> 12) & 15);
      continue;
    }

    Put(8, T);
    printf("%5d(%2d),%2d",
           K & 0xFFF,
           ((unsigned)K >> 12) & 15,
           J & 255);
  }
}
