1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /*****************************************************************************
4  *
5  * video/abc806.c
6  *
7  ****************************************************************************/
8 
9 #include "emu.h"
10 #include "includes/abc80x.h"
11 #include "screen.h"
12 
13 //#define VERBOSE 1
14 #include "logmacro.h"
15 
16 
17 #define HORIZONTAL_PORCH_HACK   109
18 #define VERTICAL_PORCH_HACK     27
19 
20 
21 
22 //-------------------------------------------------
23 //  hrs_w - high resolution memory banking
24 //-------------------------------------------------
25 
hrs_w(uint8_t data)26 void abc806_state::hrs_w(uint8_t data)
27 {
28 	/*
29 
30 	    bit     signal  description
31 
32 	    0       VM15    visible screen memory area bit 0
33 	    1       VM16    visible screen memory area bit 1
34 	    2       VM17    visible screen memory area bit 2
35 	    3       VM18    visible screen memory area bit 3
36 	    4       F15     cpu accessible screen memory area bit 0
37 	    5       F16     cpu accessible screen memory area bit 1
38 	    6       F17     cpu accessible screen memory area bit 2
39 	    7       F18     cpu accessible screen memory area bit 3
40 
41 	*/
42 
43 	LOG("%s HRS %02x\n", machine().describe_context(), data);
44 
45 	m_hrs = data;
46 }
47 
48 
49 //-------------------------------------------------
50 //  hrc_w - high resolution color write
51 //-------------------------------------------------
52 
hrc_w(offs_t offset,uint8_t data)53 void abc806_state::hrc_w(offs_t offset, uint8_t data)
54 {
55 	int reg = (offset >> 8) & 0x0f;
56 
57 	m_hrc[reg] = data;
58 }
59 
60 
61 //-------------------------------------------------
62 //  charram_r - character RAM read
63 //-------------------------------------------------
64 
charram_r(offs_t offset)65 uint8_t abc806_state::charram_r(offs_t offset)
66 {
67 	if (!machine().side_effects_disabled())
68 		m_attr_data = m_attr_ram[offset];
69 
70 	return m_char_ram[offset];
71 }
72 
73 
74 //-------------------------------------------------
75 //  charram_w - character RAM write
76 //-------------------------------------------------
77 
charram_w(offs_t offset,uint8_t data)78 void abc806_state::charram_w(offs_t offset, uint8_t data)
79 {
80 	if (!machine().side_effects_disabled())
81 		m_attr_ram[offset] = m_attr_data;
82 
83 	m_char_ram[offset] = data;
84 }
85 
86 
87 //-------------------------------------------------
88 //  ami_r - attribute memory read
89 //-------------------------------------------------
90 
ami_r()91 uint8_t abc806_state::ami_r()
92 {
93 	return m_attr_data;
94 }
95 
96 
97 //-------------------------------------------------
98 //  amo_w - attribute memory write
99 //-------------------------------------------------
100 
amo_w(uint8_t data)101 void abc806_state::amo_w(uint8_t data)
102 {
103 	m_attr_data = data;
104 }
105 
106 
107 //-------------------------------------------------
108 //  cli_r - palette PROM read
109 //-------------------------------------------------
110 
cli_r(offs_t offset)111 uint8_t abc806_state::cli_r(offs_t offset)
112 {
113 	/*
114 
115 	    bit     description
116 
117 	    0       HRU II data bit 0
118 	    1       HRU II data bit 1
119 	    2       HRU II data bit 2
120 	    3       HRU II data bit 3
121 	    4
122 	    5
123 	    6
124 	    7       RTC data output
125 
126 	*/
127 
128 	uint16_t hru2_addr = (m_hru2_a8 << 8) | (offset >> 8);
129 	uint8_t data = m_hru2_prom->base()[hru2_addr] & 0x0f;
130 
131 	LOG("HRU II %03x : %01x\n", hru2_addr, data);
132 
133 	data |= m_rtc->dio_r() << 7;
134 
135 	return data;
136 }
137 
138 
139 //-------------------------------------------------
140 //  sti_r - protection device read
141 //-------------------------------------------------
142 
sti_r()143 uint8_t abc806_state::sti_r()
144 {
145 	/*
146 
147 	    bit     description
148 
149 	    0
150 	    1
151 	    2
152 	    3
153 	    4
154 	    5
155 	    6
156 	    7       PROT DOUT
157 
158 	*/
159 
160 	return 0x7f;
161 }
162 
163 
164 //-------------------------------------------------
165 //  sto_w -
166 //-------------------------------------------------
167 
sto_w(uint8_t data)168 void abc806_state::sto_w(uint8_t data)
169 {
170 	int level = BIT(data, 7);
171 
172 	switch (data & 0x07)
173 	{
174 	case 0:
175 		// external memory enable
176 		LOG("%s EME %u\n", machine().describe_context(), level);
177 		m_eme = level;
178 		break;
179 	case 1:
180 		// 40/80 column display
181 		m_40 = level;
182 		break;
183 	case 2:
184 		// HRU II address line 8, PROT A0
185 		m_hru2_a8 = level;
186 		break;
187 	case 3:
188 		// PROT INI
189 		break;
190 	case 4:
191 		// text display enable
192 		m_txoff = level;
193 		break;
194 	case 5:
195 		// RTC chip select
196 		m_rtc->cs_w(!level);
197 		break;
198 	case 6:
199 		// RTC clock
200 		m_rtc->clk_w(level);
201 		break;
202 	case 7:
203 		// RTC data in, PROT DIN
204 		m_rtc->dio_w(level);
205 		break;
206 	}
207 }
208 
209 
210 //-------------------------------------------------
211 //  sso_w - sync offset write
212 //-------------------------------------------------
213 
sso_w(uint8_t data)214 void abc806_state::sso_w(uint8_t data)
215 {
216 	m_sync = data & 0x3f;
217 }
218 
219 
220 //-------------------------------------------------
221 //  MC6845_UPDATE_ROW( abc806_update_row )
222 //-------------------------------------------------
223 
MC6845_UPDATE_ROW(abc806_state::abc806_update_row)224 MC6845_UPDATE_ROW( abc806_state::abc806_update_row )
225 {
226 	const pen_t *pen = m_palette->pens();
227 
228 	int fg_color = 7;
229 	int bg_color = 0;
230 	int underline = 0;
231 	int flash = 0;
232 	int e5 = m_40;
233 	int e6 = m_40;
234 	int th = 0;
235 
236 	y += m_sync + vbp;
237 
238 	for (int column = 0; column < x_count; column++)
239 	{
240 		uint8_t data = m_char_ram[(ma + column) & 0x7ff];
241 		uint8_t attr = m_attr_ram[(ma + column) & 0x7ff];
242 		uint8_t rad_data;
243 
244 		if ((attr & 0x07) == ((attr >> 3) & 0x07))
245 		{
246 			// special case
247 			switch (attr >> 6)
248 			{
249 			case 0:
250 				// use previously selected attributes
251 				break;
252 
253 			case 1:
254 				// reserved for future use
255 				break;
256 
257 			case 2:
258 				// blank
259 				fg_color = 0;
260 				bg_color = 0;
261 				underline = 0;
262 				flash = 0;
263 				break;
264 
265 			case 3:
266 				// double width
267 				e5 = BIT(attr, 0);
268 				e6 = BIT(attr, 1);
269 
270 				// read attributes from next byte
271 				attr = m_attr_ram[(ma + column + 1) & 0x7ff];
272 
273 				if (attr != 0x00)
274 				{
275 					fg_color = attr & 0x07;
276 					bg_color = (attr >> 3) & 0x07;
277 					underline = BIT(attr, 6);
278 					flash = BIT(attr, 7);
279 				}
280 				break;
281 			}
282 		}
283 		else
284 		{
285 			// normal case
286 			fg_color = attr & 0x07;
287 			bg_color = (attr >> 3) & 0x07;
288 			underline = BIT(attr, 6);
289 			flash = BIT(attr, 7);
290 			e5 = m_40;
291 			e6 = m_40;
292 		}
293 
294 		if (column == cursor_x)
295 		{
296 			rad_data = 0x0f;
297 		}
298 		else
299 		{
300 			uint16_t rad_addr = (e6 << 8) | (e5 << 7) | (flash << 6) | (underline << 4) | (m_flshclk << 5) | (ra & 0x0f);
301 			rad_data = m_rad_prom->base()[rad_addr] & 0x0f;
302 		}
303 
304 		uint16_t chargen_addr = (th << 12) | (data << 4) | rad_data;
305 		uint8_t chargen_data = m_char_rom->base()[chargen_addr & 0xfff] << 2;
306 		int x = hbp + (column + 4) * ABC800_CHAR_WIDTH;
307 
308 		for (int bit = 0; bit < ABC800_CHAR_WIDTH; bit++)
309 		{
310 			int color = BIT(chargen_data, 7) ? fg_color : bg_color;
311 			if (!de) color = 0;
312 
313 			bitmap.pix(y, x++) = pen[color];
314 
315 			if (e5 || e6)
316 			{
317 				bitmap.pix(y, x++) = pen[color];
318 			}
319 
320 			chargen_data <<= 1;
321 		}
322 
323 		if (e5 || e6)
324 		{
325 			column++;
326 		}
327 	}
328 }
329 
330 
331 //-------------------------------------------------
332 //  hs_w - horizontal sync write
333 //-------------------------------------------------
334 
WRITE_LINE_MEMBER(abc806_state::hs_w)335 WRITE_LINE_MEMBER( abc806_state::hs_w )
336 {
337 	int vsync;
338 
339 	if (!state)
340 	{
341 		m_v50_addr++;
342 
343 		// clock current vsync value into the shift register
344 		m_vsync_shift <<= 1;
345 		m_vsync_shift |= m_vsync;
346 
347 		vsync = BIT(m_vsync_shift, m_sync);
348 
349 		if (!m_d_vsync && vsync)
350 		{
351 			// clear V50 address
352 			m_v50_addr = 0;
353 		}
354 		else if (m_d_vsync && !vsync)
355 		{
356 			// flash clock
357 			if (m_flshclk_ctr & 0x20)
358 			{
359 				m_flshclk = !m_flshclk;
360 				m_flshclk_ctr = 0;
361 			}
362 			else
363 			{
364 				m_flshclk_ctr++;
365 			}
366 		}
367 
368 		if (m_d_vsync != vsync)
369 		{
370 			// signal _DEW to DART
371 			m_dart->rib_w(!vsync);
372 		}
373 
374 		m_d_vsync = vsync;
375 	}
376 }
377 
378 
379 //-------------------------------------------------
380 //  vs_w - vertical sync write
381 //-------------------------------------------------
382 
WRITE_LINE_MEMBER(abc806_state::vs_w)383 WRITE_LINE_MEMBER( abc806_state::vs_w )
384 {
385 	m_vsync = state;
386 }
387 
388 
389 //-------------------------------------------------
390 //  hr_update - high resolution screen update
391 //-------------------------------------------------
392 
hr_update(bitmap_rgb32 & bitmap,const rectangle & cliprect)393 void abc806_state::hr_update(bitmap_rgb32 &bitmap, const rectangle &cliprect)
394 {
395 	const pen_t *pen = m_palette->pens();
396 
397 	uint32_t addr = (m_hrs & 0x0f) << 15;
398 
399 	for (int y = m_sync + VERTICAL_PORCH_HACK; y < std::min(cliprect.max_y + 1, m_sync + VERTICAL_PORCH_HACK + 240); y++)
400 	{
401 		for (int sx = 0; sx < 128; sx++)
402 		{
403 			uint8_t data = m_video_ram[addr++];
404 			uint16_t dot = (m_hrc[data >> 4] << 8) | m_hrc[data & 0x0f];
405 
406 			for (int pixel = 0; pixel < 4; pixel++)
407 			{
408 				int x = HORIZONTAL_PORCH_HACK + (ABC800_CHAR_WIDTH * 4) - 16 + (sx * 4) + pixel;
409 
410 				if (BIT(dot, 15) || (bitmap.pix(y, x) == rgb_t::black()))
411 				{
412 					bitmap.pix(y, x) = pen[(dot >> 12) & 0x07];
413 				}
414 
415 				dot <<= 4;
416 			}
417 		}
418 	}
419 }
420 
421 
video_start()422 void abc806_state::video_start()
423 {
424 	// allocate memory
425 	m_char_ram.allocate(m_char_ram_size);
426 	m_attr_ram.allocate(m_char_ram_size);
427 
428 	uint32_t videoram_size = m_ram->size() - 0x8000;
429 	m_video_ram.allocate(videoram_size);
430 
431 	// register for state saving
432 	save_item(NAME(m_txoff));
433 	save_item(NAME(m_40));
434 	save_item(NAME(m_flshclk_ctr));
435 	save_item(NAME(m_flshclk));
436 	save_item(NAME(m_attr_data));
437 	save_item(NAME(m_hrs));
438 	save_item(NAME(m_hrc));
439 	save_item(NAME(m_sync));
440 	save_item(NAME(m_v50_addr));
441 	save_item(NAME(m_hru2_a8));
442 	save_item(NAME(m_vsync_shift));
443 	save_item(NAME(m_vsync));
444 	save_item(NAME(m_d_vsync));
445 
446 	// initialize variables
447 	for (auto & elem : m_hrc)
448 	{
449 		elem = 0;
450 	}
451 
452 	m_sync = 10;
453 	m_d_vsync = 1;
454 	m_vsync = 1;
455 	m_40 = 1;
456 }
457 
458 
459 //-------------------------------------------------
460 //  SCREEN_UPDATE( abc806 )
461 //-------------------------------------------------
462 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)463 uint32_t abc806_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
464 {
465 	// clear screen
466 	bitmap.fill(rgb_t::black(), cliprect);
467 
468 	if (!m_txoff)
469 	{
470 		// draw text
471 		m_crtc->screen_update(screen, bitmap, cliprect);
472 	}
473 
474 	// draw HR graphics
475 	hr_update(bitmap, cliprect);
476 
477 	return 0;
478 }
479 
480 
481 //-------------------------------------------------
482 //  PALETTE_INIT( abc806 )
483 //-------------------------------------------------
484 
abc806_palette(palette_device & palette) const485 void abc806_state::abc806_palette(palette_device &palette) const
486 {
487 	palette.set_pen_color(0, rgb_t::black());
488 	palette.set_pen_color(1, rgb_t(0xff, 0x00, 0x00)); // red
489 	palette.set_pen_color(2, rgb_t::green());
490 	palette.set_pen_color(3, rgb_t(0xff, 0xff, 0x00)); // yellow
491 	palette.set_pen_color(4, rgb_t(0x00, 0x00, 0xff)); // blue
492 	palette.set_pen_color(5, rgb_t(0xff, 0x00, 0xff)); // magenta
493 	palette.set_pen_color(6, rgb_t(0x00, 0xff, 0xff)); // cyan
494 	palette.set_pen_color(7, rgb_t::white());
495 }
496 
497 
498 //-------------------------------------------------
499 //  machine_config( abc806_video )
500 //-------------------------------------------------
501 
abc806_video(machine_config & config)502 void abc806_state::abc806_video(machine_config &config)
503 {
504 	MC6845(config, m_crtc, ABC800_CCLK);
505 	m_crtc->set_screen(SCREEN_TAG);
506 	m_crtc->set_show_border_area(true);
507 	m_crtc->set_char_width(ABC800_CHAR_WIDTH);
508 	m_crtc->set_update_row_callback(FUNC(abc806_state::abc806_update_row));
509 	m_crtc->out_hsync_callback().set(FUNC(abc806_state::hs_w));
510 	m_crtc->out_vsync_callback().set(FUNC(abc806_state::vs_w));
511 
512 	screen_device &screen(SCREEN(config, SCREEN_TAG, SCREEN_TYPE_RASTER));
513 	screen.set_screen_update(FUNC(abc806_state::screen_update));
514 	screen.set_raw(XTAL(12'000'000), 0x300, 0, 0x1e0, 0x13a, 0, 0xfa);
515 
516 	PALETTE(config, m_palette, FUNC(abc806_state::abc806_palette), 8);
517 }
518