/***************************************************************************

  romdecod.c

  Functions to convert the information stored in the roms into a more
  usable format.

  Back in the early '80s, arcade machines didn't have the memory or the
  speed to handle bitmaps like we do today. They used "character maps",
  instead: they had one or more sets of characters (usually 8x8 pixels),
  which would be placed on the screen in order to form a picture. This was
  very fast: updating a character mapped display is, rougly speaking, 64
  times faster than updating an equivalent bitmap display, since you only
  modify groups of 8x8 pixels and not the single pixels. However, it was
  also much less versatile than a bitmap screen, since with only 256
  characters you had to do all of your graphics. To overcome this
  limitation, some special hardware graphics were used: "sprites". A sprite
  is essentially a bitmap, usually larger than a character, which can be
  placed anywhere on the screen (not limited to character boundaries) by
  just telling the hardware the coordinates. Moreover, sprites can be
  flipped along the major axis just by setting the appropriate bit. This
  saves precious memory, since you need only one copy of the image instead
  of four.

  What about colors? Well, the early machines had a limited palette (let's
  say 16 colors) and each character or sprite could not use all of them at
  the same time. Characters and sprites data would use 2 bits per pixel,
  allowing them to address four different colors. You then needed some way
  to tell to the hardware which, among the available colors, were the four
  colors. This was done using a "color attribute", which typically was an
  index for a lookup table.

  OK, after this brief and incomplete introduction, let's come to the
  purpose of this section: how to interpret the data which was stored in
  the graphic roms. Unfortunately, there is no easy answer: it depends on
  the hardware. The easiest way to find how data is encoded, is to start by
  making a bit by bit dump of the rom. You will usually be able to
  immediately recognize some pattern: if you are lucky, you will see
  letters and numbers right away, otherwise you will see something which
  looks like letters and numbers, but with halves switched, dilated, or
  something like that. You'll then have to find a way to put it all
  together to obtain our standard one byte per pixel representation. Two
  things to remember:
  - keep in mind that every pixel has typically two (or more) bits
    associated with it, and they are not necessarily near to each other.
  - characters might be rotated 90 degrees. That's because many games used a
    tube rotated 90 degrees. Think how your monitor would look like if you
	put it on its side ;-)

  After you have successfully decoded the characters, you have to decode
  the sprites. This is usually more difficult, because sprites are larger,
  maybe have more colors, and are more difficult to recognize when they are
  messed up, since they are pure graphics without letters and numbers.
  However, with some work you'll hopefully be able to work them out as
  well. As a rule of thumb, the sprites should be encoded in a way not too
  dissimilar from the characters.

***************************************************************************/

#include <string.h>
#include "Z80.h"
#include "romdecod.h"


/***************************************************************************

  Convert the character ROM.

***************************************************************************/
void decodechars(const unsigned char *src,unsigned char *dest, int cnt)
{
	unsigned char bits;
	int x,y,offs,plane;
	int c;


        memset(dest,0,8*8*cnt);         /* clear destination array */
	for (plane = 0;plane < 2;plane++)
	{
                for (c = 0;c < cnt;c++)
		{
                        for (y = 7 ;y >=0;y--)
			{
				bits = *(src++);

                                for (x = 0;x < 8;x++)
				{
                                        offs = 8 * 8 * c + 8 * x + y;


					dest[offs] <<= 1;
					if (bits & 0x80) dest[offs]++;
					bits <<= 1;
				}
			}
		}
	}
}



/***************************************************************************

  Convert the sprite ROM.

  In Crazy Climber, characters and sprites use the same character generator
  ROM. Here the "src" pointer is a pointer to the already converted
  characters, since it's easier to make the sprites starting from them.

***************************************************************************/
void decodesprites(const unsigned char *src,unsigned char *dest, int cnt)
{
	int x,y,s,r,c;


        for (s = 0;s < cnt;s++)
	{
		for (r = 0;r < 2;r++)
		{
			for (c = 0;c < 2;c++)
			{
				for (y = 0;y < 8;y++)
				{
					for (x = 0;x < 8;x++)
					{
                                                dest[16*16*s + 16*8*c + 16*y + 8*(1-r) + x] =
                                                                src[4*8*8*s + 2*8*8*r + 8*8*c + 8*y + x];
					}
				}
			}
		}
	}
}



