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