OSDN Git Service

[VM][PCENGINE][ADPCM] Separate around ADPCM to ADPCM:: .
authorK.Ohta <whatisthis.sowhat@gmail.com>
Sat, 9 Feb 2019 20:29:04 +0000 (05:29 +0900)
committerK.Ohta <whatisthis.sowhat@gmail.com>
Sat, 9 Feb 2019 20:29:04 +0000 (05:29 +0900)
source/src/vm/pcengine/CMakeLists.txt
source/src/vm/pcengine/adpcm.cpp [new file with mode: 0644]
source/src/vm/pcengine/adpcm.h [new file with mode: 0644]
source/src/vm/pcengine/pce.cpp
source/src/vm/pcengine/pce.h
source/src/vm/pcengine/pcengine.cpp
source/src/vm/pcengine/pcengine.h

index 42cbeae..2a95077 100644 (file)
@@ -5,10 +5,12 @@ message("* vm/pce")
 if(BUILD_X1TWIN)
 add_library(vm_pcengine
            pce.cpp
+                  
 )
 else()
 add_library(vm_pcengine
-           pce.cpp
+       pce.cpp
+          adpcm.cpp       
           pcengine.cpp
 )
-endif()
\ No newline at end of file
+endif()
diff --git a/source/src/vm/pcengine/adpcm.cpp b/source/src/vm/pcengine/adpcm.cpp
new file mode 100644 (file)
index 0000000..3b41639
--- /dev/null
@@ -0,0 +1,611 @@
+/*
+       NEC-HE PC Engine Emulator 'ePCEngine'
+       SHARP X1twin Emulator 'eX1twin'
+
+       Origin : Ootake (joypad/cdrom)
+              : xpce (psg)
+              : MESS (vdc/vce/vpc/cdrom)
+       Author : Takeda.Toshiya
+       Date   : 2009.03.11-
+       Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
+       Date   : 2019.02.09-  Split from pce.cpp
+
+       [ PC-Engine around ADPCM]
+*/
+
+#include "./adpcm.h"
+#include "./pce.h"
+
+
+#include "../msm5205.h"
+#include "../scsi_host.h"
+#include "../scsi_cdrom.h"
+
+
+namespace PCEDEV {
+
+#define PCE_CD_ADPCM_PLAY_FLAG         0x08
+#define PCE_CD_ADPCM_STOP_FLAG         0x01
+
+#define EVENT_CLEAR_ACK 1
+#define EVENT_SET_ACK   2
+#define EVENT_FADE_IN   3
+#define EVENT_FADE_OUT  4
+       
+void ADPCM::initialize()
+{
+       adpcm_clock_divider = 1;
+       event_fader = -1;
+       event_ack = -1;
+       reg_0c = 0;
+       msm_last_cmd = 0;
+       reg_0b = 0;
+
+       memset(ram, 0x00, sizeof(ram));
+}
+
+void ADPCM::reset()
+{
+       touch_sound();
+
+       read_ptr = write_ptr = 0;
+       read_buf = write_buf = 0;
+       written_size = 0;
+       dma_enabled = false;
+       play_in_progress = false;
+       adpcm_paused = false;
+       
+       msm_ptr = 0;
+       msm_length = 0;
+       msm_end_addr = 0;
+       msm_nibble = 0;
+       adpcm_length = 0;
+       addr_reg.w = 0;
+       half_addr = 0;
+       reg_0c = 0;
+       msm_last_cmd = 0;
+       reg_0b = 0;
+       adpcm_stream = false;
+       
+       adpcm_volume = 100.0;
+       if(event_fader != -1) {
+               cancel_event(this, event_fader);
+       }
+       event_fader = -1;
+       if(event_ack != -1) {
+               cancel_event(this, event_ack);
+       }
+       event_ack = -1;
+       
+       reg_0c |= PCE_CD_ADPCM_STOP_FLAG;
+       reg_0c &= ~PCE_CD_ADPCM_PLAY_FLAG;
+       
+       d_msm->set_volume((int)adpcm_volume);
+       //memset(ram, 0x00, sizeof(ram));
+}
+
+uint32_t ADPCM::read_signal(int ch)
+{
+       switch(ch) {
+       case SIG_ADPCM_DATA:
+               if(read_buf > 0) {
+                       read_buf--;
+                       return 0x00;
+               } else {
+                       uint8_t _d = ram[read_ptr & 0xffff];
+                       read_ptr = (read_ptr + 1) & 0xffff;
+                       return _d;
+               }
+               break;
+       case SIG_ADPCM_DMACTRL:
+               return reg_0b;
+               break;
+       case SIG_ADPCM_PLAY_IN_PROGRESS:
+               return ((play_in_progress) ? 0xffffffff : 0);
+               break;
+       case SIG_ADPCM_STATUS_REG:
+               {
+                       uint8_t data = reg_0c;
+                       if(play_in_progress) {
+                               data = data & ~0x85;
+                               data = data | 0x08;
+                       } else {
+                               data = data | 0x01;
+                               data = data & ~0x0c;
+                       }
+                       return data;
+               }
+               break;
+       case SIG_ADPCM_CMD_REG:
+               return msm_last_cmd;
+               break;
+       }
+       return 0x00;
+}
+
+void ADPCM::reset_adpcm()
+{
+       touch_sound();
+       // reset ADPCM hardware
+       read_ptr = write_ptr = 0;
+       msm_ptr = msm_end_addr = half_addr = 0;
+       msm_nibble = 0;
+       do_stop(false);
+       //d_msm->reset();
+       d_msm->reset_w(1);
+       out_debug_log(_T("RESET ADPCM\n"));
+       
+       // stop ADPCM dma
+       dma_enabled = false;
+       d_pce->write_signal(SIG_PCE_ADPCM_DMA, 0x00000000, 0xffffffff);
+       adpcm_repeat = false;
+       //adpcm_stream = false;
+}
+
+void ADPCM::do_play()
+{
+       reg_0c &= ~PCE_CD_ADPCM_STOP_FLAG;
+       reg_0c |= PCE_CD_ADPCM_PLAY_FLAG;
+       play_in_progress = true;
+       adpcm_paused = false;
+}
+
+void ADPCM::do_pause(bool pause)
+{
+       if(pause) {
+               if((play_in_progress) && !(adpcm_paused)) {
+                       reg_0c |= PCE_CD_ADPCM_STOP_FLAG;
+                       reg_0c &= ~PCE_CD_ADPCM_PLAY_FLAG;
+                       msm_last_cmd &= ~0x60;
+                       adpcm_paused = true;
+                       d_msm->reset_w(1);
+                       out_debug_log(_T("ADPCM PAUSE PLAY PTR=%04x\n"), msm_ptr);
+                       touch_sound();
+               }
+       } else {
+               if((adpcm_paused)) {
+                       adpcm_paused = false;
+                       touch_sound();
+                       reg_0c &= ~PCE_CD_ADPCM_STOP_FLAG;
+                       reg_0c |= PCE_CD_ADPCM_PLAY_FLAG;
+                       if(d_pce->read_signal(SIG_PCE_CDROM_DATA_IN) != 0) {
+                               do_dma(d_pce->read_signal(SIG_PCE_CDROM_RAW_DATA));
+                               reg_0c &= ~0x04;
+                       }
+                       d_msm->reset_w(0);
+                       out_debug_log(_T("ADPCM UNPAUSE PLAY PTR=%04x\n"), msm_ptr);
+               }
+       }
+}
+
+void ADPCM::do_stop(bool do_irq)
+{
+       reg_0c |= PCE_CD_ADPCM_STOP_FLAG;
+       reg_0c &= ~PCE_CD_ADPCM_PLAY_FLAG;
+       if(do_irq) {
+               d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0xffffffff, 0xffffffff);
+       }
+       msm_last_cmd &= ~0x60;
+       play_in_progress = false;
+       dma_enabled = false;
+       d_pce->write_signal(SIG_PCE_ADPCM_DMA, 0x00000000, 0xffffffff);
+       out_debug_log(_T("ADPCM STOP PLAY PTR=%04x IRQ=%s\n"), msm_ptr, (do_irq) ? _T("YES") : _T("NO"));
+       
+}
+void ADPCM::write_signal(int ch, uint32_t data, uint32_t mask)
+{
+       bool flag = ((data & mask) != 0);
+       //if(ch != SIG_ADPCM_VCLK) out_debug_log(_T("WRITE_SIGNAL SIG=%d DATA=%04x MASK=%04x\n"), ch, data, mask);
+       switch(ch) {
+       case SIG_ADPCM_DMACTRL:
+               reg_0b = data;
+               break;
+       case SIG_ADPCM_PAUSE:
+               do_pause(flag);
+               break;
+       case SIG_ADPCM_DMA_ENABLED:
+               if((flag) && (flag != dma_enabled)) {
+                       reg_0c |= 0x04;
+                       if(d_pce->read_signal(SIG_PCE_CDROM_DATA_IN) != 0) {
+                               do_dma(d_pce->read_signal(SIG_PCE_CDROM_RAW_DATA));
+                               out_debug_log(_T("Start DMA port $0B/ALREADY READ DATA ADPCM_WRITE_PTR=%04x ADPCM_READ_PTR=%04x MSM_START_ADDR=%04x\n"),write_ptr, read_ptr, msm_ptr);
+                               reg_0c &= ~0x04;
+                       } else {
+                               out_debug_log(_T("Start DMA port $0B/WAIT FOR DATA\n"));
+                       }
+               }
+               dma_enabled = flag;
+               d_pce->write_signal(SIG_PCE_ADPCM_DMA, (flag) ? 0xffffffff : 0x00000000, 0xffffffff);
+               break;
+       case SIG_ADPCM_RESET:
+               if(flag) {
+                       reset_adpcm();
+               }
+               break;
+       case SIG_ADPCM_COMMAND: // REG $0D
+               do_cmd(data);
+               break;
+       case SIG_ADPCM_WRITE_DMA_DATA:
+               do_dma(data);
+               break;
+       case SIG_ADPCM_DO_DMA_TRANSFER:
+               if((play_in_progress) && ((write_ptr & 0xffff) >= (msm_ptr & 0xffff))) {
+                       reg_0b = 0x00;
+               } else {
+                       do_dma(d_pce->read_signal(SIG_PCE_CDROM_RAW_DATA));
+                       reg_0c &= ~0x04;
+               }
+               break;
+       case SIG_ADPCM_ADDR_HI: // REG $09
+               addr_reg.b.h = data;
+               break;
+       case SIG_ADPCM_ADDR_LO: // REG $08
+               addr_reg.b.l = data;
+               break;
+       case SIG_ADPCM_VCLK:
+               do_vclk(flag);
+               break;
+       case SIG_ADPCM_DATA:
+               if(write_buf > 0) {
+                       write_buf--;
+               } else {
+                       ram[write_ptr & 0xffff] = data;
+                       write_ptr = (write_ptr + 1) & 0xffff;
+                       written_size++;
+               }
+               break;
+       case SIG_ADPCM_FADE_IN:
+               fade_in(data);
+               break;
+       case SIG_ADPCM_FADE_OUT:
+               fade_out(data);
+               break;
+       case SIG_ADPCM_SET_DIVIDER:
+               adpcm_clock_divider = 0x10 - (data & 0x0f);
+               d_msm->change_clock_w((ADPCM_CLOCK / 6) / adpcm_clock_divider);
+               break;
+       }
+}
+       
+void ADPCM::do_cmd(uint8_t cmd)
+{
+       // Register 0x0d.
+       //out_debug_log(_T("ADPCM CMD=%02x\n"), cmd);
+       if(((cmd & 0x80) != 0) && ((msm_last_cmd & 0x80) == 0)) {
+               // Reset ADPCM
+               reset_adpcm();
+               d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x00, 0xffffffff);
+               d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0x00, 0xffffffff);
+               msm_init(); // SAMPLE = 0x800, SSI=0
+               out_debug_log(_T("ADPCM CMD RESET\n"));
+       }
+       bool req_play_0 =   ((cmd & 0x40) != 0) ? true : false;
+       adpcm_repeat = ((cmd & 0x20) != 0) ? true : false;
+       uint32_t _clk = (ADPCM_CLOCK / 6) / adpcm_clock_divider;
+       
+       if(((cmd & 0x10) != 0) /*&& ((msm_last_cmd & 0x10) == 0)*/){
+               // ADPCM set length
+               d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0x00, 0xffffffff);
+               adpcm_length = (uint32_t)(addr_reg.w);
+               out_debug_log(_T("ADPCM SET READ ADDRESS ADDR=%04x\n"), adpcm_length);
+       }
+       
+       if(((cmd & 0x08) != 0) /*&& ((msm_last_cmd & 0x08) == 0)*/) {
+               // ADPCM set read address
+               read_ptr = (uint32_t)(addr_reg.w);
+               read_buf = ((cmd & 0x04) == 0) ? 2 : 1;
+               read_ptr = (read_ptr - (read_buf - 1)) & 0xffff;
+               out_debug_log(_T("ADPCM SET READ ADDRESS ADDR=%04x BUF=%01x \n"), read_ptr, read_buf);
+       }
+       if(((cmd & 0x02) != 0) /*&& ((msm_last_cmd & 0x02) == 0)*/) {
+               // ADPCM set write address
+               write_ptr = (uint32_t)(addr_reg.w);
+               write_buf = ((cmd & 0x01) == 0) ? 1 : 0;
+               written_size = 0;
+               write_ptr = (write_ptr - write_buf) & 0xffff;
+               // It's ugly... (;_;)
+               if(((read_ptr & 0xffff) >= 0x4000) &&
+                  ((write_ptr & 0xffff) == 0x0000) &&
+                  (adpcm_length != 0x8000) &&
+                  (adpcm_length != 0xffff) &&
+                  (_clk < 16000)) {
+                       adpcm_length = adpcm_length & 0x7fff;
+               }
+               out_debug_log(_T("ADPCM SET WRITE ADDRESS ADDR=%04x BUF=%01x \n"), write_ptr, write_buf);
+       }
+       bool req_play = false;
+       if((play_in_progress) && !(adpcm_repeat)) {
+               req_play = false;
+       }
+       if(!(play_in_progress) && (adpcm_repeat)) {
+               d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x00, 0xffffffff);
+               req_play = true;
+               msm_nibble = 0;
+               msm_init(); // SAMPLE = 0x800, SSI=0
+       }
+       if(req_play_0) {
+               req_play = true;
+       } else {
+               if(/*(adpcm_stream) && */(written_size > 0x8000)) {
+                       req_play = true;
+               }
+       }
+       if((req_play) && !(play_in_progress)) {
+               d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x00, 0xffffffff);
+               msm_ptr = read_ptr & 0xffff;
+               msm_end_addr = (msm_ptr + adpcm_length) & 0xffff;
+               msm_length = adpcm_length;
+               half_addr = (msm_ptr + (msm_length / 2)) & 0xffff;
+               msm_nibble = 0;
+               do_play();
+               d_msm->reset_w(0);
+               out_debug_log(_T("ADPCM START PLAY(%s) START=%04x END=%04x HALF=%04x\n"), (dma_enabled) ? _T("DMA") : _T("PIO"), msm_ptr, msm_end_addr, half_addr);
+       } else if((req_play) /*&& (cmd != msm_last_cmd)*/){
+               if(((adpcm_length & 0xffff) >= 0x8000) && ((adpcm_length & 0xffff) <= 0x80ff)) {
+                       half_addr = (read_ptr + 0x85) & 0xffff;
+                       msm_end_addr = (msm_end_addr + 0x85) & 0xffff;
+                       //half_addr = (msm_ptr + 0x85) & 0xffff;
+                       //msm_end_addr = (half_addr + 0x85) & 0xffff;
+               } else {
+                       half_addr = (read_ptr + (adpcm_length >> 1)) & 0xffff;
+                       msm_end_addr = (read_ptr + adpcm_length) & 0xffff;
+                       //half_addr = (msm_ptr + (adpcm_length >> 1)) & 0xffff;
+                       //msm_end_addr = (msm_ptr + adpcm_length) & 0xffff;
+               }
+               out_debug_log(_T("ADPCM UPDATE HALF ADDRESS HALF=%04x END=%04x\n"), half_addr, msm_end_addr);
+       } else /*if(cmd != msm_last_cmd)*/ { // !req_play
+               d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x00, 0xffffffff);
+               d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0xffffffff, 0xffffffff);
+               out_debug_log(_T("ADPCM STATUS UPDATE PLAY=%s\n"), (play_in_progress) ? _T("YES") : _T("NO"));                  
+       }
+       msm_last_cmd = cmd;
+       
+}
+
+void ADPCM::msm_init()
+{
+       //d_msm->reset();
+       //d_msm->reset_w(1);
+       d_msm->reset_w(0);
+}
+
+void ADPCM::do_vclk(bool flag)
+{
+       if((flag) && (play_in_progress)) {
+               //if((msm_ptr & 0xffff) != (msm_end_addr & 0xffff)) {
+               if(play_in_progress) {
+                       uint8_t msm_data = (msm_nibble != 0) ? (ram[msm_ptr & 0xffff] & 0x0f) : ((ram[msm_ptr & 0xffff] & 0xf0) >> 4);
+                       d_msm->data_w(msm_data);
+                       msm_nibble ^= 1;
+                       
+                       if((written_size <= 0) && (dma_enabled)) {
+                               if(!(adpcm_paused)) {
+                                       do_pause(true);
+                                       return;
+                               }
+                       } else if((adpcm_paused) && (dma_enabled)) {
+                               if(written_size > 0) {
+                                       do_pause(false);
+                               } else {
+                                       return;
+                               }
+                       }
+                       
+                       if(msm_nibble == 0) {
+                               // Increment pointers.
+                               written_size--;
+                               if((msm_ptr & 0xffff) == (msm_end_addr & 0xffff)) {
+                                       //if((adpcm_repeat) && (dma_enabled) &&
+                                       // (adpcm_length >= 0x8000) && (adpcm_length <= 0x80ff) /* && (IsHuVideo()) */) {
+                                       //      written_size++;
+                                       //      msm_ptr = (msm_ptr - 1) & 0xffff;
+                                               //goto __skip1;
+                                       //}
+                                       d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x0, 0xffffffff);
+                                       d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0xffffffff, 0xffffffff);
+                                       out_debug_log(_T("PLAY PASSED TO THE FULL ADDR=%08x SIZE=%04x\n"), msm_ptr, written_size);
+                                       do_stop(false);
+                               } else if((msm_ptr & 0xffff) == half_addr) {
+                                       // 20181213 K.O: Porting from Ootake v2.83.Thanks to developers of Ootake.
+                                       if((dma_enabled) && (adpcm_length >= 0x8000) && (adpcm_length <= 0x80ff)) {
+                                               half_addr = (half_addr + 0x85) & 0xffff;
+                                       } else if(adpcm_length < 0x7fff) {
+                                               half_addr = (half_addr + (uint16_t)(adpcm_length - 1024)) & 0xffff;
+                                       }
+                                       d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0xffffffff, 0xffffffff);
+                                       d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0x00, 0xffffffff);
+                                       out_debug_log(_T("PLAY PASSED TO THE HALF ADDR=%08x SIZE=%04x\n"), msm_ptr, written_size);
+                               } /*else if((msm_ptr & 0xffff) == ((half_addr + 1) & 0xffff)) {
+                                       d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x00, 0xffffffff);
+                                       d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0x00, 0xffffffff);
+                               } */else if((!((dma_enabled) && (adpcm_length >= 0x8000) && (adpcm_length <= 0x80ff)) &&
+                                                  !(adpcm_length < 0x7fff))) {
+                                       if(((msm_ptr & 0xffff) == 0x8000) || ((msm_ptr & 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);
+                                               d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0x00, 0xffffffff);
+                                               d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0xffffffff, 0xffffffff);
+                                               out_debug_log(_T("SPECIAL HALF ADDRESS MSM_ADDR=%08x\n"), msm_ptr);
+                                       } else if(((msm_ptr & 0xffff) == 0x8001) || ((msm_ptr & 0xffff) == 0x0001)) {
+                                               //d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x0, 0xffffffff);
+                                       }
+                               }
+                               msm_ptr++;
+                                       
+                               if(dma_enabled) {
+                                       if(d_pce->read_signal(SIG_PCE_CDROM_DATA_IN) != 0) {
+                                               do_dma(d_pce->read_signal(SIG_PCE_CDROM_RAW_DATA));
+                                               reg_0c &= ~0x04;
+                                       }
+                               } else {
+                                                       
+                               }
+                       } else {
+//                             written_size--;
+                       }
+               } else if((msm_last_cmd & 0x10) != 0) { // Data empty?
+                       bool _nf = true;
+                       if(dma_enabled) {
+                               if(d_pce->read_signal(SIG_PCE_CDROM_DATA_IN) != 0) {
+                                       do_dma(d_pce->read_signal(SIG_PCE_CDROM_RAW_DATA));
+                                       reg_0c &= ~0x04;
+                                       //_nf = false;
+                               }
+                       }
+                       if(_nf) {
+                               d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x00, 0xffffffff);
+                               d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0xffffffff, 0xffffffff);
+                               if((msm_last_cmd & 0x40) != 0) {
+                                       do_stop(false);
+                                       //play_in_progress = false;
+                                       out_debug_log(_T("PLAY REACHED TO THE END ADDR=%08x SIZE=%04x\n"), msm_ptr, written_size);
+                               }
+                       }
+               } else {
+                       d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x00, 0xffffffff);
+                       d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0xffffffff, 0xffffffff);
+                       if((msm_last_cmd & 0x40) != 0) {
+                               do_stop(false);
+                               //play_in_progress = false;
+                               out_debug_log(_T("PLAY REACHED TO THE END ADDR=%08x SIZE=%04x\n"), msm_ptr, written_size);
+                       }
+               }                       
+               
+       }
+}
+       
+bool ADPCM::do_dma(uint8_t data)
+{
+       ram[write_ptr & 0xffff] = data;
+       write_ptr = (write_ptr + 1) & 0xffff;
+       written_size++;
+       d_pce->write_signal(SIG_PCE_CDROM_SET_ACK, 0x04, 0xff);
+       reg_0c &= ~0x04;
+       return true;
+}
+
+
+void ADPCM::set_ack(int clocks)
+{
+       if(event_ack != -1) cancel_event(this, event_ack);
+       event_ack = -1;
+       if(clocks <= 0) {
+               d_pce->write_signal(SIG_PCE_CDROM_SET_ACK, 0xff, 0xff);
+       } else {
+               double us = (((double)clocks) * 1.0e6) / ((double)CPU_CLOCKS);
+               register_event(this, EVENT_SET_ACK, us, false, &event_ack);
+       }
+}
+
+void ADPCM::clear_ack(int clocks)
+{
+       if(event_ack != -1) cancel_event(this, event_ack);
+       event_ack = -1;
+       if(clocks <= 0) {
+               d_pce->write_signal(SIG_PCE_CDROM_CLEAR_ACK, 0xff, 0xff);
+       } else {
+               double us = (((double)clocks) * 1.0e6) / ((double)CPU_CLOCKS);
+               register_event(this, EVENT_CLEAR_ACK, us, false, &event_ack);
+       }
+}
+
+void ADPCM::fade_in(int usec)
+{
+       if(event_fader != -1) {
+               cancel_event(this, event_fader);
+       }
+       register_event(this, EVENT_FADE_IN, (double)usec, true, &event_fader);
+       adpcm_volume = 0.0;
+       d_msm->set_volume((int)adpcm_volume);
+}
+
+void ADPCM::fade_out(int usec)
+{
+       if(event_fader != -1) {
+               cancel_event(this, event_fader);
+       }
+       register_event(this, EVENT_FADE_OUT, (double)usec, true, &event_fader);
+       adpcm_volume = 100.0;
+       d_msm->set_volume((int)adpcm_volume);
+}
+       
+void ADPCM::event_callback(int id, int err)
+{
+       switch(id) {
+       case EVENT_CLEAR_ACK:
+               event_ack = -1;
+               d_pce->write_signal(SIG_PCE_CDROM_CLEAR_ACK, 0xff, 0xff);
+               break;
+       case EVENT_SET_ACK:
+               event_ack = -1;
+               d_pce->write_signal(SIG_PCE_CDROM_SET_ACK, 0xff, 0xff);
+               break;
+       case EVENT_FADE_IN:             
+               if((adpcm_volume += 0.1) >= 100.0) {
+                       cancel_event(this, event_fader);
+                       event_fader = -1;
+                       adpcm_volume = 100.0;
+               }
+               d_msm->set_volume((int)adpcm_volume);
+               break;
+       case EVENT_FADE_OUT:            
+               if((adpcm_volume -= 0.1) <= 0.0) {
+                       cancel_event(this, event_fader);
+                       event_fader = -1;
+                       adpcm_volume = 0.0;
+               }
+               d_msm->set_volume((int)adpcm_volume);
+               break;
+       }
+}
+
+void ADPCM::mix(int32_t* buffer, int cnt)
+{
+       d_msm->mix(buffer, cnt);
+}
+
+#define STATE_VERSION  7
+
+bool ADPCM::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(addr_reg);
+       state_fio->StateValue(reg_0b);
+       state_fio->StateValue(reg_0c);
+       state_fio->StateValue(msm_last_cmd);
+       
+       state_fio->StateBuffer(ram, sizeof(ram), 1);
+       
+       state_fio->StateValue(read_ptr);
+       state_fio->StateValue(read_buf);
+       state_fio->StateValue(write_ptr);
+       state_fio->StateValue(write_buf);
+       
+       state_fio->StateValue(msm_ptr);
+       state_fio->StateValue(msm_nibble);
+       state_fio->StateValue(msm_length);
+       state_fio->StateValue(msm_end_addr);
+       state_fio->StateValue(half_addr);
+       state_fio->StateValue(adpcm_length);
+       
+       state_fio->StateValue(written_size);
+       state_fio->StateValue(dma_enabled);
+       state_fio->StateValue(play_in_progress);
+       state_fio->StateValue(adpcm_paused);
+       state_fio->StateValue(adpcm_stream);
+       state_fio->StateValue(adpcm_repeat);
+       
+       state_fio->StateValue(adpcm_volume);
+       state_fio->StateValue(event_fader);
+       state_fio->StateValue(event_ack);
+
+       return true;
+}
+
+}
+
diff --git a/source/src/vm/pcengine/adpcm.h b/source/src/vm/pcengine/adpcm.h
new file mode 100644 (file)
index 0000000..bd9d205
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+       NEC-HE PC Engine Emulator 'ePCEngine'
+       SHARP X1twin Emulator 'eX1twin'
+
+       Origin : Ootake (joypad/cdrom)
+              : xpce (psg)
+              : MESS (vdc/vce/vpc/cdrom)
+       Author : Takeda.Toshiya
+       Date   : 2009.03.11-
+       Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
+       Date   : 2019.02.09-  Split from pce.cpp
+
+       [ PC-Engine around ADPCM]
+*/
+
+#ifndef _PCE_ADPCM_H_
+#define _PCE_ADPCM_H_
+
+#include "../vm.h"
+#include "../../emu.h"
+#include "../device.h"
+
+#define SIG_ADPCM_RESET            0
+#define SIG_ADPCM_DATA             1
+#define SIG_ADPCM_DMACTRL          2
+#define SIG_ADPCM_DMA_ENABLED      3
+#define SIG_ADPCM_WRITE_DMA_DATA   4
+#define SIG_ADPCM_DO_DMA_TRANSFER  5
+#define SIG_ADPCM_PLAY_IN_PROGRESS 6
+#define SIG_ADPCM_VCLK             7
+#define SIG_ADPCM_STATUS_REG       8
+#define SIG_ADPCM_COMMAND          9
+#define SIG_ADPCM_PAUSE            10
+#define SIG_ADPCM_FADE_IN          11
+#define SIG_ADPCM_FADE_OUT         12
+#define SIG_ADPCM_ADDR_HI          13
+#define SIG_ADPCM_ADDR_LO          14
+#define SIG_ADPCM_SET_DIVIDER      15
+#define SIG_ADPCM_CMD_REG          16
+
+class MSM5205;
+
+namespace PCEDEV {
+
+class PCE;
+       
+class ADPCM : public DEVICE
+{
+protected:
+       PCE* d_pce;
+       MSM5205* d_msm;
+
+       uint32_t read_ptr;
+       uint32_t write_ptr;
+       uint32_t read_buf;
+       uint32_t write_buf;
+       
+       uint32_t msm_ptr;
+       uint32_t msm_nibble;
+       uint32_t msm_length;
+       uint32_t msm_end_addr;
+       uint32_t half_addr;
+       uint32_t adpcm_length;
+       bool adpcm_stream;
+       int written_size;
+
+       bool dma_enabled;
+       bool adpcm_paused;
+       bool adpcm_repeat;
+       bool play_in_progress;
+
+       double adpcm_volume;
+       
+       int adpcm_clock_divider;
+       int event_fader;
+       int event_ack;
+
+       pair16_t addr_reg;
+       uint8_t reg_0b;
+       uint8_t reg_0c;
+       uint8_t msm_last_cmd; // REG $0D
+
+       uint8_t ram[0x10000];
+       
+       void do_vclk(bool flag);
+       void msm_init();
+       bool do_dma(uint8_t data);
+       void do_cmd(uint8_t cmd);
+       void do_play();
+       void do_pause(bool pause);
+       void do_stop(bool do_irq);
+       void set_ack(int clocks);
+       void clear_ack(int clocks);
+       void fade_in(int usec);
+       void fade_out(int usec);
+       void reset_adpcm();
+public:
+       ADPCM(VM_TEMPLATE* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
+       {
+               set_device_name(_T("PC-Engine CD-ROM^2 around ADPCM"));
+       }
+       ~ADPCM() { }
+       
+       void initialize();
+       void reset();
+       
+       uint32_t read_signal(int ch);
+       void write_signal(int ch, uint32_t data, uint32_t mask);
+       
+       void event_callback(int id, int err);
+       void mix(int32_t* buffer, int cnt);
+       bool process_state(FILEIO* state_fio, bool loading);
+       
+       void set_context_msm(MSM5205* dev)
+       {
+               d_msm = dev;
+       }
+
+       void set_context_pce(PCE* dev)
+       {
+               d_pce = dev;
+       }
+
+};
+
+}
+#endif
index 0aceead..d587a4d 100644 (file)
@@ -19,7 +19,9 @@
 #include "../scsi_host.h"
 #include "../scsi_cdrom.h"
 #endif
-
+#ifdef USE_SEPARATED_ADPCM
+#include "./adpcm.h"
+#endif 
 #define STATE_VSW              0
 #define STATE_VDS              1
 #define STATE_VDW              2
@@ -1712,9 +1714,11 @@ void PCE::mix(int32_t* buffer, int cnt)
        }
 #ifdef SUPPORT_CDROM
        if(support_cdrom) {
+       #ifndef USE_SEPARATED_ADPCM
                if(!msm_idle) {
                        d_msm->mix(buffer, cnt);
                }
+       #endif  
                d_scsi_cdrom->mix(buffer, cnt);
        }
 #endif
