summaryrefslogtreecommitdiffstats
path: root/src/mame/video/namco_c116.cpp
blob: 2f519eba05da90a8249a0d4f57b6a2fff648d12b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// license:BSD-3-Clause
// copyright-holders:Alex W. Jackson
/*
Namco Custom 116, used in:
System 1
System 2
NB-1/NB-2
System FL

C116 controls palette RAM, blanking/clipping, and generates raster IRQs.
It is paired with one of two priority mixer chips, depending on the board.
On System 1, its partner is Custom 120; on System 2, NB-1, NB-2, and System
FL, its partner is Custom 156. Based on schematics, C156 has more color input
pins than C120 in order to support sprites with higher bit depth; other
differences between the two mixer chips are unknown.

The mixer (C120 or C156) outputs a 13-bit address corresponding to the color
index of the highest-priority input pixel to three 6264 SRAMs, one for each of
red, green and blue. The data from the RAMs is output to C116, which either
sends it to the DAC or clips it to black if the beam position is outside the
visible area programmed via its registers.

When accessing the palette RAM from the CPU, data lines D0-D7 and address lines
A11 and A12 go to C116; these two address lines select between the three RAMs
and the C116 internal registers. A0-A10, A13 and A14 go to C120 or C156, which
simply pass them through to the RAMs (A13 becoming A11 and A14 becoming A12).
Thus, the palette RAM and the C116 registers are laid out like this from the
perspective of the CPU:

0000-07FF: Red   (first 2048 pens)
0800-0FFF: Green ("")
1000-17FF: Blue  ("")
1800-1FFF: C116 registers
2000-27FF: Red   (second 2048 pens)
2800-2FFF: Green ("")
3000-37FF: Blue  ("")
3800-3FFF: C116 registers (mirror)
4000-47FF: Red   (third 2048 pens)
4800-4FFF: Green ("")
5000-57FF: Blue  ("")
5800-5FFF: C116 registers (mirror)
6000-67FF: Red (last 2048 pens)
6800-6FFF: Green ("")
7000-77FF: Blue  ("")
7800-7FFF: C116 registers (mirror)

C116 has six (or eight?) 16-bit registers:

00-01: left clip
02-03: right clip
04-05: top clip
06-07: bottom clip
08-09: raster IRQ horizontal position?
0A-0B: raster IRQ scanline
0C-0D: unknown, some games write 0 here, but probably unused
0E-0F: ""

The registers are mirrored every 0x10 bytes within the address ranges
indicated above.

Although the registers are logically 16-bit, the chip's external interface
is 8-bit, so the registers are written a byte at a time and in a big-endian
fashion (even addresses access the MSB and odd addresses access the LSB)
regardless of the endianness of the CPU. Thus System FL, which has an Intel
i960 CPU, needs to write its clip and raster values byteswapped.
*/

#include "emu.h"
#include "video/namco_c116.h"

DEFINE_DEVICE_TYPE(NAMCO_C116, namco_c116_device, "namco_c116", "Namco C116 Video Controller")

//-------------------------------------------------
//  namco_c116_device -- constructor
//-------------------------------------------------

namco_c116_device::namco_c116_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, NAMCO_C116, tag, owner, clock),
		device_gfx_interface(mconfig, *this),
		device_video_interface(mconfig, *this)
{
}


//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void namco_c116_device::device_start()
{
	m_ram_r.resize(0x2000);
	m_ram_g.resize(0x2000);
	m_ram_b.resize(0x2000);
	memset(m_regs, 0, sizeof(m_regs));

	save_item(NAME(m_ram_r));
	save_item(NAME(m_ram_g));
	save_item(NAME(m_ram_b));
	save_item(NAME(m_regs));
}


READ8_MEMBER(namco_c116_device::read)
{
	uint8_t *RAM;

	switch (offset & 0x1800)
	{
		case 0x0000:
			RAM = &m_ram_r[0];
			break;
		case 0x0800:
			RAM = &m_ram_g[0];
			break;
		case 0x1000:
			RAM = &m_ram_b[0];
			break;
		default: // case 0x1800 (internal registers)
		{
			int reg = (offset & 0xf) >> 1;
			if (offset & 1)
				return m_regs[reg] & 0xff;
			else
				return m_regs[reg] >> 8;
		/* registers 6,7: unmapped? */
		//if (reg > 0x6) return 0xff;
		}
	}

	return RAM[((offset & 0x6000) >> 2) | (offset & 0x7ff)];
}


WRITE8_MEMBER(namco_c116_device::write)
{
	uint8_t *RAM;

	switch (offset & 0x1800)
	{
		case 0x0000:
			RAM = &m_ram_r[0];
			break;
		case 0x0800:
			RAM = &m_ram_g[0];
			break;
		case 0x1000:
			RAM = &m_ram_b[0];
			break;
		default: // case 0x1800 (internal registers)
		{   /* notes from namcos2.cpp */
			/* registers 0-3: clipping */

			/* register 4: ? */
			/* sets using it:
			assault:    $0020
			burnforc:   $0130 after titlescreen
			dirtfoxj:   $0108 at game start
			finalap1/2/3:   $00C0
			finehour:   $0168 after titlescreen
			fourtrax:   $00E8 and $00F0
			luckywld:   $00E8 at titlescreen, $00A0 in game and $0118 if in tunnel
			suzuka8h1/2:    $00E8 and $00A0 */

			/* register 5: POSIRQ scanline (only 8 bits used) */

			/* registers 6,7: nothing? */
			int reg = (offset & 0xf) >> 1;
			if (offset & 1)
				m_regs[reg] = (m_regs[reg] & 0xff00) | data;
			else
				m_regs[reg] = (m_regs[reg] & 0x00ff) | (data << 8);
			//logerror("reg%d = %d\n", reg, m_regs[reg]);
			return;
		}
	}
	int color = ((offset & 0x6000) >> 2) | (offset & 0x7ff);
	RAM[color] = data;
	palette().set_pen_color(color,m_ram_r[color],m_ram_g[color],m_ram_b[color]);
}