1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz
3 /***************************************************************************
4 
5     dpb_combiner.cpp
6     DPB-7000/1 - Combiner Card
7 
8 ***************************************************************************/
9 
10 #include "emu.h"
11 #include "dpb_combiner.h"
12 
13 #define VERBOSE (1)
14 #include "logmacro.h"
15 
16 /*****************************************************************************/
17 
18 DEFINE_DEVICE_TYPE(DPB7000_COMBINER, dpb7000_combiner_card_device, "dpb_combiner", "Quantel DPB-7000 Combiner Card")
19 
20 
21 //-------------------------------------------------
22 //  dpb7000_combiner_card_device - constructor
23 //-------------------------------------------------
24 
dpb7000_combiner_card_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)25 dpb7000_combiner_card_device::dpb7000_combiner_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
26 	: device_t(mconfig, DPB7000_COMBINER, tag, owner, clock)
27 	, m_latched_lum_sum(0)
28 	, m_latched_chr_sum(0)
29 	, m_lum_out(0)
30 	, m_chr_out(0)
31 	, m_chr_i_in(false)
32 	, m_chr_i(false)
33 	, m_palette_l(false)
34 	, m_cursor_enb(false)
35 	, m_cursor_col(false)
36 	, m_fsck(false)
37 	, m_cursor_y(0)
38 	, m_cursor_u(0)
39 	, m_cursor_v(0)
40 	, m_invert_mask(0)
41 	, m_lum(*this)
42 	, m_chr(*this)
43 	, m_fsck_timer(nullptr)
44 	//, m_screen(*this, "screen")
45 	, m_mult_ge(*this, "mult_ge") // Lum I
46 	, m_mult_gd(*this, "mult_gd") // Lum II
47 	, m_mult_gc(*this, "mult_gc") // Chroma I
48 	, m_mult_gb(*this, "mult_gb") // Chroma II
49 	, m_mult_ga(*this, "mult_ga") // Ext I & II
50 {
51 }
52 
device_start()53 void dpb7000_combiner_card_device::device_start()
54 {
55 	save_item(NAME(m_lum_in));
56 	save_item(NAME(m_latched_lum));
57 	save_item(NAME(m_selected_lum));
58 	save_item(NAME(m_chr_in));
59 	save_item(NAME(m_latched_chr));
60 	save_item(NAME(m_selected_chr));
61 	save_item(NAME(m_ext_in));
62 
63 	save_item(NAME(m_blank));
64 	save_item(NAME(m_chr_i_in));
65 	save_item(NAME(m_chr_i));
66 	save_item(NAME(m_palette_l));
67 	save_item(NAME(m_cursor_enb));
68 	save_item(NAME(m_cursor_col));
69 	save_item(NAME(m_fsck));
70 
71 	save_item(NAME(m_cursor_y));
72 	save_item(NAME(m_cursor_u));
73 	save_item(NAME(m_cursor_v));
74 	save_item(NAME(m_invert_mask));
75 	save_item(NAME(m_select_matte));
76 	save_item(NAME(m_matte_ext));
77 	save_item(NAME(m_matte_y));
78 	save_item(NAME(m_matte_u));
79 	save_item(NAME(m_matte_v));
80 
81 	save_item(NAME(m_blank_or_suppress));
82 	save_item(NAME(m_output_matte_y));
83 	save_item(NAME(m_output_matte_u));
84 	save_item(NAME(m_output_matte_v));
85 	save_item(NAME(m_output_matte_ext));
86 
87 	m_lum.resolve_safe();
88 	m_chr.resolve_safe();
89 
90 	m_fsck_timer = timer_alloc(FSCK_TIMER);
91 	m_fsck_timer->adjust(attotime::never);
92 }
93 
device_reset()94 void dpb7000_combiner_card_device::device_reset()
95 {
96 	memset(m_lum_in, 0, 2);
97 	memset(m_latched_lum, 0, 2);
98 	memset(m_selected_lum, 0, 2);
99 	memset(m_chr_in, 0, 2);
100 	memset(m_latched_chr, 0, 2);
101 	memset(m_selected_lum, 0, 2);
102 	memset(m_ext_in, 0, 2);
103 
104 	memset(m_blank, 0, 2);
105 	m_chr_i_in = false;
106 	m_chr_i = false;
107 	m_palette_l = false;
108 	m_cursor_enb = false;
109 	m_cursor_col = false;
110 	m_fsck = false;
111 
112 	memset(m_blank_or_suppress, 0, 2);
113 	memset(m_output_matte_y, 0, 2);
114 	memset(m_output_matte_u, 0, 2);
115 	memset(m_output_matte_v, 0, 2);
116 	memset(m_output_matte_ext, 0, 2);
117 
118 	m_cursor_y = 0;
119 	m_cursor_u = 0;
120 	m_cursor_v = 0;
121 	m_invert_mask = 0;
122 	memset(m_select_matte, 0, 2);
123 	memset(m_matte_ext, 0, 2);
124 	memset(m_matte_y, 0, 2);
125 	memset(m_matte_u, 0, 2);
126 	memset(m_matte_v, 0, 2);
127 
128 	m_fsck_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
129 }
130 
device_add_mconfig(machine_config & config)131 void dpb7000_combiner_card_device::device_add_mconfig(machine_config &config)
132 {
133 	TMC28KU(config, m_mult_ge);
134 	TMC28KU(config, m_mult_gd);
135 	TMC28KU(config, m_mult_gc);
136 	TMC28KU(config, m_mult_gb);
137 	TMC28KU(config, m_mult_ga);
138 
139 	//SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
140 	//m_screen->set_raw(DERIVED_CLOCK(1, 1), 910, 0, 640, 525, 0, 480);
141 	//m_screen->set_screen_update(FUNC(dpb7000_combiner_card_device::screen_update));
142 }
143 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)144 void dpb7000_combiner_card_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
145 {
146 	if (id == FSCK_TIMER)
147 	{
148 		m_fsck = !m_fsck;
149 		if (m_fsck)
150 		{
151 			fsck_tick();
152 		}
153 	}
154 }
155 
fsck_tick()156 void dpb7000_combiner_card_device::fsck_tick()
157 {
158 	for (int i = 0; i < 2; i++)
159 	{
160 		m_latched_lum[i] = m_lum_in[i];
161 		m_latched_chr[i] = m_chr_in[i];
162 		m_selected_lum[i] = m_output_matte_y[i] ? m_matte_y[i] : m_latched_lum[i];
163 		m_selected_chr[i] = m_output_matte_u[i] ? m_matte_u[i] : (m_output_matte_v[i] ? m_matte_v[i] : m_latched_chr[i]);
164 		m_selected_ext[i] = m_output_matte_ext[i] ? m_matte_ext[i] : m_ext_in[i];
165 	}
166 
167 	// MPY-8HUJ GA
168 	const uint8_t ext_product = m_palette_l ? (((uint16_t)m_selected_ext[0] * (uint16_t)m_selected_ext[1] + 0x80) >> 8) : 0xff;
169 
170 	// 74LS175 FF and 74S157 FG
171 	const bool y1 = (bool)(m_palette_l ? BIT(m_invert_mask, 3) : BIT(m_invert_mask, 4));
172 	const bool y2 = !y1;
173 
174 	// 74S86 EE/EF/FD/FE
175 	const uint8_t a = ext_product ^ (y1 ? 0xff : 0x00);
176 	const uint8_t b = ext_product ^ (y2 ? 0xff : 0x00);
177 
178 	// MPY-8HUJ GE
179 	const uint8_t lum1_product = ((uint16_t)m_selected_lum[0] * (uint16_t)a + 0x80) >> 8;
180 
181 	// MPY-8HUJ GD
182 	const uint8_t lum2_product = ((uint16_t)m_selected_lum[1] * (uint16_t)b + 0x80) >> 8;
183 
184 	// MPY-8HUJ GC
185 	const uint8_t chr1_product = ((uint16_t)m_selected_chr[0] * (uint16_t)a + 0x80) >> 8;
186 
187 	// MPY-8HUJ GB
188 	const uint8_t chr2_product = ((uint16_t)m_selected_chr[1] * (uint16_t)b + 0x80) >> 8;
189 
190 	// 74S283 FC/ED, 74S374 DD
191 	m_latched_lum_sum = lum1_product + lum2_product;
192 
193 	// 74S283 FB/EC, 74S374 DC
194 	m_latched_chr_sum = chr1_product + chr2_product;
195 
196 	m_lum_out = m_cursor_enb ? (m_cursor_col ? (m_chr_i ? m_cursor_u : m_cursor_v) : 0x7f) : m_latched_lum_sum;
197 	m_chr_out = m_cursor_enb ? (m_cursor_col ? m_cursor_y : 0x7f) : m_latched_chr_sum;
198 
199 	m_lum(m_lum_out);
200 	m_chr(m_chr_out);
201 
202 	//m_screen->update_now();
203 }
204 
205 /*uint32_t dpb7000_combiner_card_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
206 {
207     for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
208     {
209         uint32_t *dest = &bitmap.pix(y, cliprect.min_x);
210         for (int x = cliprect.min_x; x <= cliprect.max_x && x < 256; x++)
211         {
212             *dest++ = 0xff000000 | (m_lum_out << 16) | (m_lum_out << 8) | m_lum_out;
213         }
214     }
215     return 0;
216 }*/
217 
reg_w(uint16_t data)218 void dpb7000_combiner_card_device::reg_w(uint16_t data)
219 {
220 	static const char* const s_const_names[16] = { "Y0", "CY", "CU", "CV", "ES", "EI", "EII", "Y7", "IS", "IY", "IU", "IV", "IIS", "IIY", "IIU", "IIV" };
221 	LOG("%s: CPU write to Combiner Card: %s = %02x\n", machine().describe_context(), s_const_names[(data >> 10) & 0xf], (uint8_t)data);
222 	switch ((data >> 10) & 0xf)
223 	{
224 		case 1: // CY
225 			m_cursor_y = (uint8_t)data;
226 			break;
227 		case 2: // CU
228 			m_cursor_u = (uint8_t)data;
229 			break;
230 		case 3: // CV
231 			m_cursor_v = (uint8_t)data;
232 			break;
233 		case 4: // ES
234 			m_invert_mask = (uint8_t)data;
235 			update_matte_selects();
236 			break;
237 		case 5: // EI
238 			m_matte_ext[0] = (uint8_t)data;
239 			break;
240 		case 6: // EII
241 			m_matte_ext[1] = (uint8_t)data;
242 			break;
243 		case 8: // IS
244 			m_select_matte[0] = BIT(data, 0);
245 			update_matte_selects();
246 			break;
247 		case 9: // IY
248 			m_matte_y[0] = (uint8_t)data;
249 			break;
250 		case 10: // IU
251 			m_matte_u[0] = (uint8_t)data;
252 			break;
253 		case 11: // IV
254 			m_matte_v[0] = (uint8_t)data;
255 			break;
256 		case 12: // IIS
257 			m_select_matte[1] = BIT(data, 0);
258 			update_matte_selects();
259 			break;
260 		case 13: // IIY
261 			m_matte_y[1] = (uint8_t)data;
262 			break;
263 		case 14: // IIU
264 			m_matte_u[1] = (uint8_t)data;
265 			break;
266 		case 15: // IIV
267 			m_matte_v[1] = (uint8_t)data;
268 			break;
269 	}
270 }
271 
lum1_w(uint8_t data)272 void dpb7000_combiner_card_device::lum1_w(uint8_t data)
273 {
274 	m_lum_in[0] = data;
275 }
276 
lum2_w(uint8_t data)277 void dpb7000_combiner_card_device::lum2_w(uint8_t data)
278 {
279 	m_lum_in[1] = data;
280 }
281 
blank1(int state)282 void dpb7000_combiner_card_device::blank1(int state)
283 {
284 	m_blank[0] = (bool)state;
285 	update_matte_selects();
286 }
287 
blank2(int state)288 void dpb7000_combiner_card_device::blank2(int state)
289 {
290 	m_blank[1] = (bool)state;
291 	update_matte_selects();
292 }
293 
chr1_w(uint8_t data)294 void dpb7000_combiner_card_device::chr1_w(uint8_t data)
295 {
296 	m_chr_in[0] = data;
297 }
298 
chr2_w(uint8_t data)299 void dpb7000_combiner_card_device::chr2_w(uint8_t data)
300 {
301 	m_chr_in[1] = data;
302 }
303 
chr_flag_w(int state)304 void dpb7000_combiner_card_device::chr_flag_w(int state)
305 {
306 	m_chr_i_in = (bool)state;
307 	update_matte_selects();
308 }
309 
ext1_w(uint8_t data)310 void dpb7000_combiner_card_device::ext1_w(uint8_t data)
311 {
312 	m_ext_in[0] = BIT(m_invert_mask, 4) ? (data ^ 0xff) : data;
313 }
314 
ext2_w(uint8_t data)315 void dpb7000_combiner_card_device::ext2_w(uint8_t data)
316 {
317 	m_ext_in[1] = BIT(m_invert_mask, 4) ? (data ^ 0xff) : data;
318 }
319 
palette_l_w(int state)320 void dpb7000_combiner_card_device::palette_l_w(int state)
321 {
322 	m_palette_l = (bool)state;
323 	update_matte_selects();
324 }
325 
cursor_enb_w(int state)326 void dpb7000_combiner_card_device::cursor_enb_w(int state)
327 {
328 	m_cursor_enb = (bool)state;
329 }
330 
cursor_col_w(int state)331 void dpb7000_combiner_card_device::cursor_col_w(int state)
332 {
333 	m_cursor_col = (bool)state;
334 }
335 
update_matte_selects()336 void dpb7000_combiner_card_device::update_matte_selects()
337 {
338 	for (int i = 0; i < 2; i++)
339 	{
340 		m_blank_or_suppress[i] = m_select_matte[i] || m_blank[i];
341 		m_output_matte_y[i] = m_blank_or_suppress[i] && m_palette_l;
342 		m_output_matte_u[i] = m_output_matte_y[i] && m_chr_i;
343 		m_output_matte_v[i] = m_output_matte_y[i] && !m_chr_i;
344 		m_output_matte_ext[i] = !BIT(m_invert_mask, i) && m_blank[i];
345 	}
346 }
347