1 /***************************************************************************
2 
3   machine.c
4 
5   Functions to emulate general aspects of the machine (RAM, ROM, interrupts,
6   I/O ports)
7 
8   The Glob protection description:
9 
10   The Glob is designed to run on modified Pacman hardware.  It contains
11   two graphics ROMs at 5E and 5F, but contains code ROMs on a daughterboard
12   similar in concept to Ms. Pacman.  However, these code ROMs are decrypted
13   through additional circuitry.  The daughterboard was encased in epoxy.
14 
15   Here's a description of the protection as best as I can give it.
16 
17   1)  The decrypted D0 bit fed to the CPU is simply an inversion of the
18       D5 bit from the code ROMs.
19   2)  The decrypted D1 bit fed to the CPU is simply an inversion of the
20       D2 bit from the code ROMs.
21   3)  The other 6 data bits are decrypted by a 10H8 PAL.  The PAL also
22       takes as input a 4-bit counter.  The counter is incremented and
23 	  decremented as follows:
24 	  - the Z-80 command IN($xx) where xx is an odd number decrements the
25 	    counter; an even number increments the counter.
26 		Ex:  IN($64) would increment the counter, IN($6B) would decrement
27 		the counter.
28   4)  The PAL output also contains the two ROM enable lines used to enable
29       the two encrypted code ROMs.  As long as the system is working
30 	  correctly, these ROMs will always be enabled.
31 
32   As it so happens, only four counter values are ever used, which is
33   fortunate because the PAL only contains signals to enable the ROMs for
34   those four counter values.  The valid counter values are $8, $9, $A, and
35   $B.  The counter's intial value is $A, which is set by jumpers on the
36   daughterboard.  Following is a description of the resulting decryptions
37   for these four counter states.
38 
39   COUNTER		ENCRYPTED	DECRYPTED
40 				  VALUE	      VALUE
41 
42 				DDDDDDDD	DDDDDDDD
43 				76543210	76543210
44 
45   Counter = 8:  abcdefgh	EAhBDgFC
46   Counter = 9:	abcdefgh	FAgeDBFC
47   Counter = A:	abcdefgh	EHDBagFC
48   Counter = B:  abcdefgh	GHDEaBFC
49 
50   In the above diagram, capital letters represent inverted bits.  Notice
51   that bits D2 and D5 are the same independent of counter state, this is
52   because these bits are not decrypted by the PAL.
53 
54 
55   In the code below, all four of these decryption patterns are used to
56   decrypt the entire code ROMs before execution.  This is done for speed,
57   since we can then just bankswitch between the decrypted code sets on
58   each IN($xx) command, as opposed to dynamically decrypting every byte.
59 
60   - Mike Balfour (mab22@po.cwru.edu)
61 
62 ***************************************************************************/
63 
64 #include "driver.h"
65 
66 void pacman_init_machine(void);
67 
68 static int counter=0;
69 
70 
theglob_decrypt_rom_8(void)71 static void theglob_decrypt_rom_8(void)
72 {
73 	int oldbyte,inverted_oldbyte,newbyte;
74 	int mem;
75 	unsigned char *RAM;
76 
77 	RAM = memory_region(REGION_CPU1);
78 
79 
80 	for (mem=0;mem<0x4000;mem++)
81 	{
82 		oldbyte = RAM[mem];
83 		inverted_oldbyte = ~oldbyte;
84 
85 		/*	Note: D2 is inverted and connected to D1, D5 is inverted and
86 			connected to D0.  The other six data bits are converted by a
87 			PAL10H8 driven by the counter. */
88 		newbyte = 0;
89 
90 		/* Direct inversion */
91 		newbyte  = (inverted_oldbyte & 0x04) >> 1;
92 		newbyte |= (inverted_oldbyte & 0x20) >> 5;
93 		/* PAL */
94 		newbyte |= (oldbyte & 0x01) << 5;
95 		newbyte |= (oldbyte & 0x02) << 1;
96 		newbyte |= (inverted_oldbyte & 0x08) << 4;
97 		newbyte |= (inverted_oldbyte & 0x10) >> 1;
98 		newbyte |= (inverted_oldbyte & 0x40) >> 2;
99 		newbyte |= (inverted_oldbyte & 0x80) >> 1;
100 
101 		RAM[mem + 0x10000] = newbyte;
102 	}
103 
104 	return;
105 }
106 
107 
theglob_decrypt_rom_9(void)108 static void theglob_decrypt_rom_9(void)
109 {
110 	int oldbyte,inverted_oldbyte,newbyte;
111 	int mem;
112 	unsigned char *RAM;
113 
114 	RAM = memory_region(REGION_CPU1);
115 
116 	for (mem=0;mem<0x4000;mem++)
117 	{
118 		oldbyte = RAM[mem];
119 		inverted_oldbyte = ~oldbyte;
120 
121 		/*	Note: D2 is inverted and connected to D1, D5 is inverted and
122 			connected to D0.  The other six data bits are converted by a
123 			PAL10H8 driven by the counter. */
124 		newbyte = 0;
125 
126 		/* Direct inversion */
127 		newbyte  = (inverted_oldbyte & 0x04) >> 1;
128 		newbyte |= (inverted_oldbyte & 0x20) >> 5;
129 		/* PAL */
130 		newbyte |= (oldbyte & 0x01) << 5;
131 		newbyte |= (inverted_oldbyte & 0x02) << 6;
132 		newbyte |= (oldbyte & 0x08) << 1;
133 		newbyte |= (inverted_oldbyte & 0x10) >> 1;
134 		newbyte |= (inverted_oldbyte & 0x40) >> 4;
135 		newbyte |= (inverted_oldbyte & 0x80) >> 1;
136 
137 		RAM[mem + 0x14000] = newbyte;
138 	}
139 
140 	return;
141 }
142 
theglob_decrypt_rom_A(void)143 static void theglob_decrypt_rom_A(void)
144 {
145 	int oldbyte,inverted_oldbyte,newbyte;
146 	int mem;
147 	unsigned char *RAM;
148 
149 	RAM = memory_region(REGION_CPU1);
150 
151 	for (mem=0;mem<0x4000;mem++)
152 	{
153 		oldbyte = RAM[mem];
154 		inverted_oldbyte = ~oldbyte;
155 
156 		/*	Note: D2 is inverted and connected to D1, D5 is inverted and
157 			connected to D0.  The other six data bits are converted by a
158 			PAL10H8 driven by the counter. */
159 		newbyte = 0;
160 
161 		/* Direct inversion */
162 		newbyte  = (inverted_oldbyte & 0x04) >> 1;
163 		newbyte |= (inverted_oldbyte & 0x20) >> 5;
164 		/* PAL */
165 		newbyte |= (inverted_oldbyte & 0x01) << 6;
166 		newbyte |= (oldbyte & 0x02) << 1;
167 		newbyte |= (inverted_oldbyte & 0x08) << 4;
168 		newbyte |= (inverted_oldbyte & 0x10) << 1;
169 		newbyte |= (inverted_oldbyte & 0x40) >> 2;
170 		newbyte |= (oldbyte & 0x80) >> 4;
171 
172 		RAM[mem + 0x18000] = newbyte;
173 	}
174 
175 	return;
176 }
177 
theglob_decrypt_rom_B(void)178 static void theglob_decrypt_rom_B(void)
179 {
180 	int oldbyte,inverted_oldbyte,newbyte;
181 	int mem;
182 	unsigned char *RAM;
183 
184 	RAM = memory_region(REGION_CPU1);
185 
186 	for (mem=0;mem<0x4000;mem++)
187 	{
188 		oldbyte = RAM[mem];
189 		inverted_oldbyte = ~oldbyte;
190 
191 		/*	Note: D2 is inverted and connected to D1, D5 is inverted and
192 			connected to D0.  The other six data bits are converted by a
193 			PAL10H8 driven by the counter. */
194 		newbyte = 0;
195 
196 		/* Direct inversion */
197 		newbyte  = (inverted_oldbyte & 0x04) >> 1;
198 		newbyte |= (inverted_oldbyte & 0x20) >> 5;
199 		/* PAL */
200 		newbyte |= (inverted_oldbyte & 0x01) << 6;
201 		newbyte |= (inverted_oldbyte & 0x02) << 6;
202 		newbyte |= (oldbyte & 0x08) << 1;
203 		newbyte |= (inverted_oldbyte & 0x10) << 1;
204 		newbyte |= (inverted_oldbyte & 0x40) >> 4;
205 		newbyte |= (oldbyte & 0x80) >> 4;
206 
207 		RAM[mem + 0x1C000] = newbyte;
208 	}
209 
210 	return;
211 }
212 
213 
READ_HANDLER(theglob_decrypt_rom)214 READ_HANDLER( theglob_decrypt_rom )
215 {
216 	unsigned char *RAM = memory_region(REGION_CPU1);
217 
218 	if (offset & 0x01)
219 	{
220 		counter = counter - 1;
221 		if (counter < 0)
222 			counter = 0x0F;
223 	}
224 	else
225 	{
226 		counter = (counter + 1) & 0x0F;
227 	}
228 
229 	switch(counter)
230 	{
231 		case 0x08:	cpu_setbank (1, &RAM[0x10000]);		break;
232 		case 0x09:	cpu_setbank (1, &RAM[0x14000]);		break;
233 		case 0x0A:	cpu_setbank (1, &RAM[0x18000]);		break;
234 		case 0x0B:	cpu_setbank (1, &RAM[0x1C000]);		break;
235 		default:
236 			//logerror("Invalid counter = %02X\n",counter);
237 			break;
238 	}
239 
240 	return 0;
241 }
242 
243 
theglob_init_machine(void)244 void theglob_init_machine(void)
245 {
246 	unsigned char *RAM = memory_region(REGION_CPU1);
247 
248 	/* While the PAL supports up to 16 decryption methods, only four
249 		are actually used in the PAL.  Therefore, we'll take a little
250 		memory overhead and decrypt the ROMs using each method in advance. */
251 	theglob_decrypt_rom_8();
252 	theglob_decrypt_rom_9();
253 	theglob_decrypt_rom_A();
254 	theglob_decrypt_rom_B();
255 
256 	/* The initial state of the counter is 0x0A */
257 	counter = 0x0A;
258 	cpu_setbank (1, &RAM[0x18000]);
259 
260 	pacman_init_machine();
261 }
262