summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/z80/mc8123.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/z80/mc8123.cpp')
-rw-r--r--src/devices/cpu/z80/mc8123.cpp416
1 files changed, 416 insertions, 0 deletions
diff --git a/src/devices/cpu/z80/mc8123.cpp b/src/devices/cpu/z80/mc8123.cpp
new file mode 100644
index 00000000000..33acc77b096
--- /dev/null
+++ b/src/devices/cpu/z80/mc8123.cpp
@@ -0,0 +1,416 @@
+// license:BSD-3-Clause
+// copyright-holders:Nicola Salmoria, David Widel
+/***************************************************************************
+
+NEC MC-8123 encryption emulation
+
+Decryption tables provided by David Widel
+Decryption algorithm by Nicola Salmoria
+
+The NEC MC-8123 is a Z80 with built-in encryption.
+It contains 0x2000 bytes of battery-backed RAM, when the battery dies the
+game stops working. It's possible that the CPU would work as a normal Z80
+in that case, this hasn't been verified.
+
+When the CPU reads a byte from memory, it uses 12 bits of the address and
+the information of whether the byte is an opcode or not to select a byte in
+the internal RAM. The byte controls how the decryption works.
+
+A special value in the internal RAM instructs the CPU to not apply the decryption
+algorithm at all. This is necessary for the CPU to be able to use RAM areas
+normally.
+
+In theory, the size of the key would make the encryption quite secure.
+
+In practice, the contents of the internal RAM were generated using a linear
+congruential generator, so the whole key can be generated starting from a single
+24-bit seed.
+
+The LCG is the same that was used to generate the FD1094 keys.
+Note that the algorithm skips the special value that would instruct the CPU to
+not decrypt at that address.
+
+void generate_key(uint8_t (&key)[0x2000], uint32_t seed, unsigned upper_bound)
+{
+ unsigned i;
+
+ for (i = 0; i < upper_bound; ++i)
+ {
+ uint8_t byteval;
+
+ do
+ {
+ seed *= 0x29;
+ seed += seed << 16;
+
+ byteval = (~seed >> 16) & 0xff;
+ }
+ while (byteval == 0xff);
+
+ key[i] = byteval;
+ }
+
+ for ( ; i < 0x2000; ++i)
+ key[i] = 0xff;
+}
+
+
+The known games that use this CPU are:
+
+CPU # Game Notes Seed Upper Limit
+-------- ------------------------- ------------------ ------ -----
+317-0029 Block Gal NEC MC-8123B 651 091755 1800?
+317-0030 Perfect Billiard 9451EC 1C00
+317-0040 Toki no Senshi - Chrono Soldier 068713 1c00
+317-0042 Opa Opa B31FD0 1C00
+317-0043 Wonder Boy Monster Land 640708 1C00
+317-0054 Shinobi (sound CPU) NEC MC-8123B 652 088992 1800
+317-0057 Fantasy Zone 2 ADFACE 1800
+317-0064 Ufo Senshi Yohko Chan 880603 1C00
+317-0066 Altered Beast (sound CPU) NEC MC-8123B 704 ED8600 1800
+317-5002 Gigas 1 & 2 NEC MC-8123 638 234567 1C00
+317-5004 Eagle Writer Not Dumped
+317-5005 Astro Flash Not Dumped
+317-5008 Perfect Billiard 9451EC 1C00
+317-5012 Ganbare Chinsan Ooshoubu NEC MC-8123A 804B54 1C00
+317-5014 DakkoChan Jansoh NEC MC-8123B 206850 1C00
+317-5??? Ninja Kid II (sound CPU) NEC MC-8123A 646 27998D 1800
+317-???? Center Court (sound CPU) NEC MC-8123B 703 640506 1800
+317-???? Omega 861226 1C00?
+
+***************************************************************************/
+
+#include "emu.h"
+#include "mc8123.h"
+
+
+DEFINE_DEVICE_TYPE(MC8123, mc8123_device, "mc8123", "MC-8123")
+
+//-------------------------------------------------
+// mc8123_device - constructor
+//-------------------------------------------------
+
+mc8123_device::mc8123_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : z80_device(mconfig, MC8123, tag, owner, clock)
+ , m_key(*this, "key")
+{
+}
+
+
+namespace {
+
+template <typename T> constexpr u8 BITS(T b) { return u8(1) << b; }
+template <typename T, typename... U> constexpr u8 BITS(T b, U... c) { return (u8(1) << b) | BITS(c...); }
+
+} // anonymous namespace
+
+u8 mc8123_device::decrypt_type0(u8 val, u8 param, unsigned swap)
+{
+ if (swap == 0) val = bitswap<8>(val,7,5,3,1,2,0,6,4);
+ if (swap == 1) val = bitswap<8>(val,5,3,7,2,1,0,4,6);
+ if (swap == 2) val = bitswap<8>(val,0,3,4,6,7,1,5,2);
+ if (swap == 3) val = bitswap<8>(val,0,7,3,2,6,4,1,5);
+
+ if (BIT(param,3) && BIT(val,7))
+ val ^= BITS(5,3,0);
+
+ if (BIT(param,2) && BIT(val,6))
+ val ^= BITS(7,2,1);
+
+ if (BIT(val,6)) val ^= BITS(7);
+
+ if (BIT(param,1) && BIT(val,7))
+ val ^= BITS(6);
+
+ if (BIT(val,2)) val ^= BITS(5,0);
+
+ val ^= BITS(4,3,1);
+
+ if (BIT(param,2)) val ^= BITS(5,2,0);
+ if (BIT(param,1)) val ^= BITS(7,6);
+ if (BIT(param,0)) val ^= BITS(5,0);
+
+ if (BIT(param,0)) val = bitswap<8>(val,7,6,5,1,4,3,2,0);
+
+ return val;
+}
+
+
+u8 mc8123_device::decrypt_type1a(u8 val, u8 param, unsigned swap)
+{
+ if (swap == 0) val = bitswap<8>(val,4,2,6,5,3,7,1,0);
+ if (swap == 1) val = bitswap<8>(val,6,0,5,4,3,2,1,7);
+ if (swap == 2) val = bitswap<8>(val,2,3,6,1,4,0,7,5);
+ if (swap == 3) val = bitswap<8>(val,6,5,1,3,2,7,0,4);
+
+ if (BIT(param,2)) val = bitswap<8>(val,7,6,1,5,3,2,4,0);
+
+ if (BIT(val,1)) val ^= BITS(0);
+ if (BIT(val,6)) val ^= BITS(3);
+ if (BIT(val,7)) val ^= BITS(6,3);
+ if (BIT(val,2)) val ^= BITS(6,3,1);
+ if (BIT(val,4)) val ^= BITS(7,6,2);
+
+ if (BIT(val,7) ^ BIT(val,2))
+ val ^= BITS(4);
+
+ val ^= BITS(6,3,1,0);
+
+ if (BIT(param,3)) val ^= BITS(7,2);
+ if (BIT(param,1)) val ^= BITS(6,3);
+
+ if (BIT(param,0)) val = bitswap<8>(val,7,6,1,4,3,2,5,0);
+
+ return val;
+}
+
+u8 mc8123_device::decrypt_type1b(u8 val, u8 param, unsigned swap)
+{
+ if (swap == 0) val = bitswap<8>(val,1,0,3,2,5,6,4,7);
+ if (swap == 1) val = bitswap<8>(val,2,0,5,1,7,4,6,3);
+ if (swap == 2) val = bitswap<8>(val,6,4,7,2,0,5,1,3);
+ if (swap == 3) val = bitswap<8>(val,7,1,3,6,0,2,5,4);
+
+ if (BIT(val,2) && BIT(val,0))
+ val ^= BITS(7,4);
+
+ if (BIT(val,7)) val ^= BITS(2);
+ if (BIT(val,5)) val ^= BITS(7,2);
+ if (BIT(val,1)) val ^= BITS(5);
+ if (BIT(val,6)) val ^= BITS(1);
+ if (BIT(val,4)) val ^= BITS(6,5);
+ if (BIT(val,0)) val ^= BITS(6,2,1);
+ if (BIT(val,3)) val ^= BITS(7,6,2,1,0);
+
+ val ^= BITS(6,4,0);
+
+ if (BIT(param,3)) val ^= BITS(4,1);
+ if (BIT(param,2)) val ^= BITS(7,6,3,0);
+ if (BIT(param,1)) val ^= BITS(4,3);
+ if (BIT(param,0)) val ^= BITS(6,2,1,0);
+
+ return val;
+}
+
+u8 mc8123_device::decrypt_type2a(u8 val, u8 param, unsigned swap)
+{
+ if (swap == 0) val = bitswap<8>(val,0,1,4,3,5,6,2,7);
+ if (swap == 1) val = bitswap<8>(val,6,3,0,5,7,4,1,2);
+ if (swap == 2) val = bitswap<8>(val,1,6,4,5,0,3,7,2);
+ if (swap == 3) val = bitswap<8>(val,4,6,7,5,2,3,1,0);
+
+ if (BIT(val,3) || (BIT(param,1) && BIT(val,2)))
+ val = bitswap<8>(val,6,0,7,4,3,2,1,5);
+
+ if (BIT(val,5)) val ^= BITS(7);
+ if (BIT(val,6)) val ^= BITS(5);
+ if (BIT(val,0)) val ^= BITS(6);
+ if (BIT(val,4)) val ^= BITS(3,0);
+ if (BIT(val,1)) val ^= BITS(2);
+
+ val ^= BITS(7,6,5,4,1);
+
+ if (BIT(param,2)) val ^= BITS(4,3,2,1,0);
+
+ if (BIT(param,3))
+ {
+ if (BIT(param,0))
+ val = bitswap<8>(val,7,6,5,3,4,1,2,0);
+ else
+ val = bitswap<8>(val,7,6,5,1,2,4,3,0);
+ }
+ else if (BIT(param,0))
+ {
+ val = bitswap<8>(val,7,6,5,2,1,3,4,0);
+ }
+
+ return val;
+}
+
+u8 mc8123_device::decrypt_type2b(u8 val, u8 param, unsigned swap)
+{
+ // only 0x20 possible encryptions for this method - all others have 0x40
+ // this happens because BIT(param,2) cancels the other three
+
+ if (swap == 0) val = bitswap<8>(val,1,3,4,6,5,7,0,2);
+ if (swap == 1) val = bitswap<8>(val,0,1,5,4,7,3,2,6);
+ if (swap == 2) val = bitswap<8>(val,3,5,4,1,6,2,0,7);
+ if (swap == 3) val = bitswap<8>(val,5,2,3,0,4,7,6,1);
+
+ if (BIT(val,7) && BIT(val,3))
+ val ^= BITS(6,4,0);
+
+ if (BIT(val,7)) val ^= BITS(2);
+ if (BIT(val,5)) val ^= BITS(7,3);
+ if (BIT(val,1)) val ^= BITS(5);
+ if (BIT(val,4)) val ^= BITS(7,5,3,1);
+
+ if (BIT(val,7) && BIT(val,5))
+ val ^= BITS(4,0);
+
+ if (BIT(val,5) && BIT(val,1))
+ val ^= BITS(4,0);
+
+ if (BIT(val,6)) val ^= BITS(7,5);
+ if (BIT(val,3)) val ^= BITS(7,6,5,1);
+ if (BIT(val,2)) val ^= BITS(3,1);
+
+ val ^= BITS(7,3,2,1);
+
+ if (BIT(param,3)) val ^= BITS(6,3,1);
+ if (BIT(param,2)) val ^= BITS(7,6,5,3,2,1); // same as the other three combined
+ if (BIT(param,1)) val ^= BITS(7);
+ if (BIT(param,0)) val ^= BITS(5,2);
+
+ return val;
+}
+
+u8 mc8123_device::decrypt_type3a(u8 val, u8 param, unsigned swap)
+{
+ if (swap == 0) val = bitswap<8>(val,5,3,1,7,0,2,6,4);
+ if (swap == 1) val = bitswap<8>(val,3,1,2,5,4,7,0,6);
+ if (swap == 2) val = bitswap<8>(val,5,6,1,2,7,0,4,3);
+ if (swap == 3) val = bitswap<8>(val,5,6,7,0,4,2,1,3);
+
+ if (BIT(val,2)) val ^= BITS(7,5,4);
+ if (BIT(val,3)) val ^= BITS(0);
+
+ if (BIT(param,0)) val = bitswap<8>(val,7,2,5,4,3,1,0,6);
+
+ if (BIT(val,1)) val ^= BITS(6,0);
+ if (BIT(val,3)) val ^= BITS(4,2,1);
+
+ if (BIT(param,3)) val ^= BITS(4,3);
+
+ if (BIT(val,3)) val = bitswap<8>(val,5,6,7,4,3,2,1,0);
+
+ if (BIT(val,5)) val ^= BITS(2,1);
+
+ val ^= BITS(6,5,4,3);
+
+ if (BIT(param,2)) val ^= BITS(7);
+ if (BIT(param,1)) val ^= BITS(4);
+ if (BIT(param,0)) val ^= BITS(0);
+
+ return val;
+}
+
+u8 mc8123_device::decrypt_type3b(u8 val, u8 param, unsigned swap)
+{
+ if (swap == 0) val = bitswap<8>(val,3,7,5,4,0,6,2,1);
+ if (swap == 1) val = bitswap<8>(val,7,5,4,6,1,2,0,3);
+ if (swap == 2) val = bitswap<8>(val,7,4,3,0,5,1,6,2);
+ if (swap == 3) val = bitswap<8>(val,2,6,4,1,3,7,0,5);
+
+ if (BIT(val,2)) val ^= BITS(7);
+
+ if (BIT(val,7)) val = bitswap<8>(val,7,6,3,4,5,2,1,0);
+
+ if (BIT(param,3)) val ^= BITS(7);
+
+ if (BIT(val,4)) val ^= BITS(6);
+ if (BIT(val,1)) val ^= BITS(6,4,2);
+
+ if (BIT(val,7) && BIT(val,6))
+ val ^= BITS(1);
+
+ if (BIT(val,7)) val ^= BITS(1);
+
+ if (BIT(param,3)) val ^= BITS(7);
+ if (BIT(param,2)) val ^= BITS(0);
+
+ if (BIT(param,3)) val = bitswap<8>(val,4,6,3,2,5,0,1,7);
+
+ if (BIT(val,4)) val ^= BITS(1);
+ if (BIT(val,5)) val ^= BITS(4);
+ if (BIT(val,7)) val ^= BITS(2);
+
+ val ^= BITS(5,3,2);
+
+ if (BIT(param,1)) val ^= BITS(7);
+ if (BIT(param,0)) val ^= BITS(3);
+
+ return val;
+}
+
+u8 mc8123_device::decrypt_internal(u8 val, u8 key, bool opcode)
+{
+ unsigned type = 0;
+ unsigned swap = 0;
+ u8 param = 0;
+
+ key ^= 0xff;
+
+ // no encryption
+ if (key == 0x00)
+ return val;
+
+ type ^= BIT(key,0) << 0;
+ type ^= BIT(key,2) << 0;
+ type ^= BIT(key,0) << 1;
+ type ^= BIT(key,1) << 1;
+ type ^= BIT(key,2) << 1;
+ type ^= BIT(key,4) << 1;
+ type ^= BIT(key,4) << 2;
+ type ^= BIT(key,5) << 2;
+
+ swap ^= BIT(key,0) << 0;
+ swap ^= BIT(key,1) << 0;
+ swap ^= BIT(key,2) << 1;
+ swap ^= BIT(key,3) << 1;
+
+ param ^= BIT(key,0) << 0;
+ param ^= BIT(key,0) << 1;
+ param ^= BIT(key,2) << 1;
+ param ^= BIT(key,3) << 1;
+ param ^= BIT(key,0) << 2;
+ param ^= BIT(key,1) << 2;
+ param ^= BIT(key,6) << 2;
+ param ^= BIT(key,1) << 3;
+ param ^= BIT(key,6) << 3;
+ param ^= BIT(key,7) << 3;
+
+ if (!opcode)
+ {
+ param ^= BITS(0);
+ type ^= BITS(0);
+ }
+
+ switch (type)
+ {
+ default:
+ case 0: return decrypt_type0(val, param, swap);
+ case 1: return decrypt_type0(val, param, swap);
+ case 2: return decrypt_type1a(val, param, swap);
+ case 3: return decrypt_type1b(val, param, swap);
+ case 4: return decrypt_type2a(val, param, swap);
+ case 5: return decrypt_type2b(val, param, swap);
+ case 6: return decrypt_type3a(val, param, swap);
+ case 7: return decrypt_type3b(val, param, swap);
+ }
+}
+
+
+u8 mc8123_device::decrypt(offs_t addr, u8 val, bool opcode)
+{
+ // pick the translation table from bits fd57 of the address
+ offs_t const tbl_num = bitswap<12>(addr,15,14,13,12,11,10,8,6,4,2,1,0);
+
+ return decrypt_internal(val, m_key[tbl_num | (opcode ? 0x0000 : 0x1000)], opcode);
+}
+
+
+void mc8123_device::decode(u8 *rom, u8 *opcodes, unsigned length)
+{
+ for (unsigned i = 0; i < length; i++)
+ {
+ unsigned const adr = (i >= 0xc000) ? ((i & 0x3fff) | 0x8000) : i;
+ u8 const src = rom[i];
+
+ // decode the opcodes
+ opcodes[i] = decrypt(adr, src, true);
+
+ // decode the data
+ rom[i] = decrypt(adr, src, false);
+ }
+}