@@ -1888,7 +1892,8 @@ void PCE::cdrom_write(uint16_t addr, uint8_t data)
                d_scsi_host->write_signal(SIG_SCSI_SEL, 1, 1);
                d_scsi_host->write_signal(SIG_SCSI_SEL, 0, 1);
        #ifdef USE_SEPARATED_ADPCM
-               d_adpcm->write_signal(SIG_PCE_ADPCM_DMA_ENABLED, 0x00, 0xff);
+               adpcm_dma_enabled = false;
+               d_adpcm->write_signal(SIG_ADPCM_DMA_ENABLED, 0x00, 0xff);
        #else
                adpcm_dma_enabled = false;
        #endif
@@ -1929,8 +1934,9 @@ void PCE::cdrom_write(uint16_t addr, uint8_t data)
                        d_scsi_cdrom->write_signal(SIG_SCSI_CDROM_CDDA_STOP, 0xff, 0xff);
                        // Reset ADPCM hardware
        #ifdef USE_SEPARATED_ADPCM
-                       d_adpcm->write_signal(SIG_PCE_ADPCM_RESET, 0xff, 0xff);
-                       d_adpcm->write_signal(SIG_PCE_ADPCM_DMA_ENABLED, 0x00, 0xff);
+                       adpcm_dma_enabled = false;
+                       d_adpcm->write_signal(SIG_ADPCM_DMA_ENABLED, 0x00, 0xff);
+                       d_adpcm->write_signal(SIG_ADPCM_RESET, 0xff, 0xff);
        #else
                        reset_adpcm();
                        adpcm_dma_enabled = false;
