1 // license:BSD-3-Clause
2 // copyright-holders:Wilbert Pol
3 /**********************************************************************
4
5 NEC HuC6270 Video Display Controller
6
7 The HuC6270 basically outputs a 9-bit stream of pixel data which
8 holds a color index, a palette index, and an indication whether
9 the pixel contains background data or from sprite data.
10
11 This data can be used by a colour encoder to output graphics.
12
13 A regular screen is displayed as follows:
14
15 |<- HDS ->|<-- HDW -->|<- HDE ->|<- HSW ->|
16 |---------|-----------------------|---------|---------|
17 VSW | |
18 |---------|-----------------------|---------|---------|
19 VDS | |
20 | overscan |
21 |---------|-----------------------|---------|---------|
22 | | | |
23 | | | |
24 | | | |
25 | | | |
26 VDW | overscan| active display | overscan |
27 | | | |
28 | | | |
29 | | | |
30 | | | |
31 |---------|-----------------------|---------|---------|
32 VCR | overscan |
33 | |
34 |---------|-----------------------|---------|---------|
35 ^end hsync
36 ^start vsync (30 cycles after hsync)
37
38
39 KNOWN ISSUES
40 - Violent Soldier (probably connected):
41 - In the intro some artefacts appear at the top of the
42 screen every now and then.
43 - In ccovell's splitres test not all sections seem to be aligned properly.
44 - Side Arms: Seems to be totally broken.
45
46
47 TODO
48 - Fix timing of VRAM-SATB DMA
49 - Implement VRAM-VRAM DMA
50 - DMA speeds differ depending on the dot clock selected in the huc6270
51 - Convert VRAM bus to actual space address (optimization)
52
53 **********************************************************************/
54
55 #include "emu.h"
56 #include "huc6270.h"
57
58 //#define VERBOSE 1
59 #include "logmacro.h"
60
61
62 enum {
63 MAWR = 0x00,
64 MARR = 0x01,
65 VxR = 0x02,
66 CR = 0x05,
67 RCR = 0x06,
68 BXR = 0x07,
69 BYR = 0x08,
70 MWR = 0x09,
71 HSR = 0x0A,
72 HDR = 0x0B,
73 VPR = 0x0C,
74 VDW = 0x0D,
75 VCR = 0x0E,
76 DCR = 0x0F,
77 SOUR = 0x10,
78 DESR = 0x11,
79 LENR = 0x12,
80 DVSSR = 0x13
81 };
82
83 ALLOW_SAVE_TYPE(huc6270_device::v_state);
84 ALLOW_SAVE_TYPE(huc6270_device::h_state);
85
86
87 /* Bits in the VDC status register */
88 #define HUC6270_BSY 0x40 /* Set when the VDC accesses VRAM */
89 #define HUC6270_VD 0x20 /* Set when in the vertical blanking period */
90 #define HUC6270_DV 0x10 /* Set when a VRAM > VRAM DMA transfer is done */
91 #define HUC6270_DS 0x08 /* Set when a VRAM > SATB DMA transfer is done */
92 #define HUC6270_RR 0x04 /* Set when the current scanline equals the RCR register */
93 #define HUC6270_OR 0x02 /* Set when there are more than 16 sprites on a line */
94 #define HUC6270_CR 0x01 /* Set when sprite #0 overlaps with another sprite */
95
96
97 DEFINE_DEVICE_TYPE(HUC6270, huc6270_device, "huc6270", "Hudson HuC6270 VDC")
98
99
100 constexpr uint8_t huc6270_device::vram_increments[4];
101
huc6270_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)102 huc6270_device::huc6270_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
103 : device_t(mconfig, HUC6270, tag, owner, clock)
104 , m_vram_size(0)
105 , m_irq_changed_cb(*this)
106 {
107 }
108
109
110 /*
111 Read one row of tile data from video ram
112 */
fetch_bat_tile_row()113 inline void huc6270_device::fetch_bat_tile_row()
114 {
115 const uint16_t bat_data = m_vram[ m_bat_address & m_vram_mask ];
116 const uint16_t tile_palette = ( bat_data >> 8 ) & 0xF0;
117 uint16_t data1 = m_vram[ ( ( ( bat_data & 0x0FFF ) << 4 ) + m_bat_row + 0 ) & m_vram_mask ];
118 uint16_t data2 = ( data1 >> 7 ) & 0x1FE;
119 uint16_t data3 = m_vram[ ( ( ( bat_data & 0x0FFF ) << 4 ) + m_bat_row + 8 ) & m_vram_mask ];
120 uint16_t data4 = ( data3 >> 5 ) & 0x7F8;
121 data3 <<= 2;
122
123 for ( int i = 7; i >= 0; i-- )
124 {
125 uint16_t c = ( data1 & 0x01 ) | ( data2 & 0x02 ) | ( data3 & 0x04 ) | ( data4 & 0x08 );
126
127 /* Colour 0 for background tiles is always taken from palette 0 */
128 if ( c )
129 c |= tile_palette;
130
131 m_bat_tile_row[i] = c;
132
133 data1 >>= 1;
134 data2 >>= 1;
135 data3 >>= 1;
136 data4 >>= 1;
137 }
138 }
139
140
add_sprite(int index,int x,int pattern,int line,int flip_x,int palette,int priority,int sat_lsb)141 void huc6270_device::add_sprite( int index, int x, int pattern, int line, int flip_x, int palette, int priority, int sat_lsb )
142 {
143 int i = m_sprites_this_line;
144
145 if ( i < 16 )
146 {
147 uint32_t b0, b1, b2, b3;
148 int j;
149
150 if ( flip_x )
151 flip_x = 0x0F;
152
153 pattern += ( ( line >> 4 ) << 1 );
154
155 if ( ( m_mwr & 0x0c ) == 0x04 )
156 {
157 if ( ! sat_lsb )
158 {
159 b0 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x00 ) & m_vram_mask ];
160 b1 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x10 ) & m_vram_mask ] << 1;
161 }
162 else
163 {
164 b0 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x20 ) & m_vram_mask ];
165 b1 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x30 ) & m_vram_mask ] << 1;
166 }
167 b2 = 0;
168 b3 = 0;
169 }
170 else
171 {
172 b0 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x00 ) & m_vram_mask ];
173 b1 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x10 ) & m_vram_mask ] << 1;
174 b2 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x20 ) & m_vram_mask ] << 2;
175 b3 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x30 ) & m_vram_mask ] << 3;
176 }
177
178 for ( j = 15; j >= 0; j-- )
179 {
180 uint8_t data = ( b3 & 0x08 ) | ( b2 & 0x04 ) | ( b1 & 0x02 ) | ( b0 & 0x01 );
181
182 if ( data )
183 {
184 data |= palette << 4;
185
186 if ( x + ( j ^ flip_x ) < 1024 )
187 {
188 if (! m_sprite_row[ x + ( j ^ flip_x ) ] )
189 {
190 m_sprite_row[ x + ( j ^ flip_x ) ] = ( priority ? 0x4000 : 0x0000 ) | ( index << 8 ) | data;
191 }
192 else
193 {
194 if ( ! ( m_sprite_row[ x + ( j ^ flip_x ) ] & 0xFF00 ) )
195 {
196 /* Sprite 0 collission */
197 m_sprite_row[ x + ( j ^ flip_x ) ] |= 0x8000;
198 }
199 }
200 }
201 }
202
203 b0 >>= 1;
204 b1 >>= 1;
205 b2 >>= 1;
206 b3 >>= 1;
207 }
208
209 m_sprites_this_line += 1;
210 }
211 }
212
213
select_sprites()214 void huc6270_device::select_sprites()
215 {
216 int i;
217
218 m_sprites_this_line = 0;
219 memset( m_sprite_row, 0, sizeof( m_sprite_row ) );
220 m_sprite_row_index = 0x20;
221
222 for ( i = 0; i < 4 * 64; i += 4 )
223 {
224 static const int cgy_table[4] = { 16, 32, 64, 64 };
225 int cgy = ( m_sat[i+3] >> 12 ) & 0x03;
226 int height = cgy_table[ cgy ];
227 int sprite_line = m_raster_count - m_sat[i];
228
229 if ( sprite_line >= 0 && sprite_line < height )
230 {
231 int pattern = m_sat[i+2] >> 1;
232 int sat_lsb = m_sat[i+2] & 0x01;
233 int palette = m_sat[i+3] & 0x0F;
234 int priority = m_sat[i+3] & 0x80;
235 int cgx = m_sat[i+3] & 0x0100;
236
237 /* If CGY is set to 1, bit 1 of the sprite pattern index is forced to 0 */
238 if ( cgy & 1 )
239 pattern &= ~0x0002;
240
241 /* If CGY is set to 2 or 3, bits 1 and 2 of the sprite pattern index are forced to 0 */
242 if ( cgy & 2 )
243 pattern &= ~0x0006;
244
245 /* Recalculate line index when sprite is flipped vertically */
246 if ( m_sat[i+3] & 0x8000 )
247 sprite_line = ( height - 1 ) - sprite_line;
248
249 /* Is the sprite 32 pixels wide */
250 if ( cgx )
251 {
252 /* If CGX is set, bit 0 of the sprite pattern index is forced to 0 */
253 pattern &= ~0x0001;
254
255 /* Check for horizontal flip */
256 if ( m_sat[i+3] & 0x0800 )
257 {
258 /* Add to our list of sprites for this line */
259 add_sprite( i/4, m_sat[i+1], pattern + 1, sprite_line, 1, palette, priority, sat_lsb );
260 add_sprite( i/4, m_sat[i+1] + 16, pattern, sprite_line, 1, palette, priority, sat_lsb );
261 }
262 else
263 {
264 /* Add to our list of sprites for this line */
265 add_sprite( i/4, m_sat[i+1], pattern, sprite_line, 0, palette, priority, sat_lsb );
266 add_sprite( i/4, m_sat[i+1] + 16, pattern + 1, sprite_line, 0, palette, priority, sat_lsb );
267 }
268 }
269 else
270 {
271 /* Add to our list of sprites for this line */
272 add_sprite( i/4, m_sat[i+1], pattern, sprite_line, m_sat[i+3] & 0x0800, palette, priority, sat_lsb );
273 }
274 }
275 }
276
277 /* Check for sprite overflow */
278 if ( m_sprites_this_line >= 16 )
279 {
280 /* note: flag is set only if irq is taken, Mizubaku Daibouken relies on this behaviour */
281 if ( m_cr & 0x02 )
282 {
283 m_status |= HUC6270_OR;
284 m_irq_changed_cb( ASSERT_LINE );
285 }
286 }
287 }
288
289
handle_vblank()290 inline void huc6270_device::handle_vblank()
291 {
292 if ( ! m_vd_triggered )
293 {
294 if ( m_cr & 0x08 )
295 {
296 m_status |= HUC6270_VD;
297 m_irq_changed_cb( ASSERT_LINE );
298 }
299
300 /* Should we initiate a VRAM->SATB DMA transfer.
301 The timing for this is incorrect.
302 */
303 if ( m_dvssr_written || ( m_dcr & 0x10 ) )
304 {
305 int i;
306
307 LOG("SATB transfer from %05x\n", m_dvssr << 1 );
308 for ( i = 0; i < 4 * 64; i += 4 )
309 {
310 m_sat[i + 0] = m_vram[ ( m_dvssr + i + 0 ) & m_vram_mask ] & 0x03FF;
311 m_sat[i + 1] = m_vram[ ( m_dvssr + i + 1 ) & m_vram_mask ] & 0x03FF;
312 m_sat[i + 2] = m_vram[ ( m_dvssr + i + 2 ) & m_vram_mask ] & 0x07FF;
313 m_sat[i + 3] = m_vram[ ( m_dvssr + i + 3 ) & m_vram_mask ];
314 }
315 m_dvssr_written = 0;
316
317 /* Generate SATB interrupt if requested */
318 if ( m_dcr & 0x01 )
319 {
320 m_satb_countdown = 4;
321 // m_status |= HUC6270_DS;
322 // m_irq_changed_cb( ASSERT_LINE );
323 }
324 }
325
326 m_vd_triggered = 1;
327 }
328 }
329
330
next_vert_state()331 inline void huc6270_device::next_vert_state()
332 {
333 switch ( m_vert_state )
334 {
335 case v_state::VSW:
336 m_vert_state = v_state::VDS;
337 m_vert_to_go = ( ( m_vpr >> 8 ) & 0xFF ) + 2;
338 break;
339
340 case v_state::VDS:
341 m_vert_state = v_state::VDW;
342 m_vert_to_go = ( m_vdw & 0x1FF ) + 1;
343 m_byr_latched = m_byr;
344 m_vd_triggered = 0;
345 break;
346
347 case v_state::VDW:
348 m_vert_state = v_state::VCR;
349 m_vert_to_go = ( m_vcr & 0xFF );
350 handle_vblank();
351 break;
352
353 case v_state::VCR:
354 m_vert_state = v_state::VSW;
355 m_vert_to_go = ( m_vpr & 0x1F ) + 1;
356 break;
357 }
358 }
359
360
next_horz_state()361 inline void huc6270_device::next_horz_state()
362 {
363 switch ( m_horz_state )
364 {
365 case h_state::HDS:
366 m_bxr_latched = m_bxr;
367 m_horz_state = h_state::HDW;
368 m_horz_to_go = ( m_hdr & 0x7F ) + 1;
369 {
370 static const int width_shift[4] = { 5, 6, 7, 7 };
371 uint16_t v;
372
373 v = ( m_byr_latched ) & ( ( m_mwr & 0x40 ) ? 0x1FF : 0xFF );
374 m_bat_row = v & 7;
375 m_bat_address_mask = ( 1 << width_shift[ ( m_mwr >> 4 ) & 0x03 ] ) - 1;
376 m_bat_address = ( ( v >> 3 ) << ( width_shift[ ( m_mwr >> 4 ) & 0x03 ] ) )
377 | ( ( m_bxr_latched >> 3 ) & m_bat_address_mask );
378 m_bat_column = m_bxr & 7;
379 fetch_bat_tile_row();
380 }
381 break;
382
383 case h_state::HDW:
384 m_horz_state = h_state::HDE;
385 m_horz_to_go = ( ( m_hdr >> 8 ) & 0x7F ) + 1;
386 break;
387
388 case h_state::HDE:
389 m_horz_state = h_state::HSW;
390 m_horz_to_go = ( m_hsr & 0x1F ) + 1;
391 break;
392
393 case h_state::HSW:
394 m_horz_state = h_state::HDS;
395 m_horz_to_go = std::max( ( ( m_hsr >> 8 ) & 0x7F ), 2 ) + 1;
396
397 /* If section has ended, advance to next vertical state */
398 while ( m_vert_to_go == 0 )
399 next_vert_state();
400
401 /* Select sprites for the coming line */
402 select_sprites();
403 break;
404 }
405 m_horz_steps = 0;
406 }
407
408
next_pixel()409 u16 huc6270_device::next_pixel()
410 {
411 uint16_t data = HUC6270_SPRITE;
412
413 /* Check if we're on an active display line */
414 if ( m_vert_state == v_state::VDW )
415 {
416 /* Check if we're in active display area */
417 if ( m_horz_state == h_state::HDW )
418 {
419 uint8_t sprite_data = m_sprite_row[ m_sprite_row_index ] & 0x00FF;
420 int collission = ( m_sprite_row[ m_sprite_row_index ] & 0x8000 ) ? 1 : 0;
421
422 if ( m_cr & 0x80 )
423 {
424 data = HUC6270_BACKGROUND | m_bat_tile_row[ m_bat_column ];
425 if ( sprite_data && ( m_cr & 0x40 ) )
426 {
427 if ( m_sprite_row[ m_sprite_row_index ] & 0x4000 )
428 {
429 data = HUC6270_SPRITE | sprite_data;
430 }
431 else
432 {
433 if ( data == HUC6270_BACKGROUND )
434 {
435 data = HUC6270_SPRITE | sprite_data;
436 }
437 }
438 }
439 }
440 else
441 {
442 if ( m_cr & 0x40 )
443 {
444 data = HUC6270_SPRITE | sprite_data;
445 }
446 }
447
448 m_sprite_row_index = m_sprite_row_index + 1;
449 m_bat_column += 1;
450 if ( m_bat_column >= 8 )
451 {
452 m_bat_address = ( m_bat_address & ~m_bat_address_mask )
453 | ( ( m_bat_address + 1 ) & m_bat_address_mask );
454 m_bat_column = 0;
455 fetch_bat_tile_row();
456 }
457
458 if ( collission && ( m_cr & 0x01 ) )
459 {
460 m_status |= HUC6270_CR;
461 m_irq_changed_cb( ASSERT_LINE );
462 }
463 }
464 }
465
466 m_horz_steps++;
467 if ( m_horz_steps == 8 )
468 {
469 m_horz_to_go -= 1;
470 m_horz_steps = 0;
471 while ( m_horz_to_go == 0 )
472 next_horz_state();
473 }
474 return data;
475 }
476
477
478 //inline u16 huc6270_device::time_until_next_event()
479 //{
480 // return m_horz_to_go * 8 + m_horz_steps;
481 //}
482
483
WRITE_LINE_MEMBER(huc6270_device::vsync_changed)484 WRITE_LINE_MEMBER( huc6270_device::vsync_changed )
485 {
486 state &= 0x01;
487 if ( m_vsync != state )
488 {
489 /* Check for high->low VSYNC transition */
490 if ( !state )
491 {
492 m_vert_state = v_state::VCR;
493 m_vert_to_go = 0;
494
495 while ( m_vert_to_go == 0 )
496 next_vert_state();
497 }
498 else
499 {
500 /* Check for low->high VSYNC transition */
501 // VBlank IRQ happens at the beginning of HDW period after VDW ends
502 handle_vblank();
503 }
504 }
505
506 m_vsync = state;
507 }
508
509
WRITE_LINE_MEMBER(huc6270_device::hsync_changed)510 WRITE_LINE_MEMBER( huc6270_device::hsync_changed )
511 {
512 state &= 0x01;
513
514 if(m_hsync != state)
515 {
516 /* Check for low->high HSYNC transition */
517 if(state)
518 {
519 if ( m_satb_countdown )
520 {
521 m_satb_countdown--;
522
523 if ( m_satb_countdown == 0 )
524 {
525 m_status |= HUC6270_DS;
526 m_irq_changed_cb( ASSERT_LINE );
527 }
528 }
529
530 m_horz_state = h_state::HSW;
531 m_horz_to_go = 0;
532 m_horz_steps = 0;
533 m_byr_latched += 1;
534 m_raster_count += 1;
535 if ( m_vert_to_go == 1 && m_vert_state == v_state::VDS )
536 {
537 m_raster_count = 0x40;
538 }
539
540 m_vert_to_go -= 1;
541
542 while ( m_horz_to_go == 0 )
543 next_horz_state();
544
545 handle_dma();
546 }
547 else
548 {
549 /* Check for high->low HSYNC transition */
550 // RCR IRQ happens near the end of the HDW period
551 if ( m_raster_count == m_rcr && ( m_cr & 0x04 ) )
552 {
553 m_status |= HUC6270_RR;
554 m_irq_changed_cb( ASSERT_LINE );
555 }
556 }
557 }
558
559 m_hsync = state;
560 }
561
handle_dma()562 inline void huc6270_device::handle_dma()
563 {
564 /* Should we perform VRAM-VRAM dma.
565 The timing for this is incorrect.
566 */
567 if ( m_dma_enabled )
568 {
569 int desr_inc = ( m_dcr & 0x0008 ) ? -1 : +1;
570 int sour_inc = ( m_dcr & 0x0004 ) ? -1 : +1;
571
572 LOG("doing dma sour = %04x, desr = %04x, lenr = %04x\n", m_sour, m_desr, m_lenr );
573
574 do {
575 uint16_t data;
576
577 // area 0x8000-0xffff cannot be r/w (open bus)
578 if(m_sour <= m_vram_mask)
579 data = m_vram[ m_sour ];
580 else
581 data = 0;
582
583 if(m_desr <= m_vram_mask)
584 m_vram[ m_desr ] = data;
585 m_sour += sour_inc;
586 m_desr += desr_inc;
587 m_lenr -= 1;
588 } while ( m_lenr != 0xFFFF );
589
590 if ( m_dcr & 0x0002 )
591 {
592 m_status |= HUC6270_DV;
593 m_irq_changed_cb( ASSERT_LINE );
594 }
595 m_dma_enabled = 0;
596 }
597 }
598
read(offs_t offset)599 u8 huc6270_device::read(offs_t offset)
600 {
601 uint8_t data = 0x00;
602
603 switch ( offset & 3 )
604 {
605 case 0x00: /* status */
606 data = m_status;
607 m_status &= ~( HUC6270_VD | HUC6270_DV | HUC6270_RR | HUC6270_CR | HUC6270_OR | HUC6270_DS );
608 m_irq_changed_cb( CLEAR_LINE );
609 break;
610
611 case 0x02:
612 data = m_vrr & 0xFF;
613 break;
614
615 case 0x03:
616 data = m_vrr >> 8;
617 if ( m_register_index == VxR )
618 {
619 m_marr += vram_increments[ ( m_cr >> 11 ) & 3 ];
620
621 if(m_marr <= m_vram_mask)
622 m_vrr = m_vram[ m_marr ];
623 else
624 {
625 // TODO: test with real HW
626 m_vrr = 0;
627 logerror("%s Open Bus VRAM read (register read) %04x\n",this->tag(),m_marr);
628 }
629 }
630 break;
631 }
632 return data;
633 }
634
635
write(offs_t offset,u8 data)636 void huc6270_device::write(offs_t offset, u8 data)
637 {
638 LOG("%s: huc6270 write %02x <- %02x ", machine().describe_context(), offset, data);
639
640 switch ( offset & 3 )
641 {
642 case 0x00: /* VDC register select */
643 m_register_index = data & 0x1F;
644 break;
645
646 case 0x02: /* VDC data LSB */
647 switch ( m_register_index )
648 {
649 case MAWR: /* memory address write register LSB */
650 m_mawr = ( m_mawr & 0xFF00 ) | data;
651 break;
652
653 case MARR: /* memory address read register LSB */
654 m_marr = ( m_marr & 0xFF00 ) | data;
655 if(m_marr <= m_vram_mask)
656 m_vrr = m_vram[ m_marr ];
657 else
658 {
659 // TODO: test with real HW
660 m_vrr = 0;
661 logerror("%s Open Bus VRAM read (memory address) %04x\n",this->tag(),m_marr);
662 }
663 break;
664
665 case VxR: /* vram write data LSB */
666 m_vwr = ( m_vwr & 0xFF00 ) | data;
667 break;
668
669 case CR: /* control register LSB */
670 m_cr = ( m_cr & 0xFF00 ) | data;
671 break;
672
673 case RCR: /* raster compare register LSB */
674 m_rcr = ( m_rcr & 0x0300 ) | data;
675 // if ( m_raster_count == m_rcr && m_cr & 0x04 )
676 // {
677 // m_status |= HUC6270_RR;
678 // m_irq_changed_cb( ASSERT_LINE );
679 // }
680 break;
681
682 case BXR: /* background x-scroll register LSB */
683 m_bxr = ( m_bxr & 0x0300 ) | data;
684 break;
685
686 case BYR: /* background y-scroll register LSB */
687 m_byr = ( m_byr & 0x0100 ) | data;
688 m_byr_latched = m_byr;
689 break;
690
691 case MWR: /* memory width register LSB */
692 m_mwr = ( m_mwr & 0xFF00 ) | data;
693 break;
694
695 case HSR: /* horizontal sync register LSB */
696 m_hsr = ( m_hsr & 0xFF00 ) | data;
697 break;
698
699 case HDR: /* horizontal display register LSB */
700 m_hdr = ( m_hdr & 0xFF00 ) | data;
701 break;
702
703 case VPR: /* vertical sync register LSB */
704 m_vpr = ( m_vpr & 0xFF00 ) | data;
705 break;
706
707 case VDW: /* vertical display register LSB */
708 m_vdw = ( m_vdw & 0xFF00 ) | data;
709 break;
710
711 case VCR: /* vertical display end position register LSB */
712 m_vcr = ( m_vcr & 0xFF00 ) | data;
713 break;
714
715 case DCR: /* DMA control register LSB */
716 m_dcr = ( m_dcr & 0xFF00 ) | data;
717 break;
718
719 case SOUR: /* DMA source address register LSB */
720 m_sour = ( m_sour & 0xFF00 ) | data;
721 break;
722
723 case DESR: /* DMA destination address register LSB */
724 m_desr = ( m_desr & 0xFF00 ) | data;
725 break;
726
727 case LENR: /* DMA length register LSB */
728 m_lenr = ( m_lenr & 0xFF00 ) | data;
729 break;
730
731 case DVSSR: /* Sprite attribute table LSB */
732 m_dvssr = ( m_dvssr & 0xFF00 ) | data;
733 m_dvssr_written = 1;
734 break;
735 }
736 break;
737
738 case 0x03: /* VDC data MSB */
739 switch ( m_register_index )
740 {
741 case MAWR: /* memory address write register MSB */
742 m_mawr = ( m_mawr & 0x00FF ) | ( data << 8 );
743 break;
744
745 case MARR: /* memory address read register MSB */
746 m_marr = ( m_marr & 0x00FF ) | ( data << 8 );
747 if(m_marr <= m_vram_mask)
748 m_vrr = m_vram[ m_marr ];
749 else
750 m_vrr = 0;
751 break;
752
753 case VxR: /* vram write data MSB */
754 m_vwr = ( m_vwr & 0x00FF ) | ( data << 8 );
755 // area 0x8000-0xffff is NOP and cannot be written to.
756 if(m_mawr <= m_vram_mask)
757 m_vram[ m_mawr ] = m_vwr;
758 m_mawr += vram_increments[ ( m_cr >> 11 ) & 3 ];
759 break;
760
761 case CR: /* control register MSB */
762 m_cr = ( m_cr & 0x00FF ) | ( data << 8 );
763 break;
764
765 case RCR: /* raster compare register MSB */
766 m_rcr = ( m_rcr & 0x00FF ) | ( ( data & 0x03 ) << 8 );
767 //printf("%s: RCR set to %03x\n", machine().describe_context().c_str(), m_rcr);
768 // if ( m_raster_count == m_rcr && m_cr & 0x04 )
769 // {
770 // m_status |= HUC6270_RR;
771 // m_irq_changed_cb( ASSERT_LINE );
772 // }
773 break;
774
775 case BXR: /* background x-scroll register MSB */
776 m_bxr = ( m_bxr & 0x00FF ) | ( ( data & 0x03 ) << 8 );
777 break;
778
779 case BYR: /* background y-scroll register MSB */
780 m_byr = ( m_byr & 0x00FF ) | ( ( data & 0x01 ) << 8 );
781 m_byr_latched = m_byr;
782 break;
783
784 case MWR: /* memory width register MSB */
785 m_mwr = ( m_mwr & 0x00FF ) | ( data << 8 );
786 break;
787
788 case HSR: /* horizontal sync register MSB */
789 m_hsr = ( m_hsr & 0x00FF ) | ( data << 8 );
790 break;
791
792 case HDR: /* horizontal display register MSB */
793 m_hdr = ( m_hdr & 0x00FF ) | ( data << 8 );
794 break;
795
796 case VPR: /* vertical sync register MSB */
797 m_vpr = ( m_vpr & 0x00FF ) | ( data << 8 );
798 break;
799
800 case VDW: /* vertical display register MSB */
801 m_vdw = ( m_vdw & 0x00FF ) | ( data << 8 );
802 break;
803
804 case VCR: /* vertical display end position register MSB */
805 m_vcr = ( m_vcr & 0x00FF ) | ( data << 8 );
806 break;
807
808 case DCR: /* DMA control register MSB */
809 m_dcr = ( m_dcr & 0x00FF ) | ( data << 8 );
810 break;
811
812 case SOUR: /* DMA source address register MSB */
813 m_sour = ( m_sour & 0x00FF ) | ( data << 8 );
814 break;
815
816 case DESR: /* DMA destination address register MSB */
817 m_desr = ( m_desr & 0x00FF ) | ( data << 8 );
818 break;
819
820 case LENR: /* DMA length register MSB */
821 m_lenr = ( m_lenr & 0x00FF ) | ( data << 8 );
822 m_dma_enabled = 1;
823 //logerror("DMA is not supported yet.\n");
824 break;
825
826 case DVSSR: /* Sprite attribute table MSB */
827 m_dvssr = ( m_dvssr & 0x00FF ) | ( data << 8 );
828 m_dvssr_written = 1;
829 break;
830 }
831 break;
832 }
833 LOG("\n");
834 }
835
836
device_start()837 void huc6270_device::device_start()
838 {
839 /* Resolve callbacks */
840 m_irq_changed_cb.resolve_safe();
841
842 m_vram = make_unique_clear<uint16_t[]>(m_vram_size/sizeof(uint16_t));
843 m_vram_mask = (m_vram_size >> 1) - 1;
844
845 save_pointer(NAME(m_vram), m_vram_size/sizeof(uint16_t));
846
847 save_item(NAME(m_register_index));
848 save_item(NAME(m_mawr));
849 save_item(NAME(m_marr));
850 save_item(NAME(m_vrr));
851 save_item(NAME(m_vwr));
852 save_item(NAME(m_cr));
853 save_item(NAME(m_rcr));
854 save_item(NAME(m_bxr));
855 save_item(NAME(m_byr));
856 save_item(NAME(m_mwr));
857 save_item(NAME(m_hsr));
858 save_item(NAME(m_hdr));
859 save_item(NAME(m_vpr));
860 save_item(NAME(m_vdw));
861 save_item(NAME(m_vcr));
862 save_item(NAME(m_dcr));
863 save_item(NAME(m_sour));
864 save_item(NAME(m_desr));
865 save_item(NAME(m_lenr));
866 save_item(NAME(m_dvssr));
867 save_item(NAME(m_status));
868 save_item(NAME(m_hsync));
869 save_item(NAME(m_vsync));
870 save_item(NAME(m_vert_state));
871 save_item(NAME(m_horz_state));
872 save_item(NAME(m_vd_triggered));
873 save_item(NAME(m_vert_to_go));
874 save_item(NAME(m_horz_to_go));
875 save_item(NAME(m_horz_steps));
876 save_item(NAME(m_raster_count));
877 save_item(NAME(m_dvssr_written));
878 save_item(NAME(m_satb_countdown));
879 save_item(NAME(m_dma_enabled));
880 save_item(NAME(m_byr_latched));
881 save_item(NAME(m_bxr_latched));
882 save_item(NAME(m_bat_address));
883 save_item(NAME(m_bat_address_mask));
884 save_item(NAME(m_bat_row));
885 save_item(NAME(m_bat_column));
886 save_item(NAME(m_bat_tile_row));
887 save_item(NAME(m_sat));
888 save_item(NAME(m_sprites_this_line));
889 save_item(NAME(m_sprite_row_index));
890 save_item(NAME(m_sprite_row));
891 }
892
893
device_reset()894 void huc6270_device::device_reset()
895 {
896 m_mawr = 0;
897 m_marr = 0;
898 m_vrr = 0;
899 m_vwr = 0;
900 m_cr = 0;
901 m_rcr = 0;
902 m_bxr = 0;
903 m_byr = 0;
904 m_mwr = 0;
905 m_hsr = 0x0202; /* Take some defaults for horizontal timing */
906 m_hdr = 0x041f;
907 m_vpr = 0x0f02; /* Take some defaults for vertical timing */
908 m_vdw = 0x00ef;
909 m_vcr = 0x0004;
910 m_dcr = 0;
911 m_sour = 0;
912 m_lenr = 0;
913 m_dvssr = 0;
914 m_status = 0;
915 m_vd_triggered = 0;
916 m_dvssr_written = 0;
917 m_satb_countdown = 0;
918 m_raster_count = 0x4000;
919 m_vert_to_go = 0;
920 m_vert_state = v_state::VSW;
921 m_horz_steps = 0;
922 m_horz_to_go = 0;
923 m_horz_state = h_state::HDS;
924 m_hsync = 0;
925 m_vsync = 0;
926 m_dma_enabled = 0;
927 m_byr_latched = 0;
928
929 memset(m_sat, 0, sizeof(m_sat));
930 }
931