summaryrefslogtreecommitdiffstats
path: root/src/mame/machine/igs022.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/igs022.cpp')
-rw-r--r--src/mame/machine/igs022.cpp440
1 files changed, 291 insertions, 149 deletions
diff --git a/src/mame/machine/igs022.cpp b/src/mame/machine/igs022.cpp
index 0fabcd00383..d6adb617ea8 100644
--- a/src/mame/machine/igs022.cpp
+++ b/src/mame/machine/igs022.cpp
@@ -1,17 +1,23 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood, ElSemi
-/*
+/************************************************************************************************************
- IGS022 is an encrypted DMA device, most likely an MCU of some sort
- it can safely be swapped between games so doesn't appear to have
- any kind of game specific programming
+ IGS022 is an encrypted DMA device, most likely an MCU of some sort.
+ It can safely be swapped between games, so doesn't appear to have any kind of game specific programming.
-*/
+************************************************************************************************************/
#include "emu.h"
#include "igs022.h"
+#include <sstream>
-#include <algorithm>
+#define LOG_DMA (1U << 1)
+#define LOG_STACK (1U << 2)
+#define LOG_CMD_6D (1U << 3)
+
+//#define VERBOSE (LOG_GENERAL | LOG_DMA | LOG_STACK | LOG_CMD_6D)
+#define VERBOSE (0)
+#include "logmacro.h"
igs022_device::igs022_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, IGS022, tag, owner, clock)
@@ -22,76 +28,105 @@ igs022_device::igs022_device(const machine_config &mconfig, const char *tag, dev
void igs022_device::device_start()
{
- // Reset stuff
- std::fill(std::begin(m_kb_regs), std::end(m_kb_regs), 0);
-
- save_item(NAME(m_kb_regs));
+ save_item(NAME(m_regs));
+ save_item(NAME(m_stack));
+ save_item(NAME(m_stack_ptr));
}
void igs022_device::device_reset()
{
- //printf("igs022_device::device_reset()");
-
if (!m_sharedprotram)
- {
- logerror("m_sharedprotram was not set\n");
- return;
- }
- IGS022_reset();
+ fatalerror("%s: IGS022 sharedprotram was not set!\n", machine().describe_context());
- std::fill(std::begin(m_kb_regs), std::end(m_kb_regs), 0);
-}
+ // the internal MCU boot code automatically does this DMA
+ // and puts the version # of the data rom in ram
+ // reset regs and stack
+ std::fill(std::begin(m_regs), std::end(m_regs), 0);
+ std::fill(std::begin(m_stack), std::end(m_stack), 0);
+ m_stack_ptr = 0;
-void igs022_device::IGS022_do_dma(u16 src, u16 dst, u16 size, u16 mode)
-{
- //printf("igs022_device::IGS022_do_dma\n");
+ // fill ram with 0xa55a pattern
+ for (int i = 0; i < 0x4000 / 2; i++)
+ m_sharedprotram[i] = 0xa55a;
- /*
- P_SRC =0x300290 (offset from prot rom base)
- P_DST =0x300292 (words from 0x300000)
- P_SIZE=0x300294 (words)
- P_MODE=0x300296
+ // the initial auto-DMA
+ const u16 * const PROTROM = (u16 *)m_rom->base();
+
+ u16 src = PROTROM[0x100 / 2];
+ const u32 dst = PROTROM[0x102 / 2];
+ const u16 size = PROTROM[0x104 / 2];
+ u16 mode = PROTROM[0x106 / 2];
- Mode 5 direct
- Mode 6 swap nibbles and bytes
+ mode = (mode >> 8) | (mode << 8);
+
+ src >>= 1;
- 1,2,3 table based ops
+ do_dma(src, dst, size, mode);
+
+ // there is also a version ID? (or is it some kind of checksum) that is stored in the data rom, and gets copied..
+ // Dragon World 3 checks it
+ // Setting 0x3002a0 to #3 causes Dragon World 3 to skip this check
+ m_sharedprotram[0x2a2 / 2] = PROTROM[0x114 / 2];
+}
+
+// From IGS022 ROM to shared protection RAM
+void igs022_device::do_dma(u16 src, u16 dst, u16 size, u16 mode)
+{
+ LOGMASKED(LOG_DMA, "%s: IGS022 DMA src %04x, dst %04x, size %04x, mode %04x\n", machine().describe_context(), src, dst, size, mode);
+
+ /*
+ P_SRC = 0x300290 (offset from prot rom base)
+ P_DST = 0x300292 (words from 0x300000)
+ P_SIZE = 0x300294 (words)
+ P_MODE = 0x300296
+
+ Mode 0 plain copy
+ Mode 1,2,3 rom table based ops
+ Mode 4 fixed data ('IGS ') based ops
+ Mode 5 swap bytes
+ Mode 6 swap nibbles
*/
const u16 param = mode >> 8;
- // the initial DMA on kilbld has 0x10 set, drgw3 has 0x18 set, not sure how they affect the operation.
- if (mode & 0x00f8) printf("IGS022_do_dma mode bits %04x set\n", mode & 0x00f8);
+ // the initial auto-DMA on killbld/slqz2/lhzb2 has 0x10 set, drgw3 has 0x18 set, not sure how they affect the operation.
+ if (mode & 0x00f8)
+ logerror("%s: IGS022 unknown DMA mode bits %04x set\n", machine().describe_context(), mode & 0x00f8);
- mode &= 0x7; // what are the other bits?
+ mode &= 0x7; // what are the other bits?
- if ((mode == 0) || (mode == 1) || (mode == 2) || (mode == 3) || (mode == 4))
- {
- /* mode3 applies a xor from a 0x100 byte table to the data being
- transferred
+ const u16 * const PROTROM = (u16 *)m_rom->base();
- the table is stored at the start of the protection rom.
+ switch (mode)
+ {
+ case 0: case 1: case 2: case 3: case 4:
+ /*
+ modes 1-3 modify the data being transferred using a 0x100 byte table stored at the start of the protection rom.
- the param used with the mode gives a start offset into the table
+ The param used with the mode gives a start offset into the table.
- odd offsets cause an overflow
+ Odd offsets cause an overflow.
*/
-
- const u16 *PROTROM = (u16*)m_rom->base();
-
for (int x = 0; x < size; x++)
{
- u16 dat2 = PROTROM[src + x];
+ u16 dat = PROTROM[src + x];
+
+ const u8 extraoffset = param & 0xff;
+ const u8 * const dectable = (u8 *)m_rom->base(); // the basic decryption table is at the start of the mcu data rom!
+ const u8 taboff = ((x * 2) + extraoffset) & 0xff; // must allow for overflow in instances of odd offsets
- const u8 extraoffset = param & 0xff;
- const u8* dectable = (u8*)m_rom->base(); // the basic decryption table is at the start of the mcu data rom!
- const u8 taboff = ((x * 2) + extraoffset) & 0xff; // must allow for overflow in instances of odd offsets
- u16 extraxor = ((dectable[taboff + 1]) << 8) | (dectable[taboff + 0] << 0);
+ u16 extraxor = ((dectable[taboff + 1]) << 8) | (dectable[taboff + 0] << 0);
- if (mode == 4)
+ switch (mode)
{
+// case 0: plain copy
+ case 1: dat -= extraxor; break;
+ case 2: dat += extraxor; break;
+ case 3: dat ^= extraxor; break;
+ case 4:
extraxor = 0;
+
if ((x & 0x003) == 0x000) extraxor |= 0x0049; // 'I'
if ((x & 0x003) == 0x001) extraxor |= 0x0047; // 'G'
if ((x & 0x003) == 0x002) extraxor |= 0x0053; // 'S'
@@ -101,166 +136,273 @@ void igs022_device::IGS022_do_dma(u16 src, u16 dst, u16 size, u16 mode)
if ((x & 0x300) == 0x100) extraxor |= 0x4700; // 'G'
if ((x & 0x300) == 0x200) extraxor |= 0x5300; // 'S'
if ((x & 0x300) == 0x300) extraxor |= 0x2000; // ' '
- }
-
- // mode == 0 plain
- if (mode == 3) dat2 ^= extraxor;
- if (mode == 2) dat2 += extraxor;
- if (mode == 1) dat2 -= extraxor;
- if (mode == 4)
- {
- //printf("%06x | %04x (%04x)\n", (dst+x)*2, dat2, (u16)(dat2-extraxor));
+ LOGMASKED(LOG_DMA, "%s: IGS022 DMA mode 4 -> %06x | %04x (%04x)\n", machine().describe_context(), (dst + x) * 2, dat, (u16)(dat - extraxor));
- dat2 -= extraxor;
+ dat -= extraxor;
+ break;
}
- m_sharedprotram[dst + x] = dat2;
+ m_sharedprotram[dst + x] = dat;
}
- }
- else if (mode == 5)
- {
- /* mode 5 seems to be a byteswapped copy */
- const u16 *PROTROM = (u16*)m_rom->base();
+ break;
+
+ case 5: // byteswapped copy
for (int x = 0; x < size; x++)
{
u16 dat = PROTROM[src + x];
+
dat = ((dat &0x00ff) << 8) | ((dat &0xff00) >> 8);
m_sharedprotram[dst + x] = dat;
}
- }
- else if (mode == 6)
- {
- /* mode 6 seems to be a nibble swapped copy */
- const u16 *PROTROM = (u16*)m_rom->base();
+ break;
+
+ case 6: // nibble swapped copy
for (int x = 0; x < size; x++)
{
u16 dat = PROTROM[src + x];
- dat = ((dat & 0xf0f0) >> 4)|
- ((dat & 0x0f0f) << 4);
+ dat = ((dat & 0xf0f0) >> 4) | ((dat & 0x0f0f) << 4);
m_sharedprotram[dst + x] = dat;
}
+ break;
+
+ case 7:
+ logerror("%s: IGS022 DMA unhandled copy mode %04x!\n", machine().describe_context(), mode);
+ // not used by killbld
+ // weird mode, the params get left in memory? - maybe it's a NOP?
+ break;
+
+ default:
+ logerror("%s: IGS022 DMA unhandled copy mode!: %d, src: %04x, dst: %04x, size: %04x, param: %02x\n", machine().describe_context(), mode, src, dst, size, param);
+ // not used by killbld
+ // invalid?
+ }
+}
+
+void igs022_device::push_stack(u32 data)
+{
+ if (m_stack_ptr < STACK_SIZE - 1)
+ ++m_stack_ptr;
+
+ m_stack[m_stack_ptr] = data;
+}
+
+u32 igs022_device::pop_stack()
+{
+ const u32 data = m_stack[m_stack_ptr];
+
+ if (m_stack_ptr > 0)
+ --m_stack_ptr;
+
+ return data;
+}
+
+std::string igs022_device::stack_as_string() const
+{
+ std::ostringstream stream;
+ stream << "stack:";
+
+ for (int i = 0; i <= m_stack_ptr; ++i)
+ util::stream_format(stream, " %08x", m_stack[i]);
+
+ return std::move(stream).str();
+}
+
+u32 igs022_device::read_reg(u16 offset)
+{
+ if (offset < NUM_REGS)
+ {
+ return m_regs[offset];
}
- else if (mode == 7)
+ else if (offset == 0x400)
{
- printf("unhandled copy mode %04x!\n", mode);
- // not used by killing blade
- /* weird mode, the params get left in memory? - maybe it's a NOP? */
+ return pop_stack();
}
else
{
- osd_printf_debug("unhandled copy mode %04x!\n", mode);
- printf ("DMA MODE: %d, src: %4.4x, dst: %4.4x, size: %4.4x, param: %2.2x\n", mode, src, dst, size, param);
- // not used by killing blade
- /* invalid? */
+ return 0; // Invalid!
}
}
-// the internal MCU boot code automatically does this DMA
-// and puts the version # of the data rom in ram
-void igs022_device::IGS022_reset()
+void igs022_device::write_reg(u16 offset, u32 data)
{
- const u16 *PROTROM = (u16*)m_rom->base();
+ if (offset < NUM_REGS)
+ {
+ m_regs[offset] = data;
+ }
+ else if (offset == 0x300)
+ {
+ push_stack(data);
+ }
+ else
+ {
+ // Invalid!
+ }
+}
- // fill ram with A5 patern
- for (int i = 0; i < 0x4000/2; i++)
- m_sharedprotram[i] = 0xa55a;
+// What does this do? write the completion byte for now...
+void igs022_device::handle_incomplete_command(u16 cmd, u16 res)
+{
+ logerror("%s: IGS022 command %04x: INCOMPLETE (NOP)\n", machine().describe_context(), cmd);
+ m_sharedprotram[0x202 / 2] = res;
+}
- // the auto-dma
- u16 src = PROTROM[0x100 / 2];
- const u32 dst = PROTROM[0x102 / 2];
- const u16 size = PROTROM[0x104 / 2];
- u16 mode = PROTROM[0x106 / 2];
+void igs022_device::handle_command()
+{
+ const u16 cmd = m_sharedprotram[0x200 / 2];
- mode &= 0xff;
+ switch (cmd)
+ {
+ case 0x12: // Push
+ {
+ const u32 data = (m_sharedprotram[0x288 / 2] << 16) + m_sharedprotram[0x28a / 2];
- src >>= 1;
+ push_stack(data);
- IGS022_do_dma(src,dst,size,mode);
+ LOGMASKED(LOG_STACK, "%s: IGS022 command %04x: PUSH {288, 28a} (%08x) %s\n", machine().describe_context(), cmd, data, stack_as_string());
- // there is also a version ID? (or is it some kind of checksum) that is stored in the data rom, and gets copied..
- // Dragon World 3 checks it
- // Setting $3002a0 to #3 causes Dragon World 3 to skip this check
- m_sharedprotram[0x2a2/2] = PROTROM[0x114/2];
-}
+ m_sharedprotram[0x202 / 2] = 0x23; // this mode complete?
+ break;
+ }
-void igs022_device::IGS022_handle_command()
-{
- //printf("igs022_device::IGS022_handle_command\n");
+ case 0x2d: handle_incomplete_command(cmd, 0x3c); break; // killbld
- const u16 cmd = m_sharedprotram[0x200/2];
+// case 0x42: break; // killbld
- if (cmd == 0x6d) // Store values to asic ram
- {
- const u32 p1 = (m_sharedprotram[0x298/2] << 16) | m_sharedprotram[0x29a/2];
- const u32 p2 = (m_sharedprotram[0x29c/2] << 16) | m_sharedprotram[0x29e/2];
+ case 0x45: // Pop
+ {
+ const u32 data = pop_stack();
+
+ m_sharedprotram[0x28c / 2] = (data >> 16) & 0xffff;
+ m_sharedprotram[0x28e / 2] = data & 0xffff;
+
+ LOGMASKED(LOG_STACK, "%s: IGS022 command %04x: POP {28c, 28e} (%08x) %s\n", machine().describe_context(), cmd, data, stack_as_string());
+
+ m_sharedprotram[0x202 / 2] = 0x56; // this mode complete?
+ break;
+ }
- if ((p2 & 0xffff) == 0x9) // Set value
+// case 0x47: // NOP? slqz2/lhzb2
+// break;
+
+ case 0x4f: // DMA from protection ROM (memcpy with encryption / scrambling)
{
- const int reg = (p2 >> 16) & 0xffff;
+ LOGMASKED(LOG_DMA, "%s: IGS022 command %04x: DMA\n", machine().describe_context(), cmd);
- if (reg & 0x300) { // 300?? killbld expects 0x200, drgw3 expects 0x100?
- m_kb_regs[reg & 0xff] = p1;
- }
+ const u16 src = m_sharedprotram[0x290 / 2] >> 1; // External mcu data is 8 bit and addressed as such
+ const u32 dst = m_sharedprotram[0x292 / 2];
+ const u16 size = m_sharedprotram[0x294 / 2];
+ const u16 mode = m_sharedprotram[0x296 / 2];
+
+ do_dma(src, dst, size, mode);
+
+ m_sharedprotram[0x202 / 2] = 0x5e; // this mode complete?
+ break;
}
- if ((p2 & 0xffff) == 0x6) // Add value
+ case 0x5a: handle_incomplete_command(cmd, 0x4b); break; // killbld, uses {284} as input
+
+ case 0x6d: // Set/Get values to/from ASIC RAM, arithmetic operations on them
+ handle_command_6d();
+ break;
+
+ default:
+ logerror("%s: IGS022 command %04x: UNKNOWN!\n", machine().describe_context(), cmd);
+ }
+}
+
+// Set/Get values to/from ASIC RAM, arithmetic operations on them
+void igs022_device::handle_command_6d()
+{
+ const u32 p1 = (m_sharedprotram[0x298 / 2] << 16) | m_sharedprotram[0x29a / 2];
+ const u32 p2 = (m_sharedprotram[0x29c / 2] << 16) | m_sharedprotram[0x29e / 2];
+
+ std::ostringstream stream;
+ util::stream_format(stream, "%s: IGS022 command 006d: ASIC RAM %04x %04x %04x %04x ~ ", machine().describe_context(),
+ (p1 >> 16) & 0xffff, (p1 >> 0) & 0xffff, (p2 >> 16) & 0xffff, (p2 >> 0) & 0xffff
+ );
+
+ switch (p2 & 0xffff)
+ {
+ case 0x0: // Add values
{
- const int src1 = (p1 >> 16) & 0xff;
- const int src2 = (p1 >> 0) & 0xff;
- const int dst = (p2 >> 16) & 0xff;
+ const u16 src1 = p1 >> 16;
+ const u16 src2 = p1 >> 0;
+ const u16 dst = p2 >> 16;
+
+ const u32 data1 = read_reg(src1);
+ const u32 data2 = read_reg(src2);
+ const u32 res = data1 + data2;
+
+ write_reg(dst, res);
- m_kb_regs[dst] = m_kb_regs[src2] - m_kb_regs[src1];
+ util::stream_format(stream, "ADD [%04x] = [%04x] + [%04x] (%08x)\n", dst, src1, src2, res);
+ break;
}
- if ((p2 & 0xffff) == 0x1) // Add Imm?
+ case 0x1: // Sub values (src1 - src2)
{
- const int reg = (p2 >> 16) & 0xff;
- const int imm = (p1 >> 0) & 0xffff;
+ const u16 src1 = p1 >> 16;
+ const u16 src2 = p1 >> 0;
+ const u16 dst = p2 >> 16;
- m_kb_regs[reg] += imm;
+ const u32 data1 = read_reg(src1);
+ const u32 data2 = read_reg(src2);
+ const u32 res = data1 - data2;
+
+ write_reg(dst, res);
+
+ util::stream_format(stream, "SUB1 [%04x] = [%04x] - [%04x] (%08x)\n", dst, src1, src2, res);
+ break;
}
- if ((p2 & 0xffff) == 0xa) // Get value
+ case 0x6: // Sub values (src2 - src1)
{
- const int reg = (p1 >> 16) & 0xFF;
+ const u16 src1 = p1 >> 16;
+ const u16 src2 = p1 >> 0;
+ const u16 dst = p2 >> 16;
+
+ const u32 data1 = read_reg(src1);
+ const u32 data2 = read_reg(src2);
+ const u32 res = data2 - data1;
+
+ write_reg(dst, res);
- m_sharedprotram[0x29c/2] = (m_kb_regs[reg] >> 16) & 0xffff;
- m_sharedprotram[0x29e/2] = m_kb_regs[reg] & 0xffff;
+ util::stream_format(stream, "SUB2 [%04x] = [%04x] - [%04x] (%08x)\n", dst, src2, src1, res);
+ break;
}
- m_sharedprotram[0x202 / 2] = 0x7c; // this mode complete?
- }
+ case 0x9: // Set value (Shared Protection RAM -> ASIC RAM)
+ {
+ const u16 dst = p2 >> 16;
- // Is this actually what this is suppose to do? Complete guess.
- if (cmd == 0x12) // copy??
- {
- m_sharedprotram[0x28c / 2] = m_sharedprotram[0x288 / 2];
- m_sharedprotram[0x28e / 2] = m_sharedprotram[0x28a / 2];
+ const u32 data = p1;
- m_sharedprotram[0x202 / 2] = 0x23; // this mode complete?
- }
+ write_reg(dst, data);
- // what do these do? write the completion byte for now...
- if (cmd == 0x45) m_sharedprotram[0x202 / 2] = 0x56;
- if (cmd == 0x5a) m_sharedprotram[0x202 / 2] = 0x4b;
- if (cmd == 0x2d) m_sharedprotram[0x202 / 2] = 0x3c;
+ util::stream_format(stream, "SET [%04x] = {298, 29a} (%08x)\n", dst, data);
+ break;
+ }
- if (cmd == 0x4f) // memcpy with encryption / scrambling
- {
- const u16 src = m_sharedprotram[0x290 / 2] >> 1; // External mcu data is 8 bit and addressed as such
- const u32 dst = m_sharedprotram[0x292 / 2];
- const u16 size = m_sharedprotram[0x294 / 2];
- const u16 mode = m_sharedprotram[0x296 / 2];
+ case 0xa: // Get value (ASIC RAM -> Shared Protection RAM)
+ {
+ const u16 src = p1 >> 16;
+
+ const u32 data = m_regs[src];
- IGS022_do_dma(src,dst,size,mode);
+ m_sharedprotram[0x29c / 2] = (data >> 16) & 0xffff;
+ m_sharedprotram[0x29e / 2] = data & 0xffff;
- m_sharedprotram[0x202 / 2] = 0x5e; // this mode complete?
+ util::stream_format(stream, "GET {29c, 29e} = [%04x] (%08x)\n", src, data);
+ break;
+ }
}
-}
+ LOGMASKED(LOG_CMD_6D, "%s", stream.str());
+ m_sharedprotram[0x202 / 2] = 0x7c; // this mode complete?
+}
-DEFINE_DEVICE_TYPE(IGS022, igs022_device, "igs022", "IGS022")
+DEFINE_DEVICE_TYPE(IGS022, igs022_device, "igs022", "IGS022 encrypted DMA device")