summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/fd1089.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/fd1089.cpp')
-rw-r--r--src/mame/machine/fd1089.cpp488
1 files changed, 0 insertions, 488 deletions
diff --git a/src/mame/machine/fd1089.cpp b/src/mame/machine/fd1089.cpp
deleted file mode 100644
index cf42dc7f0bf..00000000000
--- a/src/mame/machine/fd1089.cpp
+++ /dev/null
@@ -1,488 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Nicola Salmoria, Andreas Naive, Charles MacDonald
-/***************************************************************************
-
- Hitachi FD1089A/FD1089B encryption emulation
-
-****************************************************************************
-
- Copyright Nicola Salmoria, Andreas Naive, and Charles MacDonald.
-
- All rights reserved.
-
-****************************************************************************
-
- Decryption tables provided by Charles MacDonald
- Decryption algorithm by Nicola Salmoria
- LCG algorithm by Andreas Naive
-
- The FD1089 is a 68000 with built-in encryption.
- It contains some battery-backed RAM, when the battery dies the CPU stops
- working.
-
- Both opcodes and data are encrypted, using different (but related) mappings.
- Decryption works on 16-bit words, but only 8 bits are affected, the other 8 are
- left untouched. A special value in internal RAM disables the encryption, this
- is necessary otherwise RAM would not work as expected (writing data and reading
- it back would return a different number).
-
- The FD1089A and FD1089B work in the same way, but the decryption tables are
- different. The internal RAM contains the 8-bit key to use at every address
- (only 12 bits of the address are used, so the encryption repeats).
-
- The FD1089 design is clearly derived from the MC8123. The MC8123 is a Z80 so it
- made sense to encrypt all 8 data bits and use 12 of the 16 address bits. It makes
- a lot less sense to encrypt only half of the 16 data bits; using 12 of the 24
- address bits might be ok, but not in the way it was done. The choice of address
- bits to use was probably dictated by the need to not encrypt data in certain areas
- of the address space, so they had to include the top 8 bits of the address.
- However this means that if you pick e.g. area 000000-00FFFF, where most of the
- program code resides, just 4 address bits affect the encryption, making it very
- weak when compared to the MC8123. Out of the 16KB of internal RAM, you need less
- than 128 bytes to decrypt a whole game - the rest is not used. A waste of space
- and security. Also, since only 8 of the 16 bits are encrypted, it is very easy
- to use the unencrypted ones to search for known sequences of code or data.
-
- Like for the MC8123, 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. Note however that the "don't decrypt" data sections need
- special treatment so it's not possible to derive the precise key without access
- to the CPU.
-
- static int rndseed;
-
- int rnd()
- {
- rndseed = rndseed * 0x290029;
- return (rndseed >> 16) & 0xff;
- }
-
- void generate_key(int seed)
- {
- int i;
-
- rndseed = seed;
- for (i = 0; i < 0x1000; ++i)
- {
- if ("we must encrypt this data table position")
- {
- uint8_t byteval;
-
- do
- {
- byteval = rnd();
- } while (byteval == 0x00);
-
- opcode_key[i] = byteval;
-
- do
- {
- byteval = rnd();
- } while (byteval == 0x00);
-
- data_key[i] = byteval;
- }
- }
-
- for (i = 0; i < 0x1000; ++i)
- {
- if ("we mustn't encrypt this data table position")
- {
- uint8_t byteval;
-
- do
- {
- byteval = rnd();
- } while (byteval == 0x00);
-
- opcode_key[i] = byteval;
- data_key[i] = 0x00;
- }
- }
- }
-
-
- Note that when both FD1089A and FD1089B versions of a game exist, they use the
- same key.
-
- Known games that use this CPU:
-
- CPU # Type Status Game Seed Unencrypted data range
- --------- ------- --- -------------------- -- -----------------------------------
- 317-0013A FD1089B [1] Enduro Racer 01 030000-04ffff + 100000-1fffff
- 317-0016 FD1089B [2] Fantasy Zone 05 ?
- 317-0018 FD1089A [1] Action Fighter 03 400000-4fffff + 840000-8dffff + c00000-c4ffff + ff0000-ffffff
- 317-0019 FD1089A [1] Outrun 07 000000-03ffff
- 317-0021 FD1089A [2] Alex Kidd 0b ?
- 317-0022 FD1089A [1] Dunk Shot 0d 030000-ffffff
- 317-0024 FD1089B [1] Time Scanner 0f 000000-02ffff
- 317-0027 FD1089B [1] SDI 11 000000-03ffff
- 317-0028 FD1089A [2] Defense 11 ?
- 317-0033 FD1089A [1] Alien Syndrome 13 030000-ffffff
- 317-0037 FD1089B [2] Alien Syndrome 13 030000-ffffff
- 317-0034 FD1089B [1] Super Hang-On 15 030000-06ffff + 100000-2fffff + ff0000-ffffff
- 317-0086 FD1089A [2] Wonder Boy III 43 ?
- 317-0167 FD1089A [2] Aurail 30 010000-ffffff
- 317-0168 FD1089B [1] Aurail 30 010000-ffffff
- 317-5021 FD1089B [1] Sukeban Jansi Ryuko 4b 000000-00ffff
-
-
- [1] Complete
- [2] Partial
-
-***************************************************************************/
-
-#include "emu.h"
-#include "fd1089.h"
-#include "segaic16.h"
-
-
-//**************************************************************************
-// CONSTANTS
-//**************************************************************************
-
-// device type definition
-DEFINE_DEVICE_TYPE(FD1089A, fd1089a_device, "fd1089a", "Hitachi FD1089A Encrypted CPU")
-DEFINE_DEVICE_TYPE(FD1089B, fd1089b_device, "fd1089b", "Hitachi FD1089B Encrypted CPU")
-
-// common base lookup table, shared between A and B variants
-const uint8_t fd1089_base_device::s_basetable_fd1089[0x100] =
-{
- 0x00,0x1c,0x76,0x6a,0x5e,0x42,0x24,0x38,0x4b,0x67,0xad,0x81,0xe9,0xc5,0x03,0x2f,
- 0x45,0x69,0xaf,0x83,0xe7,0xcb,0x01,0x2d,0x02,0x1e,0x78,0x64,0x5c,0x40,0x2a,0x36,
- 0x32,0x2e,0x44,0x58,0xe4,0xf8,0x9e,0x82,0x29,0x05,0xcf,0xe3,0x93,0xbf,0x79,0x55,
- 0x3f,0x13,0xd5,0xf9,0x85,0xa9,0x63,0x4f,0xb8,0xa4,0xc2,0xde,0x6e,0x72,0x18,0x04,
- 0x0c,0x10,0x7a,0x66,0xfc,0xe0,0x86,0x9a,0x47,0x6b,0xa1,0x8d,0xbb,0x97,0x51,0x7d,
- 0x17,0x3b,0xfd,0xd1,0xeb,0xc7,0x0d,0x21,0xa0,0xbc,0xda,0xc6,0x50,0x4c,0x26,0x3a,
- 0x3e,0x22,0x48,0x54,0x46,0x5a,0x3c,0x20,0x25,0x09,0xc3,0xef,0xc1,0xed,0x2b,0x07,
- 0x6d,0x41,0x87,0xab,0x89,0xa5,0x6f,0x43,0x1a,0x06,0x60,0x7c,0x62,0x7e,0x14,0x08,
- 0x0a,0x16,0x70,0x6c,0xdc,0xc0,0xaa,0xb6,0x4d,0x61,0xa7,0x8b,0xf7,0xdb,0x11,0x3d,
- 0x5b,0x77,0xbd,0x91,0xe1,0xcd,0x0b,0x27,0x80,0x9c,0xf6,0xea,0x56,0x4a,0x2c,0x30,
- 0xb0,0xac,0xca,0xd6,0xee,0xf2,0x98,0x84,0x37,0x1b,0xdd,0xf1,0x95,0xb9,0x73,0x5f,
- 0x39,0x15,0xdf,0xf3,0x9b,0xb7,0x71,0x5d,0xb2,0xae,0xc4,0xd8,0xec,0xf0,0x96,0x8a,
- 0xa8,0xb4,0xd2,0xce,0xd0,0xcc,0xa6,0xba,0x1f,0x33,0xf5,0xd9,0xfb,0xd7,0x1d,0x31,
- 0x57,0x7b,0xb1,0x9d,0xb3,0x9f,0x59,0x75,0x8c,0x90,0xfa,0xe6,0xf4,0xe8,0x8e,0x92,
- 0x12,0x0e,0x68,0x74,0xe2,0xfe,0x94,0x88,0x65,0x49,0x8f,0xa3,0x99,0xb5,0x7f,0x53,
- 0x35,0x19,0xd3,0xff,0xc9,0xe5,0x23,0x0f,0xbe,0xa2,0xc8,0xd4,0x4e,0x52,0x34,0x28,
-};
-
-// address decryption parameters, shared between A and B variants
-const fd1089_base_device::decrypt_parameters fd1089_base_device::s_addr_params[16] =
-{
- { 0x23, 6,4,5,7,3,0,1,2 },
- { 0x92, 2,5,3,6,7,1,0,4 },
- { 0xb8, 6,7,4,2,0,5,1,3 },
- { 0x74, 5,3,7,1,4,6,0,2 },
- { 0xcf, 7,4,1,0,6,2,3,5 },
- { 0xc4, 3,1,6,4,5,0,2,7 },
- { 0x51, 5,7,2,4,3,1,6,0 },
- { 0x14, 7,2,0,6,1,3,4,5 },
- { 0x7f, 3,5,6,0,2,1,7,4 },
- { 0x03, 2,3,4,0,6,7,5,1 },
- { 0x96, 3,1,7,5,2,4,6,0 },
- { 0x30, 7,6,2,3,0,4,5,1 },
- { 0xe2, 1,0,3,7,4,5,2,6 },
- { 0x72, 1,6,0,5,7,2,4,3 },
- { 0xf5, 0,4,1,2,6,5,7,3 },
- { 0x5b, 0,7,5,3,1,4,2,6 },
-};
-
-// data decryption parameters for the A variant
-const fd1089_base_device::decrypt_parameters fd1089_base_device::s_data_params_a[16] =
-{
- { 0x55, 6,5,1,0,7,4,2,3 },
- { 0x94, 7,6,4,2,0,5,1,3 },
- { 0x8d, 1,4,2,3,0,6,7,5 },
- { 0x9a, 4,3,5,6,0,2,1,7 },
- { 0x72, 4,3,7,0,5,6,1,2 },
- { 0xff, 1,7,2,3,6,4,5,0 },
- { 0x06, 6,5,3,2,4,1,0,7 },
- { 0xc5, 3,5,1,4,2,7,0,6 },
- { 0xec, 4,7,5,1,6,0,2,3 },
- { 0x89, 3,5,0,6,1,2,7,4 },
- { 0x5c, 1,3,0,7,5,2,4,6 },
- { 0x3f, 7,3,0,2,4,6,1,5 },
- { 0x57, 6,4,7,2,1,5,3,0 },
- { 0xf7, 6,3,7,0,5,4,2,1 },
- { 0x3a, 6,1,3,2,7,4,5,0 },
- { 0xac, 1,6,3,5,0,7,4,2 },
-};
-
-void fd1089_base_device::decrypted_opcodes_map(address_map &map)
-{
- map(0x00000, 0xfffff).rom().share(":fd1089_decrypted_opcodes");
-}
-
-
-//**************************************************************************
-// CORE IMPLEMENTATION
-//**************************************************************************
-
-//-------------------------------------------------
-// fd1089_base_device - constructor
-//-------------------------------------------------
-
-fd1089_base_device::fd1089_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : m68000_device(mconfig, type, tag, owner, clock),
- m_region(*this, DEVICE_SELF),
- m_key(*this, "key"),
- m_decrypted_opcodes(*this, ":fd1089_decrypted_opcodes")
-{
- // add the decrypted opcodes map
- set_addrmap(AS_OPCODES, address_map_constructor(FUNC(fd1089_base_device::decrypted_opcodes_map), this));
-}
-
-fd1089a_device::fd1089a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : fd1089_base_device(mconfig, FD1089A, tag, owner, clock)
-{
-}
-
-fd1089b_device::fd1089b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : fd1089_base_device(mconfig, FD1089B, tag, owner, clock)
-{
-}
-
-//-------------------------------------------------
-// device_start - one-time device initialization
-//-------------------------------------------------
-
-void fd1089_base_device::device_start()
-{
- // start the base device
- m68000_device::device_start();
-
- // get a pointer to the ROM region
- uint16_t *rombase = reinterpret_cast<uint16_t *>(m_region->base());
-
- // determine length and resize our internal buffers
- uint32_t romsize = m_region->bytes();
- m_plaintext.resize(romsize/2);
-
- // copy the plaintext
- memcpy(&m_plaintext[0], rombase, romsize);
-
- // decrypt it, overwriting original data with the decrypted data
- decrypt(0x000000, romsize, &m_plaintext[0], &m_decrypted_opcodes[0], rombase);
-}
-
-
-
-//**************************************************************************
-// INTERNAL HELPERS
-//**************************************************************************
-
-//-------------------------------------------------
-// rearrange_key - shuffle bits in the table
-// based on whether this is an opcode or a data
-// decode
-//-------------------------------------------------
-
-uint8_t fd1089_base_device::rearrange_key(uint8_t table, bool opcode)
-{
- if (!opcode)
- {
- table ^= (1<<4);
- table ^= (1<<5);
-
- if (BIT(~table,3))
- table ^= (1<<1);
-
- table = bitswap<8>(table,1,0,6,4,3,5,2,7);
-
- if (BIT(table,6))
- table = bitswap<8>(table,7,6,2,4,5,3,1,0);
- }
- else
- {
- table ^= (1<<2);
- table ^= (1<<3);
- table ^= (1<<4);
-
- if (BIT(~table,3))
- table ^= (1<<5);
-
- if (BIT(table,7))
- table ^= (1<<6);
-
- table = bitswap<8>(table,5,7,6,4,2,3,1,0);
-
- if (BIT(table,6))
- table = bitswap<8>(table,7,6,5,3,2,4,1,0);
- }
-
- if (BIT(table,6))
- {
- if (BIT(table,5))
- table ^= (1<<4);
- }
- else
- {
- if (BIT(~table,4))
- table ^= (1<<5);
- }
-
- return table;
-}
-
-
-//-------------------------------------------------
-// decode_fd1089a - decode an 8-bit value
-// according to FD1089A rules
-//-------------------------------------------------
-
-uint8_t fd1089a_device::decode(uint8_t val, uint8_t key, bool opcode)
-{
- // special case - don't decrypt
- if (key == 0x00)
- return val;
-
- uint8_t table = rearrange_key(key, opcode);
-
- const decrypt_parameters &p = s_addr_params[table >> 4];
- val = bitswap<8>(val, p.s7,p.s6,p.s5,p.s4,p.s3,p.s2,p.s1,p.s0) ^ p.xorval;
-
- if (BIT(table,3)) val ^= 0x01;
- if (BIT(table,0)) val ^= 0xb1;
- if (opcode) val ^= 0x34;
- if (opcode == 0)
- if (BIT(table,6))
- val ^= 0x01;
-
- val = s_basetable_fd1089[val];
-
- uint8_t family = table & 0x07;
- if (opcode == 0)
- {
- if (BIT(~table,6) & BIT(table,2)) family ^= 8;
- if (BIT(table,4)) family ^= 8;
- }
- else
- {
- if (BIT(table,6) & BIT(table,2)) family ^= 8;
- if (BIT(table,5)) family ^= 8;
- }
-
- if (BIT(table,0))
- {
- if (BIT(val,0)) val ^= 0xc0;
- if (BIT(~val,6) ^ BIT(val,4))
- val = bitswap<8>(val, 7,6,5,4,1,0,2,3);
- }
- else
- {
- if (BIT(~val,6) ^ BIT(val,4))
- val = bitswap<8>(val, 7,6,5,4,0,1,3,2);
- }
- if (BIT(~val,6))
- val = bitswap<8>(val, 7,6,5,4,2,3,0,1);
-
- const decrypt_parameters &q = s_data_params_a[family];
-
- val ^= q.xorval;
- val = bitswap<8>(val, q.s7,q.s6,q.s5,q.s4,q.s3,q.s2,q.s1,q.s0);
-
- return val;
-}
-
-
-//-------------------------------------------------
-// decode_fd1089b - decode an 8-bit value
-// according to FD1089B rules
-//-------------------------------------------------
-
-uint8_t fd1089b_device::decode(uint8_t val, uint8_t key, bool opcode)
-{
- // special case - don't decrypt
- if (key == 0x00)
- return val;
-
- uint8_t table = rearrange_key(key, opcode);
-
- const decrypt_parameters &p = s_addr_params[table >> 4];
- val = bitswap<8>(val, p.s7,p.s6,p.s5,p.s4,p.s3,p.s2,p.s1,p.s0) ^ p.xorval;
-
- if (BIT(table,3)) val ^= 0x01;
- if (BIT(table,0)) val ^= 0xb1;
- if (opcode) val ^= 0x34;
- if (opcode == 0)
- if (BIT(table,6))
- val ^= 0x01;
-
- val = s_basetable_fd1089[val];
-
- uint8_t xorval = 0;
- if (opcode == 0)
- {
- if (BIT(~table,6) & BIT(table,2)) xorval ^= 0x01;
- if (BIT(table,4)) xorval ^= 0x01;
- }
- else
- {
- if (BIT(table,6) & BIT(table,2)) xorval ^= 0x01;
- if (BIT(table,5)) xorval ^= 0x01;
- }
-
- val ^= xorval;
-
- if (BIT(table,2))
- {
- val = bitswap<8>(val, 7,6,5,4,1,0,3,2);
-
- if (BIT(table,0) ^ BIT(table,1))
- val = bitswap<8>(val, 7,6,5,4,0,1,3,2);
- }
- else
- {
- val = bitswap<8>(val, 7,6,5,4,3,2,0,1);
-
- if (BIT(table,0) ^ BIT(table,1))
- val = bitswap<8>(val, 7,6,5,4,1,0,2,3);
- }
-
- return val;
-}
-
-
-//-------------------------------------------------
-// decrypt_one - decrypt a single 16-bit value
-// interpreted as being read at the given address
-// as either an opcode or as data
-//-------------------------------------------------
-
-uint16_t fd1089_base_device::decrypt_one(offs_t addr, uint16_t val, const uint8_t *key, bool opcode)
-{
- // pick the translation table from bits ff022a of the address
- int tbl_num = ((addr & 0x000002) >> 1) |
- ((addr & 0x000008) >> 2) |
- ((addr & 0x000020) >> 3) |
- ((addr & 0x000200) >> 6) |
- ((addr & 0xff0000) >> 12);
-
- uint16_t src = ((val & 0x0008) >> 3) |
- ((val & 0x0040) >> 5) |
- ((val & 0xfc00) >> 8);
-
- src = decode(src, key[tbl_num + (opcode ? 0 : 1) * 0x1000], opcode);
-
- src = ((src & 0x01) << 3) |
- ((src & 0x02) << 5) |
- ((src & 0xfc) << 8);
-
- return (val & ~0xfc48) | src;
-}
-
-
-//-------------------------------------------------
-// decrypt - decrypt a buffers' worth of opcodes
-// and data
-//-------------------------------------------------
-
-void fd1089_base_device::decrypt(offs_t baseaddr, uint32_t size, const uint16_t *srcptr, uint16_t *opcodesptr, uint16_t *dataptr)
-{
- for (offs_t offset = 0; offset < size; offset += 2)
- {
- uint16_t src = srcptr[offset / 2];
- opcodesptr[offset / 2] = decrypt_one(baseaddr + offset, src, &m_key[0], true);
- dataptr[offset / 2] = decrypt_one(baseaddr + offset, src, &m_key[0], false);
- }
-}