/******************************************************************************/
/*                                                                            */
/*          BitSwap Protected ROMS decoder (c)1998 Antiriad/Raine             */
/*          -----------------------------------------------------             */
/*                                                                            */
/* Used for decoding the protected 68000 roms on Jaleco games. The games have */
/* the bits switched around in each word. This code checks all the possible   */
/* bitpatterns (which is 16 factorial, or to be precise 2,004,189,184). To    */
/* narrow down the search, you have to determine matching encoded and decoded */
/* words from the rom. This is done mainly by recognising the encoded words   */
/* from their frequency/position/distribution in the encoded rom. Good things */
/* to look for are RTS, NOP, ORI.W #$2700,SR and data in the vector table.    */
/* The more words you work out, the smaller the number of results, eventually */
/* it will narrow down to a few results and then just (the 100% correct) one. */
/*                                                                            */
/******************************************************************************/

#include "raine.h"
#include "decode.h"
#include "loadroms.h"

static DEF_INLINE UINT8 decode_byte(UINT8 src, UINT8 *bitp)
{
   UINT8 ret;
   UINT8 ta;

   ret=0;
   for(ta=0;ta<8;ta++)
      ret |= (((src>>bitp[ta])&1) << (7-ta));

   return ret;
}

void decode_ssmissin(void)
{
  /* Like Thunder Dragon Bootleg without the Program Rom Swapping */
  unsigned char *rom;
  int A;

  /* Graphic Roms Could Also Do With Rearranging to make things simpler */
  static unsigned char decode_data_tdragonbgfx[1][8] =
    {
      {0x7,0x6,0x5,0x3,0x4,0x2,0x1,0x0},
    };

  rom = load_region[REGION_GFX2];
  for (A = 0;A < get_region_size(REGION_GFX2);A++)
    {
      rom[A] = decode_byte( rom[A], decode_data_tdragonbgfx[0]);
    }

  rom = load_region[REGION_GFX3];
  for (A = 0;A < get_region_size(REGION_GFX3);A++)
    {
      rom[A] = decode_byte( rom[A], decode_data_tdragonbgfx[0]);
    }
}

static DEF_INLINE UINT8 encode_byte(UINT8 src, UINT8 *bitp)
{
   UINT8 ret;
   UINT8 ta;

   ret=0;
   for(ta=0;ta<8;ta++)
      ret |= (((src>>(7-ta))&1) << bitp[ta]);

   return ret;
}

static DEF_INLINE UINT16 decode_word(UINT16 src, UINT8 *bitp)
{
   UINT16 ret;
   UINT8 ta;

   ret=0;
   for(ta=0;ta<16;ta++)
      ret |= (((src>>bitp[ta])&1) << (15-ta));

   return ret;
}

static DEF_INLINE UINT16 encode_word(UINT16 src, UINT8 *bitp)
{
   UINT16 ret;
   UINT8 ta;

   ret=0;
   for(ta=0;ta<16;ta++)
      ret |= (((src>>(15-ta))&1) << bitp[ta]);

   return ret;
}

static UINT32 ms1_address_map(UINT32 addr)
{
   int ta;

   if(addr>=0x20000) return 3;
   if(addr>=0x18000) return 1;

   ta=1;

   if((addr&8)==0)ta=0;
   addr=addr>>4;
   if((addr&4)==0)ta=0;
   addr=addr>>4;
   if((addr&2)==0)ta=0;
   addr=addr>>4;
   if((addr&8)!=0)ta+=2;

   return ta;
}

static UINT32 bjt_address_map_obj(UINT32 addr)
{
   return ((addr&0x00010)>> 4) | ((addr&0x20000)>>16) | ((addr&0x100000)>>18);
}

static UINT32 bjt_address_map_bg0(UINT32 addr)
{
   return ((addr&0x00004)>> 2) | ((addr&0x00800)>> 10) | ((addr&0x40000)>> 16);
}

