2 NEC-HE PC Engine Emulator 'ePCEngine'
3 SHARP X1twin Emulator 'eX1twin'
5 Origin : Ootake (joypad/cdrom)
7 : MESS (vdc/vce/vpc/cdrom)
8 Author : Takeda.Toshiya
16 #include "../huc6280.h"
18 #include "../msm5205.h"
19 #include "../scsi_host.h"
20 #include "../scsi_cdrom.h"
28 /* Bits in the VDC status register */
30 #define VDC_BSY 0x40 /* Set when the VDC accesses VRAM */
31 #define VDC_VD 0x20 /* Set when in the vertical blanking period */
32 #define VDC_DV 0x10 /* Set when a VRAM > VRAM DMA transfer is done */
33 #define VDC_DS 0x08 /* Set when a VRAM > SATB DMA transfer is done */
34 #define VDC_RR 0x04 /* Set when the current scanline equals the RCR register */
35 #define VDC_OR 0x02 /* Set when there are more than 16 sprites on a line */
36 #define VDC_CR 0x01 /* Set when sprite #0 overlaps with another sprite */
38 /* Bits in the CR register */
40 #define CR_BB 0x80 /* Background blanking */
41 #define CR_SB 0x40 /* Object blanking */
42 #define CR_VR 0x08 /* Interrupt on vertical blank enable */
43 #define CR_RC 0x04 /* Interrupt on line compare enable */
44 #define CR_OV 0x02 /* Interrupt on sprite overflow enable */
45 #define CR_CC 0x01 /* Interrupt on sprite #0 collision enable */
47 /* Bits in the DCR regsiter */
49 #define DCR_DSR 0x10 /* VRAM > SATB auto-transfer enable */
50 #define DCR_DID 0x08 /* Destination diretion */
51 #define DCR_SID 0x04 /* Source direction */
52 #define DCR_DVC 0x02 /* VRAM > VRAM EOT interrupt enable */
53 #define DCR_DSC 0x01 /* VRAM > SATB EOT interrupt enable */
57 /* just to keep things simple... */
58 enum vdc_regs {MAWR = 0, MARR, VxR, reg3, reg4, CR, RCR, BXR, BYR, MWR, HSR, HDR, VPR, VDW, VCR, DCR, SOUR, DESR, LENR, DVSSR };
62 CLEAR_LINE = 0, // clear (a fired or held) line
63 ASSERT_LINE, // assert an interrupt immediately
64 HOLD_LINE, // hold interrupt line until acknowledged
65 PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
77 #define backup_locked false
80 void PCE::initialize()
83 joy_stat = emu->get_joy_buffer();
86 register_vline_event(this);
88 #ifdef SUPPORT_BACKUP_RAM
89 static const uint8_t image[8] = {0x48, 0x55, 0x42, 0x4d, 0x00, 0x88, 0x10, 0x80};
90 memset(backup, 0, sizeof(backup));
91 memcpy(backup, image, sizeof(image));
93 FILEIO* fio = new FILEIO();
94 if(fio->Fopen(create_local_path(_T("BACKUP.BIN")), FILEIO_READ_BINARY)) {
95 fio->Fread(backup, sizeof(backup), 1);
100 backup_crc32 = get_crc32(backup, sizeof(backup));
110 #ifdef SUPPORT_BACKUP_RAM
111 if(backup_crc32 != get_crc32(backup, sizeof(backup))) {
112 FILEIO* fio = new FILEIO();
113 if(fio->Fopen(create_local_path(_T("BACKUP.BIN")), FILEIO_WRITE_BINARY)) {
114 fio->Fwrite(backup, sizeof(backup), 1);
125 memset(ram, 0, sizeof(ram));
127 buffer = 0xff; // ???
140 void PCE::event_vline(int v, int clock)
142 #ifdef SUPPORT_SUPER_GFX
150 void PCE::write_data8(uint32_t addr, uint32_t data)
152 uint8_t mpr = (addr >> 13) & 0xff;
153 uint16_t ofs = addr & 0x1fff;
156 if(support_cdrom && mpr >= 0x68 && mpr <= 0x87) {
157 cdrom_ram[addr & 0x3ffff] = data;
167 cart[addr & 0xfffff] = data;
169 #ifdef SUPPORT_BACKUP_RAM
179 #ifdef SUPPORT_SUPER_GFX
184 ram[addr & 0x7fff] = data;
189 switch(addr & 0x1c00) {
191 #ifdef SUPPORT_SUPER_GFX
193 switch(addr & 0x18) {
195 vdc_w(0, addr, data);
201 vdc_w(1, addr, data);
206 vdc_w(0, addr, data);
213 psg_write(addr, data);
215 case 0x0c00: // timer
217 d_cpu->timer_w(addr, data);
219 case 0x1000: // joypad
221 joy_write(addr, data);
223 case 0x1400: // interrupt control
225 d_cpu->irq_status_w(addr, data);
229 if(support_cdrom && (addr & 0x1e00) != 0x1a00) {
230 cdrom_write(addr, data);
237 // bank switch for sf2d
238 if((addr & 0x1ffc) == 0x1ff0) {
239 bank = 0x80000 * ((addr & 3) + 1);
243 uint32_t PCE::read_data8(uint32_t addr)
245 uint8_t mpr = (addr >> 13) & 0xff;
246 uint16_t ofs = addr & 0x1fff;
249 return cart[addr & 0x7ffff];
252 if(support_cdrom && mpr >= 0x68 && mpr <= 0x87) {
253 return cdrom_ram[addr & 0x3ffff];
257 return cart[bank | (addr & 0x7ffff)];
260 #ifdef SUPPORT_BACKUP_RAM
266 #ifdef SUPPORT_SUPER_GFX
271 return ram[addr & 0x7fff];
276 switch (addr & 0x1c00) {
278 #ifdef SUPPORT_SUPER_GFX
280 switch(addr & 0x18) {
282 return vdc_r(0, addr);
286 return vdc_r(1, addr);
291 return vdc_r(0, addr);
295 // return psg_read(addr);
297 case 0x0c00: // timer
298 buffer = (buffer & 0x80) | (d_cpu->timer_r(addr) & 0x7f);
300 case 0x1000: // joypad
301 buffer = (buffer & 0xb0) | (joy_read(addr) & 0x0f);
303 case 0x1400: // interrupt control
305 buffer = (buffer & 0xf8) | (d_cpu->irq_status_r(addr) & 0x07);
310 if(support_cdrom && (addr & 0x1e00) != 0x1a00) {
311 return cdrom_read(addr);
320 void PCE::write_io8(uint32_t addr, uint32_t data)
322 #ifdef SUPPORT_SUPER_GFX
324 sgx_vdc_w(addr, data);
327 vdc_w(0, addr, data);
330 uint32_t PCE::read_io8(uint32_t addr)
332 #ifdef SUPPORT_SUPER_GFX
334 return sgx_vdc_r(addr);
337 return vdc_r(0, addr);
340 void PCE::draw_screen()
342 int dx = (SCREEN_WIDTH - vdc[0].physical_width) / 2, sx = 0;
343 int dy = (SCREEN_HEIGHT - 240) / 2;
350 if(prev_width != vdc[0].physical_width) {
351 for(int y = 0; y < SCREEN_HEIGHT; y++) {
352 memset(emu->get_screen_buffer(y), 0, sizeof(scrntype_t) * SCREEN_WIDTH);
354 prev_width = vdc[0].physical_width;
356 emu->set_vm_screen_lines(240);
358 for(int y = 0; y < 240; y++, dy++) {
359 scrntype_t* src = &vce.bmp[y + 17][86];
360 scrntype_t* dst = emu->get_screen_buffer(dy);
361 for(int x = sx, x2 = dx; x < vdc[0].physical_width && x2 < SCREEN_WIDTH; x++, x2++) {
367 void PCE::open_cart(const _TCHAR* file_path)
369 FILEIO* fio = new FILEIO();
371 support_6btn_pad = ((config.joystick_type & 1) != 0);
372 support_multi_tap = ((config.joystick_type & 2) != 0);
373 #ifdef SUPPORT_SUPER_GFX
374 support_sgfx = false;
377 support_cdrom = false;
380 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
381 memset(cart, 0xff, sizeof(cart));
382 fio->Fseek(0, FILEIO_SEEK_END);
383 int size = fio->Ftell();
384 int head = size % 1024;
386 fio->Fseek(head, FILEIO_SEEK_SET);
387 fio->Fread(cart, size, 1);
390 if(size == 512 * 1024) {
391 bool overdump = true;
392 for(int i = 0x40000; i < 0x60000; i++) {
393 if(cart[i] != cart[i + 0x20000]) {
402 if(size == 384 * 1024) {
403 memcpy(cart + 0x060000, cart + 0x040000, 0x020000); /* Set up 060000 - 07FFFF mirror */
404 memcpy(cart + 0x080000, cart + 0x040000, 0x040000); /* Set up 080000 - 0BFFFF region */
405 memcpy(cart + 0x0C0000, cart + 0x040000, 0x040000); /* Set up 0C0000 - 0FFFFF region */
406 memcpy(cart + 0x040000, cart, 0x040000); /* Set up 040000 - 07FFFF region */
408 /* mirror 256KB rom data */
409 if (size <= 0x040000)
410 memcpy(cart + 0x040000, cart, 0x040000);
411 /* mirror 512KB rom data */
412 if (size <= 0x080000)
413 memcpy(cart + 0x080000, cart, 0x080000);
415 uint32_t cart_crc32 = get_crc32(cart, size);
416 #ifdef SUPPORT_SUPER_GFX
417 if((size == 0x100000 && cart_crc32 == 0x8c4588e2) || // 1941 Counter Attack
418 (size == 0x100000 && cart_crc32 == 0x4c2126b0) || // Aldynes
419 (size == 0x080000 && cart_crc32 == 0x3b13af61) || // Battle Ace
420 (size == 0x100000 && cart_crc32 == 0xb486a8ed) || // Daimakaimura
421 (size == 0x0c0000 && cart_crc32 == 0xbebfe042) || // Darius Plus
422 (size == 0x100000 && cart_crc32 == 0x1e1d0319) || // Darius Plus (1024K)
423 (size == 0x080000 && cart_crc32 == 0x1f041166)) { // Grandzort
428 if(size >= 0x40000 && memcmp(cart + 0x3ffb6, "PC Engine CD-ROM SYSTEM", 23) == 0) {
429 support_cdrom = true;
432 if((size == 0x280000 && cart_crc32 == 0xd15cb6bb) || // Street Fighter II Champion Edition
433 (size == 0x100000 && cart_crc32 == 0xd6fc51ce)) { // Strip Figher II
434 support_6btn_pad = true;
436 if(size == 0x40000 && cart_crc32 == 0x80c3f824) { // Yokai Dochu Ki
437 support_multi_tap = false;
444 void PCE::close_cart()
446 memset(cart, 0xff, sizeof(cart));
452 void PCE::pce_interrupt()
454 /* Draw the last scanline */
455 if ( vce.current_bitmap_line >= 14 && vce.current_bitmap_line < 14 + 242 )
457 /* We are in the active display area */
458 /* First fill the line with the overscan color */
459 draw_overscan_line(vce.current_bitmap_line );
461 /* Check if we need to draw more just the overscan color */
462 if ( vdc[0].current_segment == STATE_VDW )
464 /* 0 - no sprite and background pixels drawn
465 1 - background pixel drawn
466 otherwise is 2 + sprite# */
467 uint8_t drawn[VDC_WPF];
468 /* our line buffer */
469 scrntype_t *line_buffer = &vce.bmp[vce.current_bitmap_line][86];
471 /* clear our priority/sprite collision detection buffer. */
472 memset(drawn, 0, VDC_WPF);
474 vdc[0].y_scroll = ( vdc[0].current_segment_line == 0 ) ? vdc[0].vdc_data[BYR].w.l : ( vdc[0].y_scroll + 1 );
476 /* Draw VDC #0 background layer */
477 pce_refresh_line(0, vdc[0].current_segment_line, 0, drawn, line_buffer);
479 /* Draw VDC #0 sprite layer */
480 if(vdc[0].vdc_data[CR].w.l & CR_SB)
482 pce_refresh_sprites(0, vdc[0].current_segment_line, drawn, line_buffer);
488 /* We are in one of the blanking areas */
489 draw_black_line(vce.current_bitmap_line );
492 /* bump current scanline */
493 vce.current_bitmap_line = ( vce.current_bitmap_line + 1 ) % VDC_LPF;
497 #ifdef SUPPORT_SUPER_GFX
498 void PCE::sgx_interrupt()
500 /* Draw the last scanline */
501 if ( vce.current_bitmap_line >= 14 && vce.current_bitmap_line < 14 + 242 )
503 /* We are in the active display area */
504 /* First fill the line with the overscan color */
505 draw_sgx_overscan_line(vce.current_bitmap_line );
507 /* Check if we need to draw more just the overscan color */
508 if ( vdc[0].current_segment == STATE_VDW )
510 /* 0 - no sprite and background pixels drawn
511 1 - background pixel drawn
512 otherwise is 2 + sprite# */
513 uint8_t drawn[2][512];
514 scrntype_t *line_buffer;
515 scrntype_t temp_buffer[2][512];
518 /* clear our priority/sprite collision detection buffer. */
519 memset( drawn, 0, sizeof(drawn) );
521 vdc[0].y_scroll = ( vdc[0].current_segment_line == 0 ) ? vdc[0].vdc_data[BYR].w.l : ( vdc[0].y_scroll + 1 );
522 vdc[1].y_scroll = ( vdc[1].current_segment_line == 0 ) ? vdc[1].vdc_data[BYR].w.l : ( vdc[1].y_scroll + 1 );
524 /* Draw VDC #0 background layer */
525 pce_refresh_line( 0, vdc[0].current_segment_line, 0, drawn[0], temp_buffer[0]);
527 /* Draw VDC #0 sprite layer */
528 if(vdc[0].vdc_data[CR].w.l & CR_SB)
530 pce_refresh_sprites(0, vdc[0].current_segment_line, drawn[0], temp_buffer[0]);
533 /* Draw VDC #1 background layer */
534 pce_refresh_line( 1, vdc[1].current_segment_line, 1, drawn[1], temp_buffer[1]);
536 /* Draw VDC #1 sprite layer */
537 if ( vdc[1].vdc_data[CR].w.l & CR_SB )
539 pce_refresh_sprites(1, vdc[1].current_segment_line, drawn[1], temp_buffer[1]);
542 line_buffer = &vce.bmp[vce.current_bitmap_line][86];
543 /* Combine the output of both VDCs */
544 for( i = 0; i < 512; i++ )
546 int cur_prio = vpc.prio_map[i];
548 if ( vpc.vpc_prio[cur_prio].vdc0_enabled )
550 if ( vpc.vpc_prio[cur_prio].vdc1_enabled )
552 switch( vpc.vpc_prio[cur_prio].prio )
554 case 0: /* BG1 SP1 BG0 SP0 */
557 line_buffer[i] = temp_buffer[0][i];
559 else if ( drawn[1][i] )
561 line_buffer[i] = temp_buffer[1][i];
564 case 1: /* BG1 BG0 SP1 SP0 */
567 if ( drawn[0][i] > 1 )
569 line_buffer[i] = temp_buffer[0][i];
573 if ( drawn[1][i] > 1 )
575 line_buffer[i] = temp_buffer[1][i];
579 line_buffer[i] = temp_buffer[0][i];
583 else if ( drawn[1][i] )
585 line_buffer[i] = temp_buffer[1][i];
588 case 2: /* BG1 + SP1 => SP1
596 if ( drawn[0][i] > 1 )
598 if ( drawn[1][i] == 1 )
600 line_buffer[i] = temp_buffer[1][i];
604 line_buffer[i] = temp_buffer[0][i];
609 line_buffer[i] = temp_buffer[0][i];
612 else if ( drawn[1][i] )
614 line_buffer[i] = temp_buffer[1][i];
623 line_buffer[i] = temp_buffer[0][i];
629 if ( vpc.vpc_prio[cur_prio].vdc1_enabled )
633 line_buffer[i] = temp_buffer[1][i];
642 /* We are in one of the blanking areas */
643 draw_black_line(vce.current_bitmap_line );
646 /* bump current scanline */
647 vce.current_bitmap_line = ( vce.current_bitmap_line + 1 ) % VDC_LPF;
653 void PCE::vdc_advance_line(int which)
657 vdc[which].curline += 1;
658 vdc[which].current_segment_line += 1;
659 vdc[which].raster_count += 1;
661 if ( vdc[which].satb_countdown )
663 vdc[which].satb_countdown -= 1;
664 if ( vdc[which].satb_countdown == 0 )
666 if ( vdc[which].vdc_data[DCR].w.l & DCR_DSC )
668 vdc[which].status |= VDC_DS; /* set satb done flag */
674 if ( vce.current_bitmap_line == 0 )
676 vdc[which].current_segment = STATE_VSW;
677 vdc[which].current_segment_line = 0;
678 vdc[which].vblank_triggered = 0;
679 vdc[which].curline = 0;
682 if ( STATE_VSW == vdc[which].current_segment && vdc[which].current_segment_line >= ( vdc[which].vdc_data[VPR].b.l & 0x1F ) )
684 vdc[which].current_segment = STATE_VDS;
685 vdc[which].current_segment_line = 0;
688 if ( STATE_VDS == vdc[which].current_segment && vdc[which].current_segment_line >= vdc[which].vdc_data[VPR].b.h )
690 vdc[which].current_segment = STATE_VDW;
691 vdc[which].current_segment_line = 0;
692 vdc[which].raster_count = 0x40;
695 if ( STATE_VDW == vdc[which].current_segment && vdc[which].current_segment_line > ( vdc[which].vdc_data[VDW].w.l & 0x01FF ) )
697 vdc[which].current_segment = STATE_VCR;
698 vdc[which].current_segment_line = 0;
700 /* Generate VBlank interrupt, sprite DMA */
701 vdc[which].vblank_triggered = 1;
702 if ( vdc[which].vdc_data[CR].w.l & CR_VR )
704 vdc[which].status |= VDC_VD;
708 /* do VRAM > SATB DMA if the enable bit is set or the DVSSR reg. was written to */
709 if( ( vdc[which].vdc_data[DCR].w.l & DCR_DSR ) || vdc[which].dvssr_write )
713 vdc[which].dvssr_write = 0;
715 for( i = 0; i < 256; i++ )
717 vdc[which].sprite_ram[i] = ( vdc[which].vram[ ( vdc[which].vdc_data[DVSSR].w.l << 1 ) + i * 2 + 1 ] << 8 ) | vdc[which].vram[ ( vdc[which].vdc_data[DVSSR].w.l << 1 ) + i * 2 ];
720 /* generate interrupt if needed */
721 if ( vdc[which].vdc_data[DCR].w.l & DCR_DSC )
723 vdc[which].satb_countdown = 4;
728 if ( STATE_VCR == vdc[which].current_segment )
730 if ( vdc[which].current_segment_line >= 3 && vdc[which].current_segment_line >= vdc[which].vdc_data[VCR].b.l )
732 vdc[which].current_segment = STATE_VSW;
733 vdc[which].current_segment_line = 0;
734 vdc[which].curline = 0;
738 /* generate interrupt on line compare if necessary */
739 if ( vdc[which].raster_count == vdc[which].vdc_data[RCR].w.l && vdc[which].vdc_data[CR].w.l & CR_RC )
741 vdc[which].status |= VDC_RR;
745 /* handle frame events */
746 if(vdc[which].curline == 261 && ! vdc[which].vblank_triggered )
749 vdc[which].vblank_triggered = 1;
750 if(vdc[which].vdc_data[CR].w.l & CR_VR)
751 { /* generate IRQ1 if enabled */
752 vdc[which].status |= VDC_VD; /* set vblank flag */
756 /* do VRAM > SATB DMA if the enable bit is set or the DVSSR reg. was written to */
757 if ( ( vdc[which].vdc_data[DCR].w.l & DCR_DSR ) || vdc[which].dvssr_write )
761 vdc[which].dvssr_write = 0;
762 for( i = 0; i < 256; i++ )
764 vdc[which].sprite_ram[i] = ( vdc[which].vram[ ( vdc[which].vdc_data[DVSSR].w.l << 1 ) + i * 2 + 1 ] << 8 ) | vdc[which].vram[ ( vdc[which].vdc_data[DVSSR].w.l << 1 ) + i * 2 ];
767 /* generate interrupt if needed */
768 if(vdc[which].vdc_data[DCR].w.l & DCR_DSC)
770 vdc[which].satb_countdown = 4;
776 d_cpu->write_signal(INPUT_LINE_IRQ1, HOLD_LINE, 0);
779 void PCE::vdc_reset()
782 memset(&vdc, 0, sizeof(vdc));
783 memset(&vce, 0, sizeof(vce));
784 memset(&vpc, 0, sizeof(vpc));
789 /* initialize palette */
792 for( i = 0; i < 512; i++ )
794 int r = (( i >> 3) & 7) << 5;
795 int g = (( i >> 6) & 7) << 5;
796 int b = (( i ) & 7) << 5;
797 int y = ( ( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
798 vce.palette[i] = RGB_COLOR(r, g, b);
799 vce.palette[512+i] = RGB_COLOR(y, y, y);
809 void PCE::draw_black_line(int line)
813 /* our line buffer */
814 scrntype_t *line_buffer = vce.bmp[line];
816 for( i=0; i< VDC_WPF; i++ )
820 void PCE::draw_overscan_line(int line)
824 /* Are we in greyscale mode or in color mode? */
825 scrntype_t *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
827 /* our line buffer */
828 scrntype_t *line_buffer = vce.bmp[line];
830 for ( i = 0; i < VDC_WPF; i++ )
831 line_buffer[i] = color_base[vce.vce_data[0x100].w.l];
834 #ifdef SUPPORT_SUPER_GFX
835 void PCE::draw_sgx_overscan_line(int line)
839 /* Are we in greyscale mode or in color mode? */
840 scrntype_t *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
842 /* our line buffer */
843 scrntype_t *line_buffer = vce.bmp[line];
845 for ( i = 0; i < VDC_WPF; i++ )
846 line_buffer[i] = color_base[vce.vce_data[0].w.l];
850 void PCE::vram_write(int which, uint32_t offset, uint8_t data)
858 vdc[which].vram[offset] = data;
862 uint8_t PCE::vram_read(int which, uint32_t offset)
868 temp = vdc[which].vram[offset & 0xFFFF];
872 temp = vdc[which].vram[offset];
878 void PCE::vdc_w(int which, uint16_t offset, uint8_t data)
882 case 0x00: /* VDC register select */
883 vdc[which].vdc_register = (data & 0x1F);
886 case 0x02: /* VDC data (LSB) */
887 vdc[which].vdc_data[vdc[which].vdc_register].b.l = data;
888 switch(vdc[which].vdc_register)
890 case VxR: /* LSB of data to write to VRAM */
891 vdc[which].vdc_latch = data;
895 vdc[which].y_scroll=vdc[which].vdc_data[BYR].w.l;
899 vdc[which].physical_width = ((data & 0x003F) + 1) << 3;
903 vdc[which].physical_height &= 0xFF00;
904 vdc[which].physical_height |= (data & 0xFF);
905 vdc[which].physical_height &= 0x01FF;
917 case 0x03: /* VDC data (MSB) */
918 vdc[which].vdc_data[vdc[which].vdc_register].b.h = data;
919 switch(vdc[which].vdc_register)
921 case VxR: /* MSB of data to write to VRAM */
922 vram_write(which, vdc[which].vdc_data[MAWR].w.l*2+0, vdc[which].vdc_latch);
923 vram_write(which, vdc[which].vdc_data[MAWR].w.l*2+1, data);
924 vdc[which].vdc_data[MAWR].w.l += vdc[which].inc;
929 static const unsigned char inctab[] = {1, 32, 64, 128};
930 vdc[which].inc = inctab[(data >> 3) & 3];
935 vdc[which].physical_height &= 0x00FF;
936 vdc[which].physical_height |= (data << 8);
937 vdc[which].physical_height &= 0x01FF;
941 /* Force VRAM <> SATB DMA for this frame */
942 vdc[which].dvssr_write = 1;
946 vdc[which].y_scroll=vdc[which].vdc_data[BYR].w.l;
961 uint8_t PCE::vdc_r(int which, uint16_t offset)
967 temp = vdc[which].status;
968 vdc[which].status &= ~(VDC_VD | VDC_DV | VDC_DS | VDC_RR | VDC_OR | VDC_CR);
969 d_cpu->write_signal(INPUT_LINE_IRQ1, CLEAR_LINE, 0);
973 temp = vram_read(which, vdc[which].vdc_data[MARR].w.l * 2 + 0);
977 temp = vram_read(which, vdc[which].vdc_data[MARR].w.l * 2 + 1);
978 if ( vdc[which].vdc_register == VxR )
980 vdc[which].vdc_data[MARR].w.l += vdc[which].inc;
987 uint8_t PCE::vce_r(uint16_t offset)
992 case 0x04: /* color table data (LSB) */
993 temp = vce.vce_data[vce.vce_address.w.l].b.l;
996 case 0x05: /* color table data (MSB) */
997 temp = vce.vce_data[vce.vce_address.w.l].b.h;
999 vce.vce_address.w.l = (vce.vce_address.w.l + 1) & 0x01FF;
1005 void PCE::vce_w(uint16_t offset, uint8_t data)
1009 case 0x00: /* control reg. */
1010 vce.vce_control = data;
1013 case 0x02: /* color table address (LSB) */
1014 vce.vce_address.b.l = data;
1015 vce.vce_address.w.l &= 0x1FF;
1018 case 0x03: /* color table address (MSB) */
1019 vce.vce_address.b.h = data;
1020 vce.vce_address.w.l &= 0x1FF;
1023 case 0x04: /* color table data (LSB) */
1024 vce.vce_data[vce.vce_address.w.l].b.l = data;
1027 case 0x05: /* color table data (MSB) */
1028 vce.vce_data[vce.vce_address.w.l].b.h = data & 0x01;
1030 /* bump internal address */
1031 vce.vce_address.w.l = (vce.vce_address.w.l + 1) & 0x01FF;
1036 void PCE::pce_refresh_line(int which, int line, int external_input, uint8_t *drawn, scrntype_t *line_buffer)
1038 static const int width_table[4] = {5, 6, 7, 7};
1040 int scroll_y = ( vdc[which].y_scroll & 0x01FF);
1041 int scroll_x = (vdc[which].vdc_data[BXR].w.l & 0x03FF);
1044 /* is virtual map 32 or 64 characters tall ? (256 or 512 pixels) */
1045 int v_line = (scroll_y) & (vdc[which].vdc_data[MWR].w.l & 0x0040 ? 0x1FF : 0x0FF);
1047 /* row within character */
1048 int v_row = (v_line & 7);
1050 /* row of characters in BAT */
1051 int nt_row = (v_line >> 3);
1053 /* virtual X size (# bits to shift) */
1054 int v_width = width_table[(vdc[which].vdc_data[MWR].w.l >> 4) & 3];
1056 /* pointer to the name table (Background Attribute Table) in VRAM */
1057 uint8_t *bat = &(vdc[which].vram[nt_row << (v_width+1)]);
1059 /* Are we in greyscale mode or in color mode? */
1060 scrntype_t *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
1064 int cell_pattern_index;
1068 /* character blanking bit */
1069 if(!(vdc[which].vdc_data[CR].w.l & CR_BB))
1076 int phys_x = - ( scroll_x & 0x07 );
1078 for(i=0;i<(vdc[which].physical_width >> 3) + 1;i++)
1080 nt_index = (i + (scroll_x >> 3)) & ((2 << (v_width-1))-1);
1083 /* get name table data: */
1085 /* palette # = index from 0-15 */
1086 cell_palette = ( bat[nt_index + 1] >> 4 ) & 0x0F;
1088 /* This is the 'character number', from 0-0x0FFF */
1089 /* then it is shifted left 4 bits to form a VRAM address */
1090 /* and one more bit to convert VRAM word offset to a */
1091 /* byte-offset within the VRAM space */
1092 cell_pattern_index = ( ( ( bat[nt_index + 1] << 8 ) | bat[nt_index] ) & 0x0FFF) << 5;
1094 b0 = vram_read(which, (cell_pattern_index) + (v_row << 1) + 0x00);
1095 b1 = vram_read(which, (cell_pattern_index) + (v_row << 1) + 0x01);
1096 b2 = vram_read(which, (cell_pattern_index) + (v_row << 1) + 0x10);
1097 b3 = vram_read(which, (cell_pattern_index) + (v_row << 1) + 0x11);
1101 i0 = (b0 >> (7-x)) & 1;
1102 i1 = (b1 >> (7-x)) & 1;
1103 i2 = (b2 >> (7-x)) & 1;
1104 i3 = (b3 >> (7-x)) & 1;
1105 c = (cell_palette << 4 | i3 << 3 | i2 << 2 | i1 << 1 | i0);
1107 /* colour #0 always comes from palette #0 */
1108 if ( ! ( c & 0x0F ) )
1111 if ( phys_x >= 0 && phys_x < vdc[which].physical_width )
1113 drawn[ pixel ] = c ? 1 : 0;
1114 if ( c || ! external_input )
1115 line_buffer[ pixel ] = color_base[vce.vce_data[c].w.l];
1117 // if ( vdc[which].physical_width != 512 )
1119 // while ( pixel < ( ( ( phys_x + 1 ) * 512 ) / vdc[which].physical_width ) )
1121 // drawn[ pixel ] = c ? 1 : 0;
1122 // if ( c || ! external_input )
1123 // line_buffer[ pixel ] = color_base[vce.vce_data[c].w.l];
1134 void PCE::conv_obj(int which, int i, int l, int hf, int vf, char *buf)
1136 int b0, b1, b2, b3, i0, i1, i2, i3, x;
1141 if(vf) l = (15 - l);
1143 tmp = l + ( i << 5);
1145 b0 = vram_read(which, (tmp + 0x00)<<1);
1146 b0 |= vram_read(which, ((tmp + 0x00)<<1)+1)<<8;
1147 b1 = vram_read(which, (tmp + 0x10)<<1);
1148 b1 |= vram_read(which, ((tmp + 0x10)<<1)+1)<<8;
1149 b2 = vram_read(which, (tmp + 0x20)<<1);
1150 b2 |= vram_read(which, ((tmp + 0x20)<<1)+1)<<8;
1151 b3 = vram_read(which, (tmp + 0x30)<<1);
1152 b3 |= vram_read(which, ((tmp + 0x30)<<1)+1)<<8;
1156 if(hf) xi = x; else xi = (15 - x);
1157 i0 = (b0 >> xi) & 1;
1158 i1 = (b1 >> xi) & 1;
1159 i2 = (b2 >> xi) & 1;
1160 i3 = (b3 >> xi) & 1;
1161 buf[x] = (i3 << 3 | i2 << 2 | i1 << 1 | i0);
1165 void PCE::pce_refresh_sprites(int which, int line, uint8_t *drawn, scrntype_t *line_buffer)
1168 uint8_t sprites_drawn = 0;
1170 /* Are we in greyscale mode or in color mode? */
1171 scrntype_t *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
1173 /* count up: Highest priority is Sprite 0 */
1174 for(i = 0; i < 64; i++)
1176 static const int cgy_table[] = {16, 32, 64, 64};
1178 int obj_y = (vdc[which].sprite_ram[(i << 2) + 0] & 0x03FF) - 64;
1179 int obj_x = (vdc[which].sprite_ram[(i << 2) + 1] & 0x03FF) - 32;
1180 int obj_i = (vdc[which].sprite_ram[(i << 2) + 2] & 0x07FE);
1181 int obj_a = (vdc[which].sprite_ram[(i << 2) + 3]);
1182 int cgx = (obj_a >> 8) & 1; /* sprite width */
1183 int cgy = (obj_a >> 12) & 3; /* sprite height */
1184 int hf = (obj_a >> 11) & 1; /* horizontal flip */
1185 int vf = (obj_a >> 15) & 1; /* vertical flip */
1186 int palette = (obj_a & 0x000F);
1187 int priority = (obj_a >> 7) & 1;
1188 int obj_h = cgy_table[cgy];
1189 int obj_l = (line - obj_y);
1193 if ((obj_y == -64) || (obj_y > line)) continue;
1194 if ((obj_x == -32) || (obj_x >= vdc[which].physical_width)) continue;
1196 /* no need to draw an object that's ABOVE where we are. */
1197 if((obj_y + obj_h) < line) continue;
1199 /* If CGX is set, bit 0 of sprite pattern index is forced to 0 */
1203 /* If CGY is set to 1, bit 1 of the sprite pattern index is forced to 0. */
1207 /* If CGY is set to 2 or 3, bit 1 and 2 of the sprite pattern index are forced to 0. */
1215 if(sprites_drawn > 16)
1217 if(vdc[which].vdc_data[CR].w.l & CR_OV)
1219 /* note: flag is set only if irq is taken, Mizubaku Daibouken relies on this behaviour */
1220 vdc[which].status |= VDC_OR;
1221 d_cpu->write_signal(INPUT_LINE_IRQ1, ASSERT_LINE, 0);
1223 continue; /* Should cause an interrupt */
1226 cgypos = (obj_l >> 4);
1227 if(vf) cgypos = ((obj_h - 1) >> 4) - cgypos;
1232 int pixel_x = obj_x;//( ( obj_x * 512 ) / vdc[which].physical_width );
1234 conv_obj(which, obj_i + (cgypos << 2), obj_l, hf, vf, buf);
1236 for(x = 0; x < 16; x++)
1238 if(((obj_x + x) < (vdc[which].physical_width)) && ((obj_x + x) >= 0))
1242 if( drawn[pixel_x] < 2 )
1244 if( priority || drawn[pixel_x] == 0 )
1246 line_buffer[pixel_x] = color_base[vce.vce_data[0x100 + (palette << 4) + buf[x]].w.l];
1247 // if ( vdc[which].physical_width != 512 )
1250 // while ( pixel_x + dp < ( ( ( obj_x + x + 1 ) * 512 ) / vdc[which].physical_width ) )
1252 // drawn[pixel_x + dp] = i + 2;
1253 // line_buffer[pixel_x + dp] = color_base[vce.vce_data[0x100 + (palette << 4) + buf[x]].w.l];
1258 drawn[pixel_x] = i + 2;
1260 /* Check for sprite #0 collision */
1261 else if (drawn[pixel_x] == 2)
1263 if(vdc[which].vdc_data[CR].w.l & CR_CC)
1264 d_cpu->write_signal(INPUT_LINE_IRQ1, ASSERT_LINE, 0);
1265 vdc[which].status |= VDC_CR;
1269 // if ( vdc[which].physical_width != 512 )
1271 // pixel_x = ( ( obj_x + x + 1 ) * 512 ) / vdc[which].physical_width;
1282 int pixel_x = obj_x;//( ( obj_x * 512 ) / vdc[which].physical_width );
1284 conv_obj(which, obj_i + (cgypos << 2) + (hf ? 2 : 0), obj_l, hf, vf, buf);
1286 for(x = 0; x < 16; x++)
1288 if(((obj_x + x) < (vdc[which].physical_width)) && ((obj_x + x) >= 0))
1292 if( drawn[pixel_x] < 2 )
1294 if ( priority || drawn[pixel_x] == 0 )
1296 line_buffer[pixel_x] = color_base[vce.vce_data[0x100 + (palette << 4) + buf[x]].w.l];
1297 // if ( vdc[which].physical_width != 512 )
1300 // while ( pixel_x + dp < ( ( ( obj_x + x + 1 ) * 512 ) / vdc[which].physical_width ) )
1302 // drawn[pixel_x + dp] = i + 2;
1303 // line_buffer[pixel_x + dp] = color_base[vce.vce_data[0x100 + (palette << 4) + buf[x]].w.l];
1308 drawn[pixel_x] = i + 2;
1310 /* Check for sprite #0 collision */
1311 else if ( drawn[pixel_x] == 2 )
1313 if(vdc[which].vdc_data[CR].w.l & CR_CC)
1314 d_cpu->write_signal(INPUT_LINE_IRQ1, ASSERT_LINE, 0);
1315 vdc[which].status |= VDC_CR;
1319 // if ( vdc[which].physical_width != 512 )
1321 // pixel_x = ( ( obj_x + x + 1 ) * 512 ) / vdc[which].physical_width;
1329 /* 32 pixel wide sprites are counted as 2 sprites and the right half
1330 is only drawn if there are 2 open slots.
1333 if( sprites_drawn > 16 )
1335 if(vdc[which].vdc_data[CR].w.l&CR_OV)
1337 /* note: flag is set only if irq is taken, Mizubaku Daibouken relies on this behaviour */
1338 vdc[which].status |= VDC_OR;
1339 d_cpu->write_signal(INPUT_LINE_IRQ1, ASSERT_LINE, 0);
1344 conv_obj(which, obj_i + (cgypos << 2) + (hf ? 0 : 2), obj_l, hf, vf, buf);
1345 for(x = 0; x < 16; x++)
1347 if(((obj_x + 0x10 + x) < (vdc[which].physical_width)) && ((obj_x + 0x10 + x) >= 0))
1351 if( drawn[pixel_x] < 2 )
1353 if( priority || drawn[pixel_x] == 0 )
1355 line_buffer[pixel_x] = color_base[vce.vce_data[0x100 + (palette << 4) + buf[x]].w.l];
1356 // if ( vdc[which].physical_width != 512 )
1359 // while ( pixel_x + dp < ( ( ( obj_x + x + 17 ) * 512 ) / vdc[which].physical_width ) )
1361 // drawn[pixel_x + dp] = i + 2;
1362 // line_buffer[pixel_x + dp] = color_base[vce.vce_data[0x100 + (palette << 4) + buf[x]].w.l];
1367 drawn[pixel_x] = i + 2;
1369 /* Check for sprite #0 collision */
1370 else if ( drawn[pixel_x] == 2 )
1372 if(vdc[which].vdc_data[CR].w.l & CR_CC)
1373 d_cpu->write_signal(INPUT_LINE_IRQ1, ASSERT_LINE, 0);
1374 vdc[which].status |= VDC_CR;
1378 // if ( vdc[which].physical_width != 512 )
1380 // pixel_x = ( ( obj_x + x + 17 ) * 512 ) / vdc[which].physical_width;
1393 void PCE::vdc_do_dma(int which)
1395 int src = vdc[which].vdc_data[SOUR].w.l;
1396 int dst = vdc[which].vdc_data[DESR].w.l;
1397 int len = vdc[which].vdc_data[LENR].w.l;
1399 int did = (vdc[which].vdc_data[DCR].w.l >> 3) & 1;
1400 int sid = (vdc[which].vdc_data[DCR].w.l >> 2) & 1;
1401 int dvc = (vdc[which].vdc_data[DCR].w.l >> 1) & 1;
1406 l = vram_read(which, src<<1);
1407 h = vram_read(which, (src<<1) + 1);
1409 vram_write(which, dst<<1,l);
1410 vram_write(which, 1+(dst<<1),h);
1412 if(sid) src = (src - 1) & 0xFFFF;
1413 else src = (src + 1) & 0xFFFF;
1415 if(did) dst = (dst - 1) & 0xFFFF;
1416 else dst = (dst + 1) & 0xFFFF;
1418 len = (len - 1) & 0xFFFF;
1420 } while (len != 0xFFFF);
1422 vdc[which].status |= VDC_DV;
1423 vdc[which].vdc_data[SOUR].w.l = src;
1424 vdc[which].vdc_data[DESR].w.l = dst;
1425 vdc[which].vdc_data[LENR].w.l = len;
1428 d_cpu->write_signal(INPUT_LINE_IRQ1, ASSERT_LINE, 0);
1433 void PCE::vpc_update_prio_map()
1437 for( i = 0; i < 512; i++ )
1439 vpc.prio_map[i] = 0;
1440 if ( vpc.window1.w.l < 0x40 || i > vpc.window1.w.l )
1442 vpc.prio_map[i] |= 1;
1444 if ( vpc.window2.w.l < 0x40 || i > vpc.window2.w.l )
1446 vpc.prio_map[i] |= 2;
1451 void PCE::vpc_w(uint16_t offset, uint8_t data)
1453 switch( offset & 0x07 )
1455 case 0x00: /* Priority register #0 */
1456 vpc.priority.b.l = data;
1457 vpc.vpc_prio[0].prio = ( data >> 2 ) & 3;
1458 vpc.vpc_prio[0].vdc0_enabled = data & 1;
1459 vpc.vpc_prio[0].vdc1_enabled = data & 2;
1460 vpc.vpc_prio[1].prio = ( data >> 6 ) & 3;
1461 vpc.vpc_prio[1].vdc0_enabled = data & 0x10;
1462 vpc.vpc_prio[1].vdc1_enabled = data & 0x20;
1464 case 0x01: /* Priority register #1 */
1465 vpc.priority.b.h = data;
1466 vpc.vpc_prio[2].prio = ( data >> 2 ) & 3;
1467 vpc.vpc_prio[2].vdc0_enabled = data & 1;
1468 vpc.vpc_prio[2].vdc1_enabled = data & 2;
1469 vpc.vpc_prio[3].prio = ( data >> 6 ) & 3;
1470 vpc.vpc_prio[3].vdc0_enabled = data & 0x10;
1471 vpc.vpc_prio[3].vdc1_enabled = data & 0x20;
1473 case 0x02: /* Window 1 LSB */
1474 vpc.window1.b.l = data;
1475 vpc_update_prio_map();
1477 case 0x03: /* Window 1 MSB */
1478 vpc.window1.b.h = data & 3;
1479 vpc_update_prio_map();
1481 case 0x04: /* Window 2 LSB */
1482 vpc.window2.b.l = data;
1483 vpc_update_prio_map();
1485 case 0x05: /* Window 2 MSB */
1486 vpc.window2.b.h = data & 3;
1487 vpc_update_prio_map();
1489 case 0x06: /* VDC I/O select */
1490 vpc.vdc_select = data & 1;
1495 uint8_t PCE::vpc_r(uint16_t offset)
1498 switch( offset & 0x07 )
1500 case 0x00: /* Priority register #0 */
1501 data = vpc.priority.b.l;
1503 case 0x01: /* Priority register #1 */
1504 data = vpc.priority.b.h;
1506 case 0x02: /* Window 1 LSB */
1507 data = vpc.window1.b.l;
1509 case 0x03: /* Window 1 MSB; high bits are 0 or 1? */
1510 data = vpc.window1.b.h;
1512 case 0x04: /* Window 2 LSB */
1513 data = vpc.window2.b.l;
1515 case 0x05: /* Window 2 MSB; high bits are 0 or 1? */
1516 data = vpc.window2.b.h;
1522 #ifdef SUPPORT_SUPER_GFX
1523 void PCE::sgx_vdc_w(uint16_t offset, uint8_t data)
1525 if ( vpc.vdc_select )
1527 vdc_w( 1, offset, data );
1531 vdc_w( 0, offset, data );
1535 uint8_t PCE::sgx_vdc_r(uint16_t offset)
1537 return ( vpc.vdc_select ) ? vdc_r( 1, offset ) : vdc_r( 0, offset );
1543 void PCE::psg_reset()
1546 memset(psg, 0, sizeof(psg));
1547 for (int i = 0; i < 6; i++) {
1548 psg[i].regs[4] = 0x80;
1550 psg[4].randval = psg[5].randval = 0x51f631e4;
1553 psg_vol = psg_lfo_freq = psg_lfo_ctrl = 0;
1556 void PCE::psg_write(uint16_t addr, uint8_t data)
1558 switch(addr & 0x1f) {
1569 psg[psg_ch].regs[2] = data;
1573 // psg[psg_ch].regs[3] = data & 0x1f;
1574 psg[psg_ch].regs[3] = data & 0xf;
1578 psg[psg_ch].regs[4] = data;
1582 psg[psg_ch].regs[5] = data;
1586 if(psg[psg_ch].regs[4] & 0x40) {
1587 psg[psg_ch].wav[0] =data & 0x1f;
1590 psg[psg_ch].wav[psg[psg_ch].wavptr] = data & 0x1f;
1591 psg[psg_ch].wavptr = (psg[psg_ch].wavptr + 1) & 0x1f;
1596 psg[psg_ch].regs[7] = data;
1600 psg_lfo_freq = data;
1604 psg_lfo_ctrl = data;
1609 uint8_t PCE::psg_read(uint16_t addr)
1613 switch(addr & 0x1f) {
1619 return psg[psg_ch].regs[2];
1621 return psg[psg_ch].regs[3];
1623 return psg[psg_ch].regs[4];
1625 return psg[psg_ch].regs[5];
1627 ptr = psg[psg_ch].wavptr;
1628 psg[psg_ch].wavptr = (psg[psg_ch].wavptr + 1) & 0x1f;
1629 return psg[psg_ch].wav[ptr];
1631 return psg[psg_ch].regs[7];
1633 return psg_lfo_freq;
1635 return psg_lfo_ctrl;
1640 void PCE::mix(int32_t* buffer, int cnt)
1643 100, 451, 508, 573, 646, 728, 821, 925,1043,1175,1325, 1493, 1683, 1898, 2139, 2411,
1644 2718,3064,3454,3893,4388,4947,5576,6285,7085,7986,9002,10148,11439,12894,14535,16384
1650 for(int ch = 0; ch < 6; ch++) {
1651 if(!(psg[ch].regs[4] & 0x80)) {
1653 psg[ch].genptr = psg[ch].remain = 0;
1655 else if(psg[ch].regs[4] & 0x40) {
1657 int32_t wav = ((int32_t)psg[ch].wav[0] - 16) * 702;
1658 int32_t vol = max((psg_vol >> 3) & 0x1e, (psg_vol << 1) & 0x1e) + (psg[ch].regs[4] & 0x1f) + max((psg[ch].regs[5] >> 3) & 0x1e, (psg[ch].regs[5] << 1) & 0x1e) - 60;
1659 vol = (vol < 0) ? 0 : (vol > 31) ? 31 : vol;
1660 int32_t outvol = wav * vol_tbl[vol] / 16384;
1661 for(int i = 0, j = 0; i < cnt; i++, j += 2) {
1662 buffer[j ] += apply_volume(outvol, volume_l); // L
1663 buffer[j + 1] += apply_volume(outvol, volume_r); // R
1666 else if(ch >= 4 && (psg[ch].regs[7] & 0x80)) {
1668 uint16_t freq = (psg[ch].regs[7] & 0x1f);
1669 int32_t vol = max((psg_vol >> 3) & 0x1e, (psg_vol << 1) & 0x1e) + (psg[ch].regs[4] & 0x1f) + max((psg[ch].regs[5] >> 3) & 0x1e, (psg[ch].regs[5] << 1) & 0x1e) - 60;
1670 vol = (vol < 0) ? 0 : (vol > 31) ? 31 : vol;
1672 for(int i = 0, j = 0; i < cnt; i++, j += 2) {
1673 psg[ch].remain += 3000 + freq * 512;
1674 uint32_t t = psg[ch].remain / sample_rate;
1676 if(psg[ch].randval & 0x80000) {
1677 psg[ch].randval = ((psg[ch].randval ^ 4) << 1) + 1;
1678 psg[ch].noise = true;
1681 psg[ch].randval <<= 1;
1682 psg[ch].noise = false;
1684 psg[ch].remain -= sample_rate * t;
1686 int32_t outvol = (int32_t)((psg[ch].noise ? 10 * 702 : -10 * 702) * vol / 16384);
1687 buffer[j ] += apply_volume(outvol, volume_l); // L
1688 buffer[j + 1] += apply_volume(outvol, volume_r); // R
1693 for(int i = 0; i < 32; i++) {
1694 wav[i] = ((int32_t)psg[ch].wav[i] - 16) * 702;
1696 uint32_t freq = psg[ch].regs[2] + ((uint32_t)psg[ch].regs[3] << 8);
1698 int32_t vol = max((psg_vol >> 3) & 0x1e, (psg_vol << 1) & 0x1e) + (psg[ch].regs[4] & 0x1f) + max((psg[ch].regs[5] >> 3) & 0x1e, (psg[ch].regs[5] << 1) & 0x1e) - 60;
1699 vol = (vol < 0) ? 0 : (vol > 31) ? 31 : vol;
1701 for(int i = 0, j = 0; i < cnt; i++, j += 2) {
1702 int32_t outvol = wav[psg[ch].genptr] * vol / 16384;
1703 buffer[j ] += apply_volume(outvol, volume_l); // L
1704 buffer[j + 1] += apply_volume(outvol, volume_r); // R
1705 psg[ch].remain += 32 * 1118608 / freq;
1706 uint32_t t = psg[ch].remain / (10 * sample_rate);
1707 psg[ch].genptr = (psg[ch].genptr + t) & 0x1f;
1708 psg[ch].remain -= 10 * sample_rate * t;
1713 #ifdef SUPPORT_CDROM
1716 d_msm->mix(buffer, cnt);
1718 d_scsi_cdrom->mix(buffer, cnt);
1723 void PCE::set_volume(int ch, int decibel_l, int decibel_r)
1725 volume_l = decibel_to_volume(decibel_l);
1726 volume_r = decibel_to_volume(decibel_r);
1729 // joypad (non multipad)
1731 void PCE::joy_reset()
1734 joy_high_nibble = joy_second_byte = false;
1737 void PCE::joy_write(uint16_t addr, uint8_t data)
1739 joy_high_nibble = ((data & 1) != 0);
1743 joy_high_nibble = false;
1744 joy_second_byte = !joy_second_byte;
1748 uint8_t PCE::joy_read(uint16_t addr)
1752 if(joy_high_nibble) {
1753 if(++joy_counter == 16) {
1757 if(joy_counter == 0) {
1760 if(support_multi_tap) {
1761 if(joy_counter > 4) {
1764 index = joy_counter;
1768 if(support_6btn_pad) {
1769 return joy_6btn_pad_r(index);
1771 return joy_2btn_pad_r(index);
1775 uint8_t PCE::joy_2btn_pad_r(uint8_t index)
1777 uint8_t data = 0x0f;
1779 if(joy_high_nibble) {
1780 if(joy_stat[index - 1] & 0x001) data &= ~0x01; // Up
1781 if(joy_stat[index - 1] & 0x008) data &= ~0x02; // Right
1782 if(joy_stat[index - 1] & 0x002) data &= ~0x04; // Down
1783 if(joy_stat[index - 1] & 0x004) data &= ~0x08; // Left
1785 if(joy_stat[index - 1] & 0x010) data &= ~0x01; // Button #1
1786 if(joy_stat[index - 1] & 0x020) data &= ~0x02; // Button #2
1787 if(joy_stat[index - 1] & 0x040) data &= ~0x04; // Select
1788 if(joy_stat[index - 1] & 0x080) data &= ~0x08; // Run
1793 uint8_t PCE::joy_6btn_pad_r(uint8_t index)
1795 uint8_t data = 0x0f;
1797 if(joy_second_byte) {
1798 if(joy_high_nibble) {
1799 if(joy_stat[index - 1] & 0x001) data &= ~0x01; // Up
1800 if(joy_stat[index - 1] & 0x008) data &= ~0x02; // Right
1801 if(joy_stat[index - 1] & 0x002) data &= ~0x04; // Down
1802 if(joy_stat[index - 1] & 0x004) data &= ~0x08; // Left
1804 if(joy_stat[index - 1] & 0x010) data &= ~0x01; // Button #1
1805 if(joy_stat[index - 1] & 0x020) data &= ~0x02; // Button #2
1806 if(joy_stat[index - 1] & 0x040) data &= ~0x04; // Select
1807 if(joy_stat[index - 1] & 0x080) data &= ~0x08; // Run
1810 if(joy_high_nibble) {
1813 if(joy_stat[index - 1] & 0x100) data &= ~0x01; // Button #3
1814 if(joy_stat[index - 1] & 0x200) data &= ~0x02; // Button #4
1815 if(joy_stat[index - 1] & 0x400) data &= ~0x04; // Button #5
1816 if(joy_stat[index - 1] & 0x800) data &= ~0x08; // Button #6
1819 if(!support_multi_tap) {
1820 if(joy_counter == 5 && !joy_high_nibble) {
1821 joy_second_byte = false;
1829 #ifdef SUPPORT_CDROM
1830 #define PCE_CD_IRQ_TRANSFER_READY 0x40
1831 #define PCE_CD_IRQ_TRANSFER_DONE 0x20
1832 #define PCE_CD_IRQ_BRAM 0x10 /* ??? */
1833 #define PCE_CD_IRQ_SAMPLE_FULL_PLAY 0x08
1834 #define PCE_CD_IRQ_SAMPLE_HALF_PLAY 0x04
1836 #define PCE_CD_ADPCM_PLAY_FLAG 0x08
1837 #define PCE_CD_ADPCM_STOP_FLAG 0x01
1839 #define EVENT_CDDA_FADE_IN 0
1840 #define EVENT_CDDA_FADE_OUT 1
1841 #define EVENT_ADPCM_FADE_IN 2
1842 #define EVENT_ADPCM_FADE_OUT 3
1844 void PCE::cdrom_initialize()
1846 adpcm_clock_divider = 1;
1847 backup_locked = true;
1848 event_cdda_fader = event_adpcm_fader = -1;
1851 void PCE::cdrom_reset()
1854 memset(cdrom_regs, 0, sizeof(cdrom_regs));
1855 cdrom_regs[0x0c] |= PCE_CD_ADPCM_STOP_FLAG;
1856 cdrom_regs[0x0c] &= ~PCE_CD_ADPCM_PLAY_FLAG;
1858 irq_status = drq_status = false;
1860 adpcm_read_ptr = adpcm_write_ptr = 0;
1861 adpcm_read_buf = adpcm_write_buf = 0;
1862 adpcm_dma_enabled = false;
1865 if(event_cdda_fader != -1) {
1866 cancel_event(this, event_cdda_fader);
1868 if(event_adpcm_fader != -1) {
1869 cancel_event(this, event_adpcm_fader);
1871 cdda_volume = adpcm_volume = 100.0;
1872 event_cdda_fader = event_adpcm_fader = -1;
1874 d_scsi_cdrom->set_volume((int)cdda_volume);
1875 d_msm->set_volume((int)adpcm_volume);
1878 void PCE::cdrom_write(uint16_t addr, uint8_t data)
1881 switch(addr & 0x0f) {
1882 case 0x00: /* CDC status */
1883 d_scsi_host->write_signal(SIG_SCSI_SEL, 1, 1);
1884 d_scsi_host->write_signal(SIG_SCSI_SEL, 0, 1);
1885 adpcm_dma_enabled = false;
1886 set_cdrom_irq_line(0x70, CLEAR_LINE);
1889 case 0x01: /* CDC command / status / data */
1890 write_cdrom_data(data);
1893 case 0x02: /* ADPCM / CD control / IRQ enable/disable */
1894 /* bit 6 - transfer ready irq */
1895 /* bit 5 - transfer done irq */
1896 /* bit 4 - BRAM irq? */
1897 /* bit 3 - ADPCM FULL irq */
1898 /* bit 2 - ADPCM HALF irq */
1904 /* Update mask register now otherwise it won't catch the irq enable/disable change */
1905 cdrom_regs[0x02] = data;
1906 /* Don't set or reset any irq lines, but just verify the current state */
1907 set_cdrom_irq_line(0, 0);
1910 case 0x03: /* BRAM lock / CD status / IRQ - Read Only register */
1913 case 0x04: /* CD reset */
1915 // Reset ADPCM hardware
1917 set_cdrom_irq_line(0x70, CLEAR_LINE);
1919 d_scsi_host->write_signal(SIG_SCSI_RST, data, 0x02);
1922 case 0x05: /* Convert PCM data / PCM data */
1923 case 0x06: /* PCM data */
1926 case 0x07: /* BRAM unlock / CD status */
1928 backup_locked = false;
1932 case 0x08: /* ADPCM address (LSB) / CD data */
1933 case 0x09: /* ADPCM address (MSB) */
1936 case 0x0a: /* ADPCM RAM data port */
1937 if(adpcm_write_buf > 0) {
1940 write_adpcm_ram(data);
1944 case 0x0b: /* ADPCM DMA control */
1946 /* Start CD to ADPCM transfer */
1947 adpcm_dma_enabled = true;
1949 if(d_scsi_cdrom->get_cur_command() == SCSI_CMD_READ6 &&
1950 d_scsi_host->read_signal(SIG_SCSI_BSY) != 0 &&
1951 d_scsi_host->read_signal(SIG_SCSI_REQ) != 0 &&
1952 d_scsi_host->read_signal(SIG_SCSI_CD ) == 0 &&
1953 d_scsi_host->read_signal(SIG_SCSI_MSG) == 0 &&
1954 d_scsi_host->read_signal(SIG_SCSI_IO ) != 0) {
1955 // already data is received, read first byte
1958 cdrom_regs[0x0c] |= 0x04;
1963 case 0x0c: /* ADPCM status */
1966 case 0x0d: /* ADPCM address control */
1967 if((cdrom_regs[0x0d] & 0x80) && !(data & 0x80)) {
1968 // Reset ADPCM hardware
1972 // ADPCM set write address
1973 adpcm_write_ptr = (cdrom_regs[0x09] << 8) | cdrom_regs[0x08];
1974 adpcm_write_buf = data & 1;
1978 // ADPCM set read address
1979 adpcm_read_ptr = (cdrom_regs[0x09] << 8) | cdrom_regs[0x08];
1984 adpcm_length = (cdrom_regs[0x09] << 8) | cdrom_regs[0x08];
1986 if((data & 0x40) && ((cdrom_regs[0x0D] & 0x40) == 0)) {
1988 msm_start_addr = (adpcm_read_ptr) & 0xffff;
1989 msm_end_addr = (adpcm_read_ptr + adpcm_length) & 0xffff;
1990 msm_half_addr = (adpcm_read_ptr + (adpcm_length / 2)) & 0xffff;
1991 adpcm_write_ptr &= 0xffff;
1995 } else if ((data & 0x40) == 0) {
1996 // used by Buster Bros to cancel an in-flight sample
1997 // if repeat flag (bit5) is high, ADPCM should be fully played (from Ootake)
1998 if(!(data & 0x20)) {
1999 set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
2000 set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE);
2007 case 0x0e: /* ADPCM playback rate */
2008 adpcm_clock_divider = 0x10 - (data & 0x0f);
2009 d_msm->change_clock_w((ADPCM_CLOCK / 6) / adpcm_clock_divider);
2012 case 0x0f: /* ADPCM and CD audio fade timer */
2013 if(cdrom_regs[0x0f] != data) {
2014 switch(data & 0x0f) {
2015 case 0x00: // CD-DA / ADPCM enable (100 msecs)
2019 case 0x01: // CD-DA enable (100 msecs)
2022 case 0x08: // CD-DA short (1500 msecs) fade out / ADPCM enable
2023 case 0x0c: // CD-DA short (1500 msecs) fade out / ADPCM enable
2024 cdda_fade_out(1500);
2027 case 0x09: // CD-DA long (5000 msecs) fade out
2028 cdda_fade_out(5000);
2030 case 0x0a: // ADPCM long (5000 msecs) fade out
2031 adpcm_fade_out(5000);
2033 case 0x0d: // CD-DA short (1500 msecs) fade out
2034 cdda_fade_out(1500);
2036 case 0x0e: // ADPCM short (1500 msecs) fade out
2037 adpcm_fade_out(1500);
2043 cdrom_regs[addr & 0x0f] = data;
2046 uint8_t PCE::cdrom_read(uint16_t addr)
2048 // System 3 Card header handling
2049 if((addr & 0xc0) == 0xc0) {
2050 switch(addr & 0xcf) {
2051 case 0xc1: return 0xaa;
2052 case 0xc2: return 0x55;
2053 case 0xc3: return 0x00;
2054 case 0xc5: return 0xaa;
2055 case 0xc6: return 0x55;
2056 case 0xc7: return 0x03;
2059 uint8_t data = cdrom_regs[addr & 0x0f];
2061 switch(addr & 0x0f) {
2062 case 0x00: /* CDC status */
2064 if(d_cpu->get_pc() == 0xf34b) {
2065 // XXX: Hack to wait the CD-DA will be finished for the Manhole
2066 data |= d_scsi_cdrom->read_signal(SIG_SCSI_CDROM_PLAYING) ? 0x80 : 0;
2068 data |= d_scsi_host->read_signal(SIG_SCSI_BSY) ? 0x80 : 0;
2069 data |= d_scsi_host->read_signal(SIG_SCSI_REQ) ? 0x40 : 0;
2070 data |= d_scsi_host->read_signal(SIG_SCSI_MSG) ? 0x20 : 0;
2071 data |= d_scsi_host->read_signal(SIG_SCSI_CD ) ? 0x10 : 0;
2072 data |= d_scsi_host->read_signal(SIG_SCSI_IO ) ? 0x08 : 0;
2075 case 0x01: /* CDC command / status / data */
2076 case 0x08: /* ADPCM address (LSB) / CD data */
2078 bool read6_data_in = false;
2079 if(d_scsi_cdrom->get_cur_command() == SCSI_CMD_READ6 &&
2080 d_scsi_host->read_signal(SIG_SCSI_BSY) != 0 &&
2081 d_scsi_host->read_signal(SIG_SCSI_REQ) != 0 &&
2082 d_scsi_host->read_signal(SIG_SCSI_CD ) == 0 &&
2083 d_scsi_host->read_signal(SIG_SCSI_MSG) == 0 &&
2084 d_scsi_host->read_signal(SIG_SCSI_IO ) != 0) {
2085 // read6 command, data in phase
2086 read6_data_in = true;
2088 data = read_cdrom_data();
2091 // set ack automatically and immediately for correct transfer speed
2094 // XXX: Hack to wait until next REQ signal is raised
2095 // because PCE does not check REQ signal before reads next byte
2096 d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
2101 case 0x02: /* ADPCM / CD control */
2104 case 0x03: /* BRAM lock / CD status */
2106 backup_locked = true;
2107 data |= PCE_CD_IRQ_BRAM;
2108 cdrom_regs[3] ^= 0x02;
2109 if(cdrom_regs[2] == 0) {
2110 cdrom_regs[3] &= 0x02;
2112 set_cdrom_irq_line(0, 0);
2115 case 0x04: /* CD reset */
2118 case 0x05: /* Convert PCM data / PCM data */
2119 data = (d_scsi_cdrom->read_signal((cdrom_regs[3] & 0x02) ? SIG_SCSI_CDROM_SAMPLE_L : SIG_SCSI_CDROM_SAMPLE_R) >> 0) & 0xff;
2122 case 0x06: /* PCM data */
2123 data = (d_scsi_cdrom->read_signal((cdrom_regs[3] & 0x02) ? SIG_SCSI_CDROM_SAMPLE_L : SIG_SCSI_CDROM_SAMPLE_R) >> 8) & 0xff;
2126 case 0x07: /* BRAM unlock / CD status */
2127 data = (backup_locked ? (data & 0x7f) : (data | 0x80));
2130 case 0x0a: /* ADPCM RAM data port */
2131 if(adpcm_read_buf > 0) {
2135 data = read_adpcm_ram();
2139 case 0x0b: /* ADPCM DMA control */
2142 case 0x0c: /* ADPCM status */
2145 case 0x09: /* ADPCM address (MSB) */
2146 case 0x0d: /* ADPCM address control */
2147 case 0x0e: /* ADPCM playback rate */
2148 case 0x0f: /* ADPCM and CD audio fade timer */
2155 void PCE::write_cdrom_data(uint8_t data)
2157 d_scsi_host->write_dma_io8(0, data);
2160 uint8_t PCE::read_cdrom_data()
2162 return d_scsi_host->read_dma_io8(0);
2165 void PCE::reset_adpcm()
2168 // reset ADPCM hardware
2169 adpcm_read_ptr = adpcm_write_ptr = 0;
2170 msm_start_addr = msm_end_addr = msm_half_addr = 0;
2176 adpcm_dma_enabled = false;
2179 void PCE::write_adpcm_ram(uint8_t data)
2181 adpcm_ram[(adpcm_write_ptr++) & 0xffff] = data;
2184 uint8_t PCE::read_adpcm_ram()
2186 return adpcm_ram[(adpcm_read_ptr++) & 0xffff];
2189 void PCE::adpcm_do_dma()
2191 write_adpcm_ram(read_cdrom_data());
2194 cdrom_regs[0x0c] &= ~0x04;
2197 void PCE::adpcm_play()
2200 cdrom_regs[0x0c] &= ~PCE_CD_ADPCM_STOP_FLAG;
2201 cdrom_regs[0x0c] |= PCE_CD_ADPCM_PLAY_FLAG;
2202 set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE);
2203 cdrom_regs[0x03] &= ~0x0c;
2207 void PCE::adpcm_stop()
2210 cdrom_regs[0x0c] |= PCE_CD_ADPCM_STOP_FLAG;
2211 cdrom_regs[0x0c] &= ~PCE_CD_ADPCM_PLAY_FLAG;
2212 cdrom_regs[0x0d] &= ~0x60;
2218 d_scsi_host->write_signal(SIG_SCSI_ACK, 1, 1);
2221 void PCE::clear_ack()
2223 if(d_scsi_host->read_signal(SIG_SCSI_CD) != 0) {
2224 cdrom_regs[0x0b] &= 0xfc;
2226 d_scsi_host->write_signal(SIG_SCSI_ACK, 0, 0);
2229 void PCE::set_cdrom_irq_line(int num, int state)
2231 if (state == ASSERT_LINE) {
2232 cdrom_regs[0x03] |= num;
2234 cdrom_regs[0x03] &= ~num;
2236 if (cdrom_regs[0x02] & cdrom_regs[0x03] & 0x7c) {
2237 d_cpu->write_signal(INPUT_LINE_IRQ2, ASSERT_LINE, 0);
2239 d_cpu->write_signal(INPUT_LINE_IRQ2, CLEAR_LINE, 0);
2243 void PCE::cdda_fade_in(int time)
2245 if(event_cdda_fader != -1) {
2246 cancel_event(this, event_cdda_fader);
2248 register_event(this, EVENT_CDDA_FADE_IN, time, true, &event_cdda_fader);
2249 d_scsi_cdrom->set_volume((int)(cdda_volume = 0.0));
2252 void PCE::cdda_fade_out(int time)
2254 if(event_cdda_fader != -1) {
2255 cancel_event(this, event_cdda_fader);
2257 register_event(this, EVENT_CDDA_FADE_OUT, time, true, &event_cdda_fader);
2258 d_scsi_cdrom->set_volume((int)(cdda_volume = 100.0));
2261 void PCE::adpcm_fade_in(int time)
2263 if(event_adpcm_fader != -1) {
2264 cancel_event(this, event_adpcm_fader);
2266 register_event(this, EVENT_ADPCM_FADE_IN, time, true, &event_adpcm_fader);
2267 d_msm->set_volume((int)(adpcm_volume = 0.0));
2270 void PCE::adpcm_fade_out(int time)
2272 if(event_adpcm_fader != -1) {
2273 cancel_event(this, event_adpcm_fader);
2275 register_event(this, EVENT_ADPCM_FADE_OUT, time, true, &event_adpcm_fader);
2276 d_msm->set_volume((int)(adpcm_volume = 100.0));
2279 void PCE::write_signal(int id, uint32_t data, uint32_t mask)
2282 case SIG_PCE_SCSI_IRQ:
2287 if(d_scsi_host->read_signal(SIG_SCSI_BSY) != 0 &&
2288 d_scsi_host->read_signal(SIG_SCSI_CD ) != 0 &&
2289 d_scsi_host->read_signal(SIG_SCSI_MSG) == 0 &&
2290 d_scsi_host->read_signal(SIG_SCSI_IO ) != 0) {
2291 // status phase, command is finished
2292 set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_READY, CLEAR_LINE);
2293 set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE);
2295 // clear busreq because next REQ signal is raised
2296 d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
2305 case SIG_PCE_SCSI_DRQ:
2309 set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_READY, ASSERT_LINE);
2311 // clear busreq because next REQ signal is raised
2312 d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
2314 if(adpcm_dma_enabled) {
2315 if(!msm_idle && adpcm_write_ptr >= msm_start_addr) {
2316 // now streaming, wait dma not to overwrite buffer before it is played
2326 if(d_scsi_cdrom->get_cur_command() == SCSI_CMD_READ6 &&
2327 d_scsi_host->read_signal(SIG_SCSI_BSY) != 0 &&
2328 d_scsi_host->read_signal(SIG_SCSI_CD ) == 0 &&
2329 d_scsi_host->read_signal(SIG_SCSI_MSG) == 0 &&
2330 d_scsi_host->read_signal(SIG_SCSI_IO ) != 0) {
2331 // clear ack automatically and immediately for correct transfer speed
2338 case SIG_PCE_SCSI_BSY:
2339 if(!(data & mask)) {
2341 set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_READY, CLEAR_LINE);
2342 set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_DONE, CLEAR_LINE);
2346 case SIG_PCE_CDDA_DONE:
2349 set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE);
2353 case SIG_PCE_ADPCM_VCLK:
2354 // Callback for new data from the MSM5205.
2355 // The PCE cd unit actually divides the clock signal supplied to
2356 // the MSM5205. Currently we can only use static clocks for the
2359 uint8_t msm_data = (msm_nibble) ? (adpcm_ram[msm_start_addr & 0xffff] & 0x0f) : ((adpcm_ram[msm_start_addr & 0xffff] & 0xf0) >> 4);
2360 d_msm->data_w(msm_data);
2363 if(msm_nibble == 0) {
2365 if(adpcm_dma_enabled && adpcm_written == 0) {
2366 // finish streaming when all samples are played
2367 set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
2368 set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE);
2371 } else if((msm_start_addr & 0xffff) == msm_half_addr) {
2372 // reached to half address
2373 set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE);
2374 set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, ASSERT_LINE);
2375 } else if((msm_start_addr & 0xffff) == msm_end_addr) {
2376 // reached to end address
2377 if(adpcm_dma_enabled) {
2378 // restart streaming
2379 set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
2380 set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE);
2382 // stop playing adpcm
2383 set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
2384 set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE);
2391 if(adpcm_dma_enabled) {
2392 if(!msm_idle && adpcm_write_ptr < msm_start_addr) {
2393 if(d_scsi_cdrom->get_cur_command() == SCSI_CMD_READ6 &&
2394 d_scsi_host->read_signal(SIG_SCSI_BSY) != 0 &&
2395 d_scsi_host->read_signal(SIG_SCSI_REQ) != 0 &&
2396 d_scsi_host->read_signal(SIG_SCSI_CD ) == 0 &&
2397 d_scsi_host->read_signal(SIG_SCSI_MSG) == 0 &&
2398 d_scsi_host->read_signal(SIG_SCSI_IO ) != 0) {
2399 // already data is received, read next byte
2410 void PCE::event_callback(int event_id, int err)
2413 case EVENT_CDDA_FADE_IN:
2414 if((cdda_volume += 0.1) >= 100.0) {
2415 cancel_event(this, event_cdda_fader);
2416 event_cdda_fader = -1;
2417 cdda_volume = 100.0;
2419 d_scsi_cdrom->set_volume((int)cdda_volume);
2422 case EVENT_CDDA_FADE_OUT:
2423 if((cdda_volume -= 0.1) <= 0) {
2424 cancel_event(this, event_cdda_fader);
2425 event_cdda_fader = -1;
2428 d_scsi_cdrom->set_volume((int)cdda_volume);
2431 case EVENT_ADPCM_FADE_IN:
2432 if((adpcm_volume += 0.1) >= 100.0) {
2433 cancel_event(this, event_adpcm_fader);
2434 event_adpcm_fader = -1;
2435 adpcm_volume = 100.0;
2437 d_msm->set_volume((int)adpcm_volume);
2440 case EVENT_ADPCM_FADE_OUT:
2441 if((adpcm_volume -= 0.1) <= 0) {
2442 cancel_event(this, event_adpcm_fader);
2443 event_adpcm_fader = -1;
2446 d_msm->set_volume((int)adpcm_volume);
2452 #define STATE_VERSION 5
2454 bool PCE::process_state(FILEIO* state_fio, bool loading)
2456 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
2459 if(!state_fio->StateCheckInt32(this_device_id)) {
2462 state_fio->StateBool(support_6btn_pad);
2463 state_fio->StateBool(support_multi_tap);
2464 #ifdef SUPPORT_SUPER_GFX
2465 state_fio->StateBool(support_sgfx);
2467 #ifdef SUPPORT_CDROM
2468 state_fio->StateBool(support_cdrom);
2470 state_fio->StateBuffer(ram, sizeof(ram), 1);
2471 state_fio->StateBuffer(cart + 0x80000, 0x80000, 1);
2472 #ifdef SUPPORT_BACKUP_RAM
2473 state_fio->StateBuffer(backup, sizeof(backup), 1);
2474 state_fio->StateUint32(backup_crc32);
2476 state_fio->StateUint32(bank);
2477 state_fio->StateUint8(buffer);
2478 state_fio->StateInt32(prev_width);
2479 state_fio->StateBool(inserted);
2481 //state_fio->StateBuffer(vdc, sizeof(vdc), 1);
2482 //state_fio->StateBuffer(&vce, sizeof(vce), 1);
2483 //state_fio->StateBuffer(&vpc, sizeof(vpc), 1);
2484 //state_fio->StateBuffer(psg, sizeof(psg), 1);
2486 for(int i = 0; i < 2; i++) {
2487 state_fio->StateInt32(vdc[i].dvssr_write); /* Set when the DVSSR register has been written to */
2488 state_fio->StateInt32(vdc[i].physical_width); /* Width of the display */
2489 state_fio->StateInt32(vdc[i].physical_height); /* Height of the display */
2490 for(int j = 0; j < (64 * 4); j++) {
2491 state_fio->StateUint16(vdc[i].sprite_ram[j]); /* Sprite RAM */
2493 state_fio->StateInt32(vdc[i].curline); /* the current scanline we're on */
2494 state_fio->StateInt32(vdc[i].current_segment); /* current segment of display */
2495 state_fio->StateInt32(vdc[i].current_segment_line); /* current line inside a segment of display */
2496 state_fio->StateInt32(vdc[i].vblank_triggered); /* to indicate whether vblank has been triggered */
2497 state_fio->StateInt32(vdc[i].raster_count); /* counter to compare RCR against */
2498 state_fio->StateInt32(vdc[i].satb_countdown); /* scanlines to wait to trigger the SATB irq */
2499 state_fio->StateBuffer((vdc[i].vram), 0x10000, 1);
2500 state_fio->StateUint8(vdc[i].inc);
2501 state_fio->StateUint8(vdc[i].vdc_register);
2502 state_fio->StateUint8(vdc[i].vdc_latch);
2503 for(int j = 0; j < 32; j++) {
2504 state_fio->StateUint32(vdc[i].vdc_data[j].d);
2506 state_fio->StateInt32(vdc[i].status);
2507 state_fio->StateInt32(vdc[i].y_scroll);
2511 state_fio->StateUint8(vce.vce_control); /* VCE control register */
2512 state_fio->StateUint32(vce.vce_address.d); /* Current address in the palette */
2513 for(int i = 0; i < 512; i++) {
2514 state_fio->StateUint32(vce.vce_data[i].d); /* Palette data */
2516 state_fio->StateInt32(vce.current_bitmap_line); /* The current line in the display we are on */
2517 //bitmap_ind16 *bmp;
2518 for(int i = 0; i < VDC_LPF; i++) {
2519 for(int j = 0; j < VDC_WPF; j++) {
2522 r = state_fio->FgetUint8();
2523 g = state_fio->FgetUint8();
2524 b = state_fio->FgetUint8();
2525 vce.bmp[i][j] = RGB_COLOR(r, g, b);
2528 r = R_OF_COLOR(vce.bmp[i][j]);
2529 g = G_OF_COLOR(vce.bmp[i][j]);
2530 b = B_OF_COLOR(vce.bmp[i][j]);
2531 state_fio->FputUint8(r);
2532 state_fio->FputUint8(g);
2533 state_fio->FputUint8(b);
2537 for(int i = 0; i < 1024; i++) {
2540 r = state_fio->FgetUint8();
2541 g = state_fio->FgetUint8();
2542 b = state_fio->FgetUint8();
2543 vce.palette[i] = RGB_COLOR(r, g, b);
2546 r = R_OF_COLOR(vce.palette[i]);
2547 g = G_OF_COLOR(vce.palette[i]);
2548 b = B_OF_COLOR(vce.palette[i]);
2549 state_fio->FputUint8(r);
2550 state_fio->FputUint8(g);
2551 state_fio->FputUint8(b);
2557 for(int i = 0; i < 4; i++) {
2558 state_fio->StateUint8(vpc.vpc_prio[i].prio);
2559 state_fio->StateUint8(vpc.vpc_prio[i].vdc0_enabled);
2560 state_fio->StateUint8(vpc.vpc_prio[i].vdc1_enabled);
2562 state_fio->StateBuffer(vpc.prio_map, 512, 1);
2563 state_fio->StateUint32(vpc.priority.d);
2564 state_fio->StateUint32(vpc.window1.d);
2565 state_fio->StateUint32(vpc.window2.d);
2566 state_fio->StateUint8(vpc.vdc_select);
2570 for(int i = 0; i < 8; i++ ){
2571 state_fio->StateBuffer(psg[i].regs, 8, 1);
2572 state_fio->StateBuffer(psg[i].wav, 32, 1);
2573 state_fio->StateUint8(psg[i].wavptr);
2574 state_fio->StateUint32(psg[i].genptr);
2575 state_fio->StateUint32(psg[i].remain);
2576 state_fio->StateBool(psg[i].noise);
2577 state_fio->StateUint32(psg[i].randval);
2581 state_fio->StateUint8(psg_ch);
2582 state_fio->StateUint8(psg_vol);
2583 state_fio->StateUint8(psg_lfo_freq);
2584 state_fio->StateUint8(psg_lfo_ctrl);
2585 state_fio->StateUint8(joy_counter);
2586 state_fio->StateBool(joy_high_nibble);
2587 state_fio->StateBool(joy_second_byte);
2588 #ifdef SUPPORT_CDROM
2589 state_fio->StateBuffer(cdrom_ram, sizeof(cdrom_ram), 1);
2590 state_fio->StateBuffer(cdrom_regs, sizeof(cdrom_regs), 1);
2591 state_fio->StateBool(backup_locked);
2592 state_fio->StateBool(irq_status);
2593 state_fio->StateBool(drq_status);
2594 state_fio->StateBuffer(adpcm_ram, sizeof(adpcm_ram), 1);
2595 state_fio->StateInt32(adpcm_read_ptr);
2596 state_fio->StateInt32(adpcm_write_ptr);
2597 state_fio->StateInt32(adpcm_written);
2598 state_fio->StateInt32(adpcm_length);
2599 state_fio->StateInt32(adpcm_clock_divider);
2600 state_fio->StateUint8(adpcm_read_buf);
2601 state_fio->StateUint8(adpcm_write_buf);
2602 state_fio->StateBool(adpcm_dma_enabled);
2603 state_fio->StateInt32(msm_start_addr);
2604 state_fio->StateInt32(msm_end_addr);
2605 state_fio->StateInt32(msm_half_addr);
2606 state_fio->StateUint8(msm_nibble);
2607 state_fio->StateUint8(msm_idle);
2608 state_fio->StateDouble(cdda_volume);
2609 state_fio->StateDouble(adpcm_volume);
2610 state_fio->StateInt32(event_cdda_fader);
2611 state_fio->StateInt32(event_adpcm_fader);