/***************************************************************************

  Convert the sound ROM.

  Crazy Climber uses 4 bit digital sound.

***************************************************************************/
void decodesound(unsigned char *dest,const unsigned char *src)
{
	int i;
	unsigned char bits;


	for (i = 0;i < 0x1000;i++)
	{
		bits = *src & 0xf0;
		*(dest++) = (bits | (bits >> 4)) + 0x80;

		bits = *src & 0x0f;
		*(dest++) = ((bits << 4) | bits) + 0x80;

		src++;
	}
}





/***************************************************************************

  Conversion tables for the CPU opcodes.

  Decryption of the program ROMs has to be done in real time, because it
  applies only to opcodes, not to data, and there is no easy way to know
  which is which until the code is executed.

  Implementation required some minor modifications to Z80.c, so that it uses
  M_RDMEM_ENCRYPTED_OPCODE() instead of M_RDMEM_OPCODE() to read CPU opcodes.
  Note that M_RDMEM_OPCODE() is normally used to retrieve data as well as
  opcodes.
  M_RDMEM_ENCRYPTED_OPCODE() is not defined here; it is defined as an inline
  function in Z80IO.h.

***************************************************************************/
const byte ccevetab[] =
{
	0x44,0x14,0x47,0x12,0x54,0x10,0x13,0x46,0x4c,0x1c,0x4f,0x1a,0x5c,0x18,0x1b,0x4e,
	0x11,0x41,0x07,0x52,0x05,0x50,0x53,0x06,0x19,  -1,0x0f,0x5a,0x0d,0x58,0x5b,0x0e,
	0x64,0x34,0x67,0x32,0x74,0x30,0x33,0x66,0x6c,0x3c,0x6f,0x3a,0x7c,0x38,0x3b,0x6e,
	0x31,  -1,0x27,0x72,0x25,0x70,0x73,0x26,0x39,  -1,0x2f,0x7a,0x2d,0x78,0x7b,0x2e,
	0x51,0x00,0x43,0x16,0x40,0x55,0x17,0x42,0x59,0x08,0x4b,0x1e,0x48,0x5d,0x1f,0x4a,
	  -1,0x04,0x03,0x56,0x01,0x15,0x57,0x02,  -1,  -1,0x0b,0x5e,0x09,0x1d,0x5f,0x0a,
	0x71,0x20,0x63,0x36,0x60,0x75,0x37,0x62,0x79,0x28,0x6b,0x3e,0x68,0x7d,0x3f,0x6a,
	  -1,  -1,0x23,0x76,0x21,0x35,0x77,0x22,  -1,  -1,0x2b,0x7e,0x29,0x3d,0x7f,0x2a,
	0xd4,0xd1,0xd3,0x86,0x95,0xc5,0x92,  -1,0xdc,0xd9,0xdb,  -1,0x9d,0xcd,0x9a,  -1,
	0xc4,0x81,0xd2,0xc2,0x91,0xc1,0x82,  -1,0xcc,  -1,0xda,0xca,0x99,0xc9,0x8a,  -1,
	0xf4,0xf1,0xf3,  -1,0xb5,0xe5,0xb2,  -1,0xfc,0xf9,0xfb,  -1,0xbd,0xed,0xba,  -1,
	0xe4,  -1,0xf2,0xe2,0xb1,0xe1,0xa2,  -1,0xec,  -1,0xfa,0xea,0xb9,0xe9,0xaa,  -1,
	0x84,0xd5,0xc3,0x83,0xd0,  -1,0x87,0x97,0x8c,0xdd,0xcb,  -1,0xd8,  -1,0x8f,0x9f,
	0x80,0x90,0x93,0x96,0xc0,  -1,0xc6,0xd6,0x88,0x98,0x9b,0x9e,0xc8,  -1,0xce,0xde,
	0xa4,0xf5,0xe3,  -1,0xf0,  -1,0xa7,0xb7,0xac,0xfd,0xeb,  -1,0xf8,  -1,0xaf,0xbf,
	0xa0,0xb0,0xb3,0xb6,0xe0,  -1,0xe6,0xf6,0xa8,0xb8,0xbb,0xbe,0xe8,  -1,0xee,0xfe
};
const byte ccoddtab[] =
{
	0x44,0x10,0x06,0x53,0x15,0x55,0x47,0x02,0x4c,0x18,0x0e,0x5b,0x1d,0x5d,0x4f,0x0a,
	0x00,0x41,0x46,0x12,  -1,0x51,  -1,0x57,0x08,  -1,0x4e,0x1a,  -1,0x59,  -1,0x5f,
	0x64,0x30,0x26,0x73,0x35,0x75,0x67,0x22,0x6c,0x38,0x2e,0x7b,0x3d,0x7d,0x6f,0x2a,
	0x20,  -1,0x66,0x32,  -1,0x71,  -1,0x77,0x28,  -1,0x6e,0x3a,  -1,0x79,  -1,0x7f,
	0x14,0x45,0x13,0x56,0x11,0x50,0x52,0x42,0x1c,0x4d,0x1b,0x5e,0x19,0x58,0x5a,  -1,
	0x01,0x54,0x07,  -1,0x04,0x05,0x16,0x03,0x09,0x5c,0x0f,  -1,0x0c,0x0d,0x1e,0x0b,
	0x34,0x65,0x33,0x76,0x31,0x70,0x72,  -1,0x3c,0x6d,0x3b,0x7e,0x39,0x78,0x7a,  -1,
	0x21,0x74,0x27,  -1,0x24,0x25,0x36,0x23,0x29,0x7c,0x2f,  -1,0x2c,0x2d,0x3e,0x2b,
	  -1,  -1,  -1,  -1,  -1,  -1,0xd6,0x83,  -1,0xdc,  -1,  -1,  -1,0xd8,0xde,  -1,
	0xd1,0x81,0x97,0xc2,  -1,0xc0,0xc7,0xc3,0xd9,  -1,0x9f,0xca,  -1,0xc8,  -1,0xcb,
	  -1,  -1,  -1,  -1,0xb4,  -1,0xf6,  -1,  -1,  -1,  -1,  -1,  -1,  -1,0xfe,  -1,
	0xf1,  -1,0xb7,0xe2,  -1,0xe0,  -1,0xe3,0xf9,  -1,0xbf,0xea,  -1,0xe8,  -1,0xeb,
	0xc1,0x90,0xd3,0x86,0x80,0xd5,0xd2,0x87,0xc9,0x98,0xdb,0x8e,  -1,0xdd,0xda,0x8f,
	0x85,0xc4,0x93,0xc6,0x91,0xc5,0x92,0x96,  -1,0xcc,0x9b,0xce,0x99,0xcd,  -1,0x9e,
	0xe1,0xb0,0xf3,0xa6,  -1,0xf5,0xf2,0xa7,0xe9,0xb8,0xfb,0xae,  -1,0xfd,0xfa,0xaf,
	  -1,0xe4,0xb3,0xe6,0xb1,0xe5,  -1,0xb6,  -1,0xec,0xbb,0xee,0xb9,0xed,  -1,0xbe
};


const byte ccbootevetab[] =
{
	0x41,0x54,0x46,0x13,0x51,0x14,0x02,0x52,0x49,0x5c,0x4e,0x1b,0x59,0x1c,0x0a,0x5a,
	0x05,0x10,0x43,0x56,0x01,0x55,0x06,0x16,0x0d,0x18,0x4b,0x5e,0x09,0x5d,0x0e,0x1e,
	0x61,0x74,0x66,0x33,0x71,0x34,0x22,0x72,0x69,0x7c,0x6e,0x3b,0x79,0x3c,0x2a,0x7a,
	0x25,0x30,0x63,0x76,0x21,0x75,0x26,0x36,0x2d,0x38,0x6b,0x7e,0x29,0x7d,0x2e,0x3e,
	0x44,0x11,0x17,0x42,0x00,0x50,0x53,0x57,0x4c,0x19,0x1f,0x4a,0x08,0x58,0x5b,0x5f,
	0x15,0x40,0x07,0x12,0x04,0x45,0x03,0x47,0x1d,0x48,0x0f,0x1a,0x0c,0x4d,0x0b,0x4f,
	0x64,0x31,0x37,0x62,0x20,0x70,0x73,0x77,0x6c,0x39,0x3f,0x6a,0x28,0x78,0x7b,0x7f,
	0x35,0x60,0x27,0x32,0x24,0x65,0x23,0x67,0x3d,0x68,0x2f,0x3a,0x2c,0x6d,0x2b,0x6f,
	0x94,0xc1,0x87,0xd7,0x81,0xc4,0x82,0xd2,0x9c,0xc9,0x8f,0xdf,0x89,0xcc,0x8a,0xda,
	0x84,0xd0,0x93,0xc2,0xd1,0xc5,0xd6,0x96,0x8c,0xd8,0x9b,0xca,0xd9,0xcd,0xde,0x9e,
	0xb4,0xe1,0xa7,0xf7,0xa1,0xe4,0xa2,0xf2,0xbc,0xe9,0xaf,0xff,0xa9,0xec,0xaa,0xfa,
	0xa4,0xf0,0xb3,0xe2,0xf1,0xe5,0xf6,0xb6,0xac,0xf8,0xbb,0xea,0xf9,0xed,0xfe,0xbe,
	0x91,0xc0,0xc7,0xd3,0xd4,0x95,0x92,0x86,0x99,0xc8,0xcf,0xdb,0xdc,0x9d,0x9a,0x8e,
	0x90,0x80,0xc6,0x83,0xd5,0x85,0xc3,0x97,0x98,0x88,0xce,0x8b,0xdd,0x8d,0xcb,0x9f,
	0xb1,0xe0,0xe7,0xf3,0xf4,0xb5,0xb2,0xa6,0xb9,0xe8,0xef,0xfb,0xfc,0xbd,0xba,0xae,
	0xb0,0xa0,0xe6,0xa3,0xf5,0xa5,0xe3,0xb7,0xb8,0xa8,0xee,0xab,0xfd,0xad,0xeb,0xbf,
};
const byte ccbootoddtab[] =
{
	0x50,0x11,0x12,0x52,0x40,0x55,0x56,0x57,0x58,0x19,0x1a,0x5a,0x48,0x5d,0x5e,0x5f,
	0x51,0x14,0x03,0x46,0x45,0x04,0x42,0x06,0x59,0x1c,0x0b,0x4e,0x4d,0x0c,0x4a,0x0e,
	0x70,0x31,0x32,0x72,0x60,0x75,0x76,0x77,0x78,0x39,0x3a,0x7a,0x68,0x7d,0x7e,0x7f,
	0x71,0x34,0x23,0x66,0x65,0x24,0x62,0x26,0x79,0x3c,0x2b,0x6e,0x6d,0x2c,0x6a,0x2e,
	0x54,0x15,0x16,0x13,0x10,0x05,0x02,0x43,0x5c,0x1d,0x1e,0x1b,0x18,0x0d,0x0a,0x4b,
	0x44,0x01,0x47,0x17,0x00,0x41,0x53,0x07,0x4c,0x09,0x4f,0x1f,0x08,0x49,0x5b,0x0f,
	0x74,0x35,0x36,0x33,0x30,0x25,0x22,0x63,0x7c,0x3d,0x3e,0x3b,0x38,0x2d,0x2a,0x6b,
	0x64,0x21,0x67,0x37,0x20,0x61,0x73,0x27,0x6c,0x29,0x6f,0x3f,0x28,0x69,0x7b,0x2f,
	0x81,0x85,0xd7,0xd2,0xc1,0xc5,0x97,0x92,0x89,0x8d,0xdf,0xda,0xc9,0xcd,0x9f,0x9a,
	0xd4,0xd0,0x83,0x86,0xd5,0x90,0xc3,0xc6,0xdc,0xd8,0x8b,0x8e,0xdd,0x98,0xcb,0xce,
	0xa1,0xa5,0xf7,0xf2,0xe1,0xe5,0xb7,0xb2,0xa9,0xad,0xff,0xfa,0xe9,0xed,0xbf,0xba,
	0xf4,0xf0,0xa3,0xa6,0xf5,0xb0,0xe3,0xe6,0xfc,0xf8,0xab,0xae,0xfd,0xb8,0xeb,0xee,
	0x91,0x95,0xc7,0xc2,0xd1,0x94,0x87,0x82,0x99,0x9d,0xcf,0xca,0xd9,0x9c,0x8f,0x8a,
	0xc4,0xc0,0x93,0x96,0x84,0x80,0xd3,0xd6,0xcc,0xc8,0x9b,0x9e,0x8c,0x88,0xdb,0xde,
	0xb1,0xb5,0xe7,0xe2,0xf1,0xb4,0xa7,0xa2,0xb9,0xbd,0xef,0xea,0xf9,0xbc,0xaf,0xaa,
	0xe4,0xe0,0xb3,0xb6,0xa4,0xa0,0xf3,0xf6,0xec,0xe8,0xbb,0xbe,0xac,0xa8,0xfb,0xfe
};
