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