implement YMF276-LLE core

thanks LTVA
This commit is contained in:
tildearrow 2024-03-15 20:16:29 -05:00
parent 3512591fd1
commit 892ee12d91
5 changed files with 337 additions and 10 deletions

View file

@ -2066,6 +2066,8 @@ void FMOPN2_YMF276Accumulator1(fmopn2_t *chip)
int acc_l = 0;
int acc_r = 0;
chip->osc_out = 0;
for (i = 0; i < 14; i++)
accm += ((chip->ch_accm[i][1] >> 5) & 1) << i;
if (chip->alg_output && !test_dac)
@ -2106,12 +2108,12 @@ void FMOPN2_YMF276Accumulator1(fmopn2_t *chip)
chip->fsm_op1_sel_l3[0] = chip->fsm_op1_sel;
if (sel_dac)
out |= chip->mode_dac_data[1] << 6;
chip->osc_out |= chip->mode_dac_data[1] << 6;
if (sel_fm)
out |= accm;
chip->osc_out |= accm;
if (out & 0x2000)
out |= 0x1c000;
if (chip->osc_out & 0x2000)
chip->osc_out |= 0x1c000;
for (i = 0; i < 2; i++)
pan |= (((chip->chan_pan[i][1] >> 5) & 1) ^ 1) << i;
@ -2130,8 +2132,8 @@ void FMOPN2_YMF276Accumulator1(fmopn2_t *chip)
acc_r = chip->ch_accm_r[1];
}
chip->ch_accm_l[0] = acc_l + ((pan & 2) != 0 ? out : 0);
chip->ch_accm_r[0] = acc_r + ((pan & 1) != 0 ? out : 0);
chip->ch_accm_l[0] = acc_l + ((pan & 2) != 0 ? chip->osc_out : 0);
chip->ch_accm_r[0] = acc_r + ((pan & 1) != 0 ? chip->osc_out : 0);
}
void FMOPN2_YMF276Accumulator2(fmopn2_t *chip)

View file