@@ -1953,25 +1959,35 @@ void PCE::cdrom_write(uint16_t addr, uint8_t data)
                break;
                
        case 0x08:  /* ADPCM address (LSB) / CD data */
+       #ifdef USE_SEPARATED_ADPCM
+               d_adpcm->write_signal(SIG_ADPCM_ADDR_LO, data, 0xff);
+       #endif
+               break;
        case 0x09:  /* ADPCM address (MSB) */
+       #ifdef USE_SEPARATED_ADPCM
+               d_adpcm->write_signal(SIG_ADPCM_ADDR_HI, data, 0xff);
+       #endif
                break;
                
        case 0x0a:  /* ADPCM RAM data port */
-               if(adpcm_write_buf > 0) {
-                       adpcm_write_buf--;
-               } else {
        #ifdef USE_SEPARATED_ADPCM
                        d_adpcm->write_signal(SIG_ADPCM_DATA, data, 0xff);
        #else
+               if(adpcm_write_buf > 0) {
+                       adpcm_write_buf--;
+               } else {
                        write_adpcm_ram(data);
-       #endif
                }
+       #endif
                break;
                
        case 0x0b:  /* ADPCM DMA control */
                if(data & 3) {
                        /* Start CD to ADPCM transfer */
                        adpcm_dma_enabled = true;
+       #ifdef USE_SEPARATED_ADPCM
+                       d_adpcm->write_signal(SIG_ADPCM_DMA_ENABLED, 0xffffffff, 0xffffffff);
+       #else
                        cdrom_regs[0x0c] |= 0x04;
                        if(d_scsi_cdrom->get_cur_command() == SCSI_CMD_READ6 &&
                           d_scsi_host->read_signal(SIG_SCSI_BSY) != 0 &&
@@ -1986,15 +2002,21 @@ void PCE::cdrom_write(uint16_t addr, uint8_t data)
                        } else {
                                out_debug_log(_T("Start DMA port $0B/WAIT FOR DATA\n"));
                        }
+       #endif
                } else {
                        //adpcm_dma_enabled = false;
                }
+
                break;
                
        case 0x0c:  /* ADPCM status */
                break;
                
        case 0x0d:  /* ADPCM address control */
+               out_debug_log(_T("ADPCM CMD=%02x\n"), data);
+       #ifdef USE_SEPARATED_ADPCM
+               d_adpcm->write_signal(SIG_ADPCM_COMMAND, data, 0xff);
+       #else
                {
                        uint8_t reg_bak = cdrom_regs[0x0d];
                        cdrom_regs[0x0d] = data;
@@ -2086,18 +2108,22 @@ void PCE::cdrom_write(uint16_t addr, uint8_t data)
                                                msm_half_addr = (adpcm_read_ptr + (adpcm_length >> 1)) & 0xffff;
                                        }
                                        out_debug_log(_T("ADPCM UPDATE HALF ADDRESS HALF=%04x\n"), msm_half_addr);
+                                       adpcm_pause(false);
                                }
