1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /**********************************************************************
4 
5     SMC CRT9007 CRT Video Processor and Controller (VPAC) emulation
6 
7 **********************************************************************/
8 
9 /*
10 
11     TODO:
12 
13     - cursor timer
14     - light pen
15     - non-DMA mode
16     - DMA mode
17     - cursor/blank skew
18     - sequential breaks
19     - interlaced mode
20     - smooth scroll
21     - page blank
22     - double height cursor
23     - row attributes
24     - pin configuration
25     - operation modes 0,4,7
26     - address modes 1,2,3
27     - light pen
28     - state saving
29 
30 */
31 
32 #include "emu.h"
33 #include "crt9007.h"
34 
35 #include "screen.h"
36 
37 //#define VERBOSE 1
38 #include "logmacro.h"
39 
40 
41 
42 //**************************************************************************
43 //  DEVICE DEFINITIONS
44 //**************************************************************************
45 
46 DEFINE_DEVICE_TYPE(CRT9007, crt9007_device, "crt9007", "SMC CRT9007 VPAC")
47 
48 
49 
50 //**************************************************************************
51 //  MACROS / CONSTANTS
52 //**************************************************************************
53 
54 #define HAS_VALID_PARAMETERS \
55 	(m_reg[0x00] && m_reg[0x01] && m_reg[0x07] && m_reg[0x08] && m_reg[0x09])
56 
57 #define CHARACTERS_PER_HORIZONTAL_PERIOD \
58 	m_reg[0x00]
59 
60 #define CHARACTERS_PER_DATA_ROW \
61 	(m_reg[0x01] + 1)
62 
63 #define HORIZONTAL_DELAY \
64 	m_reg[0x02]
65 
66 #define HORIZONTAL_SYNC_WIDTH \
67 	m_reg[0x03]
68 
69 #define VERTICAL_SYNC_WIDTH \
70 	m_reg[0x04]
71 
72 #define VERTICAL_DELAY \
73 	(m_reg[0x05] - 1)
74 
75 #define PIN_CONFIGURATION \
76 	(m_reg[0x06] >> 6)
77 
78 #define CURSOR_SKEW \
79 	((m_reg[0x06] >> 3) & 0x07)
80 
81 #define BLANK_SKEW \
82 	(m_reg[0x06] & 0x07)
83 
84 #define VISIBLE_DATA_ROWS_PER_FRAME \
85 	(m_reg[0x07] + 1)
86 
87 #define SCAN_LINES_PER_DATA_ROW \
88 	((m_reg[0x08] & 0x1f) + 1)
89 
90 #define SCAN_LINES_PER_FRAME \
91 	(((m_reg[0x08] << 3) & 0x0700) | m_reg[0x09])
92 
93 #define DMA_BURST_COUNT \
94 	((m_reg[0x0a] & 0x0f) + 1)
95 
96 #define DMA_BURST_DELAY \
97 	((((m_reg[0x0a] >> 4) & 0x07) + 1) % 8)
98 
99 #define DMA_DISABLE \
100 	BIT(m_reg[0x0a], 7)
101 
102 #define SINGLE_HEIGHT_CURSOR \
103 	BIT(m_reg[0x0b], 0)
104 
105 #define OPERATION_MODE \
106 	((m_reg[0x0b] >> 1) & 0x07)
107 
108 #define INTERLACE_MODE \
109 	((m_reg[0x0b] >> 4) & 0x03)
110 
111 #define PAGE_BLANK \
112 	BIT(m_reg[0x0b], 6)
113 
114 #define TABLE_START \
115 	(((m_reg[0x0d] << 8) & 0x3f00) | m_reg[0x0c])
116 
117 #define ADDRESS_MODE \
118 	((m_reg[0x0d] >> 6) & 0x03)
119 
120 #define AUXILIARY_ADDRESS_1 \
121 	(((m_reg[0x0f] << 8) & 0x3f00) | m_reg[0x0e])
122 
123 #define ROW_ATTRIBUTES_1 \
124 	((m_reg[0x0f] >> 6) & 0x03)
125 
126 #define SEQUENTIAL_BREAK_1 \
127 	m_reg[0x10]
128 
129 #define SEQUENTIAL_BREAK_2 \
130 	m_reg[0x12]
131 
132 #define DATA_ROW_START \
133 	m_reg[0x11]
134 
135 #define DATA_ROW_END \
136 	m_reg[0x12]
137 
138 #define AUXILIARY_ADDRESS_2 \
139 	(((m_reg[0x14] << 8) & 0x3f00) | m_reg[0x13])
140 
141 #define ROW_ATTRIBUTES_2 \
142 	((m_reg[0x14] >> 6) & 0x03)
143 
144 #define SMOOTH_SCROLL_OFFSET \
145 	((m_reg[0x17] >> 1) & 0x3f)
146 
147 #define SMOOTH_SCROLL_OFFSET_OVERFLOW \
148 	BIT(m_reg[0x17], 7)
149 
150 #define VERTICAL_CURSOR \
151 	m_reg[0x18]
152 
153 #define HORIZONTAL_CURSOR \
154 	m_reg[0x19]
155 
156 #define INTERRUPT_ENABLE \
157 	m_reg[0x1a]
158 
159 #define FRAME_TIMER \
160 	BIT(m_reg[0x1a], 0)
161 
162 #define LIGHT_PEN_INTERRUPT \
163 	BIT(m_reg[0x1a], 5)
164 
165 #define VERTICAL_RETRACE_INTERRUPT \
166 	BIT(m_reg[0x1a], 6)
167 
168 #define VERTICAL_LIGHT_PEN \
169 	m_reg[0x3b]
170 
171 #define HORIZONTAL_LIGHT_PEN \
172 	m_reg[0x3c]
173 
174 
175 // interlace
176 enum
177 {
178 	NON_INTERLACED = 0,
179 	ENHANCED_VIDEO_INTERFACE,
180 	NORMAL_VIDEO_INTERFACE
181 };
182 
183 
184 // operation modes
185 enum
186 {
187 	OPERATION_MODE_REPETITIVE_MEMORY_ADDRESSING = 0,    // not implemented
188 	OPERATION_MODE_DOUBLE_ROW_BUFFER = 1,
189 	OPERATION_MODE_SINGLE_ROW_BUFFER = 4,               // not implemented
190 	OPERATION_MODE_ATTRIBUTE_ASSEMBLE = 7               // not implemented
191 };
192 
193 
194 // addressing modes
195 enum
196 {
197 	ADDRESS_MODE_SEQUENTIAL_ADDRESSING = 0,
198 	ADDRESS_MODE_SEQUENTIAL_ROLL_ADDRESSING,            // not implemented
199 	ADDRESS_MODE_CONTIGUOUS_ROW_TABLE,                  // not implemented
200 	ADDRESS_MODE_LINKED_LIST_ROW_TABLE                  // not implemented
201 };
202 
203 
204 // interrupt enable register bits
205 const int IE_VERTICAL_RETRACE           = 0x40;
206 //const int IE_LIGHT_PEN                  = 0x20;
207 const int IE_FRAME_TIMER                = 0x01;
208 
209 // status register bits
210 const int STATUS_INTERRUPT_PENDING      = 0x80;
211 //const int STATUS_VERTICAL_RETRACE       = 0x40;
212 const int STATUS_LIGHT_PEN_UPDATE       = 0x20;
213 //const int STATUS_ODD_EVEN               = 0x04;
214 //const int STATUS_FRAME_TIMER_OCCURRED   = 0x01;
215 
216 
217 
218 //**************************************************************************
219 //  GLOBAL VARIABLES
220 //**************************************************************************
221 
222 // default address map
crt9007(address_map & map)223 void crt9007_device::crt9007(address_map &map)
224 {
225 	if (!has_configured_map(0))
226 		map(0x0000, 0x3fff).ram();
227 }
228 
229 
230 
231 //**************************************************************************
232 //  INLINE HELPERS
233 //**************************************************************************
234 
235 //-------------------------------------------------
236 //  readbyte - read a byte at the given address
237 //-------------------------------------------------
238 
readbyte(offs_t address)239 inline uint8_t crt9007_device::readbyte(offs_t address)
240 {
241 	return space().read_byte(address);
242 }
243 
244 
245 //-------------------------------------------------
246 //  trigger_interrupt -
247 //-------------------------------------------------
248 
trigger_interrupt(int line)249 inline void crt9007_device::trigger_interrupt(int line)
250 {
251 	int status = m_status;
252 
253 	m_status |= line;
254 
255 	if (INTERRUPT_ENABLE & line)
256 	{
257 		m_status |= STATUS_INTERRUPT_PENDING;
258 
259 		if (!(status & STATUS_INTERRUPT_PENDING))
260 		{
261 			LOG("CRT9007 INT 1\n");
262 			m_write_int(ASSERT_LINE);
263 		}
264 	}
265 }
266 
267 
268 //-------------------------------------------------
269 //  update_cblank_line -
270 //-------------------------------------------------
271 
update_cblank_line()272 inline void crt9007_device::update_cblank_line()
273 {
274 	int x = screen().hpos();
275 	int y = screen().vpos();
276 
277 	// composite blank
278 	bool cblank = !(m_hs && m_vs);
279 
280 	if (m_cblank != cblank)
281 	{
282 		m_cblank = cblank;
283 
284 		LOG("CRT9007 y %03u x %04u : CBLANK %u\n", y, x, m_cblank);
285 
286 		m_write_cblank(m_cblank);
287 	}
288 }
289 
290 
291 //-------------------------------------------------
292 //  update_hsync_timer -
293 //-------------------------------------------------
294 
update_hsync_timer(bool state)295 inline void crt9007_device::update_hsync_timer(bool state)
296 {
297 	int y = screen().vpos();
298 
299 	int next_x = state ? m_hsync_start : m_hsync_end;
300 	int next_y = state ? (y + 1) % SCAN_LINES_PER_FRAME : y;
301 
302 	attotime duration = screen().time_until_pos(next_y, next_x);
303 
304 	m_hsync_timer->adjust(duration, !state);
305 }
306 
307 
308 //-------------------------------------------------
309 //  update_vsync_timer -
310 //-------------------------------------------------
311 
update_vsync_timer(bool state)312 inline void crt9007_device::update_vsync_timer(bool state)
313 {
314 	int next_y = state ? m_vsync_start : m_vsync_end;
315 
316 	attotime duration = screen().time_until_pos(next_y, 0);
317 
318 	m_vsync_timer->adjust(duration, !state);
319 }
320 
321 
322 //-------------------------------------------------
323 //  update_vlt_timer -
324 //-------------------------------------------------
325 
update_vlt_timer(bool state)326 inline void crt9007_device::update_vlt_timer(bool state)
327 {
328 	// this signal is active during all visible scan lines and during the horizontal trace at vertical retrace
329 	int y = screen().vpos();
330 
331 	int next_x = state ? m_vlt_end : m_vlt_start;
332 	int next_y = state ? y : ((y == m_vlt_bottom) ? 0 : (y + 1));
333 
334 	attotime duration = screen().time_until_pos(next_y, next_x);
335 
336 	m_vlt_timer->adjust(duration, !state);
337 }
338 
339 
340 //-------------------------------------------------
341 //  update_curs_timer -
342 //-------------------------------------------------
343 
update_curs_timer(bool state)344 inline void crt9007_device::update_curs_timer(bool state)
345 {
346 	// this signal is active for 1 character time for all scanlines within the data row
347 	// TODO
348 }
349 
350 
351 //-------------------------------------------------
352 //  update_drb_timer -
353 //-------------------------------------------------
354 
update_drb_timer(bool state)355 inline void crt9007_device::update_drb_timer(bool state)
356 {
357 	// this signal is active for 1 full scan line (VLT edge to edge) at the top scan line of each new row
358 	// there is 1 extra DRB signal during the 1st scanline of the vertical retrace interval
359 	int y = screen().vpos();
360 
361 	int next_x = m_vlt_end;
362 	int next_y = y ? y + 1 : y;
363 
364 	if (state)
365 	{
366 		if (y == 0)
367 		{
368 			next_y = VERTICAL_DELAY - 1;
369 		}
370 		else if (y == m_drb_bottom)
371 		{
372 			next_x = 0;
373 			next_y = 0;
374 		}
375 		else
376 		{
377 			next_y = y + SCAN_LINES_PER_DATA_ROW - 1;
378 		}
379 	}
380 
381 	attotime duration = screen().time_until_pos(next_y, next_x);
382 
383 	m_drb_timer->adjust(duration, !state);
384 }
385 
386 
387 //-------------------------------------------------
388 //  update_dma_timer -
389 //-------------------------------------------------
390 
update_dma_timer()391 inline void crt9007_device::update_dma_timer()
392 {
393 	// TODO
394 }
395 
396 
397 //-------------------------------------------------
398 //  recompute_parameters -
399 //-------------------------------------------------
400 
recompute_parameters()401 inline void crt9007_device::recompute_parameters()
402 {
403 	// check that necessary registers have been loaded
404 	if (!HAS_VALID_PARAMETERS) return;
405 
406 	// screen dimensions
407 	int horiz_pix_total = CHARACTERS_PER_HORIZONTAL_PERIOD * m_hpixels_per_column;
408 	int vert_pix_total = SCAN_LINES_PER_FRAME;
409 
410 	// refresh rate
411 	attotime refresh = clocks_to_attotime(CHARACTERS_PER_HORIZONTAL_PERIOD * vert_pix_total);
412 
413 	// horizontal sync
414 	m_hsync_start = 0;
415 	m_hsync_end = HORIZONTAL_SYNC_WIDTH * m_hpixels_per_column;
416 
417 	// visible line time
418 	m_vlt_start = HORIZONTAL_DELAY * m_hpixels_per_column;
419 	m_vlt_end = (HORIZONTAL_DELAY + CHARACTERS_PER_DATA_ROW) * m_hpixels_per_column;
420 	m_vlt_bottom = VERTICAL_DELAY + (VISIBLE_DATA_ROWS_PER_FRAME * SCAN_LINES_PER_DATA_ROW) - 1;
421 
422 	// data row boundary
423 	m_drb_bottom = VERTICAL_DELAY + (VISIBLE_DATA_ROWS_PER_FRAME * SCAN_LINES_PER_DATA_ROW) - SCAN_LINES_PER_DATA_ROW;
424 
425 	// vertical sync
426 	m_vsync_start = 0;
427 	m_vsync_end = VERTICAL_SYNC_WIDTH;
428 
429 	// visible area
430 	rectangle visarea(m_hsync_end, horiz_pix_total - 1, m_vsync_end, vert_pix_total - 1);
431 
432 	LOG("CRT9007 Screen: %u x %u @ %f Hz\n", horiz_pix_total, vert_pix_total, refresh.as_hz());
433 	LOG("CRT9007 Visible Area: (%u, %u) - (%u, %u)\n", visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y);
434 
435 	//screen().configure(horiz_pix_total, vert_pix_total, visarea, refresh.as_attoseconds());
436 	(void)visarea;
437 
438 	m_hsync_timer->adjust(screen().time_until_pos(0, 0));
439 	m_vsync_timer->adjust(screen().time_until_pos(0, 0));
440 	m_vlt_timer->adjust(screen().time_until_pos(0, m_vlt_start), 1);
441 	m_drb_timer->adjust(screen().time_until_pos(0, 0));
442 
443 	int frame_timer_line = m_drb_bottom - (OPERATION_MODE == OPERATION_MODE_DOUBLE_ROW_BUFFER ? SCAN_LINES_PER_DATA_ROW : 0);
444 	m_frame_timer->adjust(screen().time_until_pos(frame_timer_line, 0), 0, refresh);
445 }
446 
447 
448 //**************************************************************************
449 //  LIVE DEVICE
450 //**************************************************************************
451 
452 //-------------------------------------------------
453 //  crt9007_device - constructor
454 //-------------------------------------------------
455 
crt9007_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)456 crt9007_device::crt9007_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
457 	device_t(mconfig, CRT9007, tag, owner, clock),
458 	device_memory_interface(mconfig, *this),
459 	device_video_interface(mconfig, *this),
460 	m_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, address_map_constructor(FUNC(crt9007_device::crt9007), this)),
461 	m_write_int(*this),
462 	m_write_dmar(*this),
463 	m_write_hs(*this),
464 	m_write_vs(*this),
465 	m_write_vlt(*this),
466 	m_write_curs(*this),
467 	m_write_drb(*this),
468 	m_write_wben(*this),
469 	m_write_cblank(*this),
470 	m_write_slg(*this),
471 	m_write_sld(*this)
472 {
473 	for (auto & elem : m_reg)
474 		elem = 0;
475 }
476 
477 
478 //-------------------------------------------------
479 //  device_resolve_objects - resolve objects that
480 //  may be needed for other devices to set
481 //  initial conditions at start time
482 //-------------------------------------------------
483 
device_resolve_objects()484 void crt9007_device::device_resolve_objects()
485 {
486 	// resolve callbacks
487 	m_write_int.resolve_safe();
488 	m_write_dmar.resolve_safe();
489 	m_write_hs.resolve_safe();
490 	m_write_vs.resolve_safe();
491 	m_write_vlt.resolve_safe();
492 	m_write_curs.resolve_safe();
493 	m_write_drb.resolve_safe();
494 	m_write_wben.resolve_safe();
495 	m_write_cblank.resolve_safe();
496 	m_write_slg.resolve_safe();
497 	m_write_sld.resolve_safe();
498 }
499 
500 
501 //-------------------------------------------------
502 //  device_start - device-specific startup
503 //-------------------------------------------------
504 
device_start()505 void crt9007_device::device_start()
506 {
507 	// allocate timers
508 	m_hsync_timer = timer_alloc(TIMER_HSYNC);
509 	m_vsync_timer = timer_alloc(TIMER_VSYNC);
510 	m_vlt_timer = timer_alloc(TIMER_VLT);
511 	m_curs_timer = timer_alloc(TIMER_CURS);
512 	m_drb_timer = timer_alloc(TIMER_DRB);
513 	m_dma_timer = timer_alloc(TIMER_DMA);
514 	m_frame_timer = timer_alloc(TIMER_FRAME);
515 
516 	// save state
517 	save_item(NAME(m_reg));
518 	save_item(NAME(m_status));
519 	save_item(NAME(m_hpixels_per_column));
520 	save_item(NAME(m_disp));
521 	save_item(NAME(m_hs));
522 	save_item(NAME(m_vs));
523 	save_item(NAME(m_cblank));
524 	save_item(NAME(m_vlt));
525 	save_item(NAME(m_drb));
526 	save_item(NAME(m_lpstb));
527 	save_item(NAME(m_dmar));
528 	save_item(NAME(m_ack));
529 	save_item(NAME(m_dma_count));
530 	save_item(NAME(m_dma_burst));
531 	save_item(NAME(m_dma_delay));
532 }
533 
534 
535 //-------------------------------------------------
536 //  device_reset - device-specific reset
537 //-------------------------------------------------
538 
device_reset()539 void crt9007_device::device_reset()
540 {
541 	m_disp = false;
542 	m_cblank = false;
543 	m_status = 0;
544 
545 	// HS = 1
546 	m_hs = true;
547 	m_write_hs(1);
548 
549 	// VS = 1
550 	m_vs = true;
551 	m_write_vs(1);
552 
553 	// CBLANK = 1
554 	m_write_cblank(0);
555 
556 	// CURS = 0
557 	m_write_curs(0);
558 
559 	// VLT = 0
560 	m_write_vlt(0);
561 
562 	// DRB = 1
563 	m_write_drb(1);
564 
565 	// INT = 0
566 	m_write_int(CLEAR_LINE);
567 
568 	// 28 (DMAR) = 0
569 	m_dmar = false;
570 	m_write_dmar(CLEAR_LINE);
571 
572 	// 29 (WBEN) = 0
573 	m_write_wben(1); // HACK
574 
575 	// 30 (SLG) = 0
576 	m_write_slg(0);
577 
578 	// 31 (SLD) = 0
579 	m_write_sld(0);
580 
581 	// 32 (LPSTB) = 0
582 }
583 
584 
585 //-------------------------------------------------
586 //  device_post_load - called after the loading a
587 //  saved state, so that registered variables can
588 //  be expanded as necessary
589 //-------------------------------------------------
590 
device_post_load()591 void crt9007_device::device_post_load()
592 {
593 	recompute_parameters();
594 }
595 
596 
597 //-------------------------------------------------
598 //  device_clock_changed - handle clock change
599 //-------------------------------------------------
600 
device_clock_changed()601 void crt9007_device::device_clock_changed()
602 {
603 	recompute_parameters();
604 }
605 
606 
607 //-------------------------------------------------
608 //  device_timer - handle timer events
609 //-------------------------------------------------
610 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)611 void crt9007_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
612 {
613 	int x = screen().hpos();
614 	int y = screen().vpos();
615 
616 	switch (id)
617 	{
618 	case TIMER_HSYNC:
619 		m_hs = bool(param);
620 
621 		LOG("CRT9007 y %03u x %04u : HS %u\n", y, x, m_hs);
622 
623 		m_write_hs(m_hs);
624 
625 		update_cblank_line();
626 
627 		update_hsync_timer(m_hs);
628 		break;
629 
630 	case TIMER_VSYNC:
631 		m_vs = bool(param);
632 
633 		LOG("CRT9007 y %03u x %04u : VS %u\n", y, x, m_vs);
634 
635 		m_write_vs(m_vs);
636 
637 		if (m_vs)
638 		{
639 			// reset all other bits except Light Pen Update to logic 0
640 			m_status &= (STATUS_LIGHT_PEN_UPDATE | STATUS_INTERRUPT_PENDING);
641 		}
642 		else
643 		{
644 			trigger_interrupt(IE_VERTICAL_RETRACE);
645 
646 			update_cblank_line();
647 		}
648 
649 		update_vsync_timer(m_vs);
650 		break;
651 
652 	case TIMER_VLT:
653 		m_vlt = bool(param);
654 
655 		LOG("CRT9007 y %03u x %04u : VLT %u\n", y, x, m_vlt);
656 
657 		m_write_vlt(m_vlt);
658 
659 		update_vlt_timer(m_vlt);
660 		break;
661 
662 	case TIMER_CURS:
663 		LOG("CRT9007 y %03u x %04u : CURS %u\n", y, x, param);
664 
665 		m_write_curs(param);
666 
667 		update_curs_timer(param);
668 		break;
669 
670 	case TIMER_DRB:
671 		m_drb = bool(param);
672 
673 		LOG("CRT9007 y %03u x %04u : DRB %u\n", y, x, m_drb);
674 
675 		m_write_drb(m_drb);
676 
677 		if (!m_drb && !DMA_DISABLE)
678 		{
679 			// start DMA burst sequence
680 			m_dma_count = CHARACTERS_PER_DATA_ROW;
681 			m_dma_burst = DMA_BURST_COUNT ? (DMA_BURST_COUNT * 4) : CHARACTERS_PER_DATA_ROW;
682 			m_dma_delay = DMA_BURST_DELAY;
683 			m_dmar = true;
684 
685 			LOG("CRT9007 DMAR 1\n");
686 			m_write_dmar(ASSERT_LINE);
687 		}
688 
689 		update_drb_timer(m_drb);
690 		break;
691 
692 	case TIMER_DMA:
693 		readbyte(AUXILIARY_ADDRESS_2);
694 
695 		update_dma_timer();
696 		break;
697 
698 	case TIMER_FRAME:
699 		trigger_interrupt(IE_FRAME_TIMER);
700 		break;
701 	}
702 }
703 
704 
705 //-------------------------------------------------
706 //  memory_space_config - return a description of
707 //  any address spaces owned by this device
708 //-------------------------------------------------
709 
memory_space_config() const710 device_memory_interface::space_config_vector crt9007_device::memory_space_config() const
711 {
712 	return space_config_vector {
713 		std::make_pair(0, &m_space_config)
714 	};
715 }
716 
717 
718 //-------------------------------------------------
719 //  read - register read
720 //-------------------------------------------------
721 
read(offs_t offset)722 uint8_t crt9007_device::read(offs_t offset)
723 {
724 	uint8_t data = 0;
725 
726 	switch (offset)
727 	{
728 	case 0x15:
729 		if (!machine().side_effects_disabled())
730 		{
731 			LOG("CRT9007 Start\n");
732 			m_disp = true;
733 		}
734 		break;
735 
736 	case 0x16:
737 		if (!machine().side_effects_disabled())
738 		{
739 			LOG("CRT9007 Reset\n");
740 			device_reset();
741 		}
742 		break;
743 
744 	case 0x38:
745 		data = VERTICAL_CURSOR;
746 		break;
747 
748 	case 0x39:
749 		data = HORIZONTAL_CURSOR;
750 		break;
751 
752 	case 0x3a:
753 		data = m_status;
754 
755 		if (!machine().side_effects_disabled() && (m_status & STATUS_INTERRUPT_PENDING))
756 		{
757 			// reset interrupt pending bit
758 			m_status &= ~STATUS_INTERRUPT_PENDING;
759 			LOG("CRT9007 INT 0\n");
760 			m_write_int(CLEAR_LINE);
761 		}
762 		break;
763 
764 	case 0x3b:
765 		data = VERTICAL_LIGHT_PEN;
766 		break;
767 
768 	case 0x3c:
769 		data = HORIZONTAL_LIGHT_PEN;
770 
771 		if (!machine().side_effects_disabled())
772 		{
773 			// reset light pen update bit
774 			m_status &= ~STATUS_LIGHT_PEN_UPDATE;
775 		}
776 		break;
777 
778 	default:
779 		if (!machine().side_effects_disabled())
780 			logerror("CRT9007 Read from Invalid Register: %02x!\n", offset);
781 	}
782 
783 	return data;
784 }
785 
786 
787 //-------------------------------------------------
788 //  write - register write
789 //-------------------------------------------------
790 
write(offs_t offset,uint8_t data)791 void crt9007_device::write(offs_t offset, uint8_t data)
792 {
793 	m_reg[offset] = data;
794 
795 	switch (offset)
796 	{
797 	case 0x00:
798 		recompute_parameters();
799 		LOG("CRT9007 Characters per Horizontal Period: %u\n", CHARACTERS_PER_HORIZONTAL_PERIOD);
800 		break;
801 
802 	case 0x01:
803 		recompute_parameters();
804 		LOG("CRT9007 Characters per Data Row: %u\n", CHARACTERS_PER_DATA_ROW);
805 		break;
806 
807 	case 0x02:
808 		recompute_parameters();
809 		LOG("CRT9007 Horizontal Delay: %u\n", HORIZONTAL_DELAY);
810 		break;
811 
812 	case 0x03:
813 		recompute_parameters();
814 		LOG("CRT9007 Horizontal Sync Width: %u\n", HORIZONTAL_SYNC_WIDTH);
815 		break;
816 
817 	case 0x04:
818 		recompute_parameters();
819 		LOG("CRT9007 Vertical Sync Width: %u\n", VERTICAL_SYNC_WIDTH);
820 		break;
821 
822 	case 0x05:
823 		recompute_parameters();
824 		LOG("CRT9007 Vertical Delay: %u\n", VERTICAL_DELAY);
825 		break;
826 
827 	case 0x06:
828 		recompute_parameters();
829 		LOG("CRT9007 Pin Configuration: %u\n", PIN_CONFIGURATION);
830 		LOG("CRT9007 Cursor Skew: %u\n", CURSOR_SKEW);
831 		LOG("CRT9007 Blank Skew: %u\n", BLANK_SKEW);
832 		break;
833 
834 	case 0x07:
835 		recompute_parameters();
836 		LOG("CRT9007 Visible Data Rows per Frame: %u\n", VISIBLE_DATA_ROWS_PER_FRAME);
837 		break;
838 
839 	case 0x08:
840 		recompute_parameters();
841 		LOG("CRT9007 Scan Lines per Data Row: %u\n", SCAN_LINES_PER_DATA_ROW);
842 		break;
843 
844 	case 0x09:
845 		recompute_parameters();
846 		LOG("CRT9007 Scan Lines per Frame: %u\n", SCAN_LINES_PER_FRAME);
847 		break;
848 
849 	case 0x0a:
850 		LOG("CRT9007 DMA Burst Count: %u\n", DMA_BURST_COUNT);
851 		LOG("CRT9007 DMA Burst Delay: %u\n", DMA_BURST_DELAY);
852 		LOG("CRT9007 DMA Disable: %u\n", DMA_DISABLE);
853 		break;
854 
855 	case 0x0b:
856 		LOG("CRT9007 %s Height Cursor\n", SINGLE_HEIGHT_CURSOR ? "Single" : "Double");
857 		LOG("CRT9007 Operation Mode: %u\n", OPERATION_MODE);
858 		LOG("CRT9007 Interlace Mode: %u\n", INTERLACE_MODE);
859 		LOG("CRT9007 %s Mechanism\n", PAGE_BLANK ? "Page Blank" : "Smooth Scroll");
860 		break;
861 
862 	case 0x0c:
863 		break;
864 
865 	case 0x0d:
866 		LOG("CRT9007 Table Start Register: %04x\n", TABLE_START);
867 		LOG("CRT9007 Address Mode: %u\n", ADDRESS_MODE);
868 		break;
869 
870 	case 0x0e:
871 		break;
872 
873 	case 0x0f:
874 		LOG("CRT9007 Auxialiary Address Register 1: %04x\n", AUXILIARY_ADDRESS_1);
875 		LOG("CRT9007 Row Attributes: %u\n", ROW_ATTRIBUTES_1);
876 		break;
877 
878 	case 0x10:
879 		LOG("CRT9007 Sequential Break Register 1: %u\n", SEQUENTIAL_BREAK_1);
880 		break;
881 
882 	case 0x11:
883 		LOG("CRT9007 Data Row Start Register: %u\n", DATA_ROW_START);
884 		break;
885 
886 	case 0x12:
887 		LOG("CRT9007 Data Row End/Sequential Break Register 2: %u\n", SEQUENTIAL_BREAK_2);
888 		break;
889 
890 	case 0x13:
891 		break;
892 
893 	case 0x14:
894 		LOG("CRT9007 Auxiliary Address Register 2: %04x\n", AUXILIARY_ADDRESS_2);
895 		LOG("CRT9007 Row Attributes: %u\n", ROW_ATTRIBUTES_2);
896 		break;
897 
898 	case 0x15:
899 		LOG("CRT9007 Start\n");
900 		m_disp = true;
901 		break;
902 
903 	case 0x16:
904 		LOG("CRT9007 Reset\n");
905 		device_reset();
906 		break;
907 
908 	case 0x17:
909 		LOG("CRT9007 Smooth Scroll Offset: %u\n", SMOOTH_SCROLL_OFFSET);
910 		LOG("CRT9007 Smooth Scroll Offset Overflow: %u\n", SMOOTH_SCROLL_OFFSET_OVERFLOW);
911 		break;
912 
913 	case 0x18:
914 		LOG("CRT9007 Vertical Cursor Register: %u\n", VERTICAL_CURSOR);
915 		break;
916 
917 	case 0x19:
918 		LOG("CRT9007 Horizontal Cursor Register: %u\n", HORIZONTAL_CURSOR);
919 		break;
920 
921 	case 0x1a:
922 		LOG("CRT9007 Frame Timer: %u\n", FRAME_TIMER);
923 		LOG("CRT9007 Light Pen Interrupt: %u\n", LIGHT_PEN_INTERRUPT);
924 		LOG("CRT9007 Vertical Retrace Interrupt: %u\n", VERTICAL_RETRACE_INTERRUPT);
925 		break;
926 
927 	default:
928 		logerror("CRT9007 Write to Invalid Register: %02x!\n", offset);
929 	}
930 }
931 
932 
933 //-------------------------------------------------
934 //  ack_w - DMA acknowledge
935 //-------------------------------------------------
936 
ack_w(int state)937 void crt9007_device::ack_w(int state)
938 {
939 	LOG("CRT9007 ACK: %u\n", state);
940 
941 	if (m_dmar && !m_ack && state)
942 	{
943 		// start DMA transfer
944 		m_dma_timer->adjust(attotime::from_hz(clock()));
945 	}
946 
947 	m_ack = bool(state);
948 }
949 
950 
951 //-------------------------------------------------
952 //  lpstb_w - light pen strobe
953 //-------------------------------------------------
954 
lpstb_w(int state)955 void crt9007_device::lpstb_w(int state)
956 {
957 	LOG("CRT9007 LPSTB: %u\n", state);
958 
959 	if (!m_lpstb && state)
960 	{
961 		// TODO latch current row/column position
962 	}
963 
964 	m_lpstb = bool(state);
965 }
966 
967 
968 //-------------------------------------------------
969 //  set_character_width -
970 //-------------------------------------------------
971 
set_character_width(unsigned value)972 void crt9007_device::set_character_width(unsigned value)
973 {
974 	m_hpixels_per_column = value;
975 
976 	if (started())
977 		recompute_parameters();
978 }
979