1 // license:BSD-3-Clause
2 // copyright-holders:Alex W. Jackson
3 /*
4 Namco Custom 116, used in:
5 System 1
6 System 2
7 NB-1/NB-2
8 System FL
9 
10 C116 controls palette RAM, blanking/clipping, and generates raster IRQs.
11 It is paired with one of two priority mixer chips, depending on the board.
12 On System 1, its partner is Custom 120; on System 2, NB-1, NB-2, and System
13 FL, its partner is Custom 156. Based on schematics, C156 has more color input
14 pins than C120 in order to support sprites with higher bit depth; other
15 differences between the two mixer chips are unknown.
16 
17 The mixer (C120 or C156) outputs a 13-bit address corresponding to the color
18 index of the highest-priority input pixel to three 6264 SRAMs, one for each of
19 red, green and blue. The data from the RAMs is output to C116, which either
20 sends it to the DAC or clips it to black if the beam position is outside the
21 visible area programmed via its registers.
22 
23 When accessing the palette RAM from the CPU, data lines D0-D7 and address lines
24 A11 and A12 go to C116; these two address lines select between the three RAMs
25 and the C116 internal registers. A0-A10, A13 and A14 go to C120 or C156, which
26 simply pass them through to the RAMs (A13 becoming A11 and A14 becoming A12).
27 Thus, the palette RAM and the C116 registers are laid out like this from the
28 perspective of the CPU:
29 
30 0000-07FF: Red   (first 2048 pens)
31 0800-0FFF: Green ("")
32 1000-17FF: Blue  ("")
33 1800-1FFF: C116 registers
34 2000-27FF: Red   (second 2048 pens)
35 2800-2FFF: Green ("")
36 3000-37FF: Blue  ("")
37 3800-3FFF: C116 registers (mirror)
38 4000-47FF: Red   (third 2048 pens)
39 4800-4FFF: Green ("")
40 5000-57FF: Blue  ("")
41 5800-5FFF: C116 registers (mirror)
42 6000-67FF: Red (last 2048 pens)
43 6800-6FFF: Green ("")
44 7000-77FF: Blue  ("")
45 7800-7FFF: C116 registers (mirror)
46 
47 C116 has six (or eight?) 16-bit registers:
48 
49 00-01: left clip
50 02-03: right clip
51 04-05: top clip
52 06-07: bottom clip
53 08-09: raster IRQ horizontal position?
54 0A-0B: raster IRQ scanline
55 0C-0D: unknown, some games write 0 here, but probably unused
56 0E-0F: ""
57 
58 The registers are mirrored every 0x10 bytes within the address ranges
59 indicated above.
60 
61 Although the registers are logically 16-bit, the chip's external interface
62 is 8-bit, so the registers are written a byte at a time and in a big-endian
63 fashion (even addresses access the MSB and odd addresses access the LSB)
64 regardless of the endianness of the CPU. Thus System FL, which has an Intel
65 i960 CPU, needs to write its clip and raster values byteswapped.
66 */
67 
68 #include "emu.h"
69 #include "video/namco_c116.h"
70 
71 #include <algorithm>
72 
73 DEFINE_DEVICE_TYPE(NAMCO_C116, namco_c116_device, "namco_c116", "Namco C116 Video Controller")
74 
75 //-------------------------------------------------
76 //  namco_c116_device -- constructor
77 //-------------------------------------------------
78 
namco_c116_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)79 namco_c116_device::namco_c116_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
80 	: device_t(mconfig, NAMCO_C116, tag, owner, clock)
81 	, device_palette_interface(mconfig, *this)
82 	, device_video_interface(mconfig, *this)
83 	, m_enable_shadows(false)
84 {
85 }
86 
87 
88 //-------------------------------------------------
89 //  device_start - device-specific startup
90 //-------------------------------------------------
91 
device_start()92 void namco_c116_device::device_start()
93 {
94 	m_ram_r.resize(0x2000);
95 	m_ram_g.resize(0x2000);
96 	m_ram_b.resize(0x2000);
97 	std::fill(std::begin(m_regs), std::end(m_regs), 0);
98 
99 	save_item(NAME(m_ram_r));
100 	save_item(NAME(m_ram_g));
101 	save_item(NAME(m_ram_b));
102 	save_item(NAME(m_regs));
103 }
104 
105 
read(offs_t offset)106 uint8_t namco_c116_device::read(offs_t offset)
107 {
108 	uint8_t *RAM;
109 
110 	switch (offset & 0x1800)
111 	{
112 		case 0x0000:
113 			RAM = &m_ram_r[0];
114 			break;
115 		case 0x0800:
116 			RAM = &m_ram_g[0];
117 			break;
118 		case 0x1000:
119 			RAM = &m_ram_b[0];
120 			break;
121 		default: // case 0x1800 (internal registers)
122 		{
123 			int reg = (offset & 0xf) >> 1;
124 			if (offset & 1)
125 				return m_regs[reg] & 0xff;
126 			else
127 				return m_regs[reg] >> 8;
128 		/* registers 6,7: unmapped? */
129 		//if (reg > 0x6) return 0xff;
130 		}
131 	}
132 
133 	return RAM[((offset & 0x6000) >> 2) | (offset & 0x7ff)];
134 }
135 
136 
write(offs_t offset,uint8_t data)137 void namco_c116_device::write(offs_t offset, uint8_t data)
138 {
139 	uint8_t *RAM;
140 
141 	switch (offset & 0x1800)
142 	{
143 		case 0x0000:
144 			RAM = &m_ram_r[0];
145 			break;
146 		case 0x0800:
147 			RAM = &m_ram_g[0];
148 			break;
149 		case 0x1000:
150 			RAM = &m_ram_b[0];
151 			break;
152 		default: // case 0x1800 (internal registers)
153 		{   /* notes from namcos2.cpp */
154 			/* registers 0-3: clipping */
155 
156 			/* register 4: ? */
157 			/* sets using it:
158 			assault:    $0020
159 			burnforc:   $0130 after titlescreen
160 			dirtfoxj:   $0108 at game start
161 			finalap1/2/3:   $00C0
162 			finehour:   $0168 after titlescreen
163 			fourtrax:   $00E8 and $00F0
164 			luckywld:   $00E8 at titlescreen, $00A0 in game and $0118 if in tunnel
165 			suzuka8h1/2:    $00E8 and $00A0 */
166 
167 			/* register 5: POSIRQ scanline (only 8 bits used) */
168 
169 			/* registers 6,7: nothing? */
170 			int reg = (offset & 0xf) >> 1;
171 			if (offset & 1)
172 				m_regs[reg] = (m_regs[reg] & 0xff00) | data;
173 			else
174 				m_regs[reg] = (m_regs[reg] & 0x00ff) | (data << 8);
175 			//logerror("reg%d = %d\n", reg, m_regs[reg]);
176 			return;
177 		}
178 	}
179 	int color = ((offset & 0x6000) >> 2) | (offset & 0x7ff);
180 	RAM[color] = data;
181 	set_pen_color(color,m_ram_r[color],m_ram_g[color],m_ram_b[color]);
182 }
183