summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/etc
diff options
context:
space:
mode:
author Dirk Best <mail@dirk-best.de>2018-08-27 22:39:26 +0200
committer Dirk Best <mail@dirk-best.de>2018-08-27 22:39:55 +0200
commit6be0b400ae28c4d7022226cfcc76260b116927db (patch)
treecaf45e43d6dd9db7212979fb4dab01a4ee4cfc1f /src/mame/etc
parentf54bfd6da6f02270001f55802f27ba260a4bcf15 (diff)
opwolf: Move cchip simulation out of driver, initial clean ups
Diffstat (limited to 'src/mame/etc')
-rw-r--r--src/mame/etc/opwolf_cchip.txt1228
1 files changed, 1228 insertions, 0 deletions
diff --git a/src/mame/etc/opwolf_cchip.txt b/src/mame/etc/opwolf_cchip.txt
new file mode 100644
index 00000000000..13904edc920
--- /dev/null
+++ b/src/mame/etc/opwolf_cchip.txt
@@ -0,0 +1,1228 @@
+Operation Wolf C-Chip Protection simulation
+===========================================
+
+The below simulation was replaced by emulating the actual cchip using an
+extracted eprom image. The information previously contained in the MAME driver
+is contained below for documentation purposes.
+
+Start of original notes and simulation below.
+
+
+***************************************************************************
+File: mame/machine/opwolf.cpp
+***************************************************************************
+
+
+ Operation Wolf C-Chip Protection
+ ================================
+
+ The C-Chip (Taito TC0030CMD) is an unidentified mask programmed
+ microcontroller of some sort with 64 pins used for copy protection.
+ It probably has about 2k of ROM and 8k of RAM. The simulation in this file
+ is verified from the unprotected prototype game and the observed behaviour
+ of the real pcb running. It should give 100% accurate gameplay. The bootleg
+ Operation Wolf uses a Z80 and custom program to replace the c-chip. However
+ it's clear that bootlegger done the minimum to make the game work, with both
+ major and minor differences to the original game, which are outlined below.
+
+ Operation Wolf has interesting software architecture. Unlike most games of this
+ era which have a simple main loop and linear code flow, Operation Wolf
+ implements a co-operative threading model where routines run in 68K user mode
+ until giving up their timeslice and a supervisor mode scheduler picks the next
+ thread to run. There are 32 thread slots, and each enemy in game run as its
+ own thread/object as well as a thread for coins, scrolling the level, level
+ specific gameplay and so on. The code is very robust when creating threads,
+ for example if there are no free slots, the creating thread just spins until
+ a slot frees up. The rest of the game just keeps on playing in the background.
+ Another interesting detail is that a thread can give up it's timeslice for more
+ than 1 frame - this makes it really easy to implement timed events. The 'WARNING'
+ text at the end of level 2 is handled by a thread that prints to screen, then just
+ waits a second before spawning the boss enemy thread.
+
+ Each level in the game implements its own logic thread and often sub-threads -
+ this is the major difference between the protected game and the bootleg - the bootleg
+ mostly implements the parts that are generic between all levels rather than all of
+ the details. The biggest single area the bootleg did not implement revolves
+ around location 0x5f in the shared c-chip RAM. The original code sets up a thread
+ that just waits for this value to become non-zero. It then jumps to a set of
+ functions defined in a look-up table (that can then spawn further threads). There
+ are 10 non-null functions tied to this routine.
+
+ 1: Enemy spawn for level 7 (first 'Located' cut-scene)
+ 2: Enemy spawn for level 8 (second 'Located' cut-scene) - zoom in helicopters
+ 3: Enemy spawn for level 9 (third 'Located' cut-scene)
+ 4: Boss & hostage sequence for level 2
+ 5: Enemy spawn when less than 45 enemies in level 2 (paratrooper drop-down)
+ 6: Enemy spawn when less than 25 enemies in level 2
+ 7: Enemy spawn when 0 men left in levels 2,4,5,6
+ 8: Enemy spawn when 0 men left in level 3
+ 9: Enemy spawn when 0 men left in level 1
+ 10: Special explosion animation when level 4 (Powder Dump) is completed
+
+ The bootleg also misses some other details, for example in level 5 the c-chip
+ sets a flag when all men are destroyed (not vehicles) and this triggers the 68K
+ to scroll the screen vertically to focus on the remaining helicopter enemies.
+
+ The 'Enemy has located you' cut-scenes appear 'randomly' between levels in the
+ original game, but are deliberately disabled in the bootleg. The exact formula
+ for determining if the cut-scene appears is '(frameCount & levelNumber)==0'.
+ See code at 0x2D68 for this logic.
+
+
+ Interesting memory locations shared by cchip/68k:
+
+ 0a/xx - copy of 3a0000
+ 28/14 - dip switch A (written by 68k at start)
+ 2a/15 - dip switch B (written by 68k at start)
+ 2c/ ??? (mapped to $982,A5) [word] in prototype)
+ 2e/ (mapped to $984,A5) [word] in prototype)
+ 58/2c m_cchip_ram[0x2c] = 0x31;
+ ee/77 m_cchip_ram[0x77] = 0x05;
+ 4a/25 m_cchip_ram[0x25] = 0x0f;
+ 4c/26 m_cchip_ram[0x26] = 0x0b;
+ 36/1b - Current level number (1-6)
+ 38/1c - Number of men remaining in level
+ 3c/1e - Number of helicopters remaining in level
+ 3e/1f - Number of tanks remaining in level
+ 40/20 - Number of boats remaining in level
+ 42/21 - Hostages in plane (last level)
+ 44/22 - Hostages remaining (last level)/Hostages saved (2nd last level)
+ 4e/27 - Set to 1 when final boss is destroyed
+ 64/32 - Set to 1 by cchip when level complete (no more enemies remaining)
+ 68/34 - Game state (0=attract mode, 1=intro, 2=in-game, 3=end-screen)
+ 69/xx - variable mapped from ($980,A5) [byte] in prototype
+ 6B/xx - variable mapped from ($981,A5) [byte] in prototype
+ A6/xx - variable mapped from ($d6e,A5) [word] in prototype
+ A8/54 - ?
+ xx/51/52 - Used by cchip to signal change in credit level to 68k
+ xx/53 - Credit count
+ EA/75 - Set to 1 to trigger end of game boss
+ EC/76 - used near above
+ xx/7a - Used to trigger level data select command
+
+ Notes on bootleg c-chip compared to original:
+ Bootleg cchip forces english language mode
+ Bootleg forces round 4 in attract mode
+ Bootleg doesn't support service switch
+ If you die after round 6 then the bootleg fails to reset the difficulty
+ for the next game.
+ The bootleg does not contain data for the 3 mini-levels ('Enemy has located you'),
+ instead it prevents them running by writing 0 to location 70 in the shared memory.
+ The bootleg does not play the special powder magazine (level 4) animation.
+ The bootleg does not vertically scroll the screen when all men killed in level 5
+ The bootleg does not update the enemy spawn tables at various points.
+
+ Notes by bmcphail@vcmame.net
+
+
+
+
+/* Select how coinage data is initialised in opwolf_cchip_data_w : 0 = user-defined in function - 1 = automatic */
+#define OPWOLF_READ_COINAGE_FROM_ROM 1
+
+/* List of possible regions */
+enum {
+ OPWOLF_REGION_BAD=0,
+ OPWOLF_REGION_JAPAN,
+ OPWOLF_REGION_US,
+ OPWOLF_REGION_WORLD,
+ OPWOLF_REGION_OTHER
+};
+
+static const uint16_t level_data_00[] = {
+ 0x0480, 0x1008, 0x0300, 0x5701, 0x0001, 0x0010,
+ 0x0480, 0x1008, 0x0300, 0x5701, 0x0001, 0x002b,
+ 0x0780, 0x0009, 0x0300, 0x4a01, 0x0004, 0x0020,
+ 0x0780, 0x1208, 0x0300, 0x5d01, 0x0004, 0x0030,
+ 0x0780, 0x0209, 0x0300, 0x4c01, 0x0004, 0x0038,
+ 0x0780, 0x0309, 0x0300, 0x4d01, 0x0004, 0x0048,
+ 0x0980, 0x1108, 0x0300, 0x5a01, 0xc005, 0x0018,
+ 0x0980, 0x0109, 0x0300, 0x4b01, 0xc005, 0x0028,
+ 0x0b80, 0x020a, 0x0000, 0x6401, 0x8006, 0x0004,
+ 0x0c80, 0x010b, 0x0000, 0xf201, 0x8006, 0x8002,
+ 0x0b80, 0x020a, 0x0000, 0x6401, 0x8006, 0x0017,
+ 0x0c80, 0x010b, 0x0000, 0xf201, 0x8006, 0x8015,
+ 0x0b80, 0x020a, 0x0000, 0x6401, 0x0007, 0x0034,
+ 0x0c80, 0x010b, 0x0000, 0xf201, 0x0007, 0x8032,
+ 0x0b80, 0x020a, 0x0000, 0x6401, 0x8006, 0x803e,
+ 0x0c80, 0x010b, 0x0000, 0xf201, 0x8006, 0x803d,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x0008,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x000b,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x001b,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x001e,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x8007, 0x0038,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x8007, 0x003b,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x8042,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x8045,
+ 0x0c80, 0x000b, 0x0000, 0xf101, 0x800b, 0x8007,
+ 0x0c80, 0x000b, 0x0000, 0xf101, 0x800b, 0x801a,
+ 0x0c80, 0x000b, 0x0000, 0xf101, 0x000c, 0x8037,
+ 0x0c80, 0x000b, 0x0000, 0xf101, 0x800b, 0x0042,
+ 0x0c80, 0xd04b, 0x0000, 0xf301, 0x8006, 0x8009,
+ 0x0c80, 0xd04b, 0x0000, 0xf301, 0x8006, 0x801c,
+ 0x0c80, 0xd04b, 0x0000, 0xf301, 0x8006, 0x0044,
+ 0x0c80, 0x030b, 0x0000, 0xf401, 0x0008, 0x0028,
+ 0x0c80, 0x030b, 0x0000, 0xf401, 0x0008, 0x804b,
+ 0x0c00, 0x040b, 0x0000, 0xf501, 0x0008, 0x8026,
+ 0xffff
+};
+
+static const uint16_t level_data_01[] = {
+ 0x0780, 0x0209, 0x0300, 0x4c01, 0x0004, 0x0010,
+ 0x0780, 0x0209, 0x0300, 0x4c01, 0x4004, 0x0020,
+ 0x0780, 0x0309, 0x0300, 0x4d01, 0xe003, 0x0030,
+ 0x0780, 0x0309, 0x0300, 0x4d01, 0x8003, 0x0040,
+ 0x0780, 0x0209, 0x0300, 0x4c01, 0x8004, 0x0018,
+ 0x0780, 0x0309, 0x0300, 0x4d01, 0xc003, 0x0028,
+ 0x0b80, 0x000b, 0x0000, 0x0b02, 0x8009, 0x0029,
+ 0x0b80, 0x0409, 0x0000, 0x0f02, 0x8008, 0x8028,
+ 0x0b80, 0x040a, 0x0000, 0x3502, 0x000a, 0x8028,
+ 0x0b80, 0x050a, 0x0000, 0x1002, 0x8006, 0x8028,
+ 0x0b80, 0x120a, 0x0000, 0x3602, 0x0008, 0x004d,
+ 0x0b80, 0x120a, 0x0000, 0x3602, 0x0008, 0x004f,
+ 0x0b80, 0x120a, 0x0000, 0x3602, 0x0008, 0x0001,
+ 0x0b80, 0x120a, 0x0000, 0x3602, 0x0008, 0x0003,
+ 0x0b80, 0x130a, 0x0000, 0x3a02, 0x0007, 0x0023,
+ 0x0b80, 0x130a, 0x0000, 0x3a02, 0x0007, 0x8025,
+ 0x0b80, 0x130a, 0x0000, 0x3a02, 0x8009, 0x0023,
+ 0x0b80, 0x130a, 0x0000, 0x3a02, 0x8009, 0x8025,
+ 0x0b80, 0x140a, 0x0000, 0x3e02, 0x0007, 0x000d,
+ 0x0b80, 0x140a, 0x0000, 0x3e02, 0x0007, 0x800f,
+ 0x0b80, 0x000b, 0x0000, 0x0102, 0x0007, 0x804e,
+ 0x0b80, 0xd24b, 0x0000, 0x0302, 0x0007, 0x000e,
+ 0x0b80, 0x000b, 0x0000, 0x0402, 0x8006, 0x0020,
+ 0x0b80, 0xd34b, 0x0000, 0x0502, 0x8006, 0x0024,
+ 0x0b80, 0x000b, 0x0000, 0x0602, 0x8009, 0x0001,
+ 0x0b80, 0xd44b, 0x0000, 0x0702, 0x800b, 0x800b,
+ 0x0b80, 0xd54b, 0x0000, 0x0802, 0x800b, 0x000e,
+ 0x0b80, 0x000b, 0x0000, 0x0902, 0x800b, 0x0010,
+ 0x0b80, 0x000b, 0x0000, 0x0a02, 0x0009, 0x0024,
+ 0x0b80, 0xd64b, 0x0000, 0x0c02, 0x000c, 0x8021,
+ 0x0b80, 0x000b, 0x0000, 0x0d02, 0x000c, 0x0025,
+ 0x0b80, 0x000b, 0x0000, 0x0e02, 0x8009, 0x004e,
+ 0x0b80, 0x000b, 0x0300, 0x4e01, 0x8006, 0x8012,
+ 0x0b80, 0x000b, 0x0300, 0x4e01, 0x0007, 0x8007,
+ 0xffff
+};
+
+static const uint16_t level_data_02[] = {
+ 0x0480, 0x000b, 0x0300, 0x4501, 0x0001, 0x0018,
+ 0x0480, 0x000b, 0x0300, 0x4501, 0x2001, 0x0030,
+ 0x0780, 0x1208, 0x0300, 0x5d01, 0x0004, 0x0010,
+ 0x0780, 0x1208, 0x0300, 0x5d01, 0x2004, 0x001c,
+ 0x0780, 0x1208, 0x0300, 0x5d01, 0xe003, 0x0026,
+ 0x0780, 0x1208, 0x0300, 0x5d01, 0x8003, 0x0034,
+ 0x0780, 0x1208, 0x0300, 0x5d01, 0x3004, 0x0040,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x4004, 0x0022,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x6004, 0x0042,
+ 0x0780, 0x000c, 0x0500, 0x7b01, 0x800b, 0x0008,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x2004, 0x0008,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0b80, 0x000b, 0x0000, 0x1902, 0x000b, 0x0004,
+ 0x0b80, 0x000b, 0x0000, 0x1a02, 0x0009, 0x8003,
+ 0x0b80, 0x000b, 0x0000, 0x1902, 0x000b, 0x000c,
+ 0x0b80, 0x000b, 0x0000, 0x1a02, 0x0009, 0x800b,
+ 0x0b80, 0x000b, 0x0000, 0x1902, 0x000b, 0x001c,
+ 0x0b80, 0x000b, 0x0000, 0x1a02, 0x0009, 0x801b,
+ 0x0b80, 0x000b, 0x0000, 0x1902, 0x000b, 0x002c,
+ 0x0b80, 0x000b, 0x0000, 0x1a02, 0x0009, 0x802b,
+ 0x0b80, 0x000b, 0x0000, 0x1902, 0x000b, 0x0044,
+ 0x0b80, 0x000b, 0x0000, 0x1a02, 0x0009, 0x8043,
+ 0x0b80, 0x000b, 0x0000, 0x1902, 0x000b, 0x004c,
+ 0x0b80, 0x000b, 0x0000, 0x1a02, 0x0009, 0x804b,
+ 0x0b80, 0x020c, 0x0300, 0x4801, 0xa009, 0x0010,
+ 0x0b80, 0x020c, 0x0300, 0x4801, 0xa009, 0x0028,
+ 0x0b80, 0x020c, 0x0300, 0x4801, 0xa009, 0x0036,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0xffff
+};
+
+static const uint16_t level_data_03[] = {
+ 0x0480, 0x000b, 0x0300, 0x4501, 0x0001, 0x0018,
+ 0x0480, 0x000b, 0x0300, 0x4501, 0x2001, 0x002b,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x0004, 0x000d,
+ 0x0780, 0x000c, 0x0500, 0x7b01, 0x800b, 0x0020,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x2004, 0x0020,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x8003, 0x0033,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x0004, 0x003c,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0xd003, 0x0045,
+ 0x0780, 0x000c, 0x0500, 0x7b01, 0x900b, 0x0041,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x3004, 0x0041,
+ 0x0b80, 0x020c, 0x0300, 0x4801, 0x0007, 0x0000,
+ 0x0b80, 0x410a, 0x0000, 0x2b02, 0xe006, 0x4049,
+ 0x0b80, 0x020c, 0x0300, 0x4801, 0x8007, 0x000b,
+ 0x0b80, 0x000b, 0x0000, 0x2702, 0x800a, 0x8005,
+ 0x0b80, 0x000b, 0x0000, 0x1e02, 0x0008, 0x800e,
+ 0x0b80, 0x000b, 0x0000, 0x1f02, 0x8007, 0x0011,
+ 0x0b80, 0x000b, 0x0000, 0x2802, 0x000b, 0x0012,
+ 0x0b80, 0x000b, 0x0000, 0x2002, 0x0007, 0x8015,
+ 0x0b80, 0x000b, 0x0000, 0x2102, 0x0007, 0x801b,
+ 0x0b80, 0x000b, 0x0000, 0x2902, 0x800a, 0x001a,
+ 0x0b80, 0x000b, 0x0000, 0x2202, 0x8007, 0x001e,
+ 0x0b80, 0x000b, 0x0000, 0x1e02, 0x0008, 0x0025,
+ 0x0b80, 0x000b, 0x0000, 0x2302, 0x8007, 0x802c,
+ 0x0b80, 0x000b, 0x0000, 0x2802, 0x000b, 0x8028,
+ 0x0b80, 0x020c, 0x0300, 0x4801, 0x0007, 0x0030,
+ 0x0b80, 0x400a, 0x0000, 0x2e02, 0x4007, 0x002d,
+ 0x0b80, 0x000b, 0x0000, 0x2702, 0x800a, 0x8035,
+ 0x0b80, 0x020c, 0x0300, 0x4801, 0x8007, 0x0022,
+ 0x0b80, 0x000b, 0x0000, 0x2402, 0x8007, 0x0047,
+ 0x0b80, 0x000b, 0x0000, 0x2a02, 0x800a, 0x004b,
+ 0x0b80, 0x000b, 0x0000, 0x2502, 0x0007, 0x804b,
+ 0x0b80, 0x000b, 0x0000, 0x2602, 0x0007, 0x004e,
+ 0x0b80, 0x020c, 0x0300, 0x4801, 0x0007, 0x8043,
+ 0x0b80, 0x020c, 0x0300, 0x4801, 0x8007, 0x803d,
+ 0xffff
+};
+
+static const uint16_t level_data_04[] = {
+ 0x0780, 0x0209, 0x0300, 0x4c01, 0x0004, 0x0010,
+ 0x0780, 0x0209, 0x0300, 0x4c01, 0x4004, 0x0020,
+ 0x0780, 0x0309, 0x0300, 0x4d01, 0xe003, 0x0030,
+ 0x0780, 0x0309, 0x0300, 0x4d01, 0x8003, 0x0040,
+ 0x0780, 0x0209, 0x0300, 0x4c01, 0x8004, 0x0018,
+ 0x0780, 0x0309, 0x0300, 0x4d01, 0xc003, 0x0028,
+ 0x0780, 0x000b, 0x0300, 0x5601, 0x8004, 0x0008,
+ 0x0780, 0x000b, 0x0300, 0x5601, 0x8004, 0x0038,
+ 0x0780, 0x000b, 0x0300, 0x5501, 0x8004, 0x0048,
+ 0x0980, 0x0509, 0x0f00, 0x0f01, 0x4005, 0x4007,
+ 0x0980, 0x0509, 0x0f00, 0x0f01, 0x4005, 0x4037,
+ 0x0b80, 0x030a, 0x0000, 0x1302, 0x8006, 0x0040,
+ 0x0b80, 0x110a, 0x0000, 0x1502, 0x8008, 0x8048,
+ 0x0b80, 0x110a, 0x0000, 0x1502, 0x8008, 0x8049,
+ 0x0b80, 0x000b, 0x0000, 0xf601, 0x0007, 0x8003,
+ 0x0b80, 0x000b, 0x0000, 0xf701, 0x0007, 0x0005,
+ 0x0b80, 0x000b, 0x0000, 0xf901, 0x0007, 0x8008,
+ 0x0b80, 0x000b, 0x0000, 0xf901, 0x0007, 0x0010,
+ 0x0b80, 0x000b, 0x0000, 0xfa01, 0x0007, 0x8013,
+ 0x0b80, 0x000b, 0x0000, 0xf801, 0x800b, 0x800b,
+ 0x0b80, 0x000b, 0x0000, 0x0002, 0x800b, 0x801a,
+ 0x0b80, 0x000b, 0x0000, 0xf901, 0x0007, 0x8017,
+ 0x0b80, 0x000b, 0x0000, 0xfa01, 0x0007, 0x001b,
+ 0x0b80, 0x000b, 0x0000, 0xf801, 0x800b, 0x0013,
+ 0x0b80, 0x000b, 0x0000, 0x4202, 0x800b, 0x0016,
+ 0x0b80, 0x000b, 0x0000, 0xfb01, 0x8007, 0x8020,
+ 0x0b80, 0x000b, 0x0000, 0xf601, 0x0007, 0x8023,
+ 0x0b80, 0x000b, 0x0000, 0x4202, 0x800b, 0x800e,
+ 0x0b80, 0x000b, 0x0000, 0x4302, 0x800b, 0x801d,
+ 0x0b80, 0x000b, 0x0000, 0xf701, 0x0007, 0x0025,
+ 0x0b80, 0x000b, 0x0000, 0xfd01, 0x8006, 0x003f,
+ 0x0b80, 0x000b, 0x0000, 0xfe01, 0x0007, 0x0046,
+ 0x0b80, 0x000b, 0x0000, 0xff01, 0x8007, 0x8049,
+ 0x0b80, 0x000b, 0x0000, 0xfc01, 0x8009, 0x0042,
+ 0xffff
+};
+
+static const uint16_t level_data_05[] = {
+ 0x0480, 0x1008, 0x0300, 0x5701, 0x0001, 0x0010,
+ 0x0480, 0x1008, 0x0300, 0x5701, 0x0001, 0x002b,
+ 0x0780, 0x0009, 0x0300, 0x4a01, 0x0004, 0x0020,
+ 0x0780, 0x1208, 0x0300, 0x5d01, 0x0004, 0x0030,
+ 0x0780, 0x0209, 0x0300, 0x4c01, 0x0004, 0x0038,
+ 0x0780, 0x0309, 0x0300, 0x4d01, 0x0004, 0x0048,
+ 0x0980, 0x1108, 0x0300, 0x5a01, 0xc005, 0x0018,
+ 0x0980, 0x0109, 0x0300, 0x4b01, 0xc005, 0x0028,
+ 0x0b80, 0x020a, 0x0000, 0x6401, 0x8006, 0x0004,
+ 0x0c80, 0x010b, 0x0000, 0xf201, 0x8006, 0x8002,
+ 0x0b80, 0x020a, 0x0000, 0x6401, 0x8006, 0x0017,
+ 0x0c80, 0x010b, 0x0000, 0xf201, 0x8006, 0x8015,
+ 0x0b80, 0x020a, 0x0000, 0x6401, 0x0007, 0x0034,
+ 0x0c80, 0x010b, 0x0000, 0xf201, 0x0007, 0x8032,
+ 0x0b80, 0x020a, 0x0000, 0x6401, 0x8006, 0x803e,
+ 0x0c80, 0x010b, 0x0000, 0xf201, 0x8006, 0x803d,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x0008,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x000b,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x001b,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x001e,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x8007, 0x0038,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x8007, 0x003b,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x8042,
+ 0x0b80, 0x100a, 0x0000, 0x6001, 0x0007, 0x8045,
+ 0x0c80, 0x000b, 0x0000, 0xf101, 0x800b, 0x8007,
+ 0x0c80, 0x000b, 0x0000, 0xf101, 0x800b, 0x801a,
+ 0x0c80, 0x000b, 0x0000, 0xf101, 0x000c, 0x8037,
+ 0x0c80, 0x000b, 0x0000, 0xf101, 0x800b, 0x0042,
+ 0x0c80, 0xd04b, 0x0000, 0xf301, 0x8006, 0x8009,
+ 0x0c80, 0xd04b, 0x0000, 0xf301, 0x8006, 0x801c,
+ 0x0c80, 0xd04b, 0x0000, 0xf301, 0x8006, 0x0044,
+ 0x0c80, 0x030b, 0x0000, 0xf401, 0x0008, 0x0028,
+ 0x0c80, 0x030b, 0x0000, 0xf401, 0x0008, 0x804b,
+ 0x0c00, 0x040b, 0x0000, 0xf501, 0x0008, 0x8026,
+ 0xffff
+};
+
+static const uint16_t level_data_06[] = {
+ 0x0000, 0x1008, 0x0300, 0x5701, 0x0001, 0x0010,
+ 0x0000, 0x1008, 0x0300, 0x5701, 0x0001, 0x002b,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0700, 0x0009, 0x0300, 0x4a01, 0x0004, 0x0020,
+ 0x0700, 0x1208, 0x0300, 0x5d01, 0x0004, 0x0030,
+ 0x0700, 0x0209, 0x0300, 0x4c01, 0x0004, 0x0038,
+ 0x0700, 0x0309, 0x0300, 0x4d01, 0x0004, 0x0048,
+ 0x0900, 0x1108, 0x0300, 0x5a01, 0xc005, 0x0018,
+ 0x0900, 0x0109, 0x0300, 0x4b01, 0xc005, 0x0028,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0980, 0xdb4c, 0x0000, 0x3202, 0x0006, 0x0004,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0x0000, 0x000b, 0x0000, 0x0000, 0x0018, 0x0000,
+ 0xffff
+};
+
+static const uint16_t level_data_07[] = {
+ 0x0480, 0x000b, 0x0300, 0x4501, 0x0001, 0x0001,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0780, 0x0109, 0x0300, 0x4a01, 0x0004, 0x0004,
+ 0x0780, 0x0009, 0x0300, 0x4a01, 0x0004, 0x000d,
+ 0x0780, 0x000c, 0x0500, 0x7b01, 0x000c, 0x0005,
+ 0x0780, 0x000c, 0x0540, 0x7b01, 0x000c, 0x0005,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x0005, 0x0005,
+ 0x0780, 0x000c, 0x0500, 0x7b01, 0x800b, 0xc00d,
+ 0x0780, 0x000c, 0x0540, 0x7b01, 0x800b, 0xc00d,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x8004, 0xc00d,
+ 0x0900, 0x0109, 0x0340, 0x4b01, 0x2006, 0x400c,
+ 0x0780, 0x020c, 0x0300, 0x4801, 0x8007, 0x0008,
+ 0x0780, 0x020c, 0x0300, 0x4801, 0x4007, 0xc00b,
+ 0x0980, 0x0109, 0x0300, 0x4b01, 0xc006, 0x8007,
+ 0x0980, 0x0109, 0x0300, 0x4b01, 0x8007, 0x8008,
+ 0x0980, 0x0109, 0x0300, 0x4b01, 0xc006, 0x800c,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0xffff
+};
+
+static const uint16_t level_data_08[] = {
+ 0xffff
+};
+
+static const uint16_t level_data_09[] = {
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0780, 0x0109, 0x0300, 0x4a01, 0x8003, 0x8003,
+ 0x0780, 0x0009, 0x0300, 0x4a01, 0x0004, 0x800e,
+ 0x0780, 0x000c, 0x0500, 0x7b01, 0x000c, 0x0005,
+ 0x0780, 0x000c, 0x0540, 0x7b01, 0x000c, 0x0005,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x0005, 0x0005,
+ 0x0780, 0x000c, 0x0500, 0x7b01, 0x800b, 0xc00d,
+ 0x0780, 0x000c, 0x0540, 0x7b01, 0x800b, 0xc00d,
+ 0x0780, 0x010c, 0x0300, 0x4601, 0x8004, 0xc00d,
+ 0x0900, 0x0109, 0x0340, 0x4b01, 0x2006, 0x400c,
+ 0x0780, 0x020c, 0x0300, 0x4801, 0x8007, 0x0008,
+ 0x0780, 0x020c, 0x0300, 0x4801, 0x4007, 0xc00b,
+ 0x0980, 0x0109, 0x0300, 0x4b01, 0xc006, 0x8007,
+ 0x0980, 0x0109, 0x0300, 0x4b01, 0x8007, 0x8008,
+ 0x0980, 0x0109, 0x0300, 0x4b01, 0xc006, 0x800c,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0xf001, 0x0000, 0x0000,
+ 0xffff
+};
+
+static const uint16_t *const level_data_lookup[] =
+{
+ level_data_00,
+ level_data_01,
+ level_data_02,
+ level_data_03,
+ level_data_04,
+ level_data_05,
+ level_data_06,
+ level_data_07,
+ level_data_08,
+ level_data_09
+};
+
+void opwolf_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_OPWOLF:
+ opwolf_timer_callback(ptr, param);
+ break;
+ case TIMER_CCHIP:
+ cchip_timer(ptr, param);
+ break;
+ default:
+ assert_always(false, "Unknown id in opwolf_state::device_timer");
+ }
+}
+
+TIMER_CALLBACK_MEMBER(opwolf_state::opwolf_timer_callback)
+{
+ // Level data command
+ if (m_current_cmd == 0xf5)
+ {
+ int const level = m_cchip_ram[0x1b] % 10;
+ uint16_t const *const level_data = level_data_lookup[level];
+
+ // The c-chip data is stored as a series of 3 word sets, delimited by 0xffff
+ memset(m_cchip_ram + 0x200, 0, 0x200);
+ for (unsigned i = 0; (i < 0x200) && (level_data[i] != 0xffff); i += 3)
+ {
+ m_cchip_ram[0x200 + i*2 + 0] = level_data[i]>>8;
+ m_cchip_ram[0x200 + i*2 + 1] = level_data[i]&0xff;
+ m_cchip_ram[0x200 + i*2 + 2] = level_data[i+1]>>8;
+ m_cchip_ram[0x200 + i*2 + 3] = level_data[i+1]&0xff;
+ m_cchip_ram[0x200 + i*2 + 4] = level_data[i+2]>>8;
+ m_cchip_ram[0x200 + i*2 + 5] = level_data[i+2]&0xff;
+ }
+
+ // The bootleg cchip writes 0 to these locations - we can probably assume the real one
+ // does similar as this is just zeroing out work variables used in the level.
+ m_cchip_ram[0x0] = 0;
+ m_cchip_ram[0x76] = 0;
+ m_cchip_ram[0x75] = 0;
+ m_cchip_ram[0x74] = 0;
+ m_cchip_ram[0x72] = 0;
+ m_cchip_ram[0x71] = 0;
+ // m_cchip_ram[0x70] = 0; // The bootleg writes this to disable mini-levels. The real c-chip does not do this.
+ m_cchip_ram[0x66] = 0;
+ m_cchip_ram[0x2b] = 0;
+ m_cchip_ram[0x30] = 0;
+ m_cchip_ram[0x31] = 0;
+ m_cchip_ram[0x32] = 0;
+ m_cchip_ram[0x27] = 0;
+ m_c588 = 0;
+ m_c589 = 0;
+ m_c58a = 0;
+ m_triggeredLevel1b = 0;
+ m_triggeredLevel13b = 0;
+ m_triggeredLevel2 = 0;
+ m_triggeredLevel2b = 0;
+ m_triggeredLevel2c = 0;
+ m_triggeredLevel3b = 0;
+ m_triggeredLevel4 = 0;
+ m_triggeredLevel5 = 0;
+ m_triggeredLevel7 = 0;
+ m_triggeredLevel8 = 0;
+ m_triggeredLevel9 = 0;
+
+ m_cchip_ram[0x1a] = 0;
+ m_cchip_ram[0x7a] = 1; // Signal command complete
+
+ //logerror("Signal level command complete\n");
+ }
+
+ m_current_cmd = 0;
+}
+
+void opwolf_state::updateDifficulty( int mode )
+{
+ // The game is made up of 6 rounds, when you complete the
+ // sixth you return to the start but with harder difficulty.
+ if (mode == 0)
+ {
+ switch (m_cchip_ram[0x15]&3) // Dipswitch B
+ {
+ case 3:
+ m_cchip_ram[0x2c] = 0x31;
+ m_cchip_ram[0x77] = 0x05;
+ m_cchip_ram[0x25] = 0x0f;
+ m_cchip_ram[0x26] = 0x0b;
+ break;
+ case 0:
+ m_cchip_ram[0x2c] = 0x20;
+ m_cchip_ram[0x77] = 0x06;
+ m_cchip_ram[0x25] = 0x07;
+ m_cchip_ram[0x26] = 0x03;
+ break;
+ case 1:
+ m_cchip_ram[0x2c] = 0x31;
+ m_cchip_ram[0x77] = 0x05;
+ m_cchip_ram[0x25] = 0x0f;
+ m_cchip_ram[0x26] = 0x0b;
+ break;
+ case 2:
+ m_cchip_ram[0x2c] = 0x3c;
+ m_cchip_ram[0x77] = 0x04;
+ m_cchip_ram[0x25] = 0x13;
+ m_cchip_ram[0x26] = 0x0f;
+ break;
+ }
+ }
+ else
+ {
+ switch (m_cchip_ram[0x15]&3) // Dipswitch B
+ {
+ case 3:
+ m_cchip_ram[0x2c] = 0x46;
+ m_cchip_ram[0x77] = 0x05;
+ m_cchip_ram[0x25] = 0x11;
+ m_cchip_ram[0x26] = 0x0e;
+ break;
+ case 0:
+ m_cchip_ram[0x2c] = 0x30;
+ m_cchip_ram[0x77] = 0x06;
+ m_cchip_ram[0x25] = 0x0b;
+ m_cchip_ram[0x26] = 0x03;
+ break;
+ case 1:
+ m_cchip_ram[0x2c] = 0x3a;
+ m_cchip_ram[0x77] = 0x05;
+ m_cchip_ram[0x25] = 0x0f;
+ m_cchip_ram[0x26] = 0x09;
+ break;
+ case 2:
+ m_cchip_ram[0x2c] = 0x4c;
+ m_cchip_ram[0x77] = 0x04;
+ m_cchip_ram[0x25] = 0x19;
+ m_cchip_ram[0x26] = 0x11;
+ break;
+ };
+ }
+}
+
+/*************************************
+ *
+ * Writes to C-Chip - Important Bits
+ *
+ *************************************/
+
+WRITE16_MEMBER(opwolf_state::opwolf_cchip_status_w)
+{
+ // This is written once after the C-Chip init is complete (and passes)
+ // We use it to setup some initial state (it's not clear if the real
+ // c-chip sets this here, or if it's as a side-effect of the other
+ // init sequence data).
+
+ m_cchip_ram[0x3d] = 1;
+ m_cchip_ram[0x7a] = 1;
+ updateDifficulty(0);
+}
+
+WRITE16_MEMBER(opwolf_state::opwolf_cchip_bank_w)
+{
+ m_current_bank = data & 7;
+}
+
+WRITE16_MEMBER(opwolf_state::opwolf_cchip_data_w)
+{
+ //int logValue=1;
+ //if (offset==0x1c && offset==0x1d && offset==0x1e && offset==0x1f && offset==0x20) // Enemies, tanks, choppers, boats
+ // logValue=0;
+ //if (offset==0x50 && offset==0x51 && offset==0x52 && offset==0x53) // Coins
+ // logValue=0;
+ //if (logValue)
+ // logerror("%s: opwolf 68K writes c-chip %02x at %04x/%04x (bank %04x)\n", machine().describe_context(), data & 0xff, offset*2, offset, m_current_bank);
+
+ m_cchip_ram[(m_current_bank * 0x400) + offset] = data & 0xff;
+
+ if (m_current_bank == 0)
+ {
+ // Dip switch A is written here by the 68k - precalculate the coinage values
+ // Shouldn't we directly read the values from the ROM area ?
+ if (offset == 0x14)
+ {
+#if OPWOLF_READ_COINAGE_FROM_ROM
+ uint16_t* rom = (uint16_t*)memregion("maincpu")->base();
+ uint32_t coin_table[2] = {0, 0};
+ uint8_t coin_offset[2];
+ int slot;
+
+ if ((m_opwolf_region == OPWOLF_REGION_JAPAN) || (m_opwolf_region == OPWOLF_REGION_US))
+ {
+ coin_table[0] = 0x03ffce;
+ coin_table[1] = 0x03ffce;
+ }
+ if ((m_opwolf_region == OPWOLF_REGION_WORLD) || (m_opwolf_region == OPWOLF_REGION_OTHER))
+ {
+ coin_table[0] = 0x03ffde;
+ coin_table[1] = 0x03ffee;
+ }
+ coin_offset[0] = 12 - (4 * ((data & 0x30) >> 4));
+ coin_offset[1] = 12 - (4 * ((data & 0xc0) >> 6));
+
+ for (slot = 0; slot < 2; slot++)
+ {
+ if (coin_table[slot])
+ {
+ m_cchip_coins_for_credit[slot] = rom[(coin_table[slot] + coin_offset[slot] + 0) / 2] & 0xff;
+ m_cchip_credits_for_coin[slot] = rom[(coin_table[slot] + coin_offset[slot] + 2) / 2] & 0xff;
+ }
+ }
+#else
+ if ((m_opwolf_region == OPWOLF_REGION_JAPAN) || (m_opwolf_region == OPWOLF_REGION_US))
+ {
+ switch (data&0x30) /* table at 0x03ffce.w - 4 * 2 words (coins for credits first) - inverted order */
+ {
+ case 0x00: m_cchip_coins_for_credit[0] = 2; cchip_credits_for_coin[0] = 3; break;
+ case 0x10: m_cchip_coins_for_credit[0] = 2; cchip_credits_for_coin[0] = 1; break;
+ case 0x20: m_cchip_coins_for_credit[0] = 1; cchip_credits_for_coin[0] = 2; break;
+ case 0x30: m_cchip_coins_for_credit[0] = 1; cchip_credits_for_coin[0] = 1; break;
+ }
+ switch (data&0xc0) /* table at 0x03ffce.w - 4 * 2 words (coins for credits first) - inverted order */
+ {
+ case 0x00: m_cchip_coins_for_credit[1] = 2; cchip_credits_for_coin[1] = 3; break;
+ case 0x40: m_cchip_coins_for_credit[1] = 2; cchip_credits_for_coin[1] = 1; break;
+ case 0x80: m_cchip_coins_for_credit[1] = 1; cchip_credits_for_coin[1] = 2; break;
+ case 0xc0: m_cchip_coins_for_credit[1] = 1; cchip_credits_for_coin[1] = 1; break;
+ }
+ }
+
+ if ((opwolf_region == OPWOLF_REGION_WORLD) || (opwolf_region == OPWOLF_REGION_OTHER))
+ {
+ switch (data&0x30) /* table at 0x03ffde.w - 4 * 2 words (coins for credits first) - inverted order */
+ {
+ case 0x00: m_cchip_coins_for_credit[0] = 4; cchip_credits_for_coin[0] = 1; break;
+ case 0x10: m_cchip_coins_for_credit[0] = 3; cchip_credits_for_coin[0] = 1; break;
+ case 0x20: m_cchip_coins_for_credit[0] = 2; cchip_credits_for_coin[0] = 1; break;
+ case 0x30: m_cchip_coins_for_credit[0] = 1; cchip_credits_for_coin[0] = 1; break;
+ }
+ switch (data & 0xc0) /* table at 0x03ffee.w - 4 * 2 words (coins for credits first) - inverted order */
+ {
+ case 0x00: m_cchip_coins_for_credit[1] = 1; cchip_credits_for_coin[1] = 6; break;
+ case 0x40: m_cchip_coins_for_credit[1] = 1; cchip_credits_for_coin[1] = 4; break;
+ case 0x80: m_cchip_coins_for_credit[1] = 1; cchip_credits_for_coin[1] = 3; break;
+ case 0xc0: m_cchip_coins_for_credit[1] = 1; cchip_credits_for_coin[1] = 2; break;
+ }
+ }
+#endif
+ }
+
+ // Dip switch B
+ if (offset == 0x15)
+ {
+ updateDifficulty(0);
+ }
+ }
+}
+
+/*************************************
+ *
+ * Reads from C-Chip
+ *
+ *************************************/
+
+READ16_MEMBER(opwolf_state::opwolf_cchip_status_r)
+{
+ /*
+ Bit 0x4 = Error signal
+ Bit 0x1 = Ready signal
+ */
+ return 0x1; /* Return 0x5 for C-Chip error */
+}
+
+READ16_MEMBER(opwolf_state::opwolf_cchip_data_r)
+{
+// if (offset!=0x7f && && m_maincpu->pc()!=0xc18 && m_maincpu->pc()!=0xc2e && m_maincpu->pc()!=0xc9e && offset!=0x50 && offset!=0x51 && offset!=0x52 && offset!=0x53 && offset!=0x5 && offset!=0x13 && offset!=0x79 && offset!=0x12 && offset!=0x34)
+// logerror("%08x: opwolf c read %04x (bank %04x)\n", m_maincpu->pc(), offset, m_current_bank);
+
+ //int logValue=1;
+ //if (offset==0x1c || offset==0x1d || offset==0x1e || offset==0x1f || offset==0x20) // Enemies, tanks, choppers, boats
+ // logValue=0;
+ //if (offset==0x50 || offset==0x51 || offset==0x52 || offset==0x53) // Coins
+ // logValue=0;
+ //if (m_maincpu->pc()==0xc18 && m_maincpu->pc()!=0xc2e && m_maincpu->pc()!=0xc9e)
+ // logValue=0;
+ //if (logValue)
+ // logerror("%08x: opwolf 68K reads c-chip at %04x/%04x (bank %04x)\n", m_maincpu->pc(), offset*2, offset, m_current_bank);
+
+ return m_cchip_ram[(m_current_bank * 0x400) + offset];
+}
+
+/*************************************
+ *
+ * C-Chip Tick
+ *
+ *************************************/
+
+TIMER_CALLBACK_MEMBER(opwolf_state::cchip_timer)
+{
+ // Update input ports, these are used by both the 68k directly and by the c-chip
+ m_cchip_ram[0x4] = ioport("IN0")->read();
+ m_cchip_ram[0x5] = ioport("IN1")->read();
+
+ // Dev Cheat - kill all enemeies
+ //if ((ioport("IN1")->read()&0x10)!=0x10)
+ //{
+ // m_cchip_ram[0x1c] = m_cchip_ram[0x1d] = m_cchip_ram[0x1e] = m_cchip_ram[0x1f] = m_cchip_ram[0x20] = 0;
+ //}
+
+ // Coin slots
+ if (m_cchip_ram[0x4] != m_cchip_last_04)
+ {
+ int slot = -1;
+
+ if (m_cchip_ram[0x4] & 1) slot = 0;
+ if (m_cchip_ram[0x4] & 2) slot = 1;
+
+ if (slot != -1)
+ {
+ m_cchip_coins[slot]++;
+ if (m_cchip_coins[slot] >= m_cchip_coins_for_credit[slot])
+ {
+ m_cchip_ram[0x53] += m_cchip_credits_for_coin[slot];
+ m_cchip_ram[0x51] = 0x55;
+ m_cchip_ram[0x52] = 0x55;
+ m_cchip_coins[slot] -= m_cchip_coins_for_credit[slot];
+ }
+ machine().bookkeeping().coin_counter_w(slot, 1);
+ }
+
+ if (m_cchip_ram[0x53] > 9)
+ m_cchip_ram[0x53] = 9;
+ }
+ m_cchip_last_04 = m_cchip_ram[0x4];
+
+ // Service switch
+ if (m_cchip_ram[0x5] != m_cchip_last_05)
+ {
+ if ((m_cchip_ram[0x5] & 4)==0)
+ {
+ m_cchip_ram[0x53]++;
+ m_cchip_ram[0x51] = 0x55;
+ m_cchip_ram[0x52] = 0x55;
+ }
+ }
+ m_cchip_last_05=m_cchip_ram[0x5];
+
+ // Cchip handles coin lockout (68k flags error if more than 9 coins)
+ machine().bookkeeping().coin_lockout_w(1, m_cchip_ram[0x53] == 9);
+ machine().bookkeeping().coin_lockout_w(0, m_cchip_ram[0x53] == 9);
+ machine().bookkeeping().coin_counter_w(0, 0);
+ machine().bookkeeping().coin_counter_w(1, 0);
+
+ // These variables are cleared every frame during attract mode and the intro.
+ if (m_cchip_ram[0x34] < 2)
+ {
+ updateDifficulty(0);
+ m_cchip_ram[0x76] = 0;
+ m_cchip_ram[0x75] = 0;
+ m_cchip_ram[0x74] = 0;
+ m_cchip_ram[0x72] = 0;
+ m_cchip_ram[0x71] = 0;
+ m_cchip_ram[0x70] = 0;
+ m_cchip_ram[0x66] = 0;
+ m_cchip_ram[0x2b] = 0;
+ m_cchip_ram[0x30] = 0;
+ m_cchip_ram[0x31] = 0;
+ m_cchip_ram[0x32] = 0;
+ m_cchip_ram[0x27] = 0;
+ m_c588 = 0;
+ m_c589 = 0;
+ m_c58a = 0;
+ }
+
+ // The unprotected Operation Wolf (prototype) shows the game sets up a special thread function specific to each level of the game.
+ // This includes the end of level check as different levels have different rules. In the protected version this logic is moved
+ // to the c-chip, so we simulate it here.
+ if (m_cchip_ram[0x1c] == 0 && m_cchip_ram[0x1d] == 0 && m_cchip_ram[0x1e] == 0 && m_cchip_ram[0x1f] == 0 && m_cchip_ram[0x20] == 0)
+ {
+ // Special handling for end of level 6
+ if (m_cchip_ram[0x1b] == 0x6)
+ {
+ // Don't signal end of level until final boss is destroyed
+ if (m_cchip_ram[0x27] == 0x1)
+ m_cchip_ram[0x32] = 1;
+ }
+ // Level 2 - Boss check - cross-referenced from logic at 0x91CE in OpWolfP
+ // When all enemies are destroyed c-chip signals function 4 in the level function table, which
+ // starts the 'WARNING' sequences for the boss.
+ else if (m_cchip_ram[0x1b] == 0x2)
+ {
+ if (m_triggeredLevel2==0 && m_cchip_ram[0x5f]==0) // Don't write unless 68K is ready (0 at 0x5f)
+ {
+ m_cchip_ram[0x5f] = 4; // 0xBE at 68K side
+ m_triggeredLevel2=1;
+ }
+
+ // When the level 2 boss has been defeated the 68K will write 0xff to $ff0ba.l - this should signal
+ // the c-chip to start the end of level routine. See code at 0xC370 in OpWolf and 0x933e in OpWolfP
+ if (m_triggeredLevel2 && m_cchip_ram[0x5d]!=0)
+ {
+ // Signal end of level
+ m_cchip_ram[0x32] = 1;
+ m_cchip_ram[0x5d] = 0; // acknowledge 68K command
+ }
+ }
+ else if (m_cchip_ram[0x1b] == 0x4)
+ {
+ m_cchip_ram[0x32] = 1;
+
+ // When level 4 (powder magazine) is complete the c-chip triggers an explosion animation.
+ if (m_triggeredLevel4==0 && m_cchip_ram[0x5f]==0) // Don't write unless 68K is ready (0 at 0x5f))
+ {
+ m_cchip_ram[0x5f]=10;
+ m_triggeredLevel4=1;
+ }
+ }
+ else
+ {
+ // Signal end of level
+ m_cchip_ram[0x32] = 1;
+ }
+ }
+
+ // When all men are destroyed (not necessarily vehicles) the enemy look up table changes
+ // Reference functions around 0x96A4 in the unprotected prototype.
+ // Level 1 has a specific table.
+ // Level 3 has an additional flag set
+ if (m_cchip_ram[0x1c] == 0 && m_cchip_ram[0x1d] == 0)
+ {
+ // Compare code at 0x96DC in prototype with 0xC3A2 in protected version
+ if (m_cchip_ram[0x1b] == 0x1 && m_triggeredLevel1b==0 && m_cchip_ram[0x5f]==0) // Don't write unless 68K is ready (0 at 0x5f))
+ {
+ m_cchip_ram[0x5f]=7;
+ m_triggeredLevel1b=1;
+ }
+
+ // Compare code at 0x96BC in prototype with 0xC3B2 in protected version
+ if (m_cchip_ram[0x1b] == 0x3 && m_triggeredLevel3b==0 && m_cchip_ram[0x5f]==0) // Don't write unless 68K is ready (0 at 0x5f))
+ {
+ m_cchip_ram[0x5f]=8;
+ m_triggeredLevel3b=1;
+ }
+
+ // Compare code at 0x96BC in prototype with 0xC3C8 in protected version
+ if ((m_cchip_ram[0x1b] != 0x1 && m_cchip_ram[0x1b] != 0x3) && m_triggeredLevel13b==0 && m_cchip_ram[0x5f]==0) // Don't write unless 68K is ready (0 at 0x5f))
+ {
+ m_cchip_ram[0x5f]=9;
+ m_triggeredLevel13b=1;
+ }
+ }
+
+ //-------------------------------------------------------------------------------------------------
+ // Level 2. On level 2 specifically when there are less than 45 men left the enemy lookup table is
+ // switched. This drops down a wave of paratroopers. When there are less than 25 men left the lookup
+ // table is switched again.
+ // See code at 0xC37A and 0xc390 in protected version against 0x9648 in prototype.
+ if (m_cchip_ram[0x1b] == 0x2)
+ {
+ // (Note: it's correct that 25 decimal is represented as 0x25 in hex here).
+ int numMen=(m_cchip_ram[0x1d]<<8) + m_cchip_ram[0x1c];
+ if (numMen<0x25 && m_triggeredLevel2b==1 && m_triggeredLevel2c==0 && m_cchip_ram[0x5f]==0) // Don't write unless 68K is ready (0 at 0x5f))
+ {
+ m_cchip_ram[0x5f]=6;
+ m_triggeredLevel2c=1;
+ }
+
+ // (Note: it's correct that 45 decimal is represented as 0x45 in hex here).
+ if (numMen<0x45 && m_triggeredLevel2b==0 && m_cchip_ram[0x5f]==0) // Don't write unless 68K is ready (0 at 0x5f))
+ {
+ m_cchip_ram[0x5f]=5;
+ m_triggeredLevel2b=1;
+ }
+ }
+
+ //-------------------------------------------------------------------------------------------------
+ // Level 5
+ if (m_cchip_ram[0x1b] == 0x5)
+ {
+ // When all men are destroyed (not necessarily vehicles), the c-chip writes 1 to location
+ // 0x2f to spawn a thread that scrolls the screen upwards to focus on the helicopter
+ // enemies. The 68K acknowledges this by writing 2 to 0x2f.
+ // See code at 0x4ED6 in prototype and 0x687e in original.
+ if (m_cchip_ram[0x1c] == 0 && m_cchip_ram[0x1d] == 0 && m_triggeredLevel5==0)
+ {
+ m_cchip_ram[0x2f] = 1;
+ m_triggeredLevel5 = 1;
+ }
+ }
+
+ //-------------------------------------------------------------------------------------------------
+ // Level 6
+ if (m_cchip_ram[0x1b] == 0x6)
+ {
+ // Check for triggering final helicopter (end boss)
+ if (m_c58a == 0)
+ {
+ if ((m_cchip_ram[0x72] & 0x7f) >= 8 && m_cchip_ram[0x74] == 0 && m_cchip_ram[0x1c] == 0 && m_cchip_ram[0x1d] == 0 && m_cchip_ram[0x1f] == 0)
+ {
+ m_cchip_ram[0x30] = 1;
+ m_cchip_ram[0x74] = 1;
+ m_c58a = 1;
+ }
+ }
+
+ if (m_cchip_ram[0x1a] == 0x90)
+ m_cchip_ram[0x74] = 0;
+
+ if (m_c58a != 0)
+ {
+ if (m_c589 == 0 && m_cchip_ram[0x27] == 0 && m_cchip_ram[0x75] == 0 && m_cchip_ram[0x1c] == 0 && m_cchip_ram[0x1d] == 0 && m_cchip_ram[0x1e] == 0 && m_cchip_ram[0x1f] == 0)
+ {
+ m_cchip_ram[0x31] = 1;
+ m_cchip_ram[0x75] = 1;
+ m_c589 = 1;
+ }
+ }
+
+ if (m_cchip_ram[0x2b] == 0x1)
+ {
+ m_cchip_ram[0x2b] = 0;
+
+ if (m_cchip_ram[0x30] == 0x1)
+ {
+ if (m_cchip_ram[0x1a] != 0x90)
+ m_cchip_ram[0x1a]--;
+ }
+
+ if (m_cchip_ram[0x72] == 0x9)
+ {
+ if (m_cchip_ram[0x76] != 0x4)
+ {
+ m_cchip_ram[0x76] = 3;
+ }
+ }
+ else
+ {
+ // This timer is derived from the bootleg rather than the real board, I'm not 100% sure about it
+ m_c588 |= 0x80;
+
+ m_cchip_ram[0x72] = m_c588;
+ m_c588++;
+
+ m_cchip_ram[0x1a]--;
+ m_cchip_ram[0x1a]--;
+ m_cchip_ram[0x1a]--;
+ }
+ }
+
+ // Update difficulty settings
+ if (m_cchip_ram[0x76] == 0)
+ {
+ m_cchip_ram[0x76] = 1;
+ updateDifficulty(1);
+ }
+ }
+
+ //-------------------------------------------------------------------------------------------------
+ // Start of level 7 - should trigger '1' in level thread table (compare 0xC164 in protected to 0x9468 in unprotected)
+ if (m_cchip_ram[0x1b] == 0x7 && m_triggeredLevel7==0 && m_cchip_ram[0x5f]==0) // Don't write unless 68K is ready (0 at 0x5f))
+ {
+ m_triggeredLevel7 = 1;
+ m_cchip_ram[0x5f] = 1;
+ }
+
+ //-------------------------------------------------------------------------------------------------
+ // Start of level 8 - should trigger '2' in level thread table (compare 0xC18E in protected to 0x9358 in unprotected)
+ // This controls the 'zoom in helicopters' enemy
+ if (m_cchip_ram[0x1b] == 0x8 && m_triggeredLevel8==0 && m_cchip_ram[0x5f]==0) // Don't write unless 68K is ready (0 at 0x5f))
+ {
+ m_triggeredLevel8 = 1;
+ m_cchip_ram[0x5f] = 2;
+ }
+
+ //-------------------------------------------------------------------------------------------------
+ // Start of level 9 - should trigger '3' in level thread table (compare 0xC1B0 in protected to 0x9500 in unprotected)
+ // This controls the 'zoom in helicopters' enemy
+ if (m_cchip_ram[0x1b] == 0x9 && m_triggeredLevel9==0 && m_cchip_ram[0x5f]==0) // Don't write unless 68K is ready (0 at 0x5f))
+ {
+ m_triggeredLevel9 = 1;
+ m_cchip_ram[0x5f] = 3;
+ }
+
+ if (m_cchip_ram[0xe] == 1)
+ {
+ m_cchip_ram[0xe] = 0xfd;
+ m_cchip_ram[0x61] = 0x04;
+ }
+
+ // Access level data command (address 0xf5 goes from 1 -> 0)
+ if (m_cchip_ram[0x7a] == 0 && m_cchip_last_7a != 0 && m_current_cmd != 0xf5)
+ {
+ // Simulate time for command to execute (exact timing unknown, this is close)
+ m_current_cmd = 0xf5;
+ m_opwolf_timer->adjust(m_maincpu->cycles_to_attotime(80000));
+ }
+ m_cchip_last_7a = m_cchip_ram[0x7a];
+
+ // This seems to some kind of periodic counter - results are expected
+ // by the 68k when the counter reaches 0xa
+ if (m_cchip_ram[0x7f] == 0xa)
+ {
+ m_cchip_ram[0xfe] = 0xf7;
+ m_cchip_ram[0xff] = 0x6e;
+ }
+
+ // These are set every frame
+ m_cchip_ram[0x64] = 0;
+ m_cchip_ram[0x66] = 0;
+}
+
+/*************************************
+ *
+ * C-Chip State Saving
+ *
+ *************************************/
+
+void opwolf_state::opwolf_cchip_init( )
+{
+ m_cchip_ram.allocate(0x400 * 8);
+
+ save_item(NAME(m_current_bank));
+ save_item(NAME(m_current_cmd));
+ save_item(NAME(m_cchip_last_7a));
+ save_item(NAME(m_cchip_last_04));
+ save_item(NAME(m_cchip_last_05));
+ save_item(NAME(m_c588));
+ save_item(NAME(m_c589));
+ save_item(NAME(m_c58a));
+ save_item(NAME(m_cchip_coins));
+ save_item(NAME(m_cchip_coins_for_credit));
+ save_item(NAME(m_cchip_credits_for_coin));
+ save_item(NAME(m_triggeredLevel1b));
+ save_item(NAME(m_triggeredLevel2));
+ save_item(NAME(m_triggeredLevel2b));
+ save_item(NAME(m_triggeredLevel2c));
+ save_item(NAME(m_triggeredLevel3b));
+ save_item(NAME(m_triggeredLevel13b));
+ save_item(NAME(m_triggeredLevel4));
+ save_item(NAME(m_triggeredLevel5));
+ save_item(NAME(m_triggeredLevel7));
+ save_item(NAME(m_triggeredLevel8));
+ save_item(NAME(m_triggeredLevel9));
+
+ m_triggeredLevel1b = 0;
+ m_triggeredLevel2 = 0;
+ m_triggeredLevel2b = 0;
+ m_triggeredLevel2c = 0;
+ m_triggeredLevel3b = 0;
+ m_triggeredLevel13b = 0;
+ m_triggeredLevel4 = 0;
+ m_triggeredLevel5 = 0;
+ m_triggeredLevel7 = 0;
+ m_triggeredLevel8 = 0;
+ m_triggeredLevel9 = 0;
+ m_current_bank = 0;
+ m_current_cmd = 0;
+ m_cchip_last_7a = 0;
+ m_cchip_last_04 = 0xfc;
+ m_cchip_last_05 = 0xff;
+ m_c588 = 0;
+ m_c589 = 0;
+ m_c58a = 0;
+ m_cchip_coins[0] = 0;
+ m_cchip_coins[1] = 0;
+ m_cchip_coins_for_credit[0] = 1;
+ m_cchip_credits_for_coin[0] = 1;
+ m_cchip_coins_for_credit[1] = 1;
+ m_cchip_credits_for_coin[1] = 1;
+
+ m_cchip_timer = timer_alloc(TIMER_CCHIP);
+ m_cchip_timer->adjust(attotime::from_hz(60), 0, attotime::from_hz(60));
+}
+
+
+***************************************************************************
+File: mame/drivers/opwolf.cpp
+***************************************************************************
+
+
+// map(0x0f0000, 0x0f07ff).mirror(0xf000).r(FUNC(opwolf_state::opwolf_cchip_data_r));
+// map(0x0f0802, 0x0f0803).mirror(0xf000).r(FUNC(opwolf_state::opwolf_cchip_status_r));
+// map(0x0ff000, 0x0ff7ff).w(FUNC(opwolf_state::opwolf_cchip_data_w));
+// map(0x0ff802, 0x0ff803).w(FUNC(opwolf_state::opwolf_cchip_status_w));
+// map(0x0ffc00, 0x0ffc01).w(FUNC(opwolf_state::opwolf_cchip_bank_w));
+
+// m_opwolf_timer = timer_alloc(TIMER_OPWOLF);
+
+// opwolf_cchip_init(); // start old simulation, including periodic timer
+
+
+***************************************************************************
+File: mame/includes/opwolf.h
+***************************************************************************
+
+
+enum
+{
+ TIMER_OPWOLF,
+ TIMER_CCHIP
+};
+
+DECLARE_WRITE16_MEMBER(opwolf_cchip_status_w);
+DECLARE_WRITE16_MEMBER(opwolf_cchip_bank_w);
+DECLARE_WRITE16_MEMBER(opwolf_cchip_data_w);
+DECLARE_READ16_MEMBER(opwolf_cchip_status_r);
+DECLARE_READ16_MEMBER(opwolf_cchip_data_r);
+
+virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+TIMER_CALLBACK_MEMBER(opwolf_timer_callback);
+TIMER_CALLBACK_MEMBER(cchip_timer);
+void updateDifficulty(int mode);
+void opwolf_cchip_init();
+
+emu_timer *m_opwolf_timer;
+
+/* c-chip */
+emu_timer *m_cchip_timer;
+
+int m_opwolf_region;
+
+uint8_t m_current_bank;
+uint8_t m_current_cmd;
+uint8_t m_cchip_last_7a;
+uint8_t m_cchip_last_04;
+uint8_t m_cchip_last_05;
+uint8_t m_cchip_coins_for_credit[2];
+uint8_t m_cchip_credits_for_coin[2];
+uint8_t m_cchip_coins[2];
+uint8_t m_c588;
+uint8_t m_c589;
+uint8_t m_c58a; // These variables derived from the bootleg
+uint8_t m_triggeredLevel1b; // These variables derived from comparison to unprotection version
+uint8_t m_triggeredLevel2;
+uint8_t m_triggeredLevel2b;
+uint8_t m_triggeredLevel2c;
+uint8_t m_triggeredLevel3b;
+uint8_t m_triggeredLevel13b;
+uint8_t m_triggeredLevel4;
+uint8_t m_triggeredLevel5;
+uint8_t m_triggeredLevel7;
+uint8_t m_triggeredLevel8;
+uint8_t m_triggeredLevel9;