NEC-HE PC Engine Emulator 'ePCEngine'
SHARP X1twin Emulator 'eX1twin'
- Origin : Ootake (joypad)
+ Origin : Ootake (joypad/cdrom)
: xpce (psg)
- : MESS (vdc/vce/vpc)
+ : MESS (vdc/vce/vpc/cdrom)
Author : Takeda.Toshiya
Date : 2009.03.11-
#include <math.h>
#include "pce.h"
#include "../huc6280.h"
+#ifdef SUPPORT_CDROM
+#include "../msm5205.h"
+#include "../scsi_host.h"
+#include "../scsi_cdrom.h"
+#endif
#define STATE_VSW 0
#define STATE_VDS 1
#define DCR_DVC 0x02 /* VRAM > VRAM EOT interrupt enable */
#define DCR_DSC 0x01 /* VRAM > SATB EOT interrupt enable */
+namespace PCEDEV {
+
/* just to keep things simple... */
enum vdc_regs {MAWR = 0, MARR, VxR, reg3, reg4, CR, RCR, BXR, BYR, MWR, HSR, HDR, VPR, VDW, VCR, DCR, SOUR, DESR, LENR, DVSSR };
INPUT_LINE_NMI
};
+#ifndef SUPPORT_CDROM
+#define backup_locked false
+#endif
+
void PCE::initialize()
{
// get context
- joy_stat = emu->joy_buffer();
- key_stat = emu->key_buffer();
+ joy_stat = emu->get_joy_buffer();
// register event
register_vline_event(this);
#ifdef SUPPORT_BACKUP_RAM
- static const uint8 image[8] = {0x48, 0x55, 0x42, 0x4d, 0x00, 0x88, 0x10, 0x80};
+ static const uint8_t image[8] = {0x48, 0x55, 0x42, 0x4d, 0x00, 0x88, 0x10, 0x80};
memset(backup, 0, sizeof(backup));
memcpy(backup, image, sizeof(image));
}
delete fio;
- backup_crc32 = getcrc32(backup, sizeof(backup));
+ backup_crc32 = get_crc32(backup, sizeof(backup));
+#endif
+#ifdef SUPPORT_CDROM
+ cdrom_initialize();
#endif
inserted = false;
}
void PCE::release()
{
#ifdef SUPPORT_BACKUP_RAM
- if(backup_crc32 != getcrc32(backup, sizeof(backup))) {
+ if(backup_crc32 != get_crc32(backup, sizeof(backup))) {
FILEIO* fio = new FILEIO();
if(fio->Fopen(create_local_path(_T("BACKUP.BIN")), FILEIO_WRITE_BINARY)) {
fio->Fwrite(backup, sizeof(backup), 1);
vdc_reset();
psg_reset();
joy_reset();
+#ifdef SUPPORT_CDROM
+ cdrom_reset();
+#endif
prev_width = -1;
}
pce_interrupt();
}
-void PCE::write_data8(uint32 addr, uint32 data)
+void PCE::write_data8(uint32_t addr, uint32_t data)
{
- uint8 mpr = (addr >> 13) & 0xff;
- uint16 ofs = addr & 0x1fff;
+ uint8_t mpr = (addr >> 13) & 0xff;
+ uint16_t ofs = addr & 0x1fff;
+#ifdef SUPPORT_CDROM
+ if(support_cdrom && mpr >= 0x68 && mpr <= 0x87) {
+ cdrom_ram[addr & 0x3ffff] = data;
+ return;
+ }
+#endif
switch(mpr) {
case 0x40:
case 0x41:
return;
#ifdef SUPPORT_BACKUP_RAM
case 0xf7:
-// if(inserted) {
+ if(!backup_locked) {
backup[ofs] = data;
-// }
+ }
return;
#endif
case 0xf8:
buffer = data;
d_cpu->irq_status_w(addr, data);
break;
+#ifdef SUPPORT_CDROM
+ case 0x1800:
+ if(support_cdrom && (addr & 0x1e00) != 0x1a00) {
+ cdrom_write(addr, data);
+ break;
+ }
+#endif
}
return;
}
}
}
-uint32 PCE::read_data8(uint32 addr)
+uint32_t PCE::read_data8(uint32_t addr)
{
- uint8 mpr = (addr >> 13) & 0xff;
- uint16 ofs = addr & 0x1fff;
+ uint8_t mpr = (addr >> 13) & 0xff;
+ uint16_t ofs = addr & 0x1fff;
if(mpr <= 0x3f) {
return cart[addr & 0x7ffff];
}
+#ifdef SUPPORT_CDROM
+ if(support_cdrom && mpr >= 0x68 && mpr <= 0x87) {
+ return cdrom_ram[addr & 0x3ffff];
+ }
+#endif
if(mpr <= 0x7f) {
return cart[bank | (addr & 0x7ffff)];
}
buffer = (buffer & 0xf8) | (d_cpu->irq_status_r(addr) & 0x07);
}
return buffer;
+#ifdef SUPPORT_CDROM
+ case 0x1800:
+ if(support_cdrom && (addr & 0x1e00) != 0x1a00) {
+ return cdrom_read(addr);
+ }
+#endif
}
break;
}
return 0xff;
}
-void PCE::write_io8(uint32 addr, uint32 data)
+void PCE::write_io8(uint32_t addr, uint32_t data)
{
#ifdef SUPPORT_SUPER_GFX
if(support_sgfx) {
vdc_w(0, addr, data);
}
-uint32 PCE::read_io8(uint32 addr)
+uint32_t PCE::read_io8(uint32_t addr)
{
#ifdef SUPPORT_SUPER_GFX
if(support_sgfx) {
void PCE::draw_screen()
{
int dx = (SCREEN_WIDTH - vdc[0].physical_width) / 2, sx = 0;
- int dy = (SCREEN_HEIGHT - 238) / 2;
+ int dy = (SCREEN_HEIGHT - 240) / 2;
if(dx < 0) {
sx = -dx;
#ifndef _X1TWIN
if(prev_width != vdc[0].physical_width) {
for(int y = 0; y < SCREEN_HEIGHT; y++) {
- memset(emu->screen_buffer(y), 0, sizeof(scrntype) * SCREEN_WIDTH);
+ memset(emu->get_screen_buffer(y), 0, sizeof(scrntype_t) * SCREEN_WIDTH);
}
prev_width = vdc[0].physical_width;
}
+ emu->set_vm_screen_lines(240);
#endif
- for(int y = 0; y < 238; y++, dy++) {
- scrntype* src = &vce.bmp[y + 17][86];
- scrntype* dst = emu->screen_buffer(dy);
+ for(int y = 0; y < 240; y++, dy++) {
+ scrntype_t* src = &vce.bmp[y + 17][86];
+ scrntype_t* dst = emu->get_screen_buffer(dy);
for(int x = sx, x2 = dx; x < vdc[0].physical_width && x2 < SCREEN_WIDTH; x++, x2++) {
dst[x2] = src[x];
}
{
FILEIO* fio = new FILEIO();
+ support_6btn_pad = ((config.joystick_type & 1) != 0);
+ support_multi_tap = ((config.joystick_type & 2) != 0);
+#ifdef SUPPORT_SUPER_GFX
+ support_sgfx = false;
+#endif
+#ifdef SUPPORT_CDROM
+ support_cdrom = false;
+#endif
+
if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
memset(cart, 0xff, sizeof(cart));
fio->Fseek(0, FILEIO_SEEK_END);
memcpy(cart + 0x080000, cart + 0x040000, 0x040000); /* Set up 080000 - 0BFFFF region */
memcpy(cart + 0x0C0000, cart + 0x040000, 0x040000); /* Set up 0C0000 - 0FFFFF region */
memcpy(cart + 0x040000, cart, 0x040000); /* Set up 040000 - 07FFFF region */
- }
- else {
+ } else {
/* mirror 256KB rom data */
if (size <= 0x040000)
memcpy(cart + 0x040000, cart, 0x040000);
if (size <= 0x080000)
memcpy(cart + 0x080000, cart, 0x080000);
}
- uint32 cart_crc32 = getcrc32(cart,size);
- support_sgfx = (size == 0x100000 && cart_crc32 == 0x8c4588e2) // 1941 Counter Attack
- || (size == 0x100000 && cart_crc32 == 0x4c2126b0) // Aldynes
- || (size == 0x080000 && cart_crc32 == 0x3b13af61) // Battle Ace
- || (size == 0x100000 && cart_crc32 == 0xb486a8ed) // Daimakaimura
- || (size == 0x0c0000 && cart_crc32 == 0xbebfe042) // Darius Plus
- || (size == 0x100000 && cart_crc32 == 0x1e1d0319) // Darius Plus (1024K)
- || (size == 0x080000 && cart_crc32 == 0x1f041166); // Grandzort
- support_6btn = (size == 0x280000 && cart_crc32 == 0xd15cb6bb); // Street Fighter II
+ uint32_t cart_crc32 = get_crc32(cart, size);
+#ifdef SUPPORT_SUPER_GFX
+ if((size == 0x100000 && cart_crc32 == 0x8c4588e2) || // 1941 Counter Attack
+ (size == 0x100000 && cart_crc32 == 0x4c2126b0) || // Aldynes
+ (size == 0x080000 && cart_crc32 == 0x3b13af61) || // Battle Ace
+ (size == 0x100000 && cart_crc32 == 0xb486a8ed) || // Daimakaimura
+ (size == 0x0c0000 && cart_crc32 == 0xbebfe042) || // Darius Plus
+ (size == 0x100000 && cart_crc32 == 0x1e1d0319) || // Darius Plus (1024K)
+ (size == 0x080000 && cart_crc32 == 0x1f041166)) { // Grandzort
+ support_sgfx = true;
+ }
+#endif
+#ifdef SUPPORT_CDROM
+ if(size >= 0x40000 && memcmp(cart + 0x3ffb6, "PC Engine CD-ROM SYSTEM", 23) == 0) {
+ support_cdrom = true;
+ }
+#endif
+ if((size == 0x280000 && cart_crc32 == 0xd15cb6bb) || // Street Fighter II Champion Edition
+ (size == 0x100000 && cart_crc32 == 0xd6fc51ce)) { // Strip Figher II
+ support_6btn_pad = true;
+ }
+ if(size == 0x40000 && cart_crc32 == 0x80c3f824) { // Yokai Dochu Ki
+ support_multi_tap = false;
+ }
inserted = true;
}
delete fio;
/* 0 - no sprite and background pixels drawn
1 - background pixel drawn
otherwise is 2 + sprite# */
- uint8 drawn[VDC_WPF];
+ uint8_t drawn[VDC_WPF];
/* our line buffer */
- scrntype *line_buffer = &vce.bmp[vce.current_bitmap_line][86];
+ scrntype_t *line_buffer = &vce.bmp[vce.current_bitmap_line][86];
/* clear our priority/sprite collision detection buffer. */
memset(drawn, 0, VDC_WPF);
vdc_advance_line(0);
}
+#ifdef SUPPORT_SUPER_GFX
void PCE::sgx_interrupt()
{
/* Draw the last scanline */
/* 0 - no sprite and background pixels drawn
1 - background pixel drawn
otherwise is 2 + sprite# */
- uint8 drawn[2][512];
- scrntype *line_buffer;
- scrntype temp_buffer[2][512];
+ uint8_t drawn[2][512];
+ scrntype_t *line_buffer;
+ scrntype_t temp_buffer[2][512];
int i;
/* clear our priority/sprite collision detection buffer. */
vdc_advance_line(0);
vdc_advance_line(1);
}
+#endif
void PCE::vdc_advance_line(int which)
{
int i;
/* our line buffer */
- scrntype *line_buffer = vce.bmp[line];
+ scrntype_t *line_buffer = vce.bmp[line];
for( i=0; i< VDC_WPF; i++ )
line_buffer[i] = 0;
int i;
/* Are we in greyscale mode or in color mode? */
- scrntype *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
+ scrntype_t *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
/* our line buffer */
- scrntype *line_buffer = vce.bmp[line];
+ scrntype_t *line_buffer = vce.bmp[line];
for ( i = 0; i < VDC_WPF; i++ )
line_buffer[i] = color_base[vce.vce_data[0x100].w.l];
}
+#ifdef SUPPORT_SUPER_GFX
void PCE::draw_sgx_overscan_line(int line)
{
int i;
/* Are we in greyscale mode or in color mode? */
- scrntype *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
+ scrntype_t *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
/* our line buffer */
- scrntype *line_buffer = vce.bmp[line];
+ scrntype_t *line_buffer = vce.bmp[line];
for ( i = 0; i < VDC_WPF; i++ )
line_buffer[i] = color_base[vce.vce_data[0].w.l];
}
+#endif
-void PCE::vram_write(int which, uint32 offset, uint8 data)
+void PCE::vram_write(int which, uint32_t offset, uint8_t data)
{
if(offset & 0x10000)
{
}
}
-uint8 PCE::vram_read(int which, uint32 offset)
+uint8_t PCE::vram_read(int which, uint32_t offset)
{
- uint8 temp;
+ uint8_t temp;
if(offset & 0x10000)
{
return temp;
}
-void PCE::vdc_w(int which, uint16 offset, uint8 data)
+void PCE::vdc_w(int which, uint16_t offset, uint8_t data)
{
switch(offset&3)
{
}
}
-uint8 PCE::vdc_r(int which, uint16 offset)
+uint8_t PCE::vdc_r(int which, uint16_t offset)
{
int temp = 0;
switch(offset & 3)
return (temp);
}
-uint8 PCE::vce_r(uint16 offset)
+uint8_t PCE::vce_r(uint16_t offset)
{
int temp = 0xFF;
switch(offset & 7)
return (temp);
}
-void PCE::vce_w(uint16 offset, uint8 data)
+void PCE::vce_w(uint16_t offset, uint8_t data)
{
switch(offset & 7)
{
}
}
-void PCE::pce_refresh_line(int which, int line, int external_input, uint8 *drawn, scrntype *line_buffer)
+void PCE::pce_refresh_line(int which, int line, int external_input, uint8_t *drawn, scrntype_t *line_buffer)
{
static const int width_table[4] = {5, 6, 7, 7};
int nt_row = (v_line >> 3);
/* virtual X size (# bits to shift) */
- int v_width = width_table[(vdc[which].vdc_data[MWR].w.l >> 4) & 3];
+ int v_width = width_table[(vdc[which].vdc_data[MWR].w.l >> 4) & 3];
/* pointer to the name table (Background Attribute Table) in VRAM */
- uint8 *bat = &(vdc[which].vram[nt_row << (v_width+1)]);
+ uint8_t *bat = &(vdc[which].vram[nt_row << (v_width+1)]);
/* Are we in greyscale mode or in color mode? */
- scrntype *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
+ scrntype_t *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
int b0, b1, b2, b3;
int i0, i1, i2, i3;
}
}
-void PCE::pce_refresh_sprites(int which, int line, uint8 *drawn, scrntype *line_buffer)
+void PCE::pce_refresh_sprites(int which, int line, uint8_t *drawn, scrntype_t *line_buffer)
{
int i;
- uint8 sprites_drawn = 0;
+ uint8_t sprites_drawn = 0;
/* Are we in greyscale mode or in color mode? */
- scrntype *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
+ scrntype_t *color_base = vce.palette + (vce.vce_control & 0x80 ? 512 : 0);
/* count up: Highest priority is Sprite 0 */
for(i = 0; i < 64; i++)
int dvc = (vdc[which].vdc_data[DCR].w.l >> 1) & 1;
do {
- uint8 l, h;
+ uint8_t l, h;
l = vram_read(which, src<<1);
h = vram_read(which, (src<<1) + 1);
}
}
-void PCE::vpc_w(uint16 offset, uint8 data)
+void PCE::vpc_w(uint16_t offset, uint8_t data)
{
switch( offset & 0x07 )
{
}
}
-uint8 PCE::vpc_r(uint16 offset)
+uint8_t PCE::vpc_r(uint16_t offset)
{
- uint8 data = 0;
+ uint8_t data = 0;
switch( offset & 0x07 )
{
case 0x00: /* Priority register #0 */
return data;
}
-void PCE::sgx_vdc_w(uint16 offset, uint8 data)
+#ifdef SUPPORT_SUPER_GFX
+void PCE::sgx_vdc_w(uint16_t offset, uint8_t data)
{
if ( vpc.vdc_select )
{
}
}
-uint8 PCE::sgx_vdc_r(uint16 offset)
+uint8_t PCE::sgx_vdc_r(uint16_t offset)
{
return ( vpc.vdc_select ) ? vdc_r( 1, offset ) : vdc_r( 0, offset );
}
+#endif
// psg
void PCE::psg_reset()
{
+ touch_sound();
memset(psg, 0, sizeof(psg));
for (int i = 0; i < 6; i++) {
psg[i].regs[4] = 0x80;
psg_vol = psg_lfo_freq = psg_lfo_ctrl = 0;
}
-void PCE::psg_write(uint16 addr, uint8 data)
+void PCE::psg_write(uint16_t addr, uint8_t data)
{
switch(addr & 0x1f) {
case 0:
+ touch_sound();
psg_ch = data & 7;
break;
case 1:
+ touch_sound();
psg_vol = data;
break;
case 2:
+ touch_sound();
psg[psg_ch].regs[2] = data;
break;
case 3:
+ touch_sound();
// psg[psg_ch].regs[3] = data & 0x1f;
psg[psg_ch].regs[3] = data & 0xf;
break;
case 4:
+ touch_sound();
psg[psg_ch].regs[4] = data;
break;
case 5:
+ touch_sound();
psg[psg_ch].regs[5] = data;
break;
case 6:
+ touch_sound();
if(psg[psg_ch].regs[4] & 0x40) {
psg[psg_ch].wav[0] =data & 0x1f;
}
}
break;
case 7:
+ touch_sound();
psg[psg_ch].regs[7] = data;
break;
case 8:
+ touch_sound();
psg_lfo_freq = data;
break;
case 9:
+ touch_sound();
psg_lfo_ctrl = data;
break;
}
}
-uint8 PCE::psg_read(uint16 addr)
+uint8_t PCE::psg_read(uint16_t addr)
{
int ptr;
return 0xff;
}
-void PCE::mix(int32* buffer, int cnt)
+void PCE::mix(int32_t* buffer, int cnt)
{
int vol_tbl[32] = {
100, 451, 508, 573, 646, 728, 821, 925,1043,1175,1325, 1493, 1683, 1898, 2139, 2411,
}
else if(psg[ch].regs[4] & 0x40) {
// dda
- int32 wav = ((int32)psg[ch].wav[0] - 16) * 702;
- int32 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;
+ int32_t wav = ((int32_t)psg[ch].wav[0] - 16) * 702;
+ 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;
vol = (vol < 0) ? 0 : (vol > 31) ? 31 : vol;
- vol = wav * vol_tbl[vol] / 16384;
+ int32_t outvol = wav * vol_tbl[vol] / 16384;
for(int i = 0, j = 0; i < cnt; i++, j += 2) {
- buffer[j ] += vol; // L
- buffer[j + 1] += vol; // R
+ buffer[j ] += apply_volume(outvol, volume_l); // L
+ buffer[j + 1] += apply_volume(outvol, volume_r); // R
}
}
else if(ch >= 4 && (psg[ch].regs[7] & 0x80)) {
// noise
- uint16 freq = (psg[ch].regs[7] & 0x1f);
- int32 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;
+ uint16_t freq = (psg[ch].regs[7] & 0x1f);
+ 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;
vol = (vol < 0) ? 0 : (vol > 31) ? 31 : vol;
vol = vol_tbl[vol];
for(int i = 0, j = 0; i < cnt; i++, j += 2) {
psg[ch].remain += 3000 + freq * 512;
- uint32 t = psg[ch].remain / sample_rate;
+ uint32_t t = psg[ch].remain / sample_rate;
if(t >= 1) {
if(psg[ch].randval & 0x80000) {
psg[ch].randval = ((psg[ch].randval ^ 4) << 1) + 1;
}
psg[ch].remain -= sample_rate * t;
}
- int32 outvol = (int32)((psg[ch].noise ? 10 * 702 : -10 * 702) * vol / 16384);
- buffer[j ] += outvol; // L
- buffer[j + 1] += outvol; // R
+ int32_t outvol = (int32_t)((psg[ch].noise ? 10 * 702 : -10 * 702) * vol / 16384);
+ buffer[j ] += apply_volume(outvol, volume_l); // L
+ buffer[j + 1] += apply_volume(outvol, volume_r); // R
}
}
else {
- int32 wav[32];
+ int32_t wav[32];
for(int i = 0; i < 32; i++) {
- wav[i] = ((int32)psg[ch].wav[i] - 16) * 702;
+ wav[i] = ((int32_t)psg[ch].wav[i] - 16) * 702;
}
- uint32 freq = psg[ch].regs[2] + ((uint32)psg[ch].regs[3] << 8);
+ uint32_t freq = psg[ch].regs[2] + ((uint32_t)psg[ch].regs[3] << 8);
if(freq) {
- int32 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;
+ 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;
vol = (vol < 0) ? 0 : (vol > 31) ? 31 : vol;
vol = vol_tbl[vol];
for(int i = 0, j = 0; i < cnt; i++, j += 2) {
- int32 outvol = wav[psg[ch].genptr] * vol / 16384;
- buffer[j ] += outvol; // L
- buffer[j + 1] += outvol; // R
+ int32_t outvol = wav[psg[ch].genptr] * vol / 16384;
+ buffer[j ] += apply_volume(outvol, volume_l); // L
+ buffer[j + 1] += apply_volume(outvol, volume_r); // R
psg[ch].remain += 32 * 1118608 / freq;
- uint32 t = psg[ch].remain / (10 * sample_rate);
+ uint32_t t = psg[ch].remain / (10 * sample_rate);
psg[ch].genptr = (psg[ch].genptr + t) & 0x1f;
psg[ch].remain -= 10 * sample_rate * t;
}
}
}
}
+#ifdef SUPPORT_CDROM
+ if(support_cdrom) {
+ if(!msm_idle) {
+ d_msm->mix(buffer, cnt);
+ }
+ d_scsi_cdrom->mix(buffer, cnt);
+ }
+#endif
+}
+
+void PCE::set_volume(int ch, int decibel_l, int decibel_r)
+{
+ volume_l = decibel_to_volume(decibel_l);
+ volume_r = decibel_to_volume(decibel_r);
}
// joypad (non multipad)
void PCE::joy_reset()
{
- joy_sel = joy_bank = 1;
- joy_clr = joy_count = 0;
+ joy_counter = 0;
+ joy_high_nibble = joy_second_byte = false;
+}
+
+void PCE::joy_write(uint16_t addr, uint8_t data)
+{
+ joy_high_nibble = ((data & 1) != 0);
+
+ if(data & 2) {
+ joy_counter = 0;
+ joy_high_nibble = false;
+ joy_second_byte = !joy_second_byte;
+ }
}
-void PCE::joy_write(uint16 addr, uint8 data)
+uint8_t PCE::joy_read(uint16_t addr)
{
- uint8 new_sel = data & 1;
- uint8 new_clr = data & 2;
+ uint8_t index;
- if(joy_sel && new_sel) {
- if(joy_clr && !new_clr) {
- joy_count = 0;
- joy_bank ^= 1;
+ if(joy_high_nibble) {
+ if(++joy_counter == 16) {
+ joy_counter = 0;
}
}
- else if(!joy_sel && new_sel) {
- joy_count = (joy_count + 1) & 15;
+ if(joy_counter == 0) {
+ return 0x00;
+ }
+ if(support_multi_tap) {
+ if(joy_counter > 4) {
+ return 0x0f;
+ }
+ index = joy_counter;
+ } else {
+ index = 1;
+ }
+ if(support_6btn_pad) {
+ return joy_6btn_pad_r(index);
+ } else {
+ return joy_2btn_pad_r(index);
}
- joy_sel = new_sel;
- joy_clr = new_clr;
}
-uint8 PCE::joy_read(uint16 addr)
+uint8_t PCE::joy_2btn_pad_r(uint8_t index)
{
- uint8 val = 0xf;
- uint32 stat = 0;
+ uint8_t data = 0x0f;
- if(joy_count == 0) {
- stat = joy_stat[0];
- if(key_stat[0x26]) stat |= 0x001; // up
- if(key_stat[0x28]) stat |= 0x002; // down
- if(key_stat[0x25]) stat |= 0x004; // left
- if(key_stat[0x27]) stat |= 0x008; // right
- if(key_stat[0x44]) stat |= 0x010; // d (1)
- if(key_stat[0x53]) stat |= 0x020; // s (2)
- if(key_stat[0x20]) stat |= 0x040; // space (select)
- if(key_stat[0x0d]) stat |= 0x080; // enter (run)
- if(key_stat[0x41]) stat |= 0x100; // a (3)
- if(key_stat[0x51]) stat |= 0x200; // q (4)
- if(key_stat[0x57]) stat |= 0x400; // w (5)
- if(key_stat[0x45]) stat |= 0x800; // e (6)
- } else if(joy_count == 1) {
- stat = joy_stat[1];
- }
- if(support_6btn && joy_bank) {
- if(joy_sel) {
- val = 0;
+ if(joy_high_nibble) {
+ if(joy_stat[index - 1] & 0x001) data &= ~0x01; // Up
+ if(joy_stat[index - 1] & 0x008) data &= ~0x02; // Right
+ if(joy_stat[index - 1] & 0x002) data &= ~0x04; // Down
+ if(joy_stat[index - 1] & 0x004) data &= ~0x08; // Left
+ } else {
+ if(joy_stat[index - 1] & 0x010) data &= ~0x01; // Button #1
+ if(joy_stat[index - 1] & 0x020) data &= ~0x02; // Button #2
+ if(joy_stat[index - 1] & 0x040) data &= ~0x04; // Select
+ if(joy_stat[index - 1] & 0x080) data &= ~0x08; // Run
+ }
+ return data;
+}
+
+uint8_t PCE::joy_6btn_pad_r(uint8_t index)
+{
+ uint8_t data = 0x0f;
+
+ if(joy_second_byte) {
+ if(joy_high_nibble) {
+ if(joy_stat[index - 1] & 0x001) data &= ~0x01; // Up
+ if(joy_stat[index - 1] & 0x008) data &= ~0x02; // Right
+ if(joy_stat[index - 1] & 0x002) data &= ~0x04; // Down
+ if(joy_stat[index - 1] & 0x004) data &= ~0x08; // Left
} else {
- if(stat & 0x100) val &= ~1; // b3
- if(stat & 0x200) val &= ~2; // b4
- if(stat & 0x400) val &= ~4; // b5
- if(stat & 0x800) val &= ~8; // b6
+ if(joy_stat[index - 1] & 0x010) data &= ~0x01; // Button #1
+ if(joy_stat[index - 1] & 0x020) data &= ~0x02; // Button #2
+ if(joy_stat[index - 1] & 0x040) data &= ~0x04; // Select
+ if(joy_stat[index - 1] & 0x080) data &= ~0x08; // Run
}
} else {
- if(joy_sel) {
- if(stat & 0x001) val &= ~1; // up
- if(stat & 0x008) val &= ~2; // right
- if(stat & 0x002) val &= ~4; // down
- if(stat & 0x004) val &= ~8; // left
+ if(joy_high_nibble) {
+ return 0x00;
} else {
- if(stat & 0x010) val &= ~1; // b1
- if(stat & 0x020) val &= ~2; // b2
- if(stat & 0x040) val &= ~4; // sel
- if(stat & 0x080) val &= ~8; // run
+ if(joy_stat[index - 1] & 0x100) data &= ~0x01; // Button #3
+ if(joy_stat[index - 1] & 0x200) data &= ~0x02; // Button #4
+ if(joy_stat[index - 1] & 0x400) data &= ~0x04; // Button #5
+ if(joy_stat[index - 1] & 0x800) data &= ~0x08; // Button #6
}
}
- if(joy_count == 4) {
- joy_bank = 1;
+ if(!support_multi_tap) {
+ if(joy_counter == 5 && !joy_high_nibble) {
+ joy_second_byte = false;
+ }
}
- return val;
+ return data;
}
-#define STATE_VERSION 2
+// CD-ROM^2
+
+#ifdef SUPPORT_CDROM
+#define PCE_CD_IRQ_TRANSFER_READY 0x40
+#define PCE_CD_IRQ_TRANSFER_DONE 0x20
+#define PCE_CD_IRQ_BRAM 0x10 /* ??? */
+#define PCE_CD_IRQ_SAMPLE_FULL_PLAY 0x08
+#define PCE_CD_IRQ_SAMPLE_HALF_PLAY 0x04
+
+#define PCE_CD_ADPCM_PLAY_FLAG 0x08
+#define PCE_CD_ADPCM_STOP_FLAG 0x01
+
+#define EVENT_CDDA_FADE_IN 0
+#define EVENT_CDDA_FADE_OUT 1
+#define EVENT_ADPCM_FADE_IN 2
+#define EVENT_ADPCM_FADE_OUT 3
+
+void PCE::cdrom_initialize()
+{
+ adpcm_clock_divider = 1;
+ backup_locked = true;
+ event_cdda_fader = event_adpcm_fader = -1;
+}
-void PCE::save_state(FILEIO* state_fio)
+void PCE::cdrom_reset()
{
- state_fio->FputUint32(STATE_VERSION);
- state_fio->FputInt32(this_device_id);
+ touch_sound();
+ memset(cdrom_regs, 0, sizeof(cdrom_regs));
+ cdrom_regs[0x0c] |= PCE_CD_ADPCM_STOP_FLAG;
+ cdrom_regs[0x0c] &= ~PCE_CD_ADPCM_PLAY_FLAG;
- state_fio->FputBool(support_6btn);
- state_fio->FputBool(support_sgfx);
- state_fio->Fwrite(ram, sizeof(ram), 1);
- state_fio->Fwrite(cart + 0x80000, 0x80000, 1);
-#ifdef SUPPORT_BACKUP_RAM
- state_fio->Fwrite(backup, sizeof(backup), 1);
- state_fio->FputUint32(backup_crc32);
+ irq_status = drq_status = false;
+
+ adpcm_read_ptr = adpcm_write_ptr = 0;
+ adpcm_read_buf = adpcm_write_buf = 0;
+ adpcm_dma_enabled = false;
+ adpcm_play_in_progress = false;
+ msm_idle = 1;
+
+ if(event_cdda_fader != -1) {
+ cancel_event(this, event_cdda_fader);
+ }
+ if(event_adpcm_fader != -1) {
+ cancel_event(this, event_adpcm_fader);
+ }
+ cdda_volume = adpcm_volume = 100.0;
+ event_cdda_fader = event_adpcm_fader = -1;
+
+ d_scsi_cdrom->set_volume((int)cdda_volume);
+ d_msm->set_volume((int)adpcm_volume);
+}
+
+void PCE::cdrom_write(uint16_t addr, uint8_t data)
+{
+ touch_sound();
+ switch(addr & 0x0f) {
+ case 0x00: /* CDC status */
+ data = 0xd0; // Force set data to $D0
+ // Reset req?
+ d_scsi_host->write_signal(SIG_SCSI_SEL, 1, 1);
+ d_scsi_host->write_signal(SIG_SCSI_SEL, 0, 1);
+ adpcm_dma_enabled = false;
+ // From Ootake v2.38
+ cdrom_regs[0x03] = 0x00; // Reset IRQ status at al.
+ set_cdrom_irq_line(0x0, 0x0); // Update IRQ
+ break;
+
+ case 0x01: /* CDC command / status / data */
+ //out_debug_log(_T("CDC CMD %02x\n"), data);
+ write_cdrom_data(data);
+ break;
+
+ case 0x02: /* ADPCM / CD control / IRQ enable/disable */
+ /* bit 6 - transfer ready irq */
+ /* bit 5 - transfer done irq */
+ /* bit 4 - BRAM irq? */
+ /* bit 3 - ADPCM FULL irq */
+ /* bit 2 - ADPCM HALF irq */
+ if(data & 0x80) {
+ set_ack();
+ } else {
+ clear_ack();
+ }
+ /* Update mask register now otherwise it won't catch the irq enable/disable change */
+ cdrom_regs[0x02] = data;
+ /* Don't set or reset any irq lines, but just verify the current state */
+ set_cdrom_irq_line(0, 0);
+ break;
+
+ case 0x03: /* BRAM lock / CD status / IRQ - Read Only register */
+ break;
+
+ case 0x04: /* CD reset */
+ if(data & 0x02) {
+ // Reset CDROM
+ // From Ootake v2.38
+ d_scsi_cdrom->write_signal(SIG_SCSI_CDROM_CDDA_STOP, 0xff, 0xff);
+ // Reset ADPCM hardware
+ reset_adpcm();
+ adpcm_dma_enabled = false;
+ out_debug_log(_T("ADPCM CMD=$04 RESET\n"));
+ cdrom_regs[0x03] = 0x00; // Reset IRQ status at al.
+ set_cdrom_irq_line(0x0, 0x0); // Update IRQ
+ }
+ d_scsi_host->write_signal(SIG_SCSI_RST, data, 0x02);
+ break;
+
+ case 0x05: /* Convert PCM data / PCM data */
+ case 0x06: /* PCM data */
+ break;
+
+ case 0x07: /* BRAM unlock / CD status */
+ if(data & 0x80) {
+ backup_locked = false;
+ }
+ break;
+
+ case 0x08: /* ADPCM address (LSB) / CD data */
+ case 0x09: /* ADPCM address (MSB) */
+ break;
+
+ case 0x0a: /* ADPCM RAM data port */
+ if(adpcm_write_buf > 0) {
+ adpcm_write_buf--;
+ } else {
+ write_adpcm_ram(data);
+ }
+ break;
+
+ case 0x0b: /* ADPCM DMA control */
+ if(data & 3) {
+ /* Start CD to ADPCM transfer */
+ adpcm_dma_enabled = true;
+ cdrom_regs[0x0c] |= 0x04;
+ if(d_scsi_cdrom->get_cur_command() == SCSI_CMD_READ6 &&
+ d_scsi_host->read_signal(SIG_SCSI_BSY) != 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_REQ) != 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_CD ) == 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_MSG) == 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_IO ) != 0) {
+ // already data is received, read first byte
+ adpcm_do_dma();
+ out_debug_log(_T("Start DMA port $0B/ALREADY READ DATA ADPCM_WRITE_PTR=%04x ADPCM_READ_PTR=%04x MSM_START_ADDR=%04x\n"),adpcm_write_ptr, adpcm_read_ptr, msm_start_addr);
+ } else {
+ //cdrom_regs[0x0c] |= 0x04;
+ out_debug_log(_T("Start DMA port $0B/WAIT FOR DATA\n"));
+ }
+ } else {
+ //adpcm_dma_enabled = false;
+ }
+ break;
+
+ case 0x0c: /* ADPCM status */
+ break;
+
+ case 0x0d: /* ADPCM address control */
+ if((cdrom_regs[0x0d] & 0x80) && !(data & 0x80)) {
+ // Reset ADPCM hardware
+ reset_adpcm();
+ adpcm_stop(true);
+ out_debug_log(_T("ADPCM CMD=$0D RESET\n"));
+ }
+ if(data & 0x02) {
+ // ADPCM set write address
+ adpcm_write_ptr = (cdrom_regs[0x09] << 8) | cdrom_regs[0x08];
+ adpcm_write_buf = ((data & 1) == 0) ? 1 : 0;
+ adpcm_written = 0;
+ out_debug_log(_T("ADPCM SET WRITE ADDRESS ADDR=%04x\n"), adpcm_write_ptr);
+ }
+ if(data & 0x08) {
+ // ADPCM set read address
+ adpcm_read_ptr = (cdrom_regs[0x09] << 8) | cdrom_regs[0x08];
+ adpcm_read_buf = ((data & 0x04) == 0) ? 2 : 1;
+ out_debug_log(_T("ADPCM SET READ ADDRESS ADDR=%04x\n"), adpcm_read_ptr);
+ }
+ if(data & 0x10) {
+ // ADPCM set length
+ adpcm_length = (cdrom_regs[0x09] << 8) | cdrom_regs[0x08];
+ uint32_t _clk = (ADPCM_CLOCK / 6) / adpcm_clock_divider;
+
+ if(((adpcm_read_ptr & 0xffff) >= 0x4000) &&
+ ((adpcm_write_ptr & 0xffff) == 0x0000) &&
+ (adpcm_length != 0x8000) &&
+ (adpcm_length != 0xffff) &&
+ (_clk < 16000)) {
+ adpcm_length = adpcm_length & 0x7fff;
+ }
+ out_debug_log(_T("ADPCM SET LENGTH LENGTH=%04x\n"), adpcm_length);
+ }
+ if((((data & 0x40) != 0) && ((cdrom_regs[0x0D] & 0x40) == 0)) ||
+ (!(adpcm_play_in_progress) && ((data & 0x20 != 0)))) { // From Ootake v2.83
+ // ADPCM play
+ msm_start_addr = (adpcm_read_ptr) & 0xffff;
+ msm_end_addr = (adpcm_read_ptr + adpcm_length) & 0xffff;
+ msm_half_addr = (adpcm_read_ptr + (adpcm_length / 2)) & 0xffff;
+ adpcm_write_ptr &= 0xffff;
+ msm_nibble = 0;
+ adpcm_play_in_progress = true;
+ adpcm_play();
+ d_msm->reset_w(0);
+ out_debug_log(_T("ADPCM START PLAY START=%04x END=%04x HALF=%04x\n"), msm_start_addr, msm_end_addr, msm_half_addr);
+ } else if(((data & 0x40) == 0)) {
+ if(((cdrom_regs[0x0D] & 0x40) != 0) && (adpcm_play_in_progress)) {
+ // 20181213 K.O: Import from Ootake v2.83.Thanks to developers of Ootake.
+ if(((data & 0x20) != 0) && ((adpcm_length & 0xffff) >= 0x8000) && ((adpcm_length & 0xffff) <= 0x80ff)) {
+ msm_half_addr = (adpcm_read_ptr + 0x85) & 0xffff;
+ } else {
+ msm_half_addr = (adpcm_read_ptr + (adpcm_length >> 1)) & 0xffff;
+ }
+ }
+ // used by Buster Bros to cancel an in-flight sample
+ // if repeat flag (bit5) is high, ADPCM should be fully played (from Ootake)
+ if(!(data & 0x20)) {
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE);
+ adpcm_stop(false);
+ d_msm->reset_w(1);
+ }
+ }
+ break;
+
+ case 0x0e: /* ADPCM playback rate */
+ adpcm_clock_divider = 0x10 - (data & 0x0f);
+ d_msm->change_clock_w((ADPCM_CLOCK / 6) / adpcm_clock_divider);
+ break;
+
+ case 0x0f: /* ADPCM and CD audio fade timer */
+ if(cdrom_regs[0x0f] != data) {
+ switch(data & 0x0f) {
+ case 0x00: // CD-DA / ADPCM enable (100 msecs)
+ cdda_fade_in(100);
+ adpcm_fade_in(100);
+ break;
+ case 0x01: // CD-DA enable (100 msecs)
+ cdda_fade_in(100);
+ break;
+ case 0x08: // CD-DA short (1500 msecs) fade out / ADPCM enable
+ case 0x0c: // CD-DA short (1500 msecs) fade out / ADPCM enable
+ cdda_fade_out(1500);
+ adpcm_fade_in(100);
+ break;
+ case 0x09: // CD-DA long (5000 msecs) fade out
+ cdda_fade_out(5000);
+ break;
+ case 0x0a: // ADPCM long (5000 msecs) fade out
+ adpcm_fade_out(5000);
+ break;
+ case 0x0d: // CD-DA short (1500 msecs) fade out
+ cdda_fade_out(1500);
+ break;
+ case 0x0e: // ADPCM short (1500 msecs) fade out
+ adpcm_fade_out(1500);
+ break;
+ }
+ }
+ break;
+ }
+ cdrom_regs[addr & 0x0f] = data;
+}
+
+uint8_t PCE::cdrom_read(uint16_t addr)
+{
+ // System 3 Card header handling
+ if((addr & 0xc0) == 0xc0) {
+ switch(addr & 0xcf) {
+ case 0xc1: return 0xaa;
+ case 0xc2: return 0x55;
+ case 0xc3: return 0x00;
+ case 0xc5: return 0xaa;
+ case 0xc6: return 0x55;
+ case 0xc7: return 0x03;
+ }
+ return 0xff; // From Ootake v2.83.
+ }
+ uint8_t data = cdrom_regs[addr & 0x0f];
+
+ switch(addr & 0x0f) {
+ case 0x00: /* CDC status */
+ if((cdrom_regs[0x02] & 0x80) != 0) {
+ // ToDo: Imprement read_1801() at Ootake v2.83.
+ // ToDo: Implement _CheckCountAfterRead at CDROM.cpp of Ootake v2.83.
+ if((d_scsi_host->read_signal(SIG_SCSI_CD) != 0) &&
+ (d_scsi_host->read_signal(SIG_SCSI_MSG) == 0) &&
+ (d_scsi_host->read_signal(SIG_SCSI_IO) != 0)) { // STATUS PHASE: Porting from Ootake v2.83.
+ // // busy = false;
+ cdrom_regs[0x02] = cdrom_regs[0x02] & ~(0x80 | PCE_CD_IRQ_TRANSFER_READY | PCE_CD_IRQ_TRANSFER_DONE);
+ set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_DONE, CLEAR_LINE);
+ }
+ return data & ~0x40; // Clear REQ
+ }
+ data = 0;
+ if(d_cpu->get_pc() == 0xf34b) {
+ // XXX: Hack to wait the CD-DA will be finished for the Manhole
+ data |= d_scsi_cdrom->read_signal(SIG_SCSI_CDROM_PLAYING) ? 0x80 : 0;
+ }
+ data |= d_scsi_host->read_signal(SIG_SCSI_BSY) ? 0x80 : 0;
+ data |= d_scsi_host->read_signal(SIG_SCSI_REQ) ? 0x40 : 0;
+ data |= d_scsi_host->read_signal(SIG_SCSI_MSG) ? 0x20 : 0;
+ data |= d_scsi_host->read_signal(SIG_SCSI_CD ) ? 0x10 : 0;
+ data |= d_scsi_host->read_signal(SIG_SCSI_IO ) ? 0x08 : 0;
+ cdrom_regs[0x00] = data;
+ if(false){
+ // Import from Ootake v2.83 20181211 K.O
+ if(((data & 0x10) != 0) &&
+ ((data & 0x20) == 0) &&
+ ((data & 0x08) == 0)){ // Command phase
+ if((data & 0x80) != 0) { // Busy
+ // data = (data & ~0x40) | 0x08; // (data & ~REQ) | IO
+ } else {
+ //data = data & ~0x40; // (data & ~REQ)
+ }
+ } else if((data & 0x80) != 0) { // BUSY
+ data = (data & ~0x40) | 0x10 | 0x80; // (data & ~REQ) | BUSY | CD
+ } /*else if(_CheckCountAfterRead == 0) && (Status phase) && (cmd == read6)){
+ data = data & ~0x40;
+ } else */ /* if(_bCDReqWait) {
+ _bCDReqWait = false;
+ if(data boundary) {
+ data = data & ~0x40;
+ }
+ }*/
+ }
+ break;
+
+ case 0x01: /* CDC command / status / data */
+ case 0x08: /* ADPCM address (LSB) / CD data */
+ {
+ bool read6_data_in = false;
+ if(d_scsi_cdrom->get_cur_command() == SCSI_CMD_READ6 &&
+ d_scsi_host->read_signal(SIG_SCSI_BSY) != 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_REQ) != 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_CD ) == 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_MSG) == 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_IO ) != 0) {
+ // read6 command, data in phase
+ read6_data_in = true;
+ }
+ data = read_cdrom_data();
+ if(read6_data_in) {
+ // set ack automatically and immediately for correct transfer speed
+ set_ack();
+
+ // XXX: Hack to wait until next REQ signal is raised
+ // because PCE does not check REQ signal before reads next byte
+ d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
+ } else {
+ if((addr & 0x0f) == 0x01) {
+ // ToDo: Imprement read_1801() at Ootake v2.83.
+ // ToDo: Implement _CheckCountAfterRead at CDROM.cpp of Ootake v2.83.
+ }
+ }
+ }
+ break;
+
+ case 0x02: /* ADPCM / CD control */
+ break;
+
+ case 0x03: /* BRAM lock / CD status */
+ // from Ootake
+ backup_locked = true;
+ data |= PCE_CD_IRQ_BRAM;
+ cdrom_regs[3] ^= 0x02;
+ if(cdrom_regs[2] == 0) {
+ cdrom_regs[3] &= 0x02;
+ }
+ set_cdrom_irq_line(0, 0);
+ break;
+
+ case 0x04: /* CD reset */
+ break;
+
+ case 0x05: /* Convert PCM data / PCM data */
+ data = (d_scsi_cdrom->read_signal((cdrom_regs[3] & 0x02) ? SIG_SCSI_CDROM_SAMPLE_L : SIG_SCSI_CDROM_SAMPLE_R) >> 0) & 0xff;
+ break;
+
+ case 0x06: /* PCM data */
+ data = (d_scsi_cdrom->read_signal((cdrom_regs[3] & 0x02) ? SIG_SCSI_CDROM_SAMPLE_L : SIG_SCSI_CDROM_SAMPLE_R) >> 8) & 0xff;
+ break;
+
+ case 0x07: /* BRAM unlock / CD status */
+ data = (backup_locked ? (data & 0x7f) : (data | 0x80));
+ break;
+
+ case 0x0a: /* ADPCM RAM data port */
+ if(adpcm_read_buf > 0) {
+ adpcm_read_buf--;
+ data = 0x00;
+ } else {
+ data = read_adpcm_ram();
+ }
+ break;
+
+ case 0x0b: /* ADPCM DMA control */
+ break;
+
+ case 0x0c: /* ADPCM status */
+ // Hack from Ootake v2.83.
+ if(adpcm_play_in_progress) {
+ data = data & ~0x85;
+ data = data | 0x08;
+ } else {
+ data = data | 0x01;
+ data = data & ~0x0c;
+ }
+ cdrom_regs[0x0c] = data;
+ // ToDo: HuVideo
+ break;
+ case 0x09: /* ADPCM address (MSB) */
+ case 0x0d: /* ADPCM address control */
+ case 0x0e: /* ADPCM playback rate */
+ case 0x0f: /* ADPCM and CD audio fade timer */
+ data = 0;
+ break;
+ }
+ return data;
+}
+
+void PCE::write_cdrom_data(uint8_t data)
+{
+ d_scsi_host->write_dma_io8(0, data);
+}
+
+uint8_t PCE::read_cdrom_data()
+{
+
+ return d_scsi_host->read_dma_io8(0);
+}
+
+void PCE::reset_adpcm()
+{
+ touch_sound();
+ // reset ADPCM hardware
+ adpcm_read_ptr = adpcm_write_ptr = 0;
+ msm_start_addr = msm_end_addr = msm_half_addr = 0;
+ msm_nibble = 0;
+ adpcm_stop(false);
+ d_msm->reset_w(1);
+ out_debug_log(_T("RESET ADPCM\n"));
+
+ // stop ADPCM dma
+ adpcm_dma_enabled = false;
+}
+
+void PCE::write_adpcm_ram(uint8_t data)
+{
+ adpcm_ram[(adpcm_write_ptr++) & 0xffff] = data;
+// adpcm_write_ptr = adpcm_write_ptr & 0xffff;
+}
+
+uint8_t PCE::read_adpcm_ram()
+{
+ uint8_t _data = adpcm_ram[(adpcm_read_ptr++) & 0xffff];
+// adpcm_read_ptr = adpcm_read_ptr & 0xffff;
+ return _data;
+}
+
+void PCE::adpcm_do_dma()
+{
+ write_adpcm_ram(read_cdrom_data());
+ adpcm_written++;
+ set_ack();
+ cdrom_regs[0x0c] &= ~0x04;
+}
+
+void PCE::adpcm_play()
+{
+ touch_sound();
+ cdrom_regs[0x0c] &= ~PCE_CD_ADPCM_STOP_FLAG;
+ cdrom_regs[0x0c] |= PCE_CD_ADPCM_PLAY_FLAG;
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE);
+ //set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
+ cdrom_regs[0x03] &= ~0x0c;
+ msm_idle = 0;
+}
+
+void PCE::adpcm_stop(bool do_irq)
+{
+ touch_sound();
+ cdrom_regs[0x0c] |= PCE_CD_ADPCM_STOP_FLAG;
+ cdrom_regs[0x0c] &= ~PCE_CD_ADPCM_PLAY_FLAG;
+ if(do_irq) {
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE);
+ }
+ cdrom_regs[0x0d] &= ~0x60;
+ msm_idle = 1;
+ adpcm_play_in_progress = false;
+// adpcm_dma_enabled = false;
+ out_debug_log(_T("ADPCM STOP PLAY PTR=%04x IRQ=%s\n"), msm_start_addr, (do_irq) ? _T("YES") : _T("NO"));
+}
+
+void PCE::set_ack()
+{
+ cdrom_regs[0x03] |= 0x40; // From Ootake v2.38
+ d_scsi_host->write_signal(SIG_SCSI_ACK, 1, 1);
+}
+
+void PCE::clear_ack()
+{
+ cdrom_regs[0x03] &= ~0x40; // From Ootake v2.38
+ if(d_scsi_host->read_signal(SIG_SCSI_CD) != 0) {
+ cdrom_regs[0x0b] &= 0xfc;
+ }
+ d_scsi_host->write_signal(SIG_SCSI_ACK, 0, 0);
+}
+
+void PCE::set_cdrom_irq_line(int num, int state)
+{
+ if (state == ASSERT_LINE) {
+ cdrom_regs[0x03] |= num;
+ } else {
+ cdrom_regs[0x03] &= ~num;
+ }
+ if (cdrom_regs[0x02] & cdrom_regs[0x03] & 0x7c) {
+ d_cpu->write_signal(INPUT_LINE_IRQ2, ASSERT_LINE, 0);
+ } else {
+ d_cpu->write_signal(INPUT_LINE_IRQ2, CLEAR_LINE, 0);
+ }
+}
+
+void PCE::cdda_fade_in(int time)
+{
+ if(event_cdda_fader != -1) {
+ cancel_event(this, event_cdda_fader);
+ }
+ register_event(this, EVENT_CDDA_FADE_IN, time, true, &event_cdda_fader);
+ d_scsi_cdrom->set_volume((int)(cdda_volume = 0.0));
+}
+
+void PCE::cdda_fade_out(int time)
+{
+ if(event_cdda_fader != -1) {
+ cancel_event(this, event_cdda_fader);
+ }
+ register_event(this, EVENT_CDDA_FADE_OUT, time, true, &event_cdda_fader);
+ d_scsi_cdrom->set_volume((int)(cdda_volume = 100.0));
+}
+
+void PCE::adpcm_fade_in(int time)
+{
+ if(event_adpcm_fader != -1) {
+ cancel_event(this, event_adpcm_fader);
+ }
+ register_event(this, EVENT_ADPCM_FADE_IN, time, true, &event_adpcm_fader);
+ d_msm->set_volume((int)(adpcm_volume = 0.0));
+}
+
+void PCE::adpcm_fade_out(int time)
+{
+ if(event_adpcm_fader != -1) {
+ cancel_event(this, event_adpcm_fader);
+ }
+ register_event(this, EVENT_ADPCM_FADE_OUT, time, true, &event_adpcm_fader);
+ d_msm->set_volume((int)(adpcm_volume = 100.0));
+}
+
+void PCE::write_signal(int id, uint32_t data, uint32_t mask)
+{
+ switch(id) {
+ case SIG_PCE_SCSI_IRQ:
+ if(data & mask) {
+ if(!irq_status) {
+ irq_status = true;
+
+ if(d_scsi_host->read_signal(SIG_SCSI_BSY) != 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_CD ) != 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_MSG) == 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_IO ) != 0) {
+ // status phase, command is finished
+ set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_READY, CLEAR_LINE);
+ set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE);
+ }
+ // clear busreq because next REQ signal is raised
+ d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
+ }
+ } else {
+ if(irq_status) {
+ irq_status = false;
+ }
+ }
+ break;
+
+ case SIG_PCE_SCSI_DRQ:
+ if(data & mask) {
+ if(!drq_status) {
+ drq_status = true;
+ set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_READY, ASSERT_LINE);
+
+ // clear busreq because next REQ signal is raised
+ d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
+
+ if(adpcm_dma_enabled) {
+ if(!(msm_idle) && ((adpcm_write_ptr & 0xffff) >= (msm_start_addr & 0xffff))) {
+ // now streaming, wait dma not to overwrite buffer before it is played
+ cdrom_regs[0x0b] = 0x00; // From Ootake v2.38.
+ //adpcm_do_dma();
+ } else {
+ adpcm_do_dma();
+ }
+ }
+ }
+ } else {
+ if(drq_status) {
+ drq_status = false;
+
+ if(d_scsi_cdrom->get_cur_command() == SCSI_CMD_READ6 &&
+ d_scsi_host->read_signal(SIG_SCSI_BSY) != 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_CD ) == 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_MSG) == 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_IO ) != 0) {
+ // clear ack automatically and immediately for correct transfer speed
+ clear_ack();
+ }
+ }
+ }
+ break;
+
+ case SIG_PCE_SCSI_BSY:
+ if(!(data & mask)) {
+ // bus free
+ set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_READY, CLEAR_LINE);
+ set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_DONE, CLEAR_LINE);
+ if(!(adpcm_play_in_progress) && (adpcm_dma_enabled)){
+ d_msm->reset_w(1);
+ adpcm_dma_enabled = false;
+ out_debug_log(_T("SIG_PCE_SCSI_BSY: RESET ADPCM\n"));
+ }
+ }
+ break;
+
+ case SIG_PCE_CDDA_DONE:
+ touch_sound();
+ if(data & mask) {
+ set_cdrom_irq_line(PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE);
+ }
+ break;
+
+ case SIG_PCE_ADPCM_VCLK:
+ // Callback for new data from the MSM5205.
+ // The PCE cd unit actually divides the clock signal supplied to
+ // the MSM5205. Currently we can only use static clocks for the
+ // MSM5205.
+ if((data & mask) == 0) {
+ if(!msm_idle) {
+ uint8_t msm_data = (msm_nibble) ? (adpcm_ram[msm_start_addr & 0xffff] & 0x0f) : ((adpcm_ram[msm_start_addr & 0xffff] & 0xf0) >> 4);
+ d_msm->data_w(msm_data);
+ msm_nibble ^= 1;
+
+ if(msm_nibble == 0) {
+ adpcm_written--;
+ // 20181213 K.O: Re-order sequence from Ootake v2.83.Thanks to developers of Ootake.
+ if((msm_start_addr & 0xffff) == msm_end_addr) {
+ // reached to end address
+ if(adpcm_dma_enabled) {
+ // restart streaming
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE);
+ //set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE);
+ out_debug_log(_T("END ADDRESS(DMA) READ_PTR=%04x WRITE_PTR=%04x\n"), adpcm_read_ptr, adpcm_write_ptr);
+ } else {
+ // stop playing adpcm
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE);
+ adpcm_stop(true);
+ d_msm->reset_w(1);
+ out_debug_log(_T("END ADDRESS(NON-DMA) READ_PTR=%04x WRITE_PTR=%04x\n"), adpcm_read_ptr, adpcm_write_ptr);
+ }
+ } else if(adpcm_dma_enabled && adpcm_written == 0) {
+ // finish streaming when all samples are played
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE);
+ adpcm_stop(true);
+ d_msm->reset_w(1);
+ } else if((msm_start_addr & 0xffff) == msm_half_addr) {
+ // reached to half address
+ // 20181213 K.O: Porting from Ootake v2.83.Thanks to developers of Ootake.
+ if((adpcm_dma_enabled) && (adpcm_length >= 0x8000) && (adpcm_length <= 0x80ff)) {
+ msm_half_addr = (msm_half_addr + 0x85) & 0xffff;
+ } else if(adpcm_length < 0x7fff) {
+ msm_half_addr = (msm_half_addr + (uint16_t)(adpcm_length - 1024)) & 0xffff;
+ }
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE);
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, ASSERT_LINE);
+ out_debug_log(_T("HALF ADDRESS READ_PTR=%04x WRITE_PTR=%04x\n"), adpcm_read_ptr, adpcm_write_ptr);
+ } else if((!((adpcm_dma_enabled) && (adpcm_length >= 0x8000) && (adpcm_length <= 0x80ff)) &&
+ !(adpcm_length < 0x7fff)) &&
+ (((msm_start_addr & 0xffff) == 0x8000) || ((msm_start_addr & 0xffff) == 0x0000))) {
+ // 20181213 K.O: Porting from Ootake v2.83.Thanks to developers of Ootake.
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE);
+ set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, ASSERT_LINE);
+ out_debug_log(_T("HALF ADDRESS READ_PTR=%04x WRITE_PTR=%04x\n"), adpcm_read_ptr, adpcm_write_ptr);
+ }
+
+ msm_start_addr++;
+ //msm_start_addr = msm_start_addr & 0xffff;
+ if(adpcm_dma_enabled) {
+ if(!(msm_idle) && (adpcm_write_ptr < msm_start_addr)) {
+ if(d_scsi_cdrom->get_cur_command() == SCSI_CMD_READ6 &&
+ d_scsi_host->read_signal(SIG_SCSI_BSY) != 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_REQ) != 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_CD ) == 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_MSG) == 0 &&
+ d_scsi_host->read_signal(SIG_SCSI_IO ) != 0) {
+ // already data is received, read next byte
+ adpcm_do_dma();
+ }
+ }
+ } else {
+ }
+ }
+ }
+ }
+ break;
+ }
+}
+
+void PCE::event_callback(int event_id, int err)
+{
+ switch(event_id) {
+ case EVENT_CDDA_FADE_IN:
+ if((cdda_volume += 0.1) >= 100.0) {
+ cancel_event(this, event_cdda_fader);
+ event_cdda_fader = -1;
+ cdda_volume = 100.0;
+ }
+ d_scsi_cdrom->set_volume((int)cdda_volume);
+ break;
+
+ case EVENT_CDDA_FADE_OUT:
+ if((cdda_volume -= 0.1) <= 0) {
+ cancel_event(this, event_cdda_fader);
+ event_cdda_fader = -1;
+ cdda_volume = 0.0;
+ }
+ d_scsi_cdrom->set_volume((int)cdda_volume);
+ break;
+
+ case EVENT_ADPCM_FADE_IN:
+ if((adpcm_volume += 0.1) >= 100.0) {
+ cancel_event(this, event_adpcm_fader);
+ event_adpcm_fader = -1;
+ adpcm_volume = 100.0;
+ }
+ d_msm->set_volume((int)adpcm_volume);
+ break;
+
+ case EVENT_ADPCM_FADE_OUT:
+ if((adpcm_volume -= 0.1) <= 0) {
+ cancel_event(this, event_adpcm_fader);
+ event_adpcm_fader = -1;
+ adpcm_volume = 0.0;
+ }
+ d_msm->set_volume((int)adpcm_volume);
+ break;
+ }
+}
#endif
- state_fio->FputUint32(bank);
- state_fio->FputUint8(buffer);
- state_fio->FputInt32(prev_width);
- state_fio->FputBool(inserted);
- state_fio->Fwrite(vdc, sizeof(vdc), 1);
- state_fio->Fwrite(&vce, sizeof(vce), 1);
- state_fio->Fwrite(&vpc, sizeof(vpc), 1);
- state_fio->Fwrite(psg, sizeof(psg), 1);
- state_fio->FputUint8(psg_ch);
- state_fio->FputUint8(psg_vol);
- state_fio->FputUint8(psg_lfo_freq);
- state_fio->FputUint8(psg_lfo_ctrl);
- state_fio->FputUint8(joy_sel);
- state_fio->FputUint8(joy_clr);
- state_fio->FputUint8(joy_count);
- state_fio->FputUint8(joy_bank);
- state_fio->FputBool(joy_6btn);
-}
-
-bool PCE::load_state(FILEIO* state_fio)
-{
- if(state_fio->FgetUint32() != STATE_VERSION) {
- return false;
- }
- if(state_fio->FgetInt32() != this_device_id) {
- return false;
- }
- support_6btn = state_fio->FgetBool();
- support_sgfx = state_fio->FgetBool();
- state_fio->Fread(ram, sizeof(ram), 1);
- state_fio->Fread(cart + 0x80000, 0x80000, 1);
-#ifdef SUPPORT_BACKUP_RAM
- state_fio->Fread(backup, sizeof(backup), 1);
- backup_crc32 = state_fio->FgetUint32();
+
+#define STATE_VERSION 6
+
+void process_state_vdc(vdc_t* val, FILEIO* state_fio)
+{
+ state_fio->StateValue(val->dvssr_write);
+ state_fio->StateValue(val->physical_width);
+ state_fio->StateValue(val->physical_height);
+ state_fio->StateArray(val->sprite_ram, sizeof(val->sprite_ram), 1);
+ state_fio->StateValue(val->curline);
+ state_fio->StateValue(val->current_segment);
+ state_fio->StateValue(val->current_segment_line);
+ state_fio->StateValue(val->vblank_triggered);
+ state_fio->StateValue(val->raster_count);
+ state_fio->StateValue(val->satb_countdown);
+ state_fio->StateArray(val->vram, sizeof(val->vram), 1);
+ state_fio->StateValue(val->inc);
+ state_fio->StateValue(val->vdc_register);
+ state_fio->StateValue(val->vdc_latch);
+ state_fio->StateArray(val->vdc_data, sizeof(val->vdc_data), 1);
+ state_fio->StateValue(val->status);
+ state_fio->StateValue(val->y_scroll);
+}
+
+void process_state_vce(vce_t* val, FILEIO* state_fio)
+{
+ state_fio->StateValue(val->vce_control);
+ state_fio->StateValue(val->vce_address);
+ state_fio->StateArray(val->vce_data, sizeof(val->vce_data), 1);
+ state_fio->StateValue(val->current_bitmap_line);
+ state_fio->StateArrayScrnType_t(&val->bmp[0][0], sizeof(val->bmp), 1);
+ state_fio->StateArrayScrnType_t(val->palette, sizeof(val->palette), 1);
+}
+
+void process_state_vpc(vpc_t* val, FILEIO* state_fio)
+{
+ for(int i = 0; i < array_length(val->vpc_prio); i++) {
+ state_fio->StateValue(val->vpc_prio[i].prio);
+ state_fio->StateValue(val->vpc_prio[i].vdc0_enabled);
+ state_fio->StateValue(val->vpc_prio[i].vdc1_enabled);
+ }
+ state_fio->StateArray(val->prio_map, sizeof(val->prio_map), 1);
+ state_fio->StateValue(val->priority);
+ state_fio->StateValue(val->window1);
+ state_fio->StateValue(val->window2);
+ state_fio->StateValue(val->vdc_select);
+}
+
+void process_state_psg(psg_t* val, FILEIO* state_fio)
+{
+ state_fio->StateArray(val->regs, sizeof(val->regs), 1);
+ state_fio->StateArray(val->wav, sizeof(val->wav), 1);
+ state_fio->StateValue(val->wavptr);
+ state_fio->StateValue(val->genptr);
+ state_fio->StateValue(val->remain);
+ state_fio->StateValue(val->noise);
+ state_fio->StateValue(val->randval);
+}
+
+bool PCE::process_state(FILEIO* state_fio, bool loading)
+{
+ if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+ return false;
+ }
+ if(!state_fio->StateCheckInt32(this_device_id)) {
+ return false;
+ }
+ state_fio->StateValue(support_6btn_pad);
+ state_fio->StateValue(support_multi_tap);
+ #ifdef SUPPORT_SUPER_GFX
+ state_fio->StateValue(support_sgfx);
+ #endif
+ #ifdef SUPPORT_CDROM
+ state_fio->StateValue(support_cdrom);
+ #endif
+ state_fio->StateArray(ram, sizeof(ram), 1);
+ state_fio->StateArray(cart + 0x80000, 0x80000, 1);
+ #ifdef SUPPORT_BACKUP_RAM
+ state_fio->StateArray(backup, sizeof(backup), 1);
+ state_fio->StateValue(backup_crc32);
+ #endif
+ state_fio->StateValue(bank);
+ state_fio->StateValue(buffer);
+ state_fio->StateValue(prev_width);
+ state_fio->StateValue(inserted);
+ for(int i = 0; i < array_length(vdc); i++) {
+ process_state_vdc(&vdc[i], state_fio);
+ }
+ process_state_vce(&vce, state_fio);
+ process_state_vpc(&vpc, state_fio);
+ for(int i = 0; i < array_length(psg); i++) {
+ process_state_psg(&psg[i], state_fio);
+ }
+ state_fio->StateValue(psg_ch);
+ state_fio->StateValue(psg_vol);
+ state_fio->StateValue(psg_lfo_freq);
+ state_fio->StateValue(psg_lfo_ctrl);
+ state_fio->StateValue(joy_counter);
+ state_fio->StateValue(joy_high_nibble);
+ state_fio->StateValue(joy_second_byte);
+#ifdef SUPPORT_CDROM
+ state_fio->StateArray(cdrom_ram, sizeof(cdrom_ram), 1);
+ state_fio->StateArray(cdrom_regs, sizeof(cdrom_regs), 1);
+ state_fio->StateValue(backup_locked);
+ state_fio->StateValue(irq_status);
+ state_fio->StateValue(drq_status);
+ state_fio->StateArray(adpcm_ram, sizeof(adpcm_ram), 1);
+ state_fio->StateValue(adpcm_read_ptr);
+ state_fio->StateValue(adpcm_write_ptr);
+ state_fio->StateValue(adpcm_written);
+ state_fio->StateValue(adpcm_length);
+ state_fio->StateValue(adpcm_clock_divider);
+ state_fio->StateValue(adpcm_read_buf);
+ state_fio->StateValue(adpcm_write_buf);
+ state_fio->StateValue(adpcm_dma_enabled);
+ state_fio->StateValue(msm_start_addr);
+ state_fio->StateValue(msm_end_addr);
+ state_fio->StateValue(msm_half_addr);
+ state_fio->StateValue(msm_nibble);
+ state_fio->StateValue(msm_idle);
+ state_fio->StateValue(cdda_volume);
+ state_fio->StateValue(adpcm_volume);
+ state_fio->StateValue(event_cdda_fader);
+ state_fio->StateValue(event_adpcm_fader);
+ state_fio->StateValue(adpcm_play_in_progress);
#endif
- bank = state_fio->FgetUint32();
- buffer = state_fio->FgetUint8();
- prev_width = state_fio->FgetInt32();
- inserted = state_fio->FgetBool();
- state_fio->Fread(vdc, sizeof(vdc), 1);
- state_fio->Fread(&vce, sizeof(vce), 1);
- state_fio->Fread(&vpc, sizeof(vpc), 1);
- state_fio->Fread(psg, sizeof(psg), 1);
- psg_ch = state_fio->FgetUint8();
- psg_vol = state_fio->FgetUint8();
- psg_lfo_freq = state_fio->FgetUint8();
- psg_lfo_ctrl = state_fio->FgetUint8();
- joy_sel = state_fio->FgetUint8();
- joy_clr = state_fio->FgetUint8();
- joy_count = state_fio->FgetUint8();
- joy_bank = state_fio->FgetUint8();
- joy_6btn = state_fio->FgetBool();
- return true;
+ return true;
}
+}