summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/namco50.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/namco50.c')
-rw-r--r--src/mame/machine/namco50.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/src/mame/machine/namco50.c b/src/mame/machine/namco50.c
new file mode 100644
index 00000000000..bd519a73594
--- /dev/null
+++ b/src/mame/machine/namco50.c
@@ -0,0 +1,338 @@
+/***************************************************************************
+
+Namco 50XX
+
+This custom chip is a Fujitsu MB8842 MCU programmed to act as a protection
+device. It keeps track of the players scores, and checks if a high score has
+been obtained or bonus lives should be awarded. The main CPU has a range of
+commands to increment/decrement the score by various fixed amounts.
+
+The device is used to its full potential only by Bosconian; Xevious uses it
+too, but only to do a protection check on startup.
+
+CMD = command from main CPU
+ANS = answer to main CPU
+
+The chip reads/writes the I/O ports when the /IRQ is pulled down. Pin 21
+determines whether a read or write should happen (1=R, 0=W).
+
+ +------+
+ EXTAL|1 28|Vcc
+ XTAL|2 27|CMD7
+/RESET|3 26|CMD6
+ ANS0|4 25|CMD5
+ ANS1|5 24|CMD4
+ ANS2|6 23|/IRQ
+ ANS3|7 22|n.c.
+ ANS4|8 21|R/W
+ ANS5|9 20|n.c.
+ ANS6|10 19|n.c.
+ ANS7|11 18|n.c.
+ CMD0|12 17|n.c.
+ CMD1|13 16|CMD3
+ GND|14 15|CMD2
+ +------+
+
+
+
+Commands:
+
+0x = nop
+
+1x = reset scores
+
+2x = set first bonus score (followed by 3 bytes)
+
+3x = set interval bonus score (followed by 3 bytes)
+
+4x = ?
+
+5x = set high score (followed by 3 bytes)
+
+60 = switch to player 1
+68 = switch to player 2
+
+70 = switch to increment score
+7x = switch to decrement score
+
+score increments/decrements:
+
+80 = 5
+81 = 10
+82 = 15
+83 = 20
+84 = 25
+85 = 30
+86 = 40
+87 = 50
+88 = 60
+89 = 70
+8A = 80
+8B = 90
+8C = 100
+8D = 200
+8E = 300
+8F = 500
+
+9x same as 8x but *10
+Ax same as 8x but *100
+
+B0h = 10
+B1h = 20
+B2h = 30
+B3h = 40
+B4h = 50
+B5h = 60
+B6h = 80
+B7h = 100
+B8h = 120
+B9h = 140
+BAh = 160
+BBh = 180
+BCh = 200
+BDh = 400
+BEh = 600
+BFh = 1000
+
+Cx same as Bx but *10
+Dx same as Bx but *100
+
+E0 = 15
+E1 = 30
+E2 = 45
+E3 = 60
+E4 = 75
+E5 = 90
+E6 = 120
+E7 = 150
+E8 = 180
+E9 = 210
+EA = 240
+EB = 270
+EC = 300
+ED = 600
+EE = 900
+EF = 1500
+
+Fx same as Ex but *10
+
+
+When reading, the score for the currently selected player is returned. The first
+byte also contains flags.
+
+Byte 0: BCD Score (fs------) and flags
+Byte 1: BCD Score (--ss----)
+Byte 2: BCD Score (----ss--)
+Byte 3: BCD Score (------ss)
+
+Flags: 80=high score, 40=first bonus, 20=interval bonus, 10=?
+
+***************************************************************************/
+
+#include "driver.h"
+#include "namco50.h"
+#include "cpu/mb88xx/mb88xx.h"
+
+
+static UINT8 latched_cmd[2];
+static UINT8 latched_rw[2];
+static UINT8 portO[2];
+
+
+static TIMER_CALLBACK( namco_50xx_latch_callback )
+{
+ latched_cmd[0] = param;
+ latched_rw[0] = 1;
+}
+
+static TIMER_CALLBACK( namco_50xx_2_latch_callback )
+{
+ latched_cmd[1] = param;
+ latched_rw[1] = 1;
+}
+
+
+static TIMER_CALLBACK( namco_50xx_readrequest_callback )
+{
+ latched_rw[0] = 0;
+}
+
+static TIMER_CALLBACK( namco_50xx_2_readrequest_callback )
+{
+ latched_rw[1] = 0;
+}
+
+
+static READ8_HANDLER( namco_50xx_K_r )
+{
+ return latched_cmd[0] >> 4;
+}
+
+static READ8_HANDLER( namco_50xx_R0_r )
+{
+ return latched_cmd[0] & 0x0f;
+}
+
+static READ8_HANDLER( namco_50xx_R2_r )
+{
+ return latched_rw[0] & 1;
+}
+
+
+
+static READ8_HANDLER( namco_50xx_2_K_r )
+{
+ return latched_cmd[1] >> 4;
+}
+
+static READ8_HANDLER( namco_50xx_2_R0_r )
+{
+ return latched_cmd[1] & 0x0f;
+}
+
+static READ8_HANDLER( namco_50xx_2_R2_r )
+{
+ return latched_rw[1] & 1;
+}
+
+
+static WRITE8_HANDLER( namco_50xx_O_w )
+{
+ UINT8 out = (data & 0x0f);
+ if (data & 0x10)
+ portO[0] = (portO[0] & 0x0f) | (out << 4);
+ else
+ portO[0] = (portO[0] & 0xf0) | (out);
+}
+
+
+
+static WRITE8_HANDLER( namco_50xx_2_O_w )
+{
+ UINT8 out = (data & 0x0f);
+ if (data & 0x10)
+ portO[1] = (portO[1] & 0x0f) | (out << 4);
+ else
+ portO[1] = (portO[1] & 0xf0) | (out);
+}
+
+
+
+ADDRESS_MAP_START( namco_50xx_map_program, ADDRESS_SPACE_PROGRAM, 8 )
+ AM_RANGE(0x000, 0x7ff) AM_ROM
+ADDRESS_MAP_END
+
+ADDRESS_MAP_START( namco_50xx_map_data, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x7f) AM_RAM
+ADDRESS_MAP_END
+
+ADDRESS_MAP_START( namco_50xx_map_io, ADDRESS_SPACE_IO, 8 )
+ AM_RANGE(MB88_PORTK, MB88_PORTK) AM_READ(namco_50xx_K_r)
+ AM_RANGE(MB88_PORTO, MB88_PORTO) AM_WRITE(namco_50xx_O_w)
+ AM_RANGE(MB88_PORTR0, MB88_PORTR0) AM_READ(namco_50xx_R0_r)
+ AM_RANGE(MB88_PORTR2, MB88_PORTR2) AM_READ(namco_50xx_R2_r)
+ADDRESS_MAP_END
+
+
+
+ADDRESS_MAP_START( namco_50xx_2_map_program, ADDRESS_SPACE_PROGRAM, 8 )
+ AM_RANGE(0x000, 0x7ff) AM_ROM
+ADDRESS_MAP_END
+
+ADDRESS_MAP_START( namco_50xx_2_map_data, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x7f) AM_RAM
+ADDRESS_MAP_END
+
+ADDRESS_MAP_START( namco_50xx_2_map_io, ADDRESS_SPACE_IO, 8 )
+ AM_RANGE(MB88_PORTK, MB88_PORTK) AM_READ(namco_50xx_2_K_r)
+ AM_RANGE(MB88_PORTO, MB88_PORTO) AM_WRITE(namco_50xx_2_O_w)
+ AM_RANGE(MB88_PORTR0, MB88_PORTR0) AM_READ(namco_50xx_2_R0_r)
+ AM_RANGE(MB88_PORTR2, MB88_PORTR2) AM_READ(namco_50xx_2_R2_r)
+ADDRESS_MAP_END
+
+
+
+static TIMER_CALLBACK( namco_50xx_irq_clear )
+{
+ cpunum_set_input_line(param, 0, CLEAR_LINE);
+}
+
+static void namco_50xx_irq_set(int cpunum)
+{
+ cpunum_set_input_line(cpunum, 0, ASSERT_LINE);
+
+ // The execution time of one instruction is ~4us, so we must make sure to
+ // give the cpu time to poll the /IRQ input before we clear it.
+ // The input clock to the 06XX interface chip is 64H, that is
+ // 18432000/6/64 = 48kHz, so it makes sense for the irq line to be
+ // asserted for one clock cycle ~= 21us.
+ timer_set(ATTOTIME_IN_USEC(21), cpunum, namco_50xx_irq_clear);
+}
+
+void namco_50xx_write(UINT8 data)
+{
+ int cpunum = mame_find_cpu_index(Machine, CPUTAG_50XX);
+
+ if (cpunum == -1)
+ return;
+
+ timer_call_after_resynch(data, namco_50xx_latch_callback);
+
+ namco_50xx_irq_set(cpunum);
+}
+
+void namco_50xx_2_write(UINT8 data)
+{
+ int cpunum = mame_find_cpu_index(Machine, CPUTAG_50XX_2);
+
+ if (cpunum == -1)
+ return;
+
+ timer_call_after_resynch(data, namco_50xx_2_latch_callback);
+
+ namco_50xx_irq_set(cpunum);
+}
+
+
+void namco_50xx_read_request(void)
+{
+ int cpunum = mame_find_cpu_index(Machine, CPUTAG_50XX);
+
+ if (cpunum == -1)
+ return;
+
+ timer_call_after_resynch(0, namco_50xx_readrequest_callback);
+
+ namco_50xx_irq_set(cpunum);
+}
+
+void namco_50xx_2_read_request(void)
+{
+ int cpunum = mame_find_cpu_index(Machine, CPUTAG_50XX_2);
+
+ if (cpunum == -1)
+ return;
+
+ timer_call_after_resynch(0, namco_50xx_2_readrequest_callback);
+
+ namco_50xx_irq_set(cpunum);
+}
+
+
+UINT8 namco_50xx_read(void)
+{
+ UINT8 res = portO[0];
+
+ namco_50xx_read_request();
+
+ return res;
+}
+
+UINT8 namco_50xx_2_read(void)
+{
+ UINT8 res = portO[1];
+
+ namco_50xx_2_read_request();
+
+ return res;
+}