+
                        } else {
                                
                                adpcm_stream = false;
                                adpcm_repeat = false;
                                set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
-                               out_debug_log(_T("ADPCM STATUS UPDATE PLAY=%s\n"), (adpcm_play_in_progress) ? _T("YES") : _T("NO"));                                                    if(adpcm_play_in_progress) {
-                                       adpcm_stop(true);
-                                       d_msm->reset_w(1);
-                               } else {
+                               out_debug_log(_T("ADPCM STATUS UPDATE PLAY=%s\n"), (adpcm_play_in_progress) ? _T("YES") : _T("NO"));                                                    //if(adpcm_play_in_progress) {
+                               //      adpcm_stop(true);
+                               //      d_msm->reset_w(1);
+                               //} else {
+                                       //adpcm_pause(true);
+                                       //d_msm->reset_w(1);
                                        set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE);
-                               }
+                                       //}
                        }
                        // used by Buster Bros to cancel an in-flight sample
                        // if repeat flag (bit5) is high, ADPCM should be fully played (from Ootake)
@@ -2108,12 +2134,16 @@ void PCE::cdrom_write(uint16_t addr, uint8_t data)
                          d_msm->reset_w(1);
                          }*/
                }
-       
+       #endif  
                break;
                
        case 0x0e:  /* ADPCM playback rate */
