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