@ -72,6 +72,9 @@ typedef struct {
int out_l;
int out_r;
// added by LTVA for Furnace tracker per-channel oscilloscopes!
int osc_out;
// io
int write_addr_trig;
int write_addr_trig_sync;

View file

@ -289,8 +289,279 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
}
}
const unsigned char chanMap276[6]={
1, 5, 3, 0, 4, 2
};
// thanks LTVA
void DivPlatformGenesis::acquire276OscSub() {
if (fm_276.fsm_cnt2[1]==0 && llePrevCycle!=0) {
lleCycle=0;
}
llePrevCycle=fm_276.fsm_cnt2[1];
if (fm_276.flags==fmopn2_flags_ym3438) {
lleOscData[lleCycle/(24*2)]+=fm_276.out_l+fm_276.out_r;
lleCycle++;
if (lleCycle==(144*2)) {
lleCycle=0;
for (int i=0; i<6; i++) {
if ((softPCM && ((chanMap276[i]!=5) || !chan[5].dacMode)) || (!softPCM)) {
oscBuf[chanMap276[i]]->data[oscBuf[chanMap276[i]]->needle++]=lleOscData[i];
}
lleOscData[i]=0;
}
if (softPCM && chan[5].dacMode) {
oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<6;
oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<6;
} else {
oscBuf[6]->data[oscBuf[6]->needle++]=0;
}
}
} else {
for (int i=0; i<6; i++) {
if (lleCycle==((7+i)*12)) {
oscBuf[i]->data[oscBuf[i]->needle]=(fm_276.osc_out>>1)*8;
}
}
lleCycle++;
if (lleCycle==(144*2)) {
lleCycle=0;
for (int i=0; i<6; i++) {
oscBuf[i]->data[oscBuf[i]->needle]>>=1;
}
if (softPCM && chan[5].dacMode) {
oscBuf[5]->data[oscBuf[5]->needle]=chan[5].dacOutput<<6;
oscBuf[6]->data[oscBuf[6]->needle]=chan[6].dacOutput<<6;
} else {
oscBuf[6]->data[oscBuf[6]->needle]=0;
}
for (int i=0; i<7; i++) {
oscBuf[i]->needle++;
}
}
}
}
// thanks LTVA
void DivPlatformGenesis::acquire_nuked276(short** buf, size_t len) {
// TODO
for (size_t h=0; h<len; h++) {
processDAC(rate);
int sum_l=0;
int sum_r=0;
int sample_l=0;
int sample_r=0;
bool was_reg_write=false;
//lleCycle=0;
if (!writes.empty()) {
QueuedWrite& w=writes.front();
if (w.addrOrVal) {
//logV("%.3x=%.2x",w.addr,w.val);
//OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
was_reg_write=true;
fm_276.input.address=w.addr<0x100?0:2;
fm_276.input.data=w.addr&0xff;
fm_276.input.wr=1;
FMOPN2_Clock(&fm_276,0);
sum_l+=fm_276.out_l;
sum_r+=fm_276.out_r;
acquire276OscSub();
fm_276.input.wr=0;
FMOPN2_Clock(&fm_276,1);
sum_l+=fm_276.out_l;
sum_r+=fm_276.out_r;
acquire276OscSub();
if (chipType==2) {
if (!o_bco && fm_276.o_bco) {
dacShifter=(dacShifter<<1)|fm_276.o_so;
if (o_lro!=fm_276.o_lro) {
if (o_lro)
sample_l=dacShifter;
else
sample_r=dacShifter;
}
o_lro=fm_276.o_lro;
}
o_bco=fm_276.o_bco;
}
for (int c=0; c<17; c++) {
FMOPN2_Clock(&fm_276,0);
sum_l+=fm_276.out_l;
sum_r+=fm_276.out_r;
acquire276OscSub();
FMOPN2_Clock(&fm_276,1);
sum_l+=fm_276.out_l;
sum_r+=fm_276.out_r;
acquire276OscSub();
if (chipType==2) {
if (!o_bco && fm_276.o_bco) {
dacShifter=(dacShifter<<1)|fm_276.o_so;
if (o_lro!=fm_276.o_lro) {
if (o_lro)
sample_l=dacShifter;
else
sample_r=dacShifter;
}
o_lro=fm_276.o_lro;
}
o_bco=fm_276.o_bco;
}
}
fm_276.input.address=w.addr<0x100?1:3;
fm_276.input.data=w.val;
fm_276.input.wr=1;
FMOPN2_Clock(&fm_276,0);
sum_l+=fm_276.out_l;
sum_r+=fm_276.out_r;
fm_276.input.wr=0;
acquire276OscSub();
FMOPN2_Clock(&fm_276,1);
sum_l+=fm_276.out_l;
sum_r+=fm_276.out_r;
acquire276OscSub();
if (chipType==2) {
if (!o_bco && fm_276.o_bco) {
dacShifter=(dacShifter<<1)|fm_276.o_so;
if (o_lro!=fm_276.o_lro) {
if (o_lro)
sample_l=dacShifter;
else
sample_r=dacShifter;
}
o_lro=fm_276.o_lro;
}
o_bco=fm_276.o_bco;
}
for (int c=0; c<83; c++) {
FMOPN2_Clock(&fm_276,0);
sum_l+=fm_276.out_l;
sum_r+=fm_276.out_r;
acquire276OscSub();
FMOPN2_Clock(&fm_276,1);
sum_l+=fm_276.out_l;
sum_r+=fm_276.out_r;
acquire276OscSub();
if (chipType==2) {
if (!o_bco && fm_276.o_bco) {
dacShifter=(dacShifter<<1)|fm_276.o_so;
if (o_lro!=fm_276.o_lro) {
if (o_lro) {
sample_l=dacShifter;
} else {
sample_r=dacShifter;
}
}
o_lro=fm_276.o_lro;
}
o_bco=fm_276.o_bco;
}
}
regPool[w.addr&0x1ff]=w.val;
writes.pop_front();
if (dacWrite>=0) {
if (!canWriteDAC) {
canWriteDAC=true;
} else {
urgentWrite(0x2a,dacWrite);
dacWrite=-1;
canWriteDAC=writes.empty();
}
}
} else {
w.addrOrVal=true;
}
} else {
canWriteDAC=true;
if (dacWrite>=0) {
urgentWrite(0x2a,dacWrite);
dacWrite=-1;
}
flushFirst=false;
}
for (int j=0; j<(was_reg_write?(144-83-19):144); j++) {
FMOPN2_Clock(&fm_276,0);
sum_l+=fm_276.out_l;
sum_r+=fm_276.out_r;
acquire276OscSub();
FMOPN2_Clock(&fm_276,1);
sum_l+=fm_276.out_l;
sum_r+=fm_276.out_r;
acquire276OscSub();
if (chipType==2) {
if (!o_bco && fm_276.o_bco) {
dacShifter=(dacShifter<<1)|fm_276.o_so;
if (o_lro!=fm_276.o_lro) {
if (o_lro)
sample_l=dacShifter;
else
sample_r=dacShifter;
}
o_lro=fm_276.o_lro;
}
o_bco=fm_276.o_bco;
}
}
if (chipType==2) {
buf[0][h]=sample_l;
buf[1][h]=sample_r;
} else {
buf[0][h]=(sum_l*3)>>2;
buf[1][h]=(sum_r*3)>>2;
}
}
}
void DivPlatformGenesis::acquire(short** buf, size_t len) {
@ -1333,7 +1604,48 @@ void DivPlatformGenesis::reset() {
writes.clear();
memset(regPool,0,512);
if (useYMFM==2) {
dacShifter=0;
o_bco=0;
o_lro=0;
lleCycle=0;
llePrevCycle=0;
for (int i=0; i<6; i++) {
lleOscData[i]=0;
}
memset(&fm_276,0,sizeof(fmopn2_t));
fm_276.input.cs=1;
fm_276.input.rd=0;
fm_276.input.wr=0;
fm_276.input.address=0;
fm_276.input.data=0;
if (chipType==2) {
fm_276.flags=0;
} else {
fm_276.flags=fmopn2_flags_ym3438;
}
fm_276.input.ic=0;
for (int i=0; i<288; i++) {
FMOPN2_Clock(&fm_276,0);
FMOPN2_Clock(&fm_276,1);
}
fm_276.input.ic=1;
for (int i=0; i<288*2; i++) {
FMOPN2_Clock(&fm_276,0);
FMOPN2_Clock(&fm_276,1);
}
fm_276.input.ic=0;
for (int i=0; i<288*2; i++) {
FMOPN2_Clock(&fm_276,0);
FMOPN2_Clock(&fm_276,1);
}
} else if (useYMFM==1) {
fm_ymfm->reset();
}
@ -1474,6 +1786,8 @@ void DivPlatformGenesis::setFlags(const DivConfig& flags) {
fm_ymfm=new ymfm::ym3438(iface);
}
rate=chipClock/144;
} else if (useYMFM==2) {
rate=chipClock/144;
} else {
rate=chipClock/36;
}

View file

@ -22,7 +22,9 @@
#include "fmshared_OPN.h"
#include "sound/ymfm/ymfm_opn.h"
extern "C" {
#include "../../../extern/YMF276-LLE/fmopn2.h"
}
class DivYM2612Interface: public ymfm::ymfm_interface {
int setA, setB;
@ -90,6 +92,11 @@ class DivPlatformGenesis: public DivPlatformOPN {
unsigned char chipType;
short dacWrite;
int lleCycle;
int llePrevCycle;
int lleOscData[6];
int dacShifter, o_lro, o_bco;
unsigned char dacVolTable[128];
friend void putDispatchChip(void*,int);
@ -97,6 +104,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
inline void processDAC(int iRate);
inline void commitState(int ch, DivInstrument* ins);
void acquire276OscSub();
void acquire_nuked(short** buf, size_t len);
void acquire_nuked276(short** buf, size_t len);
void acquire_ymfm(short** buf, size_t len);

View file

@ -1541,10 +1541,10 @@ void FurnaceGUI::drawSettings() {
ImGui::Text("YM2612");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##YM2612Core",&settings.ym2612Core,ym2612Cores,2)) settingsChanged=true;
if (ImGui::Combo("##YM2612Core",&settings.ym2612Core,ym2612Cores,3)) settingsChanged=true;
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##YM2612CoreRender",&settings.ym2612CoreRender,ym2612Cores,2)) settingsChanged=true;
if (ImGui::Combo("##YM2612CoreRender",&settings.ym2612CoreRender,ym2612Cores,3)) settingsChanged=true;
ImGui::TableNextRow();
ImGui::TableNextColumn();