+       #ifdef USE_SEPARATED_ADPCM
+               d_adpcm->write_signal(SIG_ADPCM_SET_DIVIDER, data, 0x0f);
+       #else
                adpcm_clock_divider = 0x10 - (data & 0x0f);
                d_msm->change_clock_w((ADPCM_CLOCK / 6) / adpcm_clock_divider);
+       #endif
                break;
                
        case 0x0f:  /* ADPCM and CD audio fade timer */
@@ -2121,7 +2151,11 @@ void PCE::cdrom_write(uint16_t addr, uint8_t data)
                        switch(data & 0x0f) {
                        case 0x00: // CD-DA / ADPCM enable (100 msecs)
                                cdda_fade_in(100);
+       #ifdef USE_SEPARATED_ADPCM
+                               d_adpcm->write_signal(SIG_ADPCM_FADE_IN, 100, 0xffffffff);
+       #else
                                adpcm_fade_in(100);
+       #endif
                                break;
                        case 0x01: // CD-DA enable (100 msecs)
                                cdda_fade_in(100);
@@ -2129,19 +2163,31 @@ void PCE::cdrom_write(uint16_t addr, uint8_t data)
                        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);
+       #ifdef USE_SEPARATED_ADPCM
+                               d_adpcm->write_signal(SIG_ADPCM_FADE_IN, 100, 0xffffffff);
+       #else
                                adpcm_fade_in(100);