void DecodeStDragon(UINT8 *src)
{
   static UINT8 decode_data[4][16]={
   {0xD,0xE,0xF,0x0,0x1,0x8,0x9,0xA,0xB,0xC,0x5,0x6,0x7,0x2,0x3,0x4},
   {0xF,0xD,0xB,0x9,0x7,0x5,0x3,0x1,0xE,0xC,0xA,0x8,0x6,0x4,0x2,0x0},
   {0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0xB,0xA,0x9,0x8,0xF,0xE,0xD,0xC},
   {0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0xB,0xA,0x9,0x8,0xF,0xE,0xD,0xC},
   };

   int ta;

   for(ta=0;ta<0x40000;ta+=2){
      WriteWord68k(&src[ta],decode_word(ReadWord68k(&src[ta]),&decode_data[ms1_address_map(ta)][0]));
   }
}

void DecodePlusAlpha(UINT8 *src)
{
   static UINT8 decode_data[4][16]={
   {0xD,0xE,0xF,0x0,0xA,0x9,0x8,0x1,0x6,0x5,0xC,0xB,0x7,0x2,0x3,0x4},
   {0xF,0xD,0xB,0x9,0x7,0x5,0x3,0x1,0x8,0xA,0xC,0xE,0x0,0x2,0x4,0x6},
   {0x4,0x5,0x6,0x7,0x0,0x1,0x2,0x3,0xB,0xA,0x9,0x8,0xF,0xE,0xD,0xC},
   {0x4,0x5,0x6,0x7,0x0,0x1,0x2,0x3,0xB,0xA,0x9,0x8,0xF,0xE,0xD,0xC},
   };

   int ta;

   for(ta=0;ta<0x40000;ta+=2){
      WriteWord68k(&src[ta],decode_word(ReadWord68k(&src[ta]),&decode_data[ms1_address_map(ta)][0]));
   }
}

void DecodeRodlandE(UINT8 *src)
{
   static UINT8 decode_data[4][16]={
   {0xD,0x0,0xA,0x9,0x6,0xE,0xB,0xF,0x5,0xC,0x7,0x2,0x3,0x8,0x1,0x4},
   {0x4,0x5,0x6,0x7,0x0,0x1,0x2,0x3,0xB,0xA,0x9,0x8,0xF,0xE,0xD,0xC},
   {0xF,0xD,0xB,0x9,0xC,0xE,0x0,0x7,0x5,0x3,0x1,0x8,0xA,0x2,0x4,0x6},
   {0x4,0x5,0x1,0x2,0xE,0xD,0x3,0xB,0xA,0x9,0x6,0x7,0x0,0x8,0xF,0xC},
   };

   int ta;

   for(ta=0;ta<0x40000;ta+=2){
      WriteWord68k(&src[ta],decode_word(ReadWord68k(&src[ta]),&decode_data[ms1_address_map(ta)][0]));
   }
}

void DecodePipiBibi(UINT8 *src)
{
   static UINT8 decode_data[4][16]={
   {0x9,0xD,0xE,0xF,0x0,0xA,0x8,0x1,0x6,0x5,0xC,0xB,0x7,0x2,0x3,0x4},
   {0xD,0xB,0x9,0x7,0x5,0x3,0x1,0x8,0xA,0xC,0xE,0x0,0x2,0x4,0x6,0xF},
   {0x4,0x5,0x6,0x7,0x0,0x1,0x2,0x3,0xB,0xA,0x9,0x8,0xF,0xE,0xD,0xC},
   {0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0xB,0xA,0x9,0x8,0xF,0xE,0xD,0xC},
   };

   int ta;

   for(ta=0;ta<0x40000;ta+=2){
      WriteWord68k(&src[ta],decode_word(ReadWord68k(&src[ta]),&decode_data[(ta>>1)&3][0]));
   }
}

void DecodePlotting(UINT8 *src)
{
   static UINT8 decode_data[1][8]={
   {0,1,2,3,4,5,6,7},
   };

   int ta;

   for(ta=0;ta<0x10000;ta++){
      WriteByte68k(&src[ta],decode_byte(ReadByte68k(&src[ta]),&decode_data[0][0]));
   }
}

