1 // license:BSD-3-Clause
2 // copyright-holders:Bryan McPhail
3 /*************************************************************************
4 
5     deco_ace.cpp
6 
7     Data East 99 "ACE" Chip Emulation
8 
9     Original source (from deco32.cpp) by Bryan McPhail, Splited by cam900.
10 
11 **************************************************************************/
12 /*Some notes pieced together from Tattoo Assassins info(from deco32.cpp):
13 
14     Bytes 0 to 0x1f : Alpha Control
15     Tattoo Assassins :
16     Bytes 0x00 to 0x07(0x1c) - object alpha control per palette/priority / 8
17     Bytes 0x08(0x20) to 0x16(0x58) - used, unknown condition/purpose (possibly object)
18     Bytes 0x17(0x5c) to 0x1f(0x7c) - tilemap alpha control
19 
20     Night slashers :
21     Bytes 0x00 to 0x05(0x14) - object alpha control per palette / 2 (if ((pix & 0x900) != 0x100))
22     Bytes 0x06(0x18) to 0x16(0x58) - unused/unknown
23     Bytes 0x17(0x5c) to 0x1f(0x7c) - tilemap alpha control
24 
25     Boogie Wings:
26     Bytes 0x00 to 0x0f(0x1f) - object alpha control per palette bank (if ((pix & 0x900) == 0))
27     Bytes 0x10(0x20) to 0x11(0x26) - object alpha control per palette bit 3 (if ((pix & 0x900) == 0x100))
28     Bytes 0x12(0x20) to 0x13(0x26) - object alpha control per palette bit 3 (if ((pix & 0x900) == 0x800))
29     Bytes 0x14(0x28) to 0x19(0x32) - object alpha control per pixel (if ((pix & 0x900) == 0x900))
30     Bytes 0x1a(0x34) to 0x1e(0x3c) - unused/unknown
31     Bytes 0x1f(0x3e) - 2nd tilemap chip, 'tilemap_1' alpha control, used at shadowing
32 
33     0 = opaque, 0x10 = 50% transparent,
34     0x20 = fully transparent (doesn't make sense bitwise -AS),
35     0x22 = stage 1 boss dark effect in Boogie Wings (incorrectly emulated, reverses source pixel + shifts down by 1? -AS)
36     0x21/0x1000 = used,unknown (by what!? -AS)
37 
38     Byte 0x00: ACEO000P0
39                         P8
40                         1P0
41                         1P8
42                         O010C1
43                         o010C8
44                         ??
45 
46     Hardware fade registers:
47 
48     Byte 0x20(0x80): fadeptred
49     Byte 0x21(0x84): fadeptgreen
50     Byte 0x22(0x88): fadeptblue
51     Byte 0x23(0x8c): fadestred
52     Byte 0x24(0x90): fadestgreen
53     Byte 0x25(0x94): fadestblue
54     Byte 0x26(0x98): fadetype
55     Byte 0x27(0x9c): unused/unknown
56 
57     The 'ST' value lerps between the 'PT' value and the palette entries.  So, if PT==0,
58     then ST ranging from 0 to 255 will cause a fade to black (when ST==255 the palette
59     becomes zero).
60 
61     'fadetype' - 1100 for multiplicative fade, 1000 for additive
62 
63     TODO:
64         additive fade is correct? verify additive fading from real pcb.
65 */
66 
67 
68 #include "emu.h"
69 #include "video/deco_ace.h"
70 #include <algorithm>
71 
72 
73 DEFINE_DEVICE_TYPE(DECO_ACE, deco_ace_device, "deco_ace", "Data East 99 'ACE' Chip")
74 
deco_ace_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)75 deco_ace_device::deco_ace_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
76 	: device_t(mconfig, DECO_ACE, tag, owner, clock),
77 	device_video_interface(mconfig, *this),
78 	device_palette_interface(mconfig, *this),
79 	m_paletteram(nullptr),
80 	m_paletteram_buffered(nullptr),
81 	m_ace_ram(nullptr)
82 {
83 }
84 
85 //-------------------------------------------------
86 //  device_start - device-specific startup
87 //-------------------------------------------------
88 
device_start()89 void deco_ace_device::device_start()
90 {
91 	m_paletteram = make_unique_clear<uint32_t[]>(2048);
92 	m_paletteram_buffered = make_unique_clear<uint32_t[]>(2048);
93 	m_ace_ram = make_unique_clear<uint16_t[]>(0x28);
94 
95 	save_pointer(NAME(m_paletteram), 2048);
96 	save_pointer(NAME(m_paletteram_buffered), 2048);
97 	save_pointer(NAME(m_ace_ram), 0x28);
98 }
99 
100 //-------------------------------------------------
101 //  device_reset - device-specific reset
102 //-------------------------------------------------
103 
device_reset()104 void deco_ace_device::device_reset()
105 {
106 	memset(m_ace_ram.get(),0,0x28);
107 }
108 
109 //-------------------------------------------------
110 //  device_post_load - device-specific post-load
111 //-------------------------------------------------
112 
device_post_load()113 void deco_ace_device::device_post_load()
114 {
115 	palette_update();
116 }
117 
118 /*****************************************************************************
119     DEVICE HANDLERS
120 *****************************************************************************/
121 
122 /* Games have double buffered paletteram - the real palette ram is
123 only updated on a DMA call */
124 
125 // nslasher
buffered_palette_r(offs_t offset)126 uint32_t deco_ace_device::buffered_palette_r(offs_t offset)
127 {
128 	return m_paletteram[offset];
129 }
130 
buffered_palette_w(offs_t offset,uint32_t data,uint32_t mem_mask)131 void deco_ace_device::buffered_palette_w(offs_t offset, uint32_t data, uint32_t mem_mask)
132 {
133 	COMBINE_DATA(&m_paletteram[offset]);
134 }
135 
136 // boogwing has 16 bit cpu data bus(M68000 Based)
buffered_palette16_r(offs_t offset)137 uint16_t deco_ace_device::buffered_palette16_r(offs_t offset)
138 {
139 	if ((offset & 1) == 0)
140 		return (m_paletteram[offset >> 1] >> 16) & 0xffff;
141 	else
142 		return m_paletteram[offset >> 1] & 0xffff;
143 }
144 
buffered_palette16_w(offs_t offset,uint16_t data,uint16_t mem_mask)145 void deco_ace_device::buffered_palette16_w(offs_t offset, uint16_t data, uint16_t mem_mask)
146 {
147 	if ((offset & 1) == 0)
148 		m_paletteram[offset >> 1] = (m_paletteram[offset >> 1] & ~(mem_mask<<16)) | ((data & mem_mask)<<16);
149 	else
150 		m_paletteram[offset >> 1] = (m_paletteram[offset >> 1] & ~mem_mask) | (data & mem_mask);
151 }
152 
ace_r(offs_t offset)153 uint16_t deco_ace_device::ace_r(offs_t offset)
154 {
155 	return m_ace_ram[offset];
156 }
157 
ace_w(offs_t offset,uint16_t data,uint16_t mem_mask)158 void deco_ace_device::ace_w(offs_t offset, uint16_t data, uint16_t mem_mask)
159 {
160 	COMBINE_DATA(&m_ace_ram[offset]);
161 	if ((offset >= 0x20) && (offset <= 0x26))
162 		palette_update();
163 }
164 
palette_update()165 void deco_ace_device::palette_update()
166 {
167 	int fadeptr=m_ace_ram[0x20] & 0xff;
168 	int fadeptg=m_ace_ram[0x21] & 0xff;
169 	int fadeptb=m_ace_ram[0x22] & 0xff;
170 	int fadepsr=m_ace_ram[0x23] & 0xff;
171 	int fadepsg=m_ace_ram[0x24] & 0xff;
172 	int fadepsb=m_ace_ram[0x25] & 0xff;
173 	uint16_t mode=m_ace_ram[0x26] & 0xffff;
174 
175 	for (int i = 0; i < 2048; i++)
176 	{
177 		/* Lerp palette entry to 'fadept' according to 'fadeps' */
178 		int b = (m_paletteram_buffered[i] >>16) & 0xff;
179 		int g = (m_paletteram_buffered[i] >> 8) & 0xff;
180 		int r = (m_paletteram_buffered[i] >> 0) & 0xff;
181 		set_pen_color(i + 2048, rgb_t(r, g, b)); // raw palettes
182 
183 		switch (mode)
184 		{
185 			default:
186 			case 0x1100: // multiplicative fade
187 				/* Yeah, this should really be fixed point, I know */
188 				b = std::max<int>(0, std::min<int>(255, u8((b + (((fadeptb - b) * fadepsb) / 255)))));
189 				g = std::max<int>(0, std::min<int>(255, u8((g + (((fadeptg - g) * fadepsg) / 255)))));
190 				r = std::max<int>(0, std::min<int>(255, u8((r + (((fadeptr - r) * fadepsr) / 255)))));
191 				break;
192 			case 0x1000: // additive fade, correct?
193 				b = std::min(b + fadepsb, 0xff);
194 				g = std::min(g + fadepsg, 0xff);
195 				r = std::min(r + fadepsr, 0xff);
196 				break;
197 		}
198 		set_pen_color(i, rgb_t(r, g, b)); // faded palettes
199 	}
200 }
201 
202 /*************************************************************************
203 
204     get_alpha : Get alpha value (ACE RAM Area 0x00 - 0x1f)
205 
206 *************************************************************************/
207 
get_alpha(uint8_t val)208 uint8_t deco_ace_device::get_alpha(uint8_t val)
209 {
210 	val &= 0x1f;
211 	int alpha = m_ace_ram[val] & 0xff;
212 	if (alpha > 0x20)
213 	{
214 		return 0x80; // TODO : Special blending command? 0x21, 0x22, 0x1000 confirmed
215 	}
216 	else
217 	{
218 		alpha = 255 - (alpha << 3);
219 		if (alpha < 0)
220 			alpha = 0;
221 
222 		return (uint8_t)alpha;
223 	}
224 }
225 
226 /*************************************************************************
227 
228     get_aceram : Get ACE RAM value
229 
230 *************************************************************************/
231 
get_aceram(uint8_t val)232 uint16_t deco_ace_device::get_aceram(uint8_t val)
233 {
234 	if (val >= 0x28)
235 		return 0;
236 
237 	return m_ace_ram[val];
238 }
239 
palette_dma_w(uint16_t data)240 void deco_ace_device::palette_dma_w(uint16_t data)
241 {
242 	std::copy(&m_paletteram[0], &m_paletteram[2048], &m_paletteram_buffered[0]);
243 	palette_update();
244 }
245 
246 /*****************************************************************************************/
247