+       #endif
                                break;
                        case 0x09: // CD-DA long (5000 msecs) fade out
                                cdda_fade_out(5000);
                                break;
                        case 0x0a: // ADPCM long (5000 msecs) fade out
+       #ifdef USE_SEPARATED_ADPCM
+                               d_adpcm->write_signal(SIG_ADPCM_FADE_OUT, 5000, 0xffffffff);
+       #else
                                adpcm_fade_out(5000);
+       #endif
                                break;
                        case 0x0d: // CD-DA short (1500 msecs) fade out
                                cdda_fade_out(1500);
                                break;
                        case 0x0e: // ADPCM short (1500 msecs) fade out
+       #ifdef USE_SEPARATED_ADPCM
+                               d_adpcm->write_signal(SIG_ADPCM_FADE_OUT, 1500, 0xffffffff);
+       #else
                                adpcm_fade_out(1500);
+       #endif
                                break;
                        }
                }
@@ -2313,18 +2359,28 @@ uint8_t PCE::cdrom_read(uint16_t addr)
                break;
                
        case 0x0a:  /* ADPCM RAM data port */
+       #ifdef USE_SEPARATED_ADPCM
+               data = d_adpcm->read_signal(SIG_ADPCM_DATA);
+       #else
                if(adpcm_read_buf > 0) {
                        adpcm_read_buf--;
                        data = 0x00;
                } else {
                        data = read_adpcm_ram();
                }
+       #endif
                break;
                
        case 0x0b:  /* ADPCM DMA control */
+       #ifdef USE_SEPARATED_ADPCM
+               data = d_adpcm->read_signal(SIG_ADPCM_DMACTRL);
+       #endif
                break;
                
        case 0x0c:  /* ADPCM status */
+       #ifdef USE_SEPARATED_ADPCM
+               data = d_adpcm->read_signal(SIG_ADPCM_STATUS_REG);
+       #else
                // Hack from Ootake v2.83.
                if((adpcm_play_in_progress) && (msm_idle == 0)){
                        data = data & ~0x85;
@@ -2333,6 +2389,7 @@ uint8_t PCE::cdrom_read(uint16_t addr)
                        data = data | 0x01;
                        data = data & ~0x0c;
                }
+       #endif
                cdrom_regs[0x0c] = data;
                // ToDo: HuVideo
                //cdrom_regs[0x03] &= ~0x04;
@@ -2520,6 +2577,33 @@ void PCE::adpcm_fade_out(int time)
        d_msm->set_volume((int)(adpcm_volume = 100.0));
 }
 