void DecodeBombJackTwin_OBJ(UINT8 *src, UINT32 size)
{
   static UINT8 decode_data[8][16]={
   {0x0,0xD,0x2,0xC,0xE,0x6,0xF,0xA,0x9,0x3,0x4,0x5,0x7,0x1,0xB,0x8},  /* Antiriad */
   {0x8,0x5,0xE,0x6,0xD,0x2,0x7,0x9,0x1,0x3,0xC,0x4,0x0,0xF,0xB,0xA},  /* Antiriad */
   {0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0,0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8},  /* Antiriad */
   {0x9,0x2,0x3,0x4,0x5,0xD,0x1,0x0,0xF,0xE,0xC,0x6,0xA,0xB,0x7,0x8},  /* Antiriad */
   /* The Following are used by Macross Only, and might not be 100% accurate (I'd say around 95%) */
   {0xa,0x3,0xd,0xe,    0xc,0x4,0x0,0x8,    0x1,0x6,0x2,0x5,    0xf,0x7,0xb,0x9},  /* Haze 20/07/00 */
   {0x9,0x6,0xc,0x2,    0x3,0x4,0x8,0xf,    0x7,0x5,0xd,0xe,    0xb,0xa,0x0,0x1},  /* Haze 20/07/00 */
   {0x1,0xD,0x2,0xE,    0x4,0xC,0x8,0xF,    0x0,0x5,0x6,0x3,    0x9,0xB,0xA,0x7},  /* Antiriad, Modified by Haze 20/07/00 */
   {0xA,0xD,0x3,0x6,    0x5,0xE,0x1,0x7,    0x9,0xC,0x4,0x2,    0xF,0x0,0xB,0x8},  /* Antiriad, Modified by Haze 20/07/00 */
   };

   int ta;

   for(ta=0;(UINT32)ta<size;ta+=2){
      WriteWord68k(&src[ta],decode_word(ReadWord68k(&src[ta]),&decode_data[bjt_address_map_obj(ta)][0]));
   }
}

void DecodeBombJackTwin_BG0(UINT8 *src, UINT32 size)
{
   static UINT8 decode_data[8][8]={
   {0x3,0x0,0x7,0x2,0x5,0x1,0x4,0x6},
   {0x1,0x2,0x6,0x5,0x4,0x0,0x3,0x7},
   {0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0},
   {0x7,0x6,0x5,0x0,0x1,0x4,0x3,0x2},
   {0x2,0x0,0x1,0x4,0x3,0x5,0x7,0x6},
   {0x5,0x3,0x7,0x0,0x4,0x6,0x2,0x1},
   {0x2,0x7,0x0,0x6,0x5,0x3,0x1,0x4},
   {0x3,0x4,0x7,0x6,0x2,0x0,0x5,0x1},
   };

   int ta;

   for(ta=0;(UINT32)ta<size;ta++){
      WriteByte68k(&src[ta],decode_byte(ReadByte68k(&src[ta]),&decode_data[bjt_address_map_bg0(ta)][0]));
   }
}

void DecodeThunderDragon_OBJ(UINT8 *src)
{
   static UINT8 decode_data[1][8]={
   {7,6,5,3,4,2,1,0},
   };

   int ta;

   for(ta=0;ta<0x100000;ta++){
      WriteByte68k(&src[ta],decode_byte(ReadByte68k(&src[ta]),&decode_data[0][0]));
   }
}

void DecodeThunderDragon_ROM(UINT8 *src)
{
   static UINT8 decode_data[1][16]={
   {0xE,0xC,0xA,0x8,0x7,0x5,0x3,0x1,0xF,0xD,0xB,0x9,0x6,0x4,0x2,0x0},
   };

   int ta;

   for(ta=0;ta<0x40000;ta+=2){
      WriteWord68k(&src[ta],decode_word(ReadWord68k(&src[ta]),&decode_data[0][0]));
   }
}
