1 // license:BSD-3-Clause
2 // copyright-holders:David Haywood, ElSemi
3 /*
4 
5  IGS022 is an encrypted DMA device, most likely an MCU of some sort
6  it can safely be swapped between games so doesn't appear to have
7  any kind of game specific programming
8 
9 */
10 
11 #include "emu.h"
12 #include "igs022.h"
13 
14 #include <algorithm>
15 
igs022_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)16 igs022_device::igs022_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
17 	: device_t(mconfig, IGS022, tag, owner, clock)
18 	, m_sharedprotram(*this, "sharedprotram")
19 	, m_rom(*this, DEVICE_SELF)
20 {
21 }
22 
device_start()23 void igs022_device::device_start()
24 {
25 	// Reset  stuff
26 	std::fill(std::begin(m_kb_regs), std::end(m_kb_regs), 0);
27 
28 	save_item(NAME(m_kb_regs));
29 }
30 
device_reset()31 void igs022_device::device_reset()
32 {
33 	//printf("igs022_device::device_reset()");
34 
35 	if (!m_sharedprotram)
36 	{
37 		logerror("m_sharedprotram was not set\n");
38 		return;
39 	}
40 	IGS022_reset();
41 
42 	std::fill(std::begin(m_kb_regs), std::end(m_kb_regs), 0);
43 }
44 
45 
IGS022_do_dma(u16 src,u16 dst,u16 size,u16 mode)46 void igs022_device::IGS022_do_dma(u16 src, u16 dst, u16 size, u16 mode)
47 {
48 	//printf("igs022_device::IGS022_do_dma\n");
49 
50 	/*
51 	P_SRC =0x300290 (offset from prot rom base)
52 	P_DST =0x300292 (words from 0x300000)
53 	P_SIZE=0x300294 (words)
54 	P_MODE=0x300296
55 
56 	Mode 5 direct
57 	Mode 6 swap nibbles and bytes
58 
59 	1,2,3 table based ops
60 	*/
61 
62 	const u16 param = mode >> 8;
63 
64 	// the initial DMA on kilbld has 0x10 set, drgw3 has 0x18 set, not sure how they affect the operation.
65 	if (mode & 0x00f8) printf("IGS022_do_dma mode bits %04x set\n", mode & 0x00f8);
66 
67 	mode &= 0x7;  // what are the other bits?
68 
69 	if ((mode == 0) || (mode == 1) || (mode == 2) || (mode == 3)  || (mode == 4))
70 	{
71 		/* mode3 applies a xor from a 0x100 byte table to the data being
72 		   transferred
73 
74 		   the table is stored at the start of the protection rom.
75 
76 		   the param used with the mode gives a start offset into the table
77 
78 		   odd offsets cause an overflow
79 		*/
80 
81 		const u16 *PROTROM = (u16*)m_rom->base();
82 
83 		for (int x = 0; x < size; x++)
84 		{
85 			u16 dat2 = PROTROM[src + x];
86 
87 			const u8 extraoffset = param & 0xff;
88 			const u8* dectable = (u8*)m_rom->base(); // the basic decryption table is at the start of the mcu data rom!
89 			const u8 taboff = ((x * 2) + extraoffset) & 0xff; // must allow for overflow in instances of odd offsets
90 			u16 extraxor = ((dectable[taboff + 1]) << 8) | (dectable[taboff + 0] << 0);
91 
92 			if (mode == 4)
93 			{
94 				extraxor = 0;
95 				if ((x & 0x003) == 0x000) extraxor |= 0x0049; // 'I'
96 				if ((x & 0x003) == 0x001) extraxor |= 0x0047; // 'G'
97 				if ((x & 0x003) == 0x002) extraxor |= 0x0053; // 'S'
98 				if ((x & 0x003) == 0x003) extraxor |= 0x0020; // ' '
99 
100 				if ((x & 0x300) == 0x000) extraxor |= 0x4900; // 'I'
101 				if ((x & 0x300) == 0x100) extraxor |= 0x4700; // 'G'
102 				if ((x & 0x300) == 0x200) extraxor |= 0x5300; // 'S'
103 				if ((x & 0x300) == 0x300) extraxor |= 0x2000; // ' '
104 			}
105 
106 			//  mode == 0 plain
107 			if (mode == 3) dat2 ^= extraxor;
108 			if (mode == 2) dat2 += extraxor;
109 			if (mode == 1) dat2 -= extraxor;
110 
111 			if (mode == 4)
112 			{
113 				//printf("%06x | %04x (%04x)\n", (dst+x)*2, dat2, (u16)(dat2-extraxor));
114 
115 				dat2 -= extraxor;
116 			}
117 
118 			m_sharedprotram[dst + x] = dat2;
119 		}
120 	}
121 	else if (mode == 5)
122 	{
123 		/* mode 5 seems to be a byteswapped copy */
124 		const u16 *PROTROM = (u16*)m_rom->base();
125 		for (int x = 0; x < size; x++)
126 		{
127 			u16 dat = PROTROM[src + x];
128 			dat = ((dat &0x00ff) << 8) | ((dat &0xff00) >> 8);
129 
130 			m_sharedprotram[dst + x] = dat;
131 		}
132 	}
133 	else if (mode == 6)
134 	{
135 		/* mode 6 seems to be a nibble swapped copy */
136 		const u16 *PROTROM = (u16*)m_rom->base();
137 		for (int x = 0; x < size; x++)
138 		{
139 			u16 dat = PROTROM[src + x];
140 
141 			dat = ((dat & 0xf0f0) >> 4)|
142 					((dat & 0x0f0f) << 4);
143 
144 			m_sharedprotram[dst + x] = dat;
145 		}
146 	}
147 	else if (mode == 7)
148 	{
149 		printf("unhandled copy mode %04x!\n", mode);
150 		// not used by killing blade
151 		/* weird mode, the params get left in memory? - maybe it's a NOP? */
152 	}
153 	else
154 	{
155 		osd_printf_debug("unhandled copy mode %04x!\n", mode);
156 		printf ("DMA MODE: %d, src: %4.4x, dst: %4.4x, size: %4.4x, param: %2.2x\n", mode, src, dst, size, param);
157 		// not used by killing blade
158 		/* invalid? */
159 	}
160 }
161 
162 // the internal MCU boot code automatically does this DMA
163 // and puts the version # of the data rom in ram
IGS022_reset()164 void igs022_device::IGS022_reset()
165 {
166 	const u16 *PROTROM = (u16*)m_rom->base();
167 
168 	// fill ram with A5 patern
169 	for (int i = 0; i < 0x4000/2; i++)
170 		m_sharedprotram[i] = 0xa55a;
171 
172 	// the auto-dma
173 	u16 src        = PROTROM[0x100 / 2];
174 	const u32 dst  = PROTROM[0x102 / 2];
175 	const u16 size = PROTROM[0x104 / 2];
176 	u16 mode       = PROTROM[0x106 / 2];
177 
178 	mode &= 0xff;
179 
180 	src >>= 1;
181 
182 	IGS022_do_dma(src,dst,size,mode);
183 
184 	// there is also a version ID? (or is it some kind of checksum) that is stored in the data rom, and gets copied..
185 	// Dragon World 3 checks it
186 	// Setting $3002a0 to #3 causes Dragon World 3 to skip this check
187 	m_sharedprotram[0x2a2/2] = PROTROM[0x114/2];
188 }
189 
IGS022_handle_command()190 void igs022_device::IGS022_handle_command()
191 {
192 	//printf("igs022_device::IGS022_handle_command\n");
193 
194 	const u16 cmd = m_sharedprotram[0x200/2];
195 
196 	if (cmd == 0x6d)    // Store values to asic ram
197 	{
198 		const u32 p1 = (m_sharedprotram[0x298/2] << 16) | m_sharedprotram[0x29a/2];
199 		const u32 p2 = (m_sharedprotram[0x29c/2] << 16) | m_sharedprotram[0x29e/2];
200 
201 		if ((p2 & 0xffff) == 0x9)   // Set value
202 		{
203 			const int reg = (p2 >> 16) & 0xffff;
204 
205 			if (reg & 0x300) { // 300?? killbld expects 0x200, drgw3 expects 0x100?
206 				m_kb_regs[reg & 0xff] = p1;
207 			}
208 		}
209 
210 		if ((p2 & 0xffff) == 0x6)   // Add value
211 		{
212 			const int src1 = (p1 >> 16) & 0xff;
213 			const int src2 = (p1 >> 0) & 0xff;
214 			const int dst = (p2 >> 16) & 0xff;
215 
216 			m_kb_regs[dst] = m_kb_regs[src2] - m_kb_regs[src1];
217 		}
218 
219 		if ((p2 & 0xffff) == 0x1)   // Add Imm?
220 		{
221 			const int reg = (p2 >> 16) & 0xff;
222 			const int imm = (p1 >> 0) & 0xffff;
223 
224 			m_kb_regs[reg] += imm;
225 		}
226 
227 		if ((p2 & 0xffff) == 0xa)   // Get value
228 		{
229 			const int reg = (p1 >> 16) & 0xFF;
230 
231 			m_sharedprotram[0x29c/2] = (m_kb_regs[reg] >> 16) & 0xffff;
232 			m_sharedprotram[0x29e/2] = m_kb_regs[reg] & 0xffff;
233 		}
234 
235 		m_sharedprotram[0x202 / 2] = 0x7c;  // this mode complete?
236 	}
237 
238 	// Is this actually what this is suppose to do? Complete guess.
239 	if (cmd == 0x12) // copy??
240 	{
241 		m_sharedprotram[0x28c / 2] = m_sharedprotram[0x288 / 2];
242 		m_sharedprotram[0x28e / 2] = m_sharedprotram[0x28a / 2];
243 
244 		m_sharedprotram[0x202 / 2] = 0x23;  // this mode complete?
245 	}
246 
247 	// what do these do? write the completion byte for now...
248 	if (cmd == 0x45) m_sharedprotram[0x202 / 2] = 0x56;
249 	if (cmd == 0x5a) m_sharedprotram[0x202 / 2] = 0x4b;
250 	if (cmd == 0x2d) m_sharedprotram[0x202 / 2] = 0x3c;
251 
252 	if (cmd == 0x4f) // memcpy with encryption / scrambling
253 	{
254 		const u16 src  = m_sharedprotram[0x290 / 2] >> 1; // External mcu data is 8 bit and addressed as such
255 		const u32 dst  = m_sharedprotram[0x292 / 2];
256 		const u16 size = m_sharedprotram[0x294 / 2];
257 		const u16 mode = m_sharedprotram[0x296 / 2];
258 
259 		IGS022_do_dma(src,dst,size,mode);
260 
261 		m_sharedprotram[0x202 / 2] = 0x5e;  // this mode complete?
262 	}
263 }
264 
265 
266 DEFINE_DEVICE_TYPE(IGS022, igs022_device, "igs022", "IGS022")
267