+uint32_t PCE::read_signal(int id)
+{
+       uint32_t data = 0;
+#ifdef USE_SEPARATED_ADPCM
+       switch(id) {
+       case SIG_PCE_CDROM_RAW_DATA:
+               data = read_cdrom_data();
+               set_ack();
+               //cdrom_regs[0x0c] &= ~0x04;
+               break;
+       case SIG_PCE_CDROM_DATA_IN:
+               {
+                       uint8_t cmd = d_scsi_cdrom->get_cur_command();
+                       if(((cmd == SCSI_CMD_READ6) || (cmd == SCSI_CMD_READ10) || (cmd == SCSI_CMD_READ12))  &&
+                          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) {
+                               return 0xffffffff;
+                       }
+               }
+               break;
+       }
+#endif
+       return data;
+}
 void PCE::write_signal(int id, uint32_t data, uint32_t mask)
 {
        switch(id) {
@@ -2554,7 +2638,14 @@ void PCE::write_signal(int id, uint32_t data, uint32_t mask)
                                // clear busreq because next REQ signal is raised
                                d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
                                
-                               //      out_debug_log(_T("CDROM DRQ(ADPCM)\n"));
+                               //out_debug_log(_T("CDROM DRQ(ADPCM)\n"));
+       #ifdef USE_SEPARATED_ADPCM
+                               if(adpcm_dma_enabled) {
+                                       d_adpcm->write_signal(SIG_ADPCM_DMACTRL, cdrom_regs[0x0b], 0xff);
+                                       d_adpcm->write_signal(SIG_ADPCM_DO_DMA_TRANSFER, 0xff, 0xff);
+                                       cdrom_regs[0x0b] = d_adpcm->read_signal(SIG_ADPCM_DMACTRL);
+                               }
+       #else
                                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
@@ -2564,6 +2655,7 @@ void PCE::write_signal(int id, uint32_t data, uint32_t mask)
                                                adpcm_do_dma();
                                        }
                                }
+       #endif
                        }
                } else {
                        if(drq_status) {
@@ -2588,16 +2680,29 @@ void PCE::write_signal(int id, uint32_t data, uint32_t mask)
                        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)){
+       #ifdef USE_SEPARATED_ADPCM
+                               d_adpcm->write_signal(SIG_ADPCM_PAUSE, 0xff, 0xff);
+       #else
                                adpcm_pause(true);
+       #endif
                                //adpcm_dma_enabled = false;
                                out_debug_log(_T("SIG_PCE_SCSI_BSY: PAUSE ADPCM\n"));
                        }
                } else {
                        if(/*!(adpcm_play_in_progress) && */(adpcm_dma_enabled)){
+       #ifdef USE_SEPARATED_ADPCM
+                               {
+                                       d_adpcm->write_signal(SIG_ADPCM_DMACTRL, cdrom_regs[0x0b], 0xff);
+                                       d_adpcm->write_signal(SIG_ADPCM_DO_DMA_TRANSFER, 0xff, 0xff);
+                                       cdrom_regs[0x0b] = d_adpcm->read_signal(SIG_ADPCM_DMACTRL);
+                                       d_adpcm->write_signal(SIG_ADPCM_PAUSE, 0x00, 0xff);
+                               }
+       #else
                                if(adpcm_play_in_progress) {
                                        adpcm_do_dma();
                                        adpcm_pause(false);
                                }
+       #endif
                                //adpcm_dma_enabled = false;
                                out_debug_log(_T("SIG_PCE_SCSI_BSY: UNPAUSE ADPCM\n"));
                        }
@@ -2612,6 +2717,9 @@ void PCE::write_signal(int id, uint32_t data, uint32_t mask)
                break;
                
        case SIG_PCE_ADPCM_VCLK:
+       #ifdef USE_SEPARATED_ADPCM
+               d_adpcm->write_signal(SIG_ADPCM_VCLK, data, mask);
+       #else
                // 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
@@ -2648,7 +2756,7 @@ void PCE::write_signal(int id, uint32_t data, uint32_t mask)
                                                out_debug_log(_T("END ADDRESS(NON-DMA) MSM_ADDR=%08x\n"), msm_start_addr);
                                                adpcm_stream = false;
                                                adpcm_repeat = false;
-                               } else if(((msm_start_addr & 0xffff) == msm_end_addr) && (adpcm_written <= 0) && (adpcm_dma_enabled)) {
+                               } else if(((msm_start_addr & 0xffff) == msm_end_addr) && (adpcm_dma_enabled)) {
                                        // reached to end address
                                        if((adpcm_repeat) &&
                                           (adpcm_length >= 0x8000) && (adpcm_length <= 0x80ff) /* && (IsHuVideo()) */) {
@@ -2656,36 +2764,36 @@ void PCE::write_signal(int id, uint32_t data, uint32_t mask)
                                                msm_start_addr = msm_start_addr - 1;
                                                goto __skip1;
                                        }
-                                       if(adpcm_written == 0) {
+                                       /*if(adpcm_written == 0) */{
                                                // 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);
                                                //set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE);
                                                out_debug_log(_T("END ADDRESS(DMA) MSM_ADDR=%08x\n"), msm_start_addr);
                                                //msm_start_addr = msm_start_addr & 0xffff; // Continue
-#if 0
-                                               if(!(adpcm_repeat)) {
-                                                       adpcm_stop(true); // true?
-                                                       d_msm->reset_w(1);
-                                               } else {
-                                                       adpcm_stop(true);
-                                                       d_msm->reset_w(0);
-                                               }
+#if 1
+                                               //if(!(adpcm_repeat)) {
+                                               adpcm_stop(true); // true?
+                                               d_msm->reset_w(1);
+                                                       //} else {
+                                                       //adpcm_pause(true);
+                                                       //d_msm->reset_w(0);
+                                                       //}
 #endif
                                                adpcm_stream = false;
                                                adpcm_repeat = false;
                                        }                                       
-                       } else if(adpcm_dma_enabled && adpcm_written < 0) {
+                               } 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, CLEAR_LINE);
+                                       set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE);
                                        out_debug_log(_T("ADPCM DMA QUEUE EMPTY MSM_ADDR=%08x\n"), msm_start_addr);
-                                   adpcm_stop(false);
-                                       d_msm->reset_w(1);
-                                       adpcm_stream = false;
-                                       adpcm_repeat = false;
-                                       goto __skip1;
-                               } else if((msm_start_addr & 0xffff) == msm_half_addr) {
+                                       //adpcm_stop(true);
+                                       //d_msm->reset_w(1);
+                                       //adpcm_stream = false;
+                                       //adpcm_repeat = false;
+                                       //goto __skip1;
+                               }  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)) {
@@ -2700,7 +2808,7 @@ void PCE::write_signal(int id, uint32_t data, uint32_t mask)
                                                   !(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_FULL_PLAY, CLEAR_LINE);
                                        set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, ASSERT_LINE);
                                        out_debug_log(_T("SPECIAL HALF ADDRESS MSM_ADDR=%08x\n"), msm_start_addr);
                                } 
