YM2608-LLE, part 15

OPNB early progress
This commit is contained in:
tildearrow 2024-04-28 12:57:45 -05:00
parent 42fd63847e
commit 22f612b32a
8 changed files with 259 additions and 5 deletions

View file

@ -939,7 +939,8 @@ void FMOPNA_2612_Clock(fmopna_2612_t* chip, int clk)
#endif
)
#ifdef FMOPNA_YM2610
&& (chip->reg_kon_channel[0] & 3) != 0
// tildearrow: changed to allow YM2610B emulation
&& (chip->ym2610b || (chip->reg_kon_channel[0] & 3) != 0)
#endif
;

View file

@ -930,6 +930,8 @@ typedef struct {
int o_pad;
int o_pad_d;
int o_pa8;
int ym2610b;
#endif
#ifndef FMOPNA_YM2612

View file

@ -1763,7 +1763,6 @@ void DivPlatformYM2608::reset() {
lastS=false;
cas=0;
ras=0;
adReadCount=0;
adMemAddr=0;
}

View file

@ -63,7 +63,6 @@ class DivPlatformYM2608: public DivPlatformOPN {
bool lastS;
unsigned char cas, ras, rssCycle, rssSubCycle;
unsigned int adMemAddr;
int adReadCount;
unsigned char* adpcmBMem;
size_t adpcmBMemLen;

View file

@ -233,7 +233,9 @@ const char** DivPlatformYM2610::getRegisterSheet() {
}
void DivPlatformYM2610::acquire(short** buf, size_t len) {
if (useCombo) {
if (useCombo==2) {
acquire_lle(buf,len);
} else if (useCombo==1) {
acquire_combo(buf,len);
} else {
acquire_ymfm(buf,len);
@ -421,6 +423,189 @@ void DivPlatformYM2610::acquire_ymfm(short** buf, size_t len) {
}
}
static const unsigned char subCycleMap[6]={
4, 2, 3, 5, 0, 1
};
void DivPlatformYM2610::acquire_lle(short** buf, size_t len) {
thread_local int fmOut[6];
for (size_t h=0; h<len; h++) {
bool have0=false;
bool have1=false;
signed char subCycle=0;
unsigned char subSubCycle=0;
for (int i=0; i<6; i++) {
fmOut[i]=0;
}
while (true) {
bool canWeWrite=fm_lle.prescaler_latch[1]&1;
if (canWeWrite) {
if (delay>0) {
if (delay==3) {
fm_lle.input.cs=1;
fm_lle.input.rd=1;
fm_lle.input.wr=1;
fm_lle.input.a0=0;
fm_lle.input.a1=0;
delay=0;
} else {
fm_lle.input.cs=0;
fm_lle.input.rd=0;
fm_lle.input.wr=1;
fm_lle.input.a0=0;
fm_lle.input.a1=0;
fm_lle.input.data=0;
delay=1;
}
} else if (!writes.empty()) {
QueuedWrite& w=writes.front();
if (w.addrOrVal) {
fm_lle.input.cs=0;
fm_lle.input.rd=1;
fm_lle.input.wr=0;
fm_lle.input.a1=w.addr>>8;
fm_lle.input.a0=1;
fm_lle.input.data=w.val;
delay=2;
regPool[w.addr&0x1ff]=w.val;
writes.pop_front();
} else {
fm_lle.input.cs=0;
fm_lle.input.rd=1;
fm_lle.input.wr=0;
fm_lle.input.a1=w.addr>>8;
fm_lle.input.a0=0;
fm_lle.input.data=w.addr&0xff;
delay=2;
w.addrOrVal=true;
}
} else {
fm_lle.input.cs=1;
fm_lle.input.rd=1;
fm_lle.input.wr=1;
fm_lle.input.a0=0;
fm_lle.input.a1=0;
}
}
FMOPNA_2610_Clock(&fm_lle,0);
FMOPNA_2610_Clock(&fm_lle,1);
if (++subSubCycle>=6) {
subSubCycle=0;
if (subCycle>=0 && subCycle<6 && fm_lle.ac_fm_output_en) {
fmOut[subCycleMap[subCycle]]+=((short)fm_lle.ac_fm_output)<<2;
}
if (++subCycle>=6) subCycle=0;
}
/*if (fm_lle.rss_eclk1) {
if (++rssSubCycle>=24) {
rssSubCycle=0;
rssOut[rssCycle]=(short)fm_lle.last_rss_sample;
if (++rssCycle>=6) rssCycle=0;
}
}*/
if (canWeWrite) {
if (delay==1) {
// check busy status here
if (!fm_lle.busy_cnt_en[1]) {
delay=0;
}
}
}
if (!fm_lle.o_s && lastS) {
if (!fm_lle.o_sh1 && lastSH) {
dacVal2=dacVal;
}
if (!fm_lle.o_sh2 && lastSH2) {
dacVal2=dacVal;
}
if (fm_lle.o_sh1 && !lastSH) {
dacOut[0]=dacVal2^0x8000;
have0=true;
}
if (fm_lle.o_sh2 && !lastSH2) {
dacOut[1]=dacVal2^0x8000;
have1=true;
}
dacVal>>=1;
dacVal|=(fm_lle.o_opo&1)<<15;
lastSH=fm_lle.o_sh1;
lastSH2=fm_lle.o_sh2;
}
lastS=fm_lle.o_s;
// ADPCM data bus
if (!fm_lle.o_roe) {
fm_lle.input.rad=adpcmAMem[adMemAddrA&0xffffff];
} else {
if (!fm_lle.o_rmpx && rmpx) {
adMemAddrA&=~0x3ff;
adMemAddrA=(fm_lle.o_rad&0xff)|(fm_lle.o_ra8<<8);
}
if (fm_lle.o_rmpx && !rmpx) {
adMemAddrA&=0x3ff;
adMemAddrA=((fm_lle.o_rad&0xff)|(fm_lle.o_ra8<<8)|(fm_lle.o_ra20<<10))<<10;
}
rmpx=fm_lle.o_rmpx;
}
if (have0 && have1) break;
}
// chan osc
// FM
for (int i=0; i<4; i++) {
if (fmOut[i]<-32768) fmOut[i]=-32768;
if (fmOut[i]>32767) fmOut[i]=32767;
oscBuf[i]->data[oscBuf[i]->needle++]=fmOut[i];
}
// SSG
for (int i=0; i<3; i++) {
oscBuf[i+4]->data[oscBuf[i+4]->needle++]=fm_lle.o_analog_ch[i]*32767;
}
// RSS
for (int i=0; i<6; i++) {
if (rssOut[i]<-32768) rssOut[i]=-32768;
if (rssOut[i]>32767) rssOut[i]=32767;
oscBuf[7+i]->data[oscBuf[7+i]->needle++]=rssOut[i];
}
// ADPCM
oscBuf[13]->data[oscBuf[13]->needle++]=fm_lle.ac_ad_output;
// DAC
int accm1=(short)dacOut[0];
int accm2=(short)dacOut[1];
int outL=((accm1*fmVol)>>8)+fm_lle.o_analog*ssgVol*42;
int outR=((accm2*fmVol)>>8)+fm_lle.o_analog*ssgVol*42;
if (outL<-32768) outL=-32768;
if (outL>32767) outL=32767;
if (outR<-32768) outR=-32768;
if (outR>32767) outR=32767;
buf[0][h]=outL;
buf[1][h]=outR;
}
}
void DivPlatformYM2610::tick(bool sysTick) {
// FM
for (int i=0; i<psgChanOffs; i++) {

View file

@ -42,6 +42,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
void acquire_combo(short** buf, size_t len);
void acquire_ymfm(short** buf, size_t len);
void acquire_lle(short** buf, size_t len);
public:
void acquire(short** buf, size_t len);

View file

@ -38,6 +38,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
void acquire_combo(short** buf, size_t len);
void acquire_ymfm(short** buf, size_t len);
void acquire_lle(short** buf, size_t len);
public:
void acquire(short** buf, size_t len);

View file

@ -27,6 +27,9 @@
#include "sound/ymfm/ymfm.h"
#include "sound/ymfm/ymfm_opn.h"
#include <string.h>
extern "C" {
#include "../../../extern/YM2608-LLE/fmopna_2610.h"
}
#define CHIP_FREQBASE fmFreqBase
#define CHIP_DIVIDER fmDivBase
@ -54,6 +57,17 @@ class DivPlatformYM2610Base: public DivPlatformOPN {
ymfm::ym2610b* fm;
ymfm::ym2610b::output_data fmout;
DivPlatformAY8910* ay;
fmopna_2610_t fm_lle;
unsigned int dacVal;
unsigned int dacVal2;
int dacOut[2];
int rssOut[6];
bool lastSH;
bool lastSH2;
bool lastS;
unsigned char rmpx, pmpx, rssCycle, rssSubCycle;
unsigned int adMemAddrA;
unsigned int adMemAddrB;
unsigned char* adpcmAMem;
size_t adpcmAMemLen;
@ -102,6 +116,54 @@ class DivPlatformYM2610Base: public DivPlatformOPN {
OPN2_Reset(&fm_nuked);
OPN2_SetChipType(&fm_nuked,ym3438_mode_opn);
if (useCombo==2) {
fm_lle.input.cs=1;
fm_lle.input.rd=0;
fm_lle.input.wr=0;
fm_lle.input.a0=0;
fm_lle.input.a1=0;
fm_lle.input.data=0;
fm_lle.input.rad=0;
fm_lle.input.pad=0;
fm_lle.input.test=1;
fm_lle.input.ic=1;
for (size_t h=0; h<576; h++) {
FMOPNA_2610_Clock(&fm_lle,0);
FMOPNA_2610_Clock(&fm_lle,1);
}
fm_lle.input.ic=0;
for (size_t h=0; h<576; h++) {
FMOPNA_2610_Clock(&fm_lle,0);
FMOPNA_2610_Clock(&fm_lle,1);
}
fm_lle.input.ic=1;
for (size_t h=0; h<576; h++) {
FMOPNA_2610_Clock(&fm_lle,0);
FMOPNA_2610_Clock(&fm_lle,1);
}
for (int i=0; i<6; i++) {
rssOut[i]=0;
}
dacVal=0;
dacVal2=0;
dacOut[0]=0;
dacOut[1]=0;
lastSH=0;
lastSH2=0;
lastS=0;
rmpx=0;
pmpx=0;
rssCycle=0;
rssSubCycle=0;
adMemAddrA=0;
adMemAddrB=0;
}
ay->reset();
ay->getRegisterWrites().clear();
ay->flushWrites();
@ -247,7 +309,11 @@ class DivPlatformYM2610Base: public DivPlatformOPN {
fbAllOps=flags.getBool("fbAllOps",false);
ssgVol=flags.getInt("ssgVol",128);
fmVol=flags.getInt("fmVol",256);
rate=fm->sample_rate(chipClock);
if (useCombo==2) {
rate=chipClock/144;
} else {
rate=fm->sample_rate(chipClock);
}
for (int i=0; i<16; i++) {
oscBuf[i]->rate=rate;
}