summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/etc
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/etc')
-rw-r--r--src/mame/etc/fd1094dp.c587
-rw-r--r--src/mame/etc/jrcrypt.c537
2 files changed, 1124 insertions, 0 deletions
diff --git a/src/mame/etc/fd1094dp.c b/src/mame/etc/fd1094dp.c
new file mode 100644
index 00000000000..b340bf66ec1
--- /dev/null
+++ b/src/mame/etc/fd1094dp.c
@@ -0,0 +1,587 @@
+/*****************************************************************************
+
+FD1094 key dumper
+
+This file is not part of MAME, it is a standalone program that reads 128MB of
+data extracted from the FD1094 CPU and produces a 8KB keyfile, used by
+fd1094.c to decrypt the ROM data.
+
+*****************************************************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+int state2;
+char srcpath[250],dstfilename[250];
+
+#define BIT(x,n) (((x)>>(n))&1)
+
+#define BITSWAP16(val,B15,B14,B13,B12,B11,B10,B9,B8,B7,B6,B5,B4,B3,B2,B1,B0) \
+ ((BIT(val,B15) << 15) | \
+ (BIT(val,B14) << 14) | \
+ (BIT(val,B13) << 13) | \
+ (BIT(val,B12) << 12) | \
+ (BIT(val,B11) << 11) | \
+ (BIT(val,B10) << 10) | \
+ (BIT(val, B9) << 9) | \
+ (BIT(val, B8) << 8) | \
+ (BIT(val, B7) << 7) | \
+ (BIT(val, B6) << 6) | \
+ (BIT(val, B5) << 5) | \
+ (BIT(val, B4) << 4) | \
+ (BIT(val, B3) << 3) | \
+ (BIT(val, B2) << 2) | \
+ (BIT(val, B1) << 1) | \
+ (BIT(val, B0) << 0))
+
+UINT16 buffer[0x2000];
+int little_endian;
+
+int is_little_endian(void)
+{
+ short magic, test;
+ char *ptr;
+
+ magic = 0xABCD;
+ ptr = (char *)&magic;
+ test = (ptr[1]<<8) + (ptr[0]&0xFF);
+ return (magic == test);
+}
+
+
+
+void load_table(int n)
+{
+ static int last_loaded = -1;
+
+ if (last_loaded != n)
+ {
+ FILE *f1;
+ int i;
+ char name[250];
+
+
+ last_loaded = n;
+
+ sprintf(name,"%s/00%04x.tbl",srcpath,n);
+
+ f1 = fopen(name,"rb");
+ if (!f1)
+ {
+ printf("Can't open %s for reading.\n",name);
+ exit(1);
+ }
+
+ /* read repeatedly so we support both full dumps and reduced E000-FFFF dumps */
+ while (fread(buffer,1,0x4000,f1) == 0x4000) ;
+
+ fclose(f1);
+
+ if (little_endian)
+ {
+ for (i = 0;i < 0x2000;i++)
+ buffer[i] = (buffer[i] >> 8) | (buffer[i] << 8);
+ }
+ }
+}
+
+
+/*
+317-0162 CPU also needs to mask:
+0x107a,
+0x127a,
+0x147a,
+0x167a,
+0x187a,
+0x1a7a,
+0x1c7a,
+0x1e7a,
+this only happens with 317-0162 so far; I assume it is a fault in the CPU.
+*/
+int masked_opcodes[] =
+{
+ 0x013a,0x033a,0x053a,0x073a,0x083a,0x093a,0x0b3a,0x0d3a,0x0f3a,
+
+ 0x103a, 0x10ba,0x10fa, 0x113a,0x117a,0x11ba,0x11fa,
+ 0x123a, 0x12ba,0x12fa, 0x133a,0x137a,0x13ba,0x13fa,
+ 0x143a, 0x14ba,0x14fa, 0x153a,0x157a,0x15ba,
+ 0x163a, 0x16ba,0x16fa, 0x173a,0x177a,0x17ba,
+ 0x183a, 0x18ba,0x18fa, 0x193a,0x197a,0x19ba,
+ 0x1a3a, 0x1aba,0x1afa, 0x1b3a,0x1b7a,0x1bba,
+ 0x1c3a, 0x1cba,0x1cfa, 0x1d3a,0x1d7a,0x1dba,
+ 0x1e3a, 0x1eba,0x1efa, 0x1f3a,0x1f7a,0x1fba,
+
+ 0x203a,0x207a,0x20ba,0x20fa, 0x213a,0x217a,0x21ba,0x21fa,
+ 0x223a,0x227a,0x22ba,0x22fa, 0x233a,0x237a,0x23ba,0x23fa,
+ 0x243a,0x247a,0x24ba,0x24fa, 0x253a,0x257a,0x25ba,
+ 0x263a,0x267a,0x26ba,0x26fa, 0x273a,0x277a,0x27ba,
+ 0x283a,0x287a,0x28ba,0x28fa, 0x293a,0x297a,0x29ba,
+ 0x2a3a,0x2a7a,0x2aba,0x2afa, 0x2b3a,0x2b7a,0x2bba,
+ 0x2c3a,0x2c7a,0x2cba,0x2cfa, 0x2d3a,0x2d7a,0x2dba,
+ 0x2e3a,0x2e7a,0x2eba,0x2efa, 0x2f3a,0x2f7a,0x2fba,
+
+ 0x303a,0x307a,0x30ba,0x30fa, 0x313a,0x317a,0x31ba,0x31fa,
+ 0x323a,0x327a,0x32ba,0x32fa, 0x333a,0x337a,0x33ba,0x33fa,
+ 0x343a,0x347a,0x34ba,0x34fa, 0x353a,0x357a,0x35ba,
+ 0x363a,0x367a,0x36ba,0x36fa, 0x373a,0x377a,0x37ba,
+ 0x383a,0x387a,0x38ba,0x38fa, 0x393a,0x397a,0x39ba,
+ 0x3a3a,0x3a7a,0x3aba,0x3afa, 0x3b3a,0x3b7a,0x3bba,
+ 0x3c3a,0x3c7a,0x3cba,0x3cfa, 0x3d3a,0x3d7a,0x3dba,
+ 0x3e3a,0x3e7a,0x3eba,0x3efa, 0x3f3a,0x3f7a,0x3fba,
+
+ 0x41ba,0x43ba,0x44fa,0x45ba,0x46fa,0x47ba,0x49ba,0x4bba,0x4cba,0x4cfa,0x4dba,0x4fba,
+
+ 0x803a,0x807a,0x80ba,0x80fa, 0x81fa,
+ 0x823a,0x827a,0x82ba,0x82fa, 0x83fa,
+ 0x843a,0x847a,0x84ba,0x84fa, 0x85fa,
+ 0x863a,0x867a,0x86ba,0x86fa, 0x87fa,
+ 0x883a,0x887a,0x88ba,0x88fa, 0x89fa,
+ 0x8a3a,0x8a7a,0x8aba,0x8afa, 0x8bfa,
+ 0x8c3a,0x8c7a,0x8cba,0x8cfa, 0x8dfa,
+ 0x8e3a,0x8e7a,0x8eba,0x8efa, 0x8ffa,
+
+ 0x903a,0x907a,0x90ba,0x90fa, 0x91fa,
+ 0x923a,0x927a,0x92ba,0x92fa, 0x93fa,
+ 0x943a,0x947a,0x94ba,0x94fa, 0x95fa,
+ 0x963a,0x967a,0x96ba,0x96fa, 0x97fa,
+ 0x983a,0x987a,0x98ba,0x98fa, 0x99fa,
+ 0x9a3a,0x9a7a,0x9aba,0x9afa, 0x9bfa,
+ 0x9c3a,0x9c7a,0x9cba,0x9cfa, 0x9dfa,
+ 0x9e3a,0x9e7a,0x9eba,0x9efa, 0x9ffa,
+
+ 0xb03a,0xb07a,0xb0ba,0xb0fa, 0xb1fa,
+ 0xb23a,0xb27a,0xb2ba,0xb2fa, 0xb3fa,
+ 0xb43a,0xb47a,0xb4ba,0xb4fa, 0xb5fa,
+ 0xb63a,0xb67a,0xb6ba,0xb6fa, 0xb7fa,
+ 0xb83a,0xb87a,0xb8ba,0xb8fa, 0xb9fa,
+ 0xba3a,0xba7a,0xbaba,0xbafa, 0xbbfa,
+ 0xbc3a,0xbc7a,0xbcba,0xbcfa, 0xbdfa,
+ 0xbe3a,0xbe7a,0xbeba,0xbefa, 0xbffa,
+
+ 0xc03a,0xc07a,0xc0ba,0xc0fa, 0xc1fa,
+ 0xc23a,0xc27a,0xc2ba,0xc2fa, 0xc3fa,
+ 0xc43a,0xc47a,0xc4ba,0xc4fa, 0xc5fa,
+ 0xc63a,0xc67a,0xc6ba,0xc6fa, 0xc7fa,
+ 0xc83a,0xc87a,0xc8ba,0xc8fa, 0xc9fa,
+ 0xca3a,0xca7a,0xcaba,0xcafa, 0xcbfa,
+ 0xcc3a,0xcc7a,0xccba,0xccfa, 0xcdfa,
+ 0xce3a,0xce7a,0xceba,0xcefa, 0xcffa,
+
+ 0xd03a,0xd07a,0xd0ba,0xd0fa, 0xd1fa,
+ 0xd23a,0xd27a,0xd2ba,0xd2fa, 0xd3fa,
+ 0xd43a,0xd47a,0xd4ba,0xd4fa, 0xd5fa,
+ 0xd63a,0xd67a,0xd6ba,0xd6fa, 0xd7fa,
+ 0xd83a,0xd87a,0xd8ba,0xd8fa, 0xd9fa,
+ 0xda3a,0xda7a,0xdaba,0xdafa, 0xdbfa,
+ 0xdc3a,0xdc7a,0xdcba,0xdcfa, 0xddfa,
+ 0xde3a,0xde7a,0xdeba,0xdefa, 0xdffa
+};
+
+
+int final_decrypt(int i,int moreffff)
+{
+ int j;
+
+ /* final "obfuscation": invert bits 7 and 14 following a fixed pattern */
+ int dec = i;
+ if ((i & 0xf080) == 0x8000) dec ^= 0x0080;
+ if ((i & 0xf080) == 0xc080) dec ^= 0x0080;
+ if ((i & 0xb080) == 0x8000) dec ^= 0x4000;
+ if ((i & 0xb100) == 0x0000) dec ^= 0x4000;
+
+ /* mask out opcodes doing PC-relative addressing, replace them with FFFF */
+ for (j = 0;j < sizeof(masked_opcodes)/sizeof(masked_opcodes[0]);j++)
+ {
+ if ((dec & 0xfffe) == masked_opcodes[j])
+ {
+ dec = 0xffff;
+ break;
+ }
+ }
+
+ /* optionally, even more values can be replaced with FFFF */
+ if (moreffff)
+ {
+ if ((dec & 0xff80) == 0x4e80)
+ dec = 0xffff;
+ if ((dec & 0xf0f8) == 0x50c8)
+ dec = 0xffff;
+ if ((dec & 0xf000) == 0x6000)
+ dec = 0xffff;
+ }
+
+ return dec;
+}
+
+
+static int parametric_decode(int val,int mainkey,int key_F,int gkey1,int gkey2,int gkey3)
+{
+ int key_6a,key_7a,key_6b;
+ int key_0a,key_0b,key_0c;
+ int key_1a,key_1b,key_2a,key_2b,key_3a,key_3b,key_4a,key_4b,key_5a,key_5b;
+ int global_xor0,global_xor1;
+ int global_swap0a,global_swap1,global_swap2,global_swap3,global_swap4;
+ int global_swap0b;
+
+ global_xor0 = 1^BIT(gkey1,5); // could be bit 7
+ global_xor1 = 1^BIT(gkey1,2);
+ global_swap2 = 1^BIT(gkey1,0);
+
+ global_swap0a = 1^BIT(gkey2,5);
+ global_swap0b = 1^BIT(gkey2,2);
+
+ global_swap3 = 1^BIT(gkey3,6);
+ global_swap1 = 1^BIT(gkey3,4);
+ global_swap4 = 1^BIT(gkey3,2);
+
+ key_0a = BIT(mainkey,0) ^ BIT(gkey3,1);
+ key_0b = BIT(mainkey,0) ^ BIT(gkey1,7); // could be bit 5
+ key_0c = BIT(mainkey,0) ^ BIT(gkey1,1);
+
+ key_1a = BIT(mainkey,1) ^ BIT(gkey2,7);
+ key_1b = BIT(mainkey,1) ^ BIT(gkey1,3);
+
+ key_2a = BIT(mainkey,2) ^ BIT(gkey3,7); // could be bit 5
+ key_2b = BIT(mainkey,2) ^ BIT(gkey1,4);
+
+ key_3a = BIT(mainkey,3) ^ BIT(gkey2,0);
+ key_3b = BIT(mainkey,3) ^ BIT(gkey3,3);
+
+ key_4a = BIT(mainkey,4) ^ BIT(gkey2,3);
+ key_4b = BIT(mainkey,4) ^ BIT(gkey3,0);
+
+ key_5a = BIT(mainkey,5) ^ BIT(gkey3,5); // could be bit 7
+ key_5b = BIT(mainkey,5) ^ BIT(gkey1,6);
+
+ key_6a = BIT(mainkey,6) ^ BIT(gkey2,1);
+ key_6b = BIT(mainkey,6) ^ BIT(gkey2,6);
+
+ key_7a = BIT(mainkey,7) ^ BIT(gkey2,4);
+
+
+ if ((val & 0xe000) == 0x0000)
+ val = BITSWAP16(val, 12,15,14,13,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
+ else
+ {
+ if (val & 0x8000)
+ {
+ if (!global_xor1) if (~val & 0x0008) val ^= 0x2410; // 13,10,4
+ if (~val & 0x0004) val ^= 0x0022; // 5,1
+ if (!key_1b) if (~val & 0x1000) val ^= 0x0848; // 11,6,3
+ if (!global_swap2) if (!key_0c) val ^= 0x4101; // 14,8,0
+ if (!key_2b) val = BITSWAP16(val, 15,14,13, 9,11,10,12, 8, 2, 6, 5, 4, 3, 7, 1, 0); // 12,9,7,2
+
+ val = 0x6561 ^ BITSWAP16(val, 15, 9,10,13, 3,12, 0,14, 6, 5, 2,11, 8, 1, 4, 7);
+ }
+ if (val & 0x4000)
+ {
+ if (!global_xor0) if (val & 0x0800) val ^= 0x9048; // 15,12,6,3
+ if (!key_3a) if (val & 0x0004) val ^= 0x0202; // 9,1
+ if (!key_6a) if (val & 0x0400) val ^= 0x0004; // 2
+ if (!key_5b) if (!key_0b) val ^= 0x08a1; // 11,7,5,0
+ if (!global_swap0b) val = BITSWAP16(val, 15,14,10,12,11,13, 9, 4, 7, 6, 5, 8, 3, 2, 1, 0); // 13,10,8,4
+
+ val = 0x3523 ^ BITSWAP16(val, 13,14, 7, 0, 8, 6, 4, 2, 1,15, 3,11,12,10, 5, 9);
+ }
+ if (val & 0x2000)
+ {
+ if (!key_4a) if (val & 0x0100) val ^= 0x4210; // 14,9,4
+ if (!key_1a) if (val & 0x0040) val ^= 0x0080; // 7
+ if (!key_7a) if (val & 0x0001) val ^= 0x110a; // 12,8,3,1
+ if (!key_4b) if (!key_0a) val ^= 0x0040; // 6
+ if (!global_swap0a) if (!key_6b) val ^= 0x0404; // 10,2
+ if (!key_5b) val = BITSWAP16(val, 0,14,13,12,15,10, 9, 8, 7, 6,11, 4, 3, 2, 1, 5); // 15,11,5,0
+
+ val = 0x99a5 ^ BITSWAP16(val, 10, 2,13, 7, 8, 0, 3,14, 6,15, 1,11, 9, 4, 5,12);
+ }
+
+ val = 0x87ff ^ BITSWAP16(val, 5,15,13,14, 6, 0, 9,10, 4,11, 1, 2,12, 3, 7, 8);
+
+ if (!global_swap4) val = BITSWAP16(val, 6,14,13,12,11,10, 9, 5, 7,15, 8, 4, 3, 2, 1, 0); // 15-6, 8-5
+ if (!global_swap3) val = BITSWAP16(val, 15,12,14,13,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); // 12-13-14
+ if (!global_swap2) val = BITSWAP16(val, 15,14,13,12,11, 2, 9, 8,10, 6, 5, 4, 3, 0, 1, 7); // 10-2-0-7
+ if (!key_3b) val = BITSWAP16(val, 15,14,13,12,11,10, 4, 8, 7, 6, 5, 9, 1, 2, 3, 0); // 9-4, 3-1
+
+ if (!key_2a) val = BITSWAP16(val, 15,12,13,14,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); // 14-12
+ if (!global_swap1) val = BITSWAP16(val, 15,14,13,12, 9, 8,11,10, 7, 6, 5, 4, 3, 2, 1, 0); // 11...8
+ if (!key_5a) val = BITSWAP16(val, 15,14,13,12,11,10, 9, 8, 4, 5, 7, 6, 3, 2, 1, 0); // 7...4
+ if (!global_swap0a) val = BITSWAP16(val, 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 0, 3, 2, 1); // 3...0
+ }
+
+ return final_decrypt(val,key_F);
+}
+
+
+
+int check_key(int key,int key_F,int gkey1,int gkey2,int gkey3)
+{
+ int i;
+ int err_ffff = 0;
+
+ if (state2)
+ {
+ gkey1 ^= 0x01;
+ gkey2 ^= 0x10;
+ gkey3 ^= 0x01;
+ }
+
+ for (i = 0xffff;i >= 0xe000;i--)
+ {
+ if (parametric_decode(i,key,key_F,gkey1,gkey2,gkey3) != buffer[i - 0xe000])
+ {
+ if (buffer[i - 0xe000] == 0xffff)
+ {
+ err_ffff++;
+ if (err_ffff > 8) break;
+ }
+ else
+ break;
+ }
+ }
+
+ if (i < 0xe000)
+ {
+ /* special handling for CPU 317-0162 */
+ if (err_ffff)
+ {
+ printf("warning: %d FFFF errors: ",err_ffff);
+ for (i = 0xe000;i < 0x10000;i++)
+ {
+ if (parametric_decode(i,key,key_F,gkey1,gkey2,gkey3) != buffer[i - 0xe000])
+ printf("%04x ",parametric_decode(i,key,key_F,gkey1,gkey2,gkey3));
+ }
+ printf("\n");
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static void print_binary(int num)
+{
+ int i;
+
+ for (i = 7;i >= 0;i--)
+ printf("%d",BIT(num,i));
+}
+
+
+static int global_key1,global_key2,global_key3;
+
+
+void find_global_key(void)
+{
+ int gkey1,gkey2,gkey3;
+ int found = 0;
+
+ printf("Searching for global key...\n");
+
+ for (gkey1 = 0;gkey1 < 0x100;gkey1++)
+ {
+ fprintf(stderr,"%02x/ff\r",gkey1);
+ for (gkey2 = 0;gkey2 < 0x100;gkey2++)
+ {
+ for (gkey3 = 0;gkey3 < 0x100;gkey3++)
+ {
+ load_table(2);
+ if (check_key(gkey1,BIT(gkey1,6),gkey1,gkey2,gkey3))
+ {
+ load_table(4);
+ if (check_key(gkey2,BIT(gkey2,6),gkey1,gkey2,gkey3))
+ {
+ load_table(6);
+ if (check_key(gkey3,BIT(gkey3,6),gkey1,gkey2,gkey3))
+ {
+ global_key1 = gkey1;
+ global_key2 = gkey2;
+ global_key3 = gkey3;
+
+ printf("global key: ");
+ print_binary(gkey1);
+ printf(" ");
+ print_binary(gkey2);
+ printf(" ");
+ print_binary(gkey3);
+ printf("\n");
+
+ found++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (found > 1)
+ {
+ printf("The tables from state %02x don't allow to uniquely determine the global key.\n",state2*2);
+ printf("You should dump tables from state %02x and run the program again.\n",(state2^1)*2);
+ exit(0);
+ }
+
+ if (found == 0)
+ {
+ int key1,key2,key3;
+
+ printf("Couldn't find the global key. This might be caused by:\n");
+ printf("1) Incorrectly dumped data\n");
+ printf("2) Wrong <state> parameter. 00 instead of 02, or 02 instead of 00.\n");
+ printf("3) An error in the current FD1094 emulation.\n\n");
+
+ printf("I will now execute a broader key search, which will take a longer time.\n");
+ printf("If 1) and 2) are correct, and this search succeeds, contact MAMEDEV.\n");
+
+ for (gkey1 = 0;gkey1 < 0x100;gkey1++)
+ {
+ fprintf(stderr,"%02x/ff\r",gkey1);
+ for (gkey2 = 0;gkey2 < 0x100;gkey2++)
+ {
+ for (gkey3 = 0;gkey3 < 0x100;gkey3++)
+ {
+ load_table(2);
+ for (key1 = gkey1 & 0x5f;key1 < 0x100;key1 += 0x20)
+ {
+ if (check_key(key1,BIT(key1,6),gkey1,gkey2,gkey3) || check_key(key1,BIT(key1,6)^1,gkey1,gkey2,gkey3))
+ {
+ load_table(4);
+ key2 = gkey2;
+ {
+ if (check_key(key2,BIT(key2,6),gkey1,gkey2,gkey3) || check_key(key2,BIT(key2,6)^1,gkey1,gkey2,gkey3))
+ {
+ load_table(6);
+ for (key3 = gkey3 & 0x5f;key3 < 0x100;key3 += 0x20)
+ {
+ if (check_key(key3,BIT(key3,6),gkey1,gkey2,gkey3) || check_key(key3,BIT(key3,6)^1,gkey1,gkey2,gkey3))
+ {
+ printf("key: ");
+ print_binary(key1);
+ printf(" ");
+ print_binary(key2);
+ printf(" ");
+ print_binary(key3);
+ printf(" ");
+ printf("global key: ");
+ print_binary(gkey1);
+ printf(" ");
+ print_binary(gkey2);
+ printf(" ");
+ print_binary(gkey3);
+ printf("\n");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ exit(0);
+ }
+}
+
+
+UINT8 mainkey[0x2000];
+
+void find_main_key(void)
+{
+ int n,key,keyF,allfound = 0,found;
+
+ printf("Searching for main key...\n");
+
+ for (n = 0;n < 0x2000;n++)
+ {
+ if (n % 16 == 0) fprintf(stderr,"%03x/1ff\r",n/16);
+ load_table(n*2);
+ found = 0;
+ for (key = 0;key < 0x100;key++)
+ {
+ if (n & 0x1000) keyF = BIT(key,7);
+ else keyF = BIT(key,6);
+
+ if (check_key(key,keyF,global_key1,global_key2,global_key3))
+ {
+ mainkey[n] = key;
+ found++;
+ }
+ }
+
+ if (found == 0)
+ printf("00%04x.tbl: can't decrypt\n",n*2);
+ else if (found == 1)
+ allfound++;
+ else if (found > 1)
+ {
+ printf("00%04x.tbl: ambiguous key\n",n*2);
+ printf("The tables from state %02x don't allow to uniquely determine the main key.\n",state2*2);
+ printf("You should dump tables from state %02x and run the program again.\n",(state2^1)*2);
+ exit(0);
+ }
+ }
+
+ if (allfound != 0x2000)
+ {
+ printf("The tables listed above are probably bad dumps.\n");
+ printf("You should try redumping them and run the program again.\n");
+ exit(0);
+ }
+
+ printf("Key generation succeeded!\n");
+}
+
+void save_main_key()
+{
+ FILE *f1;
+ f1 = fopen(dstfilename,"wb");
+ if (!f1)
+ {
+ printf("Can't open %s for writing.\n",dstfilename);
+ exit(1);
+ }
+ if (fwrite(mainkey,1,0x2000,f1) == 0x2000)
+ printf("Key saved in current directory as %s.\n",dstfilename);
+ else
+ printf("Error saving key.\n");
+
+ fclose(f1);
+}
+
+
+int main(int argc,char **argv)
+{
+ if (argc != 4 || (strcmp(argv[2],"00") && strcmp(argv[2],"02")))
+ {
+ printf("Usage: %s <path> <state> <CPU name>\n\n",argv[0]);
+ printf("<path>: path to the directory holding the tables\n");
+ printf(" files must be called 000000.tbl, 000002.tbl ... 003FFE.tbl\n");
+ printf("<state>: must be 00 or 02 - CPU state in which the tables were extracted\n");
+ printf("<CPU name>: part name of the CPU\n");
+ printf("\nExample: %s c:/dumps/0053-0000 00 317-0053\n",argv[0]);
+ return 0;
+ }
+
+ sprintf(srcpath,argv[1]);
+ if (strcmp(argv[2],"02") == 0)
+ state2 = 1;
+ else
+ state2 = 0;
+ sprintf(dstfilename,"%s.key",argv[3]);
+
+ printf("reading tables from %s\n",srcpath);
+ printf("tables were read from the CPU in state %s\n",state2 ? "02" : "00");
+ printf("output file will be %s\n\n",dstfilename);
+
+ little_endian = is_little_endian();
+
+ find_global_key();
+ find_main_key();
+ save_main_key();
+
+ return 0;
+}
diff --git a/src/mame/etc/jrcrypt.c b/src/mame/etc/jrcrypt.c
new file mode 100644
index 00000000000..8f561ca2ad0
--- /dev/null
+++ b/src/mame/etc/jrcrypt.c
@@ -0,0 +1,537 @@
+/***************************************************************************
+
+ jrcrypt.c
+
+ This file is not part of MAME. It is here to provide detailed
+ documentation of the encryption used by Jr. Pac Man ROMs.
+
+ David Caldwell 6-1-97
+ bug reports and comments to:
+ david@indigita.com
+
+ This code is published under the GNU Public License. (GPL)
+
+***************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "mame.h"
+#include "driver.h"
+#include "osdepend.h"
+
+static int interrupt_enable;
+
+typedef UINT16 word;
+typedef UINT8 byte;
+
+#define PreDecryptedRoms
+
+#ifndef PreDecryptedRoms
+static int s0,s1,s2,s3; /* 1 bit registers inside decoder PAL */
+static UINT8 shadowROM[0xffff];
+static UINT8 used[0xFFFF];
+UINT32 numberUsed = 0;
+#else
+struct {
+ int count;
+ int value;
+} Jr_PacManTable[] = {
+ { 0x00C1, 0x00 },
+ { 0x0002, 0x80 },
+ { 0x0004, 0x00 },
+ { 0x0006, 0x80 },
+ { 0x0003, 0x00 },
+ { 0x0002, 0x80 },
+ { 0x0009, 0x00 },
+ { 0x0004, 0x80 },
+ { 0x9968, 0x00 },
+ { 0x0001, 0x80 },
+ { 0x0002, 0x00 },
+ { 0x0001, 0x80 },
+ { 0x0009, 0x00 },
+ { 0x0002, 0x80 },
+ { 0x0009, 0x00 },
+ { 0x0001, 0x80 },
+ { 0x00AF, 0x00 },
+ { 0x000E, 0x04 },
+ { 0x0002, 0x00 },
+ { 0x0004, 0x04 },
+ { 0x001E, 0x00 },
+ { 0x0001, 0x80 },
+ { 0x0002, 0x00 },
+ { 0x0001, 0x80 },
+ { 0x0002, 0x00 },
+ { 0x0002, 0x80 },
+ { 0x0009, 0x00 },
+ { 0x0002, 0x80 },
+ { 0x0009, 0x00 },
+ { 0x0002, 0x80 },
+ { 0x0083, 0x00 },
+ { 0x0001, 0x04 },
+ { 0x0001, 0x01 },
+ { 0x0001, 0x00 },
+ { 0x0002, 0x05 },
+ { 0x0001, 0x00 },
+ { 0x0003, 0x04 },
+ { 0x0003, 0x01 },
+ { 0x0002, 0x00 },
+ { 0x0001, 0x04 },
+ { 0x0003, 0x01 },
+ { 0x0003, 0x00 },
+ { 0x0003, 0x04 },
+ { 0x0001, 0x01 },
+ { 0x002E, 0x00 },
+ { 0x0078, 0x01 },
+ { 0x0001, 0x04 },
+ { 0x0001, 0x05 },
+ { 0x0001, 0x00 },
+ { 0x0001, 0x01 },
+ { 0x0001, 0x04 },
+ { 0x0002, 0x00 },
+ { 0x0001, 0x01 },
+ { 0x0001, 0x04 },
+ { 0x0002, 0x00 },
+ { 0x0001, 0x01 },
+ { 0x0001, 0x04 },
+ { 0x0002, 0x00 },
+ { 0x0001, 0x01 },
+ { 0x0001, 0x04 },
+ { 0x0001, 0x05 },
+ { 0x0001, 0x00 },
+ { 0x0001, 0x01 },
+ { 0x0001, 0x04 },
+ { 0x0002, 0x00 },
+ { 0x0001, 0x01 },
+ { 0x0001, 0x04 },
+ { 0x0002, 0x00 },
+ { 0x0001, 0x01 },
+ { 0x0001, 0x04 },
+ { 0x0001, 0x05 },
+ { 0x0001, 0x00 },
+ { 0x01B0, 0x01 },
+ { 0x0001, 0x00 },
+ { 0x0002, 0x01 },
+ { 0x00AD, 0x00 },
+ { 0x0031, 0x01 },
+ { 0x005C, 0x00 },
+ { 0x0005, 0x01 },
+ { 0x604E, 0x00 },
+ { 0,0 }
+};
+#endif
+
+MACHINE_RESET( jrpacman )
+{
+#ifndef PreDecryptedRoms
+ s0 = 1;
+ s1 = 1;
+ s2 = 0;
+ s3 = 0;
+
+ memset(shadowROM,0,sizeof(shadowROM));
+ memset(used,0,sizeof(used));
+#endif
+}
+
+
+#ifdef PreDecryptedRoms
+unsigned jrpacman_decode_roms(int address)
+{
+ int i;
+ int cumulative=0;
+ for (i=0;Jr_PacManTable[i].count;i++)
+ {
+ cumulative += Jr_PacManTable[i].count;
+ if (cumulative > address)
+ return RAM[address] ^ Jr_PacManTable[i].value;
+ }
+ return RAM[address]; // this should never happen!
+}
+#else
+INLINE WordBit(word theWord, int theBit)
+{
+ return (theWord >> theBit)&1;
+}
+INLINE ByteBit(byte theByte, int theBit)
+{
+ return (theByte >> theBit)&1;
+}
+
+int jrpacman_romdecode(int offset);
+int jrpacman_romdecodeA(int offset)
+{
+ jrpacman_romdecode(offset);
+}
+
+int jrpacman_romdecodeB(int offset)
+{
+ jrpacman_romdecode(offset + 0x8000);
+}
+
+
+/****************************************************************************
+
+ This function would look suprisingly similiar to the source code to
+the encoder pals, I imagine. I wrote is based on the jedec file that I
+got from VideoDoctor. It needs to be run during the game, since the
+logic is kind of wierd and state based. This is slow. So you'll see
+that I made it store its "decrypted" opcodes in another array. When I
+ran the program and was satisfied that it had decrypted enough code, I
+dumped this new array out into some ROM files. These ROM files are
+effectively decrypted. But nobody else has them, so I'd have to upload
+them to some ROM archive somewhere and hope for the best. Besides, If
+I ever found a bug in them its not easy to upgrade every ROM archive
+site out there. So I created a table that has the decrypted ROMs and
+the encrypted ROMs xor-ed with each other. So if something wrong is
+ever discovered , all that is needed to update is the table. Jr. Pac
+only messes with 3 bits (d0, d2 and d7) so the table doesn't look too
+excited. Also I run length encoded it so its not unwieldly.
+
+ A lot of the functions that are ifdef-ed out here were debugging
+functions that I used to help me during the decoding process.
+
+ -David Caldwell
+ david@indigita.com
+
+***************************************************************************/
+
+int jrpacman_romdecode(int offset)
+{
+ int addressBus = offset;
+ Z80_Regs Regs;
+ Z80_GetRegs(&Regs);
+
+ {
+ int m1 = !Regs.M1;//active low (supposedly means opcode read)
+
+ /* Pal 8C (16L8) */
+ int pcbe = !(addressBus >= 0x0000 && addressBus <= 0x3fff ||
+ addressBus >= 0x8000 && addressBus <=
+0xdfff);
+
+ int sop0 = !(addressBus >= 0x0000 && addressBus <= 0x001f ||
+ addressBus >= 0x00e0 && addressBus <=
+0x00ff ||
+ addressBus >= 0x9a60 && addressBus <=
+0x9a7f ||
+ addressBus >= 0x9ac0 && addressBus <=
+0x9adf ||
+ addressBus >= 0x9b60 && addressBus <=
+0x9b7f ||
+ addressBus >= 0x9be0 && addressBus <=
+0x9bff && m1);
+
+ int sop1 = !(addressBus >= 0x9be0 && addressBus <= 0x9bff && m1 ||
+ addressBus >= 0x9ca0 && addressBus <=
+0x9cbf);
+
+ int sop2 = !(addressBus >= 0x00c0 && addressBus <= 0x00df ||
+ addressBus >= 0x9a40 && addressBus <=
+0x9a5f);
+
+
+ /* Pal 9c (16r4) */
+ int md0 = ByteBit(RAM[addressBus],0);
+ int md2 = ByteBit(RAM[addressBus],2);
+ int md7 = ByteBit(RAM[addressBus],7);
+
+ int d0 = !( s0 && s1 && !md0 ||
+ !s0 && s1 && md0 ||
+ s0 && !s1 && !md0 ||
+ !s0 && !s1 && !md2);
+
+ int d2 = !( s0 && s1 && !md2 ||
+ !s0 && s1 && !md2 ||
+ s0 && !s1 && md2 ||
+ !s0 && !s1 && !md0);
+
+ int d7 = !( s2 && s3 ||
+ !s2 && !md7);
+
+ int pb1 = !( sop0 && s0 ||
+ !sop0 && !s0);
+
+ int ns0 = ( sop1 && s0 ||
+ !sop1 && !s0 ||
+ !sop0 && sop1);
+
+ int ns1 = ( sop1 && s1 && !pb1 ||
+ !sop1 && s1 && !pb1 ||
+ sop1 && s1 && pb1 ||
+ !sop1 && !s1 && pb1 ||
+ !sop0 && sop1);
+
+ int ns2 = ( sop0 && sop1 && s2 ||
+ sop0 && !sop1 && s2 ||
+ !sop0 && !sop1 && s2 ||
+ sop0 && !sop2);
+
+ int ns3 = ( !md7 );
+
+// DebugPrint("%04x: %02x & %02x | %02x = %02x",addressBus,RAM[addressBus],~(1<<0) & ~(1<<2) & ~(1<<7), (d0) | (d2<<2) | (d7<<7),(RAM[addressBus] & ~(1<<0) & ~(1<<2) & ~(1<<7)) | (d0) | (d2<<2) | (d7<<7));
+/* printf("%04x: %02x & %02x | %02x = %02x\n",addressBus,RAM[addressBus],~(1<<0) & ~(1<<2) & ~(1<<7), (d0) | (d2<<2) | (d7<<7),(RAM[addressBus] & ~(1<<0) & ~(1<<2) & ~(1<<7)) | (d0) | (d2<<2) | (d7<<7));
+ {static int i=0;
+ if (i++>100)
+ {
+ while (getchar()!='\n')
+ {}
+ }}*/
+ {
+ int temp= ((int)RAM[addressBus] & 0x7A) | ((d7<<7) | (d2<<2) | (d0));
+
+// if (Z80_Trace==1)
+ if (!used[addressBus])
+ {
+ used[addressBus]=1;
+ shadowROM[addressBus] = temp;
+ numberUsed++;
+ }
+ else
+ {
+ if (shadowROM[addressBus] != temp)
+ DebugPrint("Address: %04x translates to 2 different values!!!! (%02x and %02x)",addressBus,shadowROM[addressBus],temp);
+ }
+
+
+ if (Z80_Trace==1)
+ {
+ static last = 0;
+ if (last + 30 <= TickCount()) /* print bnanner if we havent been called in half a second */
+ printf("m1 sop0 sop1 sop2 pcbe md7 md2 md0 d7 d2 d0 pb1 s0 s1 s2 s3 ns0 ns1 ns2 ns3\n");
+ last = TickCount();
+ printf("%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d ",
+ m1, sop0,sop1,sop2,pcbe, md7, md2, md0,
+d7, d2, d0, pb1, s0, s1, s2, s3, ns0, ns1, ns2, ns3);
+ printf("%04x: %02x & %02x | %02x = %02x\n",addressBus,RAM[addressBus],~(1<<0) & ~(1<<2) & ~(1<<7), (d0) | (d2<<2) | (d7<<7),(RAM[addressBus] & ~(1<<0) & ~(1<<2) & ~(1<<7)) | (d0) | (d2<<2) | (d7<<7));
+ Z80_Trace = 1; /* stop it if it was running for a count */
+ }
+
+ /* latch new flip flops on rising edge of pcbe */
+ if (!pcbe)
+ {
+ s0 = ns0;
+ s1 = ns1;
+ s2 = ns2;
+ s3 = ns3;
+ }
+ return temp;
+ }
+ }
+}
+
+int Z80_Trace=0;
+
+void jr_monitor()
+{
+ int i;
+ int encrypted=0;
+ int last_used=-1;
+ int unmapped_encrypted=0;
+ int unmapped=0;
+ printf("statistics: \n");
+ printf(" Successfully mapped: %d\n",numberUsed);
+ for (i=0;i<0xe000;i=(i==0x4000?0x8000:i+1)) /* skip hole where
+hardware and RAM is */
+ {
+ if (used[i])
+ {
+ if (shadowROM[i] != RAM[i])
+ encrypted = 1;
+ else
+ encrypted = 0;
+ last_used = i;
+ }
+ else
+ {
+ if (encrypted)
+ unmapped_encrypted++;
+ else
+ unmapped++;
+ }
+ }
+ printf(" Non mapped, Probably not encrypted: %d\n",unmapped);
+ printf(" Non mapped, but Probably encrypted:
+%d\n",unmapped_encrypted);
+
+ while (1)
+ {
+ void write_rom_section(char *prefix,char *suffix,int
+start,int end);
+ char c;
+ printf(" Enter D to Merge mapped and unmapped and dump to
+rom file,\n");
+ printf(" Enter Q to quit.\n");
+ c=tolower(getchar());
+ while (getchar()!='\n') {}
+ if (c=='q')
+ return;
+ if (c=='d')
+ {
+ char line[100],*l;
+ int i;
+ printf("Enter file prefix (files will be named
+'prefix'.8d 'prefix'.8e, etc.\n");
+ gets(line);
+ // kill newline:
+ for (l=line;*l!='\n' && *l!='\0';l++)
+ {}
+ *l = '\0';
+
+ write_rom_section(line,".8d",0x0000,0x2000);
+ write_rom_section(line,".8e",0x2000,0x4000);
+ write_rom_section(line,".8h",0x8000,0xa000);
+ write_rom_section(line,".8j",0xa000,0xc000);
+ write_rom_section(line,".8k",0xc000,0xe000);
+ }
+ }
+}
+
+void write_rom_section(char *prefix,char *suffix,int start,int end)
+{
+ FILE *out;
+ char file[100];
+ int i;
+
+ strcpy(file,prefix);
+ strcat(file,suffix);
+ out = fopen(file,"wb");
+ for (i=start;i<end;i++)
+ if (used[i])
+ putc(shadowROM[i],out);
+ else
+ putc(RAM[i],out);
+ fclose(out);
+}
+#endif
+
+WRITE8_HANDLER( jrpacman_interrupt_enable_w )
+{
+ interrupt_enable = data;
+}
+
+
+
+/***************************************************************************
+
+ Interrupt handler. This function is called at regular intervals
+ (determined by IPeriod) by the CPU emulation.
+
+***************************************************************************/
+
+static int IntVector = 0xff; /* Here we store the interrupt vector, if
+the code performs */
+ /* an OUT to port $0. Not
+all games do it: many use */
+ /* Interrupt Mode 1, which
+doesn't use an interrupt vector */
+ /* (see Z80.c for details). */
+
+INTERRUPT_GEN( jrpacman_interrupt )
+{
+ irq0_line_hold();
+}
+
+
+
+/***************************************************************************
+
+ The Pac Man machine uses OUT to port $0 to set the interrupt vector, so
+ we have to remember the value passed.
+
+***************************************************************************/
+void jrpacman_out(byte Port,byte Value)
+{
+ /* OUT to port $0 is used to set the interrupt vector */
+ if (Port == 0) IntVector = Value;
+}
+
+#if 0
+/****************************************************************************
+What follows is the program I used to create the JrPacMan_Table[] array at
+the top of this file. It is included here for completeness.
+***************************************************************************/
+
+
+// CreateJrDecodeTable.c
+//
+// Copyright (C) 1997 David Caldwell
+// This program is published under the GNU Public License.
+//
+// Comments, questions to: david@indigita.com
+
+#include <stdio.h>
+
+typedef UINT8 byte;
+
+void CreateJrDecodeTable(byte *x, int length);
+void Load(char *name,byte *buffer,int from, int length);
+
+byte encrypted[0x10000],decrypted[0x10000];
+byte xored[0x10000];
+void main()
+{
+ int i;
+
+ Load("jr8d",encrypted,0x0000,0x2000);
+ Load("jr8e",encrypted,0x2000,0x2000);
+ Load("jr8h",encrypted,0x8000,0x2000);
+ Load("jr8j",encrypted,0xA000,0x2000);
+ Load("jr8k",encrypted,0xC000,0x2000);
+
+ Load("1.8d",decrypted,0x0000,0x2000);
+ Load("1.8e",decrypted,0x2000,0x2000);
+ Load("1.8h",decrypted,0x8000,0x2000);
+ Load("1.8j",decrypted,0xA000,0x2000);
+ Load("1.8k",decrypted,0xC000,0x2000);
+
+ for (i=0;i<0x10000;i++)
+ xored[i] = encrypted[i] ^ decrypted[i];
+
+ CreateJrDecodeTable(xored,0x10000);
+}
+
+void Load(char *name,byte *buffer,int from, int length)
+{
+ file_error filerr;
+ mame_file *file;
+
+ filerr = mame_fopen(NULL, name, OPEN_FLAG_READ, &file);
+ if (filerr != FILERR_NONE)
+ return;
+ while (length--)
+ buffer[from++]=mame_fgetc(file);
+ mame_fclose(file);
+}
+
+void CreateJrDecodeTable(byte *x, int length)
+{
+ int i=0;
+ byte last = 0;
+ int count = 0;
+
+ printf( "struct {\n"
+ " int count;\n"
+ " int value;\n"
+ "} Jr_PacManTable[] = {\n");
+
+ goto first;
+
+ for (i=0;i<length;i++)
+ {
+ if (x[i] != last)
+ {
+ printf(" { 0x%04X, 0x%02X },\n",count,last);
+ count = 0;
+ }
+first:
+ last = x[i];
+ count++;
+ }
+
+ printf(" { 0x%04X, 0x%02X },\n",count,last);
+ printf( " { 0,0 }\n"
+ "};\n");
+}
+#endif