@@ -2708,7 +2816,7 @@ void PCE::write_signal(int id, uint32_t data, uint32_t mask)
                                msm_start_addr++;
                        __skip1:
                                if(adpcm_dma_enabled) {
-                                       if(!(msm_idle) && (adpcm_write_ptr < msm_start_addr)) {
+                                       if(((adpcm_write_ptr & 0xffff) < (msm_start_addr & 0xffff) )) {
                                                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 &&
@@ -2739,7 +2847,41 @@ void PCE::write_signal(int id, uint32_t data, uint32_t mask)
                        }
                }
                }
+       #endif
+               break;
+#ifdef USE_SEPARATED_ADPCM
+       case SIG_PCE_CDROM_SET_ACK:
+               if((data & mask) != 0) {
+                       set_ack();
+               }
+               break;
+       case SIG_PCE_CDROM_CLEAR_ACK:
+               if((data & mask) != 0) {
+                       clear_ack();
+               }
+               break;
+       case SIG_PCE_ADPCM_HALF:
+               if((data & mask) != 0) {
+                       set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, ASSERT_LINE);
+               } else {
+                       set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
+               }
+               break;
+       case SIG_PCE_ADPCM_FULL:
+               if((data & mask) != 0) {
+                       set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE);
+               } else {
+                       set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE);
+               }
                break;
+       case SIG_PCE_ADPCM_DMA:
+               if((data & mask) != 0) {
+                       adpcm_dma_enabled = true;
+               } else {
+                       adpcm_dma_enabled = false;
+               }
+               break;
+#endif
        }
 }
 
index 6f989fd..0641e6a 100644 (file)
@@ -8,7 +8,7 @@
        Author : Takeda.Toshiya
        Date   : 2009.03.11-
 
-       [ PC-Eninge ]
+       [ PC-Engine ]
 */
 
 #ifndef _PCE_H_
@@ -18,6 +18,7 @@
 #include "../../emu.h"
 #include "../device.h"
 
+
 #ifdef SUPPORT_CDROM
 #define SIG_PCE_SCSI_IRQ       0
 #define SIG_PCE_SCSI_DRQ       1
 #define SIG_PCE_ADPCM_VCLK     4
 #endif
 
+#define SIG_PCE_CDROM_RAW_DATA   10
+#define SIG_PCE_CDROM_DATA_IN    11
+#define SIG_PCE_CDROM_SET_ACK    12
+#define SIG_PCE_CDROM_CLEAR_ACK  13
+#define SIG_PCE_ADPCM_HALF       14
+#define SIG_PCE_ADPCM_FULL       15
+#define SIG_PCE_ADPCM_DMA        16
+
+
 #define VDC_WPF                684     /* width of a line in frame including blanking areas */
 #define VDC_LPF                262     /* number of lines in a single frame */
 #ifdef SUPPORT_CDROM
@@ -41,6 +51,11 @@ class SCSI_HOST;
 class SCSI_CDROM;
 #endif
 
+#ifdef USE_SEPARATED_ADPCM
+namespace PCEDEV {
+       class ADPCM;
+}
+#endif
 namespace PCEDEV {
 
 typedef struct vdc_s {
@@ -107,7 +122,9 @@ private:
        SCSI_HOST* d_scsi_host;
        SCSI_CDROM* d_scsi_cdrom;
 #endif
-       
+#ifdef USE_SEPARATED_ADPCM
+       ADPCM* d_adpcm;
+#endif
        bool support_6btn_pad;
        bool support_multi_tap;
 #ifdef SUPPORT_SUPER_GFX
@@ -251,6 +268,7 @@ public:
        void write_io8(uint32_t addr, uint32_t data);
        uint32_t read_io8(uint32_t addr);
 #ifdef SUPPORT_CDROM
+       uint32_t read_signal(int id);
        void write_signal(int id, uint32_t data, uint32_t mask);
        void event_callback(int event_id, int err);
 #endif
@@ -277,6 +295,12 @@ public:
                d_scsi_cdrom = device;
        }
 #endif
+#ifdef USE_SEPARATED_ADPCM
+       void set_context_adpcm(ADPCM* device)
+       {
+               d_adpcm = device;
+       }
+#endif
        void initialize_sound(int rate)
        {
                sample_rate = rate;
index 5811dd2..e8e2b77 100644 (file)
 #endif
 
 #include "pce.h"
+#ifdef USE_SEPARATED_ADPCM
+#include "./adpcm.h"
 
+using PCEDEV::ADPCM;
+#endif
 using PCEDEV::PCE;
 // ----------------------------------------------------------------------------
 // initialize
@@ -51,6 +55,9 @@ VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
 //     scsi_cdrom->set_context_event_manager(pceevent);
        
        pce = new PCE(this, emu);
+#ifdef USE_SEPARATED_ADPCM
+       pce_adpcm = new ADPCM(this, emu);
+#endif
 //     pce->set_context_event_manager(pceevent);
 #if defined(_USE_QT)
        pce->set_device_name(_T("PC-ENGINE MAIN"));
@@ -58,6 +65,9 @@ VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
        
        pceevent->set_context_cpu(pcecpu, CPU_CLOCKS);
        pceevent->set_context_sound(pce);
+#ifdef USE_SEPARATED_ADPCM
+       pceevent->set_context_sound(pce_adpcm);
+#endif
        // NOTE: adpcm::mix() and scsi_cdrom::mix() will be called in pce::mix()
 //     pceevent->set_context_sound(adpcm);
 //     pceevent->set_context_sound(scsi_cdrom);
@@ -82,6 +92,11 @@ VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
        pce->set_context_scsi_host(scsi_host);
        pce->set_context_scsi_cdrom(scsi_cdrom);
        
+#ifdef USE_SEPARATED_ADPCM
+       pce->set_context_adpcm(pce_adpcm);
+       pce_adpcm->set_context_msm(adpcm);
+       pce_adpcm->set_context_pce(pce);
+#endif 
        // initialize all devices
 #if defined(__GIT_REPO_VERSION)
        strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
index c1728e1..37ac483 100644 (file)
@@ -39,6 +39,7 @@
 #define USE_JOY_BUTTON_CAPTIONS
 #define USE_DEBUGGER
 #define USE_STATE
+#define USE_SEPARATED_ADPCM
 
 #include "../../common.h"
 #include "../../fileio.h"
@@ -78,6 +79,9 @@ class SCSI_CDROM;
 
 namespace PCEDEV {
        class PCE;
+#ifdef USE_SEPARATED_ADPCM
+       class ADPCM;
+#endif
 }
 class VM : public VM_TEMPLATE
 {
@@ -93,7 +97,9 @@ protected:
        SCSI_HOST* scsi_host;
        SCSI_CDROM* scsi_cdrom;
        PCEDEV::PCE* pce;
-       
+#ifdef USE_SEPARATED_ADPCM
+       PCEDEV::ADPCM* pce_adpcm;
+#endif
 public:
        // ----------------------------------------
        // initialize