#ifndef EMU_COMPILE
#error "Hi I forgot to set EMU_COMPILE"
#endif
#include "yam.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(HAVE_MPROTECT)
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#endif
#include <math.h>
#ifndef _WIN32
#define __cdecl
#define __fastcall
#endif
#if defined(_WIN32) || defined(__i386__)
#define ENABLE_DYNAREC
#endif
#if defined(_WIN64) || defined(__amd64__)
#undef ENABLE_DYNAREC
#endif
#pragma warning (disable: 4244)
#define RENDERMAX (200)
#define RINGMAX (256)
#define INT_ONE_SAMPLE (10)
#define INT_MIDI_OUTPUT (9)
#define INT_TIMER_C (8)
#define INT_TIMER_B (7)
#define INT_TIMER_A (6)
#define INT_CPU (5)
#define INT_DMA_END (4)
#define INT_MIDI_INPUT (3)
#define INT_RESERVED_2 (2)
#define INT_RESERVED_1 (1)
#define INT_EXTERNAL (0)
#define MAKELFOPHASEINC(x) (((uint64)(0x100000000)) / ((uint64)(x)))
static uint32 lfophaseinctable[0x20] = {
MAKELFOPHASEINC(0x3FC00),MAKELFOPHASEINC(0x37C00),MAKELFOPHASEINC(0x2FC00),MAKELFOPHASEINC(0x27C00),
MAKELFOPHASEINC(0x1FC00),MAKELFOPHASEINC(0x1BC00),MAKELFOPHASEINC(0x17C00),MAKELFOPHASEINC(0x13C00),
MAKELFOPHASEINC(0x0FC00),MAKELFOPHASEINC(0x0BC00),MAKELFOPHASEINC(0x0DC00),MAKELFOPHASEINC(0x09C00),
MAKELFOPHASEINC(0x07C00),MAKELFOPHASEINC(0x06C00),MAKELFOPHASEINC(0x05C00),MAKELFOPHASEINC(0x04C00),
MAKELFOPHASEINC(0x03C00),MAKELFOPHASEINC(0x03400),MAKELFOPHASEINC(0x02C00),MAKELFOPHASEINC(0x02400),
MAKELFOPHASEINC(0x01C00),MAKELFOPHASEINC(0x01800),MAKELFOPHASEINC(0x01400),MAKELFOPHASEINC(0x01000),
MAKELFOPHASEINC(0x00C00),MAKELFOPHASEINC(0x00A00),MAKELFOPHASEINC(0x00800),MAKELFOPHASEINC(0x00600),
MAKELFOPHASEINC(0x00400),MAKELFOPHASEINC(0x00300),MAKELFOPHASEINC(0x00200),MAKELFOPHASEINC(0x00100)
};
static uint8 envattackshift[0x3D][4] = {
{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},
{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},
{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},
{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},
{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},
{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},
{4,4,4,4},{3,4,4,4},{3,4,3,4},{3,3,3,4},{3,3,3,3},{2,3,3,3},{2,3,2,3},{2,2,2,3},
{2,2,2,2},{1,2,2,2},{1,2,1,2},{1,1,1,2},{1,1,1,1}
};
static uint8 envdecayvalue[0x3D][4] = {
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},
{1,1,1,1},{2,1,1,1},{2,1,2,1},{2,2,2,1},{2,2,2,2},{4,2,2,2},{4,2,4,2},{4,4,4,2},
{4,4,4,4},{8,4,4,4},{8,4,8,4},{8,8,8,4},{8,8,8,8}
};
static sint32 adpcmscale[8] = {
0x0E6, 0x0E6, 0x0E6, 0x0E6, 0x133, 0x199, 0x200, 0x266
};
static sint32 adpcmdiff[16] = {
1, 3, 5, 7, 9, 11, 13, 15,
-1,-3,-5,-7,-9,-11,-13,-15
};
static sint32 qtable[32] = {
0x0E00,0x0E80,0x0F00,0x0F80,
0x1000,0x1080,0x1100,0x1180,
0x1200,0x1280,0x1300,0x1280,
0x1400,0x1480,0x1500,0x1580,
0x1600,0x1680,0x1700,0x1780,
0x1800,0x1880,0x1900,0x1980,
0x1A00,0x1A80,0x1B00,0x1B80,
0x1C00,0x1D00,0x1E00,0x1F00
};
#define LFO_SHIFT 8
struct _LFO
{
unsigned short phase;
uint32 phase_step;
int *table;
int *scale;
};
#define LFIX(v) ((unsigned int) ((float) (1<<LFO_SHIFT)*(v)))
#define DB(v) LFIX(pow(10.0,v/20.0))
#define CENTS(v) LFIX(pow(2.0,v/1200.0))
static int PLFO_TRI[256],PLFO_SQR[256],PLFO_SAW[256],PLFO_NOI[256];
static int ALFO_TRI[256],ALFO_SQR[256],ALFO_SAW[256],ALFO_NOI[256];
static float LFOFreq[32]={0.17,0.19,0.23,0.27,0.34,0.39,0.45,0.55,0.68,0.78,0.92,1.10,1.39,1.60,1.87,2.27,
2.87,3.31,3.92,4.79,6.15,7.18,8.60,10.8,14.4,17.2,21.5,28.7,43.1,57.4,86.1,172.3};
static float ASCALE[8]={0.0,0.4,0.8,1.5,3.0,6.0,12.0,24.0};
static float PSCALE[8]={0.0,7.0,13.5,27.0,55.0,112.0,230.0,494};
static int PSCALES[8][256];
static int ASCALES[8][256];
static const double ARTimes[64]={100000,100000,8100.0,6900.0,6000.0,4800.0,4000.0,3400.0,3000.0,2400.0,2000.0,1700.0,1500.0,
1200.0,1000.0,860.0,760.0,600.0,500.0,430.0,380.0,300.0,250.0,220.0,190.0,150.0,130.0,110.0,95.0,
76.0,63.0,55.0,47.0,38.0,31.0,27.0,24.0,19.0,15.0,13.0,12.0,9.4,7.9,6.8,6.0,4.7,3.8,3.4,3.0,2.4,
2.0,1.8,1.6,1.3,1.1,0.93,0.85,0.65,0.53,0.44,0.40,0.35,0.0,0.0};
static const double DRTimes[64]={100000,100000,118200.0,101300.0,88600.0,70900.0,59100.0,50700.0,44300.0,35500.0,29600.0,25300.0,22200.0,17700.0,
14800.0,12700.0,11100.0,8900.0,7400.0,6300.0,5500.0,4400.0,3700.0,3200.0,2800.0,2200.0,1800.0,1600.0,1400.0,1100.0,
920.0,790.0,690.0,550.0,460.0,390.0,340.0,270.0,230.0,200.0,170.0,140.0,110.0,98.0,85.0,68.0,57.0,49.0,43.0,34.0,
28.0,25.0,22.0,18.0,14.0,12.0,11.0,8.5,7.1,6.1,5.4,4.3,3.6,3.1};
static uint32 FNS_Table[0x400];
static sint32 EG_TABLE[0x400];
static int ARTABLE[64];
static int DRTABLE[64];
static const float SDLT_AICA[16]={-1000000.0,-42.0,-39.0,-36.0,-33.0,-30.0,-27.0,-24.0,-21.0,-18.0,-15.0,-12.0,-9.0,-6.0,-3.0,0.0};
static const float SDLT_SCSP[8]={-1000000.0,-36.0,-30.0,-24.0,-18.0,-12.0,-6.0,0.0};
static sint32 LPANTABLE_SCSP[0x10000];
static sint32 RPANTABLE_SCSP[0x10000];
static sint32 LPANTABLE_AICA[0x20000];
static sint32 RPANTABLE_AICA[0x20000];
#define EG_SHIFT 16
#define SHIFT 10
#define FIX(v) ((sint32) ((float) (1<<SHIFT)*(v)))
#define log_base_2(n) (log((float) n)/log((float) 2))
static void yam_init_tables()
{
sint32 i,s;
for(i=0;i<256;++i) {
int a,p;
a=255-i;
if(i<128)
p=i;
else
p=i-256;
ALFO_SAW[i]=a;
PLFO_SAW[i]=p;
if(i<128) {
a=255;
p=127;
}
else {
a=0;
p=-128;
}
ALFO_SQR[i]=a;
PLFO_SQR[i]=p;
if(i<128)
a=255-(i*2);
else
a=(i*2)-256;
if(i<64)
p=i*2;
else if(i<128)
p=255-i*2;
else if(i<192)
p=256-i*2;
else
p=i*2-511;
ALFO_TRI[i]=a;
PLFO_TRI[i]=p;
a=rand()&0xff;
p=128-a;
ALFO_NOI[i]=a;
PLFO_NOI[i]=p;
}
for(s=0;s<8;++s) {
float limit=PSCALE[s];
for(i=-128;i<128;++i) {
PSCALES[s][i+128]=CENTS(((limit*(float) i)/128.0));
}
limit=-ASCALE[s];
for(i=0;i<256;++i) {
ASCALES[s][i]=DB(((limit*(float) i)/256.0));
}
}
for(i=0;i<0x400;++i) {
float fcent=(double) 1200.0*log_base_2((double)(((double) 1024.0+(double)i)/(double)1024.0));
fcent=(double) 44100.0*pow(2.0,fcent/1200.0);
FNS_Table[i]=(float) (1<<SHIFT) *fcent;
}
for(i=0;i<0x400;++i) {
float envDB=((float)(3*(i-0x3ff)))/32.0;
float scale=(float)(1<<SHIFT);
EG_TABLE[i]=(sint32)(pow(10.0,envDB/20.0)*scale);
}
for(i=0;i<0x10000;++i) {
int iTL =(i>>0x0)&0xff;
int iPAN=(i>>0x8)&0x1f;
int iSDL=(i>>0xD)&0x07;
float TL=1.0;
float SegaDB=0;
float fSDL=1.0;
float PAN=1.0;
float LPAN,RPAN;
if(iTL&0x01) SegaDB-=0.4;
if(iTL&0x02) SegaDB-=0.8;
if(iTL&0x04) SegaDB-=1.5;
if(iTL&0x08) SegaDB-=3;
if(iTL&0x10) SegaDB-=6;
if(iTL&0x20) SegaDB-=12;
if(iTL&0x40) SegaDB-=24;
if(iTL&0x80) SegaDB-=48;
TL=pow(10.0,SegaDB/20.0);
SegaDB=0;
if(iPAN&0x1) SegaDB-=3;
if(iPAN&0x2) SegaDB-=6;
if(iPAN&0x4) SegaDB-=12;
if(iPAN&0x8) SegaDB-=24;
if((iPAN&0xf)==0xf) PAN=0.0;
else PAN=pow(10.0,SegaDB/20.0);
if(iPAN<0x10)
{
LPAN=PAN;
RPAN=1.0;
}
else
{
RPAN=PAN;
LPAN=1.0;
}
if(iSDL)
fSDL=pow(10.0,(SDLT_SCSP[iSDL])/20.0);
else
fSDL=0.0;
LPANTABLE_SCSP[i]=FIX((4.0*LPAN*TL*fSDL));
RPANTABLE_SCSP[i]=FIX((4.0*RPAN*TL*fSDL));
}
for(i=0;i<0x20000;++i) {
int iTL =(i>>0x0)&0xff;
int iPAN=(i>>0x8)&0x1f;
int iSDL=(i>>0xD)&0x0F;
float TL=1.0;
float SegaDB=0;
float fSDL=1.0;
float PAN=1.0;
float LPAN,RPAN;
if(iTL&0x01) SegaDB-=0.4;
if(iTL&0x02) SegaDB-=0.8;
if(iTL&0x04) SegaDB-=1.5;
if(iTL&0x08) SegaDB-=3;
if(iTL&0x10) SegaDB-=6;
if(iTL&0x20) SegaDB-=12;
if(iTL&0x40) SegaDB-=24;
if(iTL&0x80) SegaDB-=48;
TL=pow(10.0,SegaDB/20.0);
SegaDB=0;
if(iPAN&0x1) SegaDB-=3;
if(iPAN&0x2) SegaDB-=6;
if(iPAN&0x4) SegaDB-=12;
if(iPAN&0x8) SegaDB-=24;
if((iPAN&0xf)==0xf) PAN=0.0;
else PAN=pow(10.0,SegaDB/20.0);
if(iPAN<0x10)
{
LPAN=PAN;
RPAN=1.0;
}
else
{
RPAN=PAN;
LPAN=1.0;
}
if(iSDL)
fSDL=pow(10.0,(SDLT_AICA[iSDL])/20.0);
else
fSDL=0.0;
LPANTABLE_AICA[i]=FIX((4.0*LPAN*TL*fSDL));
RPANTABLE_AICA[i]=FIX((4.0*RPAN*TL*fSDL));
}
ARTABLE[0]=DRTABLE[0]=0; ARTABLE[1]=DRTABLE[1]=0; for(i=2;i<64;++i) {
double t,step,scale;
t=ARTimes[i]; if(t!=0.0) {
step=(1023*1000.0)/((float) 44100.0f*t);
scale=(double) (1<<EG_SHIFT);
ARTABLE[i]=(int) (step*scale);
}
else
ARTABLE[i]=1024<<EG_SHIFT;
t=DRTimes[i]; step=(1023*1000.0)/((float) 44100.0f*t);
scale=(double) (1<<EG_SHIFT);
DRTABLE[i]=(int) (step*scale);
}
}
static void convert_stereo_send_level(
uint8 tl, uint8 sdl, uint8 pan,
sint32 *vol_l, sint32 *vol_r,
uint32 version
) {
uint32 Enc = (tl<<0) | (pan<<8) | (sdl<<13);
if (version == 1) {
Enc &= 0xFFFF;
*vol_l = LPANTABLE_SCSP[Enc];
*vol_r = RPANTABLE_SCSP[Enc];
} else {
*vol_l = LPANTABLE_AICA[Enc];
*vol_r = RPANTABLE_AICA[Enc];
}
}
sint32 EMU_CALL yam_init(void) {
yam_init_tables();
return 0;
}
#define YAMSTATE ((struct YAM_STATE*)(state))
#define LOOP_NONE (0)
#define LOOP_FORWARDS (1)
#define LOOP_BACKWARDS (2)
#define LOOP_BIDIRECTIONAL (3)
typedef enum {ATTACK,DECAY1,DECAY2,RELEASE} _STATE;
struct _EG
{
int volume; _STATE state;
int step;
int AR; int D1R; int D2R; int RR;
int DL; uint8 EGHOLD;
uint8 LPLINK;
};
struct YAM_CHAN {
uint8 kyonb;
uint8 ssctl;
uint8 sampler_looptype;
sint32 sampler_invert; uint8 pcms;
uint32 sampleaddr;
sint32 loopstart;
sint32 loopend;
uint8 Backwards; struct _EG EG;
struct _LFO PLFO; struct _LFO ALFO; uint8 ar[4]; uint8 dl;
uint8 krs;
uint8 link;
uint8 eghold;
uint8 oct;
uint16 fns;
uint8 lfore;
uint8 lfof;
uint8 plfows;
uint8 plfos;
uint8 alfows;
uint8 alfos;
uint8 dspchan;
uint8 dsplevel;
uint8 disdl;
uint8 dipan;
uint8 tl;
uint8 voff;
uint8 lpoff;
uint8 q;
uint8 stwinh;
uint8 mdl;
uint8 mdxsl;
uint8 mdysl;
uint16 flv[5];
uint8 fr[4]; uint16 lpflevel;
uint8 lpfstate;
uint8 lp;
sint32 prv_addr; uint32 cur_addr;
uint32 nxt_addr;
uint32 step; uint32 frcphase;
uint32 lfophase;
sint32 samplebufcur; sint32 samplebufnext; int cur_sample; int cur_quant; int curstep;
int cur_lpquant, cur_lpsample, cur_lpstep;
uint32 adbase, adlpbase;
sint32 lpp1;
sint32 lpp2;
};
struct MPRO {
uint8 c_0rrrrrrr; uint8 t_0rrrrrrr; uint8 t_Twwwwwww; sint8 tablemask; sint8 adrmask; sint8 negb; uint8 __kisxzbon; uint8 m_wrAFyyYh; uint8 i_00rrrrrr; uint8 i_0T0wwwww; uint8 e_000Twwww; uint8 m_00aaaaaa; };
static uint64 mpro_scsp_read(struct MPRO *mpro) {
uint64 value = 0;
value |= ((uint64)(mpro->t_0rrrrrrr )) << 56; value |= ((uint64)(mpro->t_Twwwwwww ^ 0x80)) << 48; value |= ((uint64)(mpro->tablemask & 1)) << 31; value |= ((uint64)(mpro->adrmask & 1)) << 1; value |= ((uint64)(mpro->negb & 1)) << 18; { uint64 sh = mpro->m_wrAFyyYh & 1;
if((mpro->__kisxzbon & 0x20) == 0) { sh ^= 3; }
value |= (sh << 20); }
value |= ((uint64)(mpro->__kisxzbon & 0x10)) << 43; value |= ((uint64)(mpro->__kisxzbon & 0x0C)) << 14; value |= ((uint64)(mpro->__kisxzbon & 0x02)) << 6; value |= ((uint64)(mpro->__kisxzbon & 0x01)) << 0; value |= ((uint64)(mpro->m_wrAFyyYh & 0xC0)) << 23; value |= ((uint64)(mpro->m_wrAFyyYh & 0x32)) << 18; value |= ((uint64)(mpro->m_wrAFyyYh & 0x0C)) << 43; value |= ((uint64)(mpro->i_00rrrrrr & 0x3F)) << 38; value |= ((uint64)(mpro->i_0T0wwwww & 0x1F)) << 32; value |= ((uint64)((mpro->i_0T0wwwww & 0x40) ^ 0x40)) << 31; value |= ((uint64)((mpro->e_000Twwww & 0x1F) ^ 0x10)) << 24; value |= ((uint64)(mpro->m_00aaaaaa & 0x1F)) << 2; value |= ((uint64)(mpro->c_0rrrrrrr & 0x3F)) << 9;
return value;
}
static void mpro_scsp_write(struct MPRO *mpro, uint64 value) {
mpro->t_0rrrrrrr = ((value >> 56) & 0x7F); mpro->t_Twwwwwww = ((value >> 48) ^ 0x80); mpro->tablemask = ((value >> 31) & 1) ? (-1) : (0); mpro->adrmask = ((value >> 1) & 1) ? (-1) : (0); mpro->negb = ((value >> 18) & 1) ? (-1) : (0); mpro->__kisxzbon = 0;
if(!value) { mpro->__kisxzbon |= 0x80; } if(((value >> 20) & 3) == 3) { mpro->__kisxzbon |= 0x40; } if(((value >> 21) & 1) == 0) { mpro->__kisxzbon |= 0x20; } mpro->__kisxzbon |= (value >> 43) & 0x10; mpro->__kisxzbon |= (value >> 14) & 0x0C; mpro->__kisxzbon |= (value >> 6) & 0x02; mpro->__kisxzbon |= (value >> 0) & 1; mpro->m_wrAFyyYh = (value >> 23) & 0xC0; mpro->m_wrAFyyYh |= (value >> 18) & 0x32; mpro->m_wrAFyyYh |= (value >> 43) & 0x0C; mpro->m_wrAFyyYh |= ((value >> 20) & 1) ^ ((value >> 21) & 1); mpro->i_00rrrrrr = (value >> 38) & 0x3F; mpro->i_0T0wwwww = (value >> 32) & 0x1F; mpro->i_0T0wwwww |= ((value >> 31) & 0x40) ^ 0x40; mpro->e_000Twwww = ((value >> 24) & 0x1F) ^ 0x10; mpro->m_00aaaaaa = (value >> 2) & 0x1F; mpro->c_0rrrrrrr = (value >> 9) & 0x3F; }
static void mpro_aica_write(struct MPRO *mpro, uint64 value) {
mpro->t_0rrrrrrr = ((value >> 57) & 0x7F); mpro->t_Twwwwwww = ((value >> 49) ^ 0x80); mpro->tablemask = ((value >> 31) & 1) ? (-1) : (0); mpro->adrmask = ((value >> 8) & 1) ? (-1) : (0); mpro->negb = ((value >> 18) & 1) ? (-1) : (0); mpro->__kisxzbon = 0;
if(!value) { mpro->__kisxzbon |= 0x80; } if(((value >> 20) & 3) == 3) { mpro->__kisxzbon |= 0x40; } if(((value >> 21) & 1) == 0) { mpro->__kisxzbon |= 0x20; } mpro->__kisxzbon |= (value >> 43) & 0x10; mpro->__kisxzbon |= (value >> 14) & 0x0E; mpro->__kisxzbon |= (value >> 7) & 1; mpro->m_wrAFyyYh = (value >> 23) & 0xC0; mpro->m_wrAFyyYh |= (value >> 18) & 0x32; mpro->m_wrAFyyYh |= (value >> 43) & 0x0C; mpro->m_wrAFyyYh |= ((value >> 20) & 1) ^ ((value >> 21) & 1); mpro->i_00rrrrrr = (value >> 39) & 0x3F; mpro->i_0T0wwwww = (value >> 33) & 0x1F; mpro->i_0T0wwwww |= ((value >> 32) & 0x40) ^ 0x40; mpro->e_000Twwww = ((value >> 24) & 0x1F) ^ 0x10; mpro->m_00aaaaaa = (value >> 9) & 0x3F; }
static uint64 mpro_aica_read(struct MPRO *mpro) {
uint64 value = 0;
value |= ((uint64)(mpro->t_0rrrrrrr )) << 57; value |= ((uint64)(mpro->t_Twwwwwww ^ 0x80)) << 49; value |= ((uint64)(mpro->tablemask & 1)) << 31; value |= ((uint64)(mpro->adrmask & 1)) << 8; value |= ((uint64)(mpro->negb & 1)) << 18; { uint64 sh = mpro->m_wrAFyyYh & 1;
if((mpro->__kisxzbon & 0x20) == 0) { sh ^= 3; }
value |= (sh << 20); }
value |= ((uint64)(mpro->__kisxzbon & 0x10)) << 43; value |= ((uint64)(mpro->__kisxzbon & 0x0E)) << 14; value |= ((uint64)(mpro->__kisxzbon & 0x01)) << 7; value |= ((uint64)(mpro->m_wrAFyyYh & 0xC0)) << 23; value |= ((uint64)(mpro->m_wrAFyyYh & 0x32)) << 18; value |= ((uint64)(mpro->m_wrAFyyYh & 0x0C)) << 43; value |= ((uint64)(mpro->i_00rrrrrr & 0x3F)) << 39; value |= ((uint64)(mpro->i_0T0wwwww & 0x1F)) << 33; value |= ((uint64)((mpro->i_0T0wwwww & 0x40) ^ 0x40)) << 32; value |= ((uint64)((mpro->e_000Twwww & 0x1F) ^ 0x10)) << 24; value |= ((uint64)(mpro->m_00aaaaaa & 0x3F)) << 9; return value;
}
#define DYNACODE_MAX_SIZE (0x6000)
#define DYNACODE_SLOP_SIZE (0x80)
struct YAM_STATE {
uint32 version;
void *ram_ptr; uint32 ram_mask;
sint16 *out_buf; uint32 out_pending;
uint32 odometer;
uint8 dry_out_enabled;
uint8 dsp_emulation_enabled;
#ifdef ENABLE_DYNAREC
uint8 dsp_dyna_enabled;
uint8 dsp_dyna_valid;
#endif
uint32 randseed;
uint32 mem_word_address_xor;
uint32 mem_byte_address_xor;
uint8 efsdl[18];
uint8 efpan[18];
uint8 mono;
uint8 mvol;
uint32 rbp;
uint8 rbl;
uint8 afsel;
uint8 mslc;
uint8 mrwinh;
uint8 tctl[3], tim[3];
uint16 mcieb, mcipd;
uint16 scieb, scipd;
uint8 scilv0, scilv1, scilv2;
uint8 inton, intreq;
uint32 rtc;
sint16 coef[128]; uint16 madrs[64];
struct MPRO mpro[128];
sint32 temp[128];
sint32 inputs[0x60];
sint16 efreg[0x20];
uint32 mdec_ct;
uint32 adrs_reg;
sint32 xzbchoice[5];
#define XZBCHOICE_TEMP (0)
#define XZBCHOICE_ACC (1)
#define XZBCHOICE_ZERO (2)
#define XZBCHOICE_ZERO_ACC (3)
#define XZBCHOICE_INPUTS (4)
sint32 yychoice[4];
#define YYCHOICE_FRC_REG (0)
#define YYCHOICE_COEF (1)
#define YYCHOICE_Y_REG_H (2)
#define YYCHOICE_Y_REG_L (3)
sint32 mem_in_data[4];
sint16 ringbuf[32*RINGMAX];
uint32 bufptr;
uint32 dmea;
uint16 drga;
uint16 dtlg;
struct YAM_CHAN chan[64];
#ifdef ENABLE_DYNAREC
uint8 dynacode[DYNACODE_MAX_SIZE];
#endif
};
uint32 EMU_CALL yam_get_state_size(uint8 version) {
return sizeof(struct YAM_STATE);
}
void EMU_CALL yam_clear_state(void *state, uint8 version) {
int i;
if(version != 2) { version = 1; }
memset(state, 0, sizeof(struct YAM_STATE));
YAMSTATE->version = version;
for(i = 0; i < 64; i++) {
YAMSTATE->chan[i].EG.state = RELEASE;
YAMSTATE->chan[i].lpfstate = 3;
YAMSTATE->chan[i].eghold = 0;
YAMSTATE->chan[i].lpflevel = 0x1FFF;
if(version == 1) { YAMSTATE->chan[i].lpoff = 1; }
}
for(i = 0; i < 128; i++) {
switch(version) {
case 1:
mpro_scsp_write((YAMSTATE->mpro) + i, 0);
break;
case 2:
YAMSTATE->mpro[i].c_0rrrrrrr = i;
mpro_aica_write((YAMSTATE->mpro) + i, 0);
break;
}
}
YAMSTATE->dry_out_enabled = 1;
YAMSTATE->dsp_emulation_enabled = 1;
#ifdef ENABLE_DYNAREC
YAMSTATE->dsp_dyna_enabled = 1;
#endif
}
void EMU_CALL yam_setram(void *state, uint32 *ram, uint32 size, uint8 mbx, uint8 mwx) {
YAMSTATE->ram_ptr = ram;
if((size & (size-1)) == 0) {
YAMSTATE->ram_mask = size-1;
} else {
YAMSTATE->ram_mask = 0;
}
YAMSTATE->mem_byte_address_xor = mbx;
YAMSTATE->mem_word_address_xor = mwx;
#ifdef ENABLE_DYNAREC
YAMSTATE->dsp_dyna_valid = 0;
#endif
}
void EMU_CALL yam_beginbuffer(void *state, sint16 *buf) {
YAMSTATE->out_buf = buf;
YAMSTATE->out_pending = 0;
}
void EMU_CALL yam_enable_dry(void *state, uint8 enable) {
YAMSTATE->dry_out_enabled = (enable != 0);
}
void EMU_CALL yam_enable_dsp(void *state, uint8 enable) {
YAMSTATE->dsp_emulation_enabled = (enable != 0);
#ifdef ENABLE_DYNAREC
if(enable == 0) { YAMSTATE->dsp_dyna_valid = 0; }
#endif
}
void EMU_CALL yam_enable_dsp_dynarec(void *state, uint8 enable) {
#ifdef ENABLE_DYNAREC
YAMSTATE->dsp_dyna_enabled = (enable != 0);
if(enable == 0) { YAMSTATE->dsp_dyna_valid = 0; }
#endif
}
static void sci_recompute(struct YAM_STATE *state) {
int i;
uint16 scipd = (state->scipd) & (state->scieb);
state->inton = 0;
for(i = 10; i >= 0; i--) {
if(((scipd) >> i) & 1) {
if(i > 7) i = 7;
state->intreq =
((((state->scilv0) >> i) & 1) << 0) |
((((state->scilv1) >> i) & 1) << 1) |
((((state->scilv2) >> i) & 1) << 2);
state->inton = state->intreq;
return;
}
}
}
static void sci_signal(struct YAM_STATE *state, int n) {
state->scipd |= (1 << n);
if(!(state->inton)) {
sci_recompute(state);
}
}
uint8* EMU_CALL yam_get_interrupt_pending_ptr(void *state) {
return &(YAMSTATE->inton);
}
uint32 EMU_CALL yam_get_min_samples_until_interrupt(void *state) {
uint32 min = 0xFFFFFFFF;
uint32 t, samples;
for(t = 0; t < 3; t++) {
if(YAMSTATE->scieb & (1 << (INT_TIMER_A + t))) {
samples = 0x100-((uint32)(YAMSTATE->tim[t]));
samples <<= YAMSTATE->tctl[t];
samples -= (YAMSTATE->odometer) & ((1<<YAMSTATE->tctl[t])-1);
if(samples < min) { min = samples; }
}
}
return min;
}
void EMU_CALL yam_advance(void *state, uint32 samples) {
uint32 t;
for(t = 0; t < 3; t++) {
uint8 scale = YAMSTATE->tctl[t];
uint32 whole = YAMSTATE->tim[t];
uint32 frac = (YAMSTATE->odometer) & ((1<<scale)-1);
uint32 remain = ((0x100 - whole) << scale) - frac;
if(samples >= remain) { sci_signal(state, INT_TIMER_A + t); }
YAMSTATE->tim[t] = ((frac + samples + (whole << scale)) >> scale) & 0xFF;
}
YAMSTATE->out_pending += samples;
YAMSTATE->odometer += samples;
}
static int Get_AR(int base,int R)
{
int Rate=base+(R<<1);
if(Rate>63) Rate=63;
if(Rate<0) Rate=0;
return ARTABLE[Rate];
}
static int Get_DR(int base,int R)
{
int Rate=base+(R<<1);
if(Rate>63) Rate=63;
if(Rate<0) Rate=0;
return DRTABLE[Rate];
}
static int Get_RR(int base,int R)
{
int Rate=base+(R<<1);
if(Rate>63) Rate=63;
if(Rate<0) Rate=0;
return DRTABLE[Rate];
}
static void Compute_EG(struct YAM_CHAN *chan)
{
int octave=chan->oct;
int rate;
if(octave&8) octave=octave-16;
if(chan->krs!=0xf)
rate=octave+2*chan->krs+((chan->fns>>9)&1);
else
rate=0;
chan->EG.volume=0x17F<<EG_SHIFT;
chan->EG.AR=Get_AR(rate,chan->ar[0]);
chan->EG.D1R=Get_DR(rate,chan->ar[1]);
chan->EG.D2R=Get_DR(rate,chan->ar[2]);
chan->EG.RR=Get_RR(rate,chan->ar[3]);
chan->EG.DL=0x1f-chan->dl;
chan->EG.EGHOLD=chan->eghold;
}
static void keyoff(struct YAM_CHAN *chan, int keyoff);
static int EG_Update(struct YAM_CHAN *chan)
{
switch(chan->EG.state) {
case ATTACK:
chan->EG.volume+=chan->EG.AR;
if(chan->EG.volume>=(0x3ff<<EG_SHIFT)) {
if (!chan->link) {
chan->EG.state=DECAY1;
if(chan->EG.D1R>=(1024<<EG_SHIFT)) chan->EG.state=DECAY2;
}
chan->EG.volume=0x3ff<<EG_SHIFT;
}
if(chan->EG.EGHOLD)
#if SHIFT >= 10
return 0x3ff<<(SHIFT-10);
#else
return 0x3ff>>(10-SHIFT);
#endif
break;
case DECAY1:
chan->EG.volume-=chan->EG.D1R;
if(chan->EG.volume<=0)
chan->EG.volume=0;
if(chan->EG.volume>>(EG_SHIFT+5)<=chan->EG.DL)
chan->EG.state=DECAY2;
break;
case DECAY2:
if(chan->ar[2]==0)
#if SHIFT >= 10
return (chan->EG.volume>>EG_SHIFT)<<(SHIFT-10);
#else
return (chan->EG.volume>>EG_SHIFT)>>(10-SHIFT);
#endif
chan->EG.volume-=chan->EG.D2R;
if(chan->EG.volume<=0)
chan->EG.volume=0;
break;
case RELEASE:
chan->EG.volume-=chan->EG.RR;
if(chan->EG.volume<=0) {
chan->EG.volume=0;
keyoff(chan, 0);
}
break;
default:
return 1<<SHIFT;
}
#if SHIFT >= 10
return (chan->EG.volume>>EG_SHIFT)<<(SHIFT-10);
#else
return (chan->EG.volume>>EG_SHIFT)>>(10-SHIFT);
#endif
}
static uint32 AICA_Step(struct YAM_CHAN *chan)
{
int octave=chan->oct;
uint32 Fn;
Fn=(FNS_Table[chan->fns]); if(octave&8)
Fn>>=(16-octave);
else
Fn<<=octave;
return Fn/(44100);
}
static signed int PLFO_Step(struct _LFO *LFO)
{
int p;
LFO->phase+=LFO->phase_step;
#if LFO_SHIFT!=8
LFO->phase&=(1<<(LFO_SHIFT+8))-1;
#endif
p=LFO->table[LFO->phase>>LFO_SHIFT];
p=LFO->scale[p+128];
return p<<(SHIFT-LFO_SHIFT);
}
static signed int ALFO_Step(struct _LFO *LFO)
{
int p;
LFO->phase+=LFO->phase_step;
#if LFO_SHIFT!=8
LFO->phase&=(1<<(LFO_SHIFT+8))-1;
#endif
p=LFO->table[LFO->phase>>LFO_SHIFT];
p=LFO->scale[p];
return p<<(SHIFT-LFO_SHIFT);
}
static void LFO_ComputeStep(struct _LFO *LFO,sint32 LFOF,sint32 LFOWS,sint32 LFOS,int ALFO)
{
float step=(float) LFOFreq[LFOF]*256.0/(float)44100.0;
LFO->phase_step=(unsigned int) ((float) (1<<LFO_SHIFT)*step);
if(ALFO) {
switch(LFOWS)
{
case 0: LFO->table=ALFO_SAW; break;
case 1: LFO->table=ALFO_SQR; break;
case 2: LFO->table=ALFO_TRI; break;
case 3: LFO->table=ALFO_NOI; break;
}
LFO->scale=ASCALES[LFOS];
}
else {
switch(LFOWS)
{
case 0: LFO->table=PLFO_SAW; break;
case 1: LFO->table=PLFO_SQR; break;
case 2: LFO->table=PLFO_TRI; break;
case 3: LFO->table=PLFO_NOI; break;
}
LFO->scale=PSCALES[LFOS];
}
}
static void Compute_LFO(struct YAM_CHAN *chan)
{
if(chan->plfos!=0)
LFO_ComputeStep(&(chan->PLFO),chan->lfof,chan->plfows,chan->plfos,0);
if(chan->alfos!=0)
LFO_ComputeStep(&(chan->ALFO),chan->lfof,chan->alfows,chan->alfos,1);
}
#define ADPCMSHIFT 8
#define ADFIX(f) (int) ((float) f*(float) (1<<ADPCMSHIFT))
const int TableQuant[8]={ADFIX(0.8984375),ADFIX(0.8984375),ADFIX(0.8984375),ADFIX(0.8984375),ADFIX(1.19921875),ADFIX(1.59765625),ADFIX(2.0),ADFIX(2.3984375)};
const int quant_mul[16]= { 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15};
void InitADPCM(int *PrevSignal, int *PrevQuant)
{
*PrevSignal=0;
*PrevQuant=0x7f;
}
#define ICLIP16(x) ((((x)+0x8000)&0xFFFF0000)?(((x)>>31)^0x7FFF):(x))
static signed short DecodeADPCM(int *PrevSignal, unsigned char Delta, int *PrevQuant)
{
int x = *PrevQuant * quant_mul [Delta & 15];
x = *PrevSignal + ((int)(x + ((uint32)x >> 29)) >> 3);
*PrevSignal=ICLIP16(x);
*PrevQuant=(*PrevQuant*TableQuant[Delta&7])>>ADPCMSHIFT;
*PrevQuant=(*PrevQuant<0x7f)?0x7f:((*PrevQuant>0x6000)?0x6000:*PrevQuant);
return *PrevSignal;
}
static void keyon(struct YAM_STATE *state, struct YAM_CHAN *chan) {
if(chan->EG.state != RELEASE) return;
chan->cur_addr = 0;
chan->nxt_addr = 1 << SHIFT;
chan->Backwards=0;
chan->step=AICA_Step(chan);
chan->lpflevel = chan->flv[0];
chan->lpfstate = 0;
chan->samplebufcur = 0;
chan->samplebufnext = 0;
Compute_EG(chan);
chan->EG.state=ATTACK;
chan->EG.volume=0x17F<<EG_SHIFT;
Compute_LFO(chan);
if (chan->pcms >= 2)
{
uint8 *base;
uint32 adbase;
uint32 curstep, steps_to_go;
chan->curstep = 0;
chan->adbase = chan->sampleaddr & state->ram_mask;
InitADPCM(&(chan->cur_sample), &(chan->cur_quant));
InitADPCM(&(chan->cur_lpsample), &(chan->cur_lpquant));
curstep = 0;
base = ((uint8*)state->ram_ptr);
adbase = chan->adbase;
steps_to_go = chan->loopstart;
while (curstep < steps_to_go) {
int shift1, delta1;
shift1 = 4*((curstep&1));
delta1 = (base[adbase]>>shift1)&0xf;
DecodeADPCM(&(chan->cur_lpsample),delta1,&(chan->cur_lpquant));
curstep++;
if (!(curstep & 1)) {
adbase = (adbase + 1) & state->ram_mask;
}
}
chan->cur_lpstep = curstep;
chan->adlpbase = adbase;
if (chan->loopstart > chan->loopend) {
chan->loopend = 0xFFFF;
}
}
}
static void keyoff(struct YAM_CHAN *chan,int keyoff) {
chan->EG.state = RELEASE;
chan->lpfstate = 3;
if(!keyoff) chan->EG.volume = 0;
chan->kyonb = 0;
}
static uint32 chan_scsp_load_reg(struct YAM_STATE *state, uint8 ch, uint8 a) {
struct YAM_CHAN *chan = state->chan + (((uint32)ch) & 0x1F);
uint16 d = 0;
switch(a & 0x1E) {
case 0x00: d = (((uint32)(chan->kyonb )) & 0x0001) << 11;
d |= (((uint32)(chan->sampler_invert )) & 0xC000) >> 5;
d |= (((uint32)(chan->ssctl )) & 0x0003) << 7;
d |= (((uint32)(chan->sampler_looptype)) & 0x0003) << 5;
d |= (((uint32)(chan->pcms )) & 0x0001) << 4;
d |= ((chan->sampleaddr) >> 16) & 0xF;
break;
case 0x02: d = chan->sampleaddr;
break;
case 0x04: d = chan->loopstart;
break;
case 0x06: d = chan->loopend;
break;
case 0x08: d = (((uint32)(chan->ar[2] )) & 0x001F) << 11;
d |= (((uint32)(chan->ar[1] )) & 0x001F) << 6;
d |= (((uint32)(chan->eghold )) & 1) << 5;
d |= (((uint32)(chan->ar[0] )) & 0x001F) << 0;
break;
case 0x0A: d = (((uint32)(chan->link )) & 0x0001) << 14;
d |= (((uint32)(chan->krs )) & 0x000F) << 10;
d |= (((uint32)(chan->dl )) & 0x001F) << 5;
d |= (((uint32)(chan->ar[3] )) & 0x001F) << 0;
break;
case 0x0C: d = (((uint32)(chan->stwinh )) & 0x0001) << 9;
d |= (((uint32)(chan->voff )) & 0x0001) << 8;
d |= (((uint32)(chan->tl )) & 0x00FF) << 0;
break;
case 0x0E: d = (((uint32)(chan->mdl )) & 0x000F) << 12;
d |= (((uint32)(chan->mdxsl )) & 0x003F) << 6;
d |= (((uint32)(chan->mdysl )) & 0x003F) << 0;
break;
case 0x10: d = (((uint32)(chan->oct )) & 0x000F) << 11;
d |= (((uint32)(chan->fns )) & 0x07FF) << 0;
break;
case 0x12: d = (((uint32)(chan->lfore )) & 0x0001) << 15;
d |= (((uint32)(chan->lfof )) & 0x001F) << 10;
d |= (((uint32)(chan->plfows )) & 0x0003) << 8;
d |= (((uint32)(chan->plfos )) & 0x0007) << 5;
d |= (((uint32)(chan->alfows )) & 0x0003) << 3;
d |= (((uint32)(chan->alfos )) & 0x0007) << 0;
break;
case 0x14: d = (((uint32)(chan->dspchan )) & 0x000F) << 3;
d |= (((uint32)(chan->dsplevel )) & 0x0007) >> 0;
break;
case 0x16: d = (((uint32)(chan->disdl )) & 0x0007) << 13;
d |= (((uint32)(chan->dipan )) & 0x001F) << 8;
if(ch < 18) {
d |= (((uint32)(state->efsdl[ch])) & 0x07) << 5;
d |= (((uint32)(state->efpan[ch])) & 0x1F) << 0;
}
break;
}
return d;
}
static void chan_scsp_store_reg(struct YAM_STATE *state, uint8 ch, uint8 a, uint32 d, uint32 mask) {
struct YAM_CHAN *chan;
a &= 0x1E;
if(a >= 0x18) return;
yam_flush(YAMSTATE);
chan = state->chan + (((uint32)ch) & 0x1F);
switch(a & 0x1E) {
case 0x00: if(mask & 0x00FF) {
chan->sampleaddr &= 0xFFFF;
chan->sampleaddr |= (((uint32)d) & 0xF) << 16;
chan->pcms = (d >> 4) & 1;
chan->sampler_looptype = (d >> 5) & 3;
chan->ssctl &= 2;
chan->ssctl |= (d >> 7) & 1;
}
if(mask & 0xFF00) {
chan->ssctl &= 1;
chan->ssctl |= (d >> 7) & 2;
chan->sampler_invert = 0;
if(d & (1<< 9)) chan->sampler_invert |= 0x00007FFF;
if(d & (1<<10)) chan->sampler_invert |= 0xFFFF8000;
chan->kyonb = (d >> 11) & 1;
if(d & 0x1000) { int ch;
for(ch = 0; ch < 32; ch++) {
if(state->chan[ch].kyonb) {
keyon(state, state->chan + ch);
} else {
keyoff(state->chan + ch, 1);
}
}
}
}
break;
case 0x02: chan->sampleaddr &= (0xFFFFF ^ mask);
chan->sampleaddr |= (d & mask);
break;
case 0x04: chan->loopstart &= (0xFFFF ^ mask);
chan->loopstart |= (d & mask);
break;
case 0x06: chan->loopend &= (0xFFFF ^ mask);
chan->loopend |= (d & mask);
break;
case 0x08: if(mask & 0x00FF) {
chan->ar[0] = d & 0x1F;
chan->eghold = !!(d & (1<<5));
chan->ar[1] &= 0x1C;
chan->ar[1] |= (d >> 6) & 0x03;
}
if(mask & 0xFF00) {
chan->ar[1] &= 0x03;
chan->ar[1] |= (d >> 6) & 0x1C;
chan->ar[2] = (d >> 11) & 0x1F;
}
break;
case 0x0A: if(mask & 0x00FF) {
chan->ar[3] = d & 0x1F;
chan->dl &= 0x18;
chan->dl |= (d >> 5) & 0x07;
}
if(mask & 0xFF00) {
chan->dl &= 0x07;
chan->dl |= (d >> 5) & 0x18;
chan->krs = (d >> 10) & 0xF;
chan->link = (d >> 14) & 1;
}
break;
case 0x0C: if(mask & 0x00FF) {
chan->tl = d & 0xFF;
}
if(mask & 0xFF00) {
chan->voff = (d >> 8) & 1;
chan->stwinh = (d >> 9) & 1;
}
break;
case 0x0E: if(mask & 0x00FF) {
chan->mdysl = d & 0x3F;
chan->mdxsl &= 0x3C;
chan->mdxsl |= (d >> 6) & 0x03;
}
if(mask & 0xFF00) {
chan->mdxsl &= 0x03;
chan->mdxsl |= (d >> 6) & 0x3C;
chan->mdl = (d >> 12) & 0xF;
}
break;
case 0x10: if(mask & 0x00FF) {
chan->fns &= 0x700;
chan->fns |= d & 0x0FF;
}
if(mask & 0xFF00) {
chan->fns &= 0x0FF;
chan->fns |= d & 0x700;
chan->oct = (d >> 11) & 0xF;
}
chan->step = AICA_Step(chan);
break;
case 0x12: if(mask & 0x00FF) {
chan->alfos = d & 7;
chan->alfows = (d >> 3) & 3;
chan->plfos = (d >> 5) & 7;
}
if(mask & 0xFF00) {
chan->plfows = (d >> 8) & 3;
chan->lfof = (d >> 10) & 0x1F;
chan->lfore = (d >> 15) & 1;
}
Compute_LFO(chan);
break;
case 0x14: if(mask & 0x00FF) {
chan->dsplevel = d & 0x7;
chan->dspchan = (d >> 3) & 0xF;
}
break;
case 0x16: if(mask & 0x00FF) {
if(ch < 18) {
state->efpan[ch] = d & 0x1F;
state->efsdl[ch] = (d >> 5) & 0x7;
}
}
if(mask & 0xFF00) {
chan->dipan = (d >> 8) & 0x1F;
chan->disdl = (d >> 13) & 0x7;
}
break;
}
}
static uint32 chan_aica_load_reg(struct YAM_STATE *state, uint8 ch, uint8 a) {
struct YAM_CHAN *chan = state->chan + (((uint32)ch) & 0x3F);
uint16 d = 0;
switch(a & 0x7C) {
case 0x00: d = (((uint32)(chan->kyonb )) & 0x0001) << 14;
d |= (((uint32)(chan->ssctl )) & 0x0001) << 10;
d |= (((uint32)(chan->sampler_looptype)) & 0x0001) << 9;
d |= (((uint32)(chan->pcms )) & 0x0003) << 7;
d |= ((chan->sampleaddr) >> 16) & 0x7F;
break;
case 0x04: d = chan->sampleaddr;
break;
case 0x08: d = chan->loopstart;
break;
case 0x0C: d = chan->loopend;
break;
case 0x10: d = (((uint32)(chan->ar[2] )) & 0x001F) << 11;
d |= (((uint32)(chan->ar[1] )) & 0x001F) << 6;
d |= (((uint32)(chan->ar[0] )) & 0x001F) << 0;
break;
case 0x14: d = (((uint32)(chan->link )) & 0x0001) << 14;
d |= (((uint32)(chan->krs )) & 0x000F) << 10;
d |= (((uint32)(chan->dl )) & 0x001F) << 5;
d |= (((uint32)(chan->ar[3] )) & 0x001F) << 0;
break;
case 0x18: d = (((uint32)(chan->oct )) & 0x000F) << 11;
d |= (((uint32)(chan->fns )) & 0x07FF) << 0;
break;
case 0x1C: d = (((uint32)(chan->lfore )) & 0x0001) << 15;
d |= (((uint32)(chan->lfof )) & 0x001F) << 10;
d |= (((uint32)(chan->plfows )) & 0x0003) << 8;
d |= (((uint32)(chan->plfos )) & 0x0007) << 5;
d |= (((uint32)(chan->alfows )) & 0x0003) << 3;
d |= (((uint32)(chan->alfos )) & 0x0007) << 0;
break;
case 0x20: d = (((uint32)(chan->dsplevel )) & 0x000F) << 4;
d |= (((uint32)(chan->dspchan )) & 0x000F) << 0;
break;
case 0x24: d = (((uint32)(chan->disdl )) & 0x000F) << 8;
d |= (((uint32)(chan->dipan )) & 0x001F) << 0;
break;
case 0x28: d = (((uint32)(chan->tl )) & 0x00FF) << 8;
d |= (((uint32)(chan->voff )) & 0x0001) << 6;
d |= (((uint32)(chan->lpoff )) & 0x0001) << 5;
d |= (((uint32)(chan->q )) & 0x001F) << 0;
break;
case 0x2C: d = (chan->flv[0]) & 0x1FFF;
break;
case 0x30: d = (chan->flv[1]) & 0x1FFF;
break;
case 0x34: d = (chan->flv[2]) & 0x1FFF;
break;
case 0x38: d = (chan->flv[3]) & 0x1FFF;
break;
case 0x3C: d = (chan->flv[4]) & 0x1FFF;
break;
case 0x40: d = (((uint32)(chan->fr[0] )) & 0x001F) << 8;
d |= (((uint32)(chan->fr[1] )) & 0x001F) << 0;
break;
case 0x44: d = (((uint32)(chan->fr[2] )) & 0x001F) << 8;
d |= (((uint32)(chan->fr[3] )) & 0x001F) << 0;
break;
}
return d;
}
static void chan_aica_store_reg(struct YAM_STATE *state, uint8 ch, uint8 a, uint32 d, uint32 mask) {
struct YAM_CHAN *chan;
a &= 0x7C;
if(a >= 0x48) return;
yam_flush(YAMSTATE);
chan = state->chan + (((uint32)ch) & 0x3F);
switch(a) {
case 0x00: if(mask & 0x00FF) {
chan->sampleaddr &= 0xFFFF;
chan->sampleaddr |= (((uint32)d) & 0x7F) << 16;
chan->pcms &= 2;
chan->pcms |= (d >> 7) & 1;
}
if(mask & 0xFF00) {
chan->pcms &= 1;
chan->pcms |= (d >> 7) & 2;
chan->sampler_looptype = (d >> 9) & 1;
chan->ssctl = (d >> 10) & 1;
chan->kyonb = (d >> 14) & 1;
if(d & 0x8000) { int ch;
for(ch = 0; ch < 64; ch++) {
if(state->chan[ch].kyonb) { keyon(state, state->chan + ch); }
else { keyoff(state->chan + ch, 1); }
}
}
}
break;
case 0x04: chan->sampleaddr &= (0x7FFFFF ^ mask);
chan->sampleaddr |= (d & mask);
break;
case 0x08: chan->loopstart &= (0xFFFF ^ mask);
chan->loopstart |= (d & mask);
break;
case 0x0C: chan->loopend &= (0xFFFF ^ mask);
chan->loopend |= (d & mask);
break;
case 0x10: if(mask & 0x00FF) {
chan->ar[0] = d & 0x1F;
chan->ar[1] &= 0x1C;
chan->ar[1] |= (d >> 6) & 0x03;
}
if(mask & 0xFF00) {
chan->ar[1] &= 0x03;
chan->ar[1] |= (d >> 6) & 0x1C;
chan->ar[2] = (d >> 11) & 0x1F;
}
break;
case 0x14: if(mask & 0x00FF) {
chan->ar[3] = d & 0x1F;
chan->dl &= 0x18;
chan->dl |= (d >> 5) & 0x07;
}
if(mask & 0xFF00) {
chan->dl &= 0x07;
chan->dl |= (d >> 5) & 0x18;
chan->krs = (d >> 10) & 0xF;
chan->link = (d >> 14) & 1;
}
break;
case 0x18: if(mask & 0x00FF) {
chan->fns &= 0x700;
chan->fns |= d & 0x0FF;
}
if(mask & 0xFF00) {
chan->fns &= 0x0FF;
chan->fns |= d & 0x700;
chan->oct = (d >> 11) & 0xF;
}
chan->step = AICA_Step(chan);
break;
case 0x1C: if(mask & 0x00FF) {
chan->alfos = d & 7;
chan->alfows = (d >> 3) & 3;
chan->plfos = (d >> 5) & 7;
}
if(mask & 0xFF00) {
chan->plfows = (d >> 8) & 3;
chan->lfof = (d >> 10) & 0x1F;
chan->lfore = (d >> 15) & 1;
}
Compute_LFO(chan);
break;
case 0x20: if(mask & 0x00FF) {
chan->dspchan = d & 0xF;
chan->dsplevel = (d >> 4) & 0xF;
}
break;
case 0x24: if(mask & 0x00FF) { chan->dipan = d & 0x1F; }
if(mask & 0xFF00) { chan->disdl = (d >> 8) & 0xF; }
break;
case 0x28: if(mask & 0x00FF) {
chan->q = d & 0x1F;
chan->lpoff = (d >> 5) & 1;
chan->voff = (d >> 6) & 1;
}
if(mask & 0xFF00) {
chan->tl = (d >> 8) & 0xFF;
}
break;
case 0x2C: chan->flv[0] = (((chan->flv[0]) & (0xFFFF ^ mask)) | (d & mask)) & 0x1FFF;
break;
case 0x30: chan->flv[1] = (((chan->flv[1]) & (0xFFFF ^ mask)) | (d & mask)) & 0x1FFF;
break;
case 0x34: chan->flv[2] = (((chan->flv[2]) & (0xFFFF ^ mask)) | (d & mask)) & 0x1FFF;
break;
case 0x38: chan->flv[3] = (((chan->flv[3]) & (0xFFFF ^ mask)) | (d & mask)) & 0x1FFF;
break;
case 0x3C: chan->flv[4] = (((chan->flv[4]) & (0xFFFF ^ mask)) | (d & mask)) & 0x1FFF;
break;
case 0x40: if(mask & 0x00FF) { chan->fr[1] = (d >> 0) & 0x1F; }
if(mask & 0xFF00) { chan->fr[0] = (d >> 8) & 0x1F; }
break;
case 0x44: if(mask & 0x00FF) { chan->fr[3] = (d >> 0) & 0x1F; }
if(mask & 0xFF00) { chan->fr[2] = (d >> 8) & 0x1F; }
break;
}
}
static void coef_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) {
sint16 old = state->coef[n];
yam_flush(state);
n &= 0x7F;
state->coef[n] <<= 3;
state->coef[n] &= ~mask;
state->coef[n] |= d & mask;
state->coef[n] = ((sint16)(state->coef[n])) >> 3;
#ifdef ENABLE_DYNAREC
if(old != state->coef[n]) { state->dsp_dyna_valid = 0; }
#endif
}
static void madrs_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) {
uint16 old = state->madrs[n];
yam_flush(state);
n &= 0x3F;
state->madrs[n] &= ~mask;
state->madrs[n] |= d & mask;
#ifdef ENABLE_DYNAREC
if(old != state->madrs[n]) { state->dsp_dyna_valid = 0; }
#endif
}
static uint32 temp_read(struct YAM_STATE *state, uint32 n) {
yam_flush(state);
if((n & 1) == 0) { return ((state->temp[(n/2)&0x7F]) >> 0) & 0x00FF; }
else { return ((state->temp[(n/2)&0x7F]) >> 8) & 0xFFFF; }
}
static void temp_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) {
yam_flush(state);
switch(n & 1) {
case 0: mask &= 0x00FF; break;
case 1: mask &= 0xFFFF; mask <<= 8; d <<= 8; break;
}
n /= 2; n &= 0x1F;
state->temp[n] &= ~mask;
state->temp[n] |= d & mask;
state->temp[n] <<= 8;
state->temp[n] >>= 8;
}
static uint32 mems_read(struct YAM_STATE *state, uint32 n) {
yam_flush(state);
if((n & 1) == 0) { return ((state->inputs[(n/2)&0x1F]) >> 0) & 0x00FF; }
else { return ((state->inputs[(n/2)&0x1F]) >> 8) & 0xFFFF; }
}
static void mems_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) {
yam_flush(state);
switch(n & 1) {
case 0: mask &= 0x00FF; break;
case 1: mask &= 0xFFFF; mask <<= 8; d <<= 8; break;
}
n /= 2; n &= 0x1F;
state->inputs[n] &= ~mask;
state->inputs[n] |= d & mask;
state->inputs[n] <<= 8;
state->inputs[n] >>= 8;
}
static uint32 mixs_read(struct YAM_STATE *state, uint32 n) {
yam_flush(state);
if((n & 1) == 0) { return ((state->inputs[0x20+((n/2)&0xF)]) >> 4) & 0x000F; }
else { return ((state->inputs[0x20+((n/2)&0xF)]) >> 8) & 0xFFFF; }
}
static uint32 efreg_read(struct YAM_STATE *state, uint32 n) {
yam_flush(state);
return ((uint32)(state->efreg[n & 0xF])) & 0xFFFF;
}
static void efreg_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) {
yam_flush(state);
state->efreg[n & 0xF] &= ~mask;
state->efreg[n & 0xF] |= d & mask;
}
static uint32 exts_read(struct YAM_STATE *state, uint32 n) {
yam_flush(state);
return (state->inputs[0x30 + (n & 1)] >> 8) & 0xFFFF;
}
static void exts_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) {
yam_flush(state);
state->inputs[0x30 + (n & 1)] >>= 8;
state->inputs[0x30 + (n & 1)] &= ~mask;
state->inputs[0x30 + (n & 1)] |= d & mask;
state->inputs[0x30 + (n & 1)] <<= 16;
state->inputs[0x30 + (n & 1)] >>= 8;
}
static uint32 dsp_scsp_load_reg(struct YAM_STATE *state, uint32 a) {
a &= 0xFFE;
if(a < 0x700) return 0;
if(a < 0x780) return state->coef[(a/2) & 0x3F] << 3;
if(a < 0x7C0) return state->madrs[(a/2) & 0x1F];
if(a < 0x800) return 0;
if(a < 0xC00) {
uint8 shift = ((a&6)^6) * 8;
uint32 index = ((a-0x800)/8)&0x7F;
return (mpro_scsp_read(state->mpro + index) >> shift) & 0xFFFF;
}
if(a < 0xE00) return temp_read(state, (a/2) & 0xFF);
if(a < 0xE80) return mems_read(state, (a/2) & 0x3F);
if(a < 0xEC0) return mixs_read(state, (a/2) & 0x1F);
if(a < 0xEE0) return efreg_read(state, (a/2) & 0xF);
if(a < 0xEE4) return exts_read(state, (a/2) & 1);
return 0;
}
static void dsp_scsp_store_reg(
struct YAM_STATE *state,
uint32 a, uint32 d, uint32 mask
) {
a &= 0xFFE;
if(a < 0x700) { return; }
if(a < 0x780) { coef_write(state, (a/2) & 0x3F, d, mask); return; }
if(a < 0x7C0) { madrs_write(state, (a/2) & 0x1F, d, mask); return; }
if(a < 0x800) { return; }
if(a < 0xC00) {
uint8 shift64 = ((a&6)^6) * 8;
uint32 index64 = ((a-0x800)/8)&0x7F;
uint64 mask64sh = ((uint64)(mask & 0xFFFF)) << shift64;
uint64 dm64sh = ((uint64)(d & mask & 0xFFFF)) << shift64;
uint64 oldvalue = mpro_scsp_read(state->mpro + index64);
uint64 newvalue = (oldvalue & (~mask64sh)) | dm64sh;
if(newvalue != oldvalue) {
yam_flush(state);
mpro_scsp_write(state->mpro + index64, newvalue);
#ifdef ENABLE_DYNAREC
state->dsp_dyna_valid = 0;
#endif
}
return;
}
if(a < 0xE00) { temp_write(state, (a/2) & 0xFF, d, mask); return; }
if(a < 0xE80) { mems_write(state, (a/2) & 0x3F, d, mask); return; }
if(a < 0xEC0) { return; }
if(a < 0xEE0) { efreg_write(state, (a/2) & 0xF, d, mask); return; }
if(a < 0xEE4) { exts_write(state, (a/2) & 1, d, mask); return; }
}
static uint32 dsp_aica_load_reg(struct YAM_STATE *state, uint32 a) {
a &= 0xFFFC;
if(a < 0x3000) return 0;
if(a < 0x3200) return state->coef[(a/4) & 0x7F] << 3;
if(a < 0x3300) return state->madrs[(a/4) & 0x3F];
if(a < 0x3400) return 0;
if(a < 0x3C00) {
uint8 shift64 = ((a&0xC)^0xC) * 4;
uint32 index64 = ((a-0x3400)/16)&0x7F;
return (mpro_aica_read(state->mpro + index64) >> shift64) & 0xFFFF;
}
if(a < 0x4000) return 0;
if(a < 0x4400) return temp_read(state, (a/4) & 0xFF);
if(a < 0x4500) return mems_read(state, (a/4) & 0x3F);
if(a < 0x4580) return mixs_read(state, (a/4) & 0x1F);
if(a < 0x45C0) return efreg_read(state, (a/4) & 0xF);
if(a < 0x45C8) return exts_read(state, (a/4) & 1);
return 0;
}
static void dsp_aica_store_reg(
struct YAM_STATE *state,
uint32 a, uint32 d, uint32 mask
) {
a &= 0xFFFC;
if(a < 0x3000) { return; }
if(a < 0x3200) { coef_write(state, (a/4) & 0x7F, d, mask); return; }
if(a < 0x3300) { madrs_write(state, (a/4) & 0x3F, d, mask); return; }
if(a < 0x3400) { return; }
if(a < 0x3C00) {
uint8 shift64 = ((a&0xC)^0xC) * 4;
uint32 index64 = ((a-0x3400)/16)&0x7F;
uint64 mask64sh = ((uint64)(mask & 0xFFFF)) << shift64;
uint64 dm64sh = ((uint64)(d & mask & 0xFFFF)) << shift64;
uint64 oldvalue = mpro_aica_read(state->mpro + index64);
uint64 newvalue = (oldvalue & (~mask64sh)) | dm64sh;
if(newvalue != oldvalue) {
yam_flush(state);
mpro_aica_write(state->mpro + index64, newvalue);
#ifdef ENABLE_DYNAREC
state->dsp_dyna_valid = 0;
#endif
}
return;
}
if(a < 0x4000) { return; }
if(a < 0x4400) { temp_write(state, (a/4) & 0xFF, d, mask); return; }
if(a < 0x4500) { mems_write(state, (a/4) & 0x3F, d, mask); return; }
if(a < 0x4580) { return; }
if(a < 0x45C0) { efreg_write(state, (a/4) & 0xF, d, mask); return; }
if(a < 0x45C8) { exts_write(state, (a/4) & 1, d, mask); return; }
}
#if defined(SCSP_LOG) && !defined(USE_STARSCREAM)
#include <stdio.h>
extern FILE * scsp_log;
extern unsigned char ** scsp_pc, ** scsp_basepc;
#endif
uint32 EMU_CALL yam_scsp_load_reg(void *state, uint32 a, uint32 mask) {
uint32 d = 0;
a &= 0xFFE;
if(a < 0x400) return chan_scsp_load_reg(YAMSTATE, a>>5, a&0x1E) & mask;
if(a >= 0x700) return dsp_scsp_load_reg(YAMSTATE, a) & mask;
if(a >= 0x600) return YAMSTATE->ringbuf[(YAMSTATE->bufptr-64+(a-0x600)/2)&(32*RINGMAX-1)] & mask;
switch(a) {
case 0x400: d = 0x0010; break; case 0x402: d = (((uint32)(YAMSTATE->rbl)) & 3) << 7;
d |= ((YAMSTATE->rbp >> 13) & 0x7F);
break;
case 0x404: d = (1<<11) | (1 << 8); break; case 0x406: d = 0; break; case 0x408: { int c = (YAMSTATE->mslc) & 0x1F;
int sgc, ca, eg;
struct YAM_CHAN * chan;
if(YAMSTATE->out_pending > 0) yam_flush(YAMSTATE);
chan = YAMSTATE->chan + c;
sgc = chan->EG.state & 3;
ca = ( chan->cur_addr >> (SHIFT + 12) ) & 0xf;
eg = ( 0x1f - ( chan->EG.volume >> (EG_SHIFT + 5) ) ) & 0x1f;
d = (c << 11) | (ca << 7) | (sgc << 5) | eg;
}
break;
case 0x412:
d = YAMSTATE->dmea & 0xFFFF;
break;
case 0x414:
d = (((uint32)(YAMSTATE->dmea)) & 0xF0000) >> 4;
d |= (((uint32)(YAMSTATE->drga)) & 0xFFE) << 0;
break;
case 0x416:
d = (((uint32)(YAMSTATE->dtlg)) & 0xFFE) << 0;
break;
case 0x418:
d = (((uint32)(YAMSTATE->tctl[0])) & 0x7) << 8;
d |= (((uint32)(YAMSTATE->tim[0])) & 0xFF) << 0;
break;
case 0x41A:
d = (((uint32)(YAMSTATE->tctl[1])) & 0x7) << 8;
d |= (((uint32)(YAMSTATE->tim[1])) & 0xFF) << 0;
break;
case 0x41C:
d = (((uint32)(YAMSTATE->tctl[2])) & 0x7) << 8;
d |= (((uint32)(YAMSTATE->tim[2])) & 0xFF) << 0;
break;
case 0x41E: d = YAMSTATE->scieb & 0x07FF; break;
case 0x420: d = YAMSTATE->scipd & 0x07FF; break;
case 0x424: d = YAMSTATE->scilv0 & 0xFF; break;
case 0x426: d = YAMSTATE->scilv1 & 0xFF; break;
case 0x428: d = YAMSTATE->scilv2 & 0xFF; break;
case 0x42A: d = YAMSTATE->mcieb & 0x07FF; break;
case 0x42C: d = YAMSTATE->mcipd & 0x07FF; break;
}
#if defined(SCSP_LOG) && !defined(USE_STARSCREAM)
fprintf(scsp_log, "%u - %08x r: %04x, %04x\n", YAMSTATE->odometer, (int)(*scsp_pc - *scsp_basepc), a, d);
#endif
return d & mask;
}
void EMU_CALL yam_scsp_store_reg(void *state, uint32 a, uint32 d, uint32 mask, uint8 *breakcpu) {
a &= 0xFFE;
d &= 0xFFFF & mask;
#if defined(SCSP_LOG) && !defined(USE_STARSCREAM)
fprintf(scsp_log, "%u - %08x w: %04x, %04x\n", YAMSTATE->odometer, (int)(*scsp_pc - *scsp_basepc), a, d);
#endif
mask &= 0xFFFF;
if(a < 0x400) { chan_scsp_store_reg(YAMSTATE, a>>5, a&0x1E, d, mask); return; }
if(a >= 0x700) { dsp_scsp_store_reg(YAMSTATE, a, d, mask); return; }
if(a >= 0x600) { uint32 offset = (YAMSTATE->bufptr-64+(a-0x600)/2)&(32*RINGMAX-1); YAMSTATE->ringbuf[offset] = (d & mask) | (YAMSTATE->ringbuf[offset] & ~mask); return; }
switch(a) {
case 0x400: yam_flush(YAMSTATE);
if(mask & 0x00FF) {
YAMSTATE->mvol = d & 0xF;
}
break;
case 0x402: { uint32 oldrbp = YAMSTATE->rbp;
uint8 oldrbl = YAMSTATE->rbl;
if(mask & 0x00FF) {
YAMSTATE->rbp = (((uint32)d) & 0x7F) << 13;
YAMSTATE->rbl &= 2;
YAMSTATE->rbl |= (d >> 7) & 1;
}
if(mask & 0xFF00) {
YAMSTATE->rbl &= 1;
YAMSTATE->rbl |= (d >> 7) & 2;
}
if((oldrbp != YAMSTATE->rbp) || (oldrbl != YAMSTATE->rbl)) {
uint32 newrbp = YAMSTATE->rbp;
uint8 newrbl = YAMSTATE->rbl;
YAMSTATE->rbp = oldrbp;
YAMSTATE->rbl = oldrbl;
yam_flush(YAMSTATE);
#ifdef ENABLE_DYNAREC
YAMSTATE->dsp_dyna_valid = 0;
#endif
YAMSTATE->rbp = newrbp;
YAMSTATE->rbl = newrbl;
}
}
break;
case 0x408: if(mask & 0xFF00) {
YAMSTATE->mslc = (d >> 11) & 0x1F;
}
break;
case 0x412: if(mask & 0x00FF) { YAMSTATE->dmea = (YAMSTATE->dmea & 0xFFF00) | (d & 0xFF); }
if(mask & 0xFF00) { YAMSTATE->dmea = (YAMSTATE->dmea & 0xF00FF) | (d & 0xFF00); }
break;
case 0x414:
if(mask & 0xFF) { YAMSTATE->drga = (YAMSTATE->drga & 0xF00) | (d & 0xFE); }
if(mask & 0xFF00) { YAMSTATE->drga = (YAMSTATE->drga & 0x0FF) | (d & 0xF00); YAMSTATE->dmea = (YAMSTATE->dmea & 0xFFFF) | ((d & 0xF000) << 4); }
break;
case 0x416:
if(mask & 0xFF) { YAMSTATE->dtlg = (YAMSTATE->dtlg & 0xF00) | (d & 0xFE); }
if(mask & 0xFF00) { YAMSTATE->dtlg = (YAMSTATE->dtlg & 0xFF) | (d & 0xF00); }
break;
case 0x418: if(mask & 0x00FF) { YAMSTATE->tim[0] = d & 0xFF; }
if(mask & 0xFF00) { YAMSTATE->tctl[0] = (d >> 8) & 7; }
if(breakcpu) *breakcpu = 1;
break;
case 0x41A: if(mask & 0x00FF) { YAMSTATE->tim[1] = d & 0xFF; }
if(mask & 0xFF00) { YAMSTATE->tctl[1] = (d >> 8) & 7; }
if(breakcpu) *breakcpu = 1;
break;
case 0x41C: if(mask & 0x00FF) { YAMSTATE->tim[2] = d & 0xFF; }
if(mask & 0xFF00) { YAMSTATE->tctl[2] = (d >> 8) & 7; }
if(breakcpu) *breakcpu = 1;
break;
case 0x41E: YAMSTATE->scieb = (((YAMSTATE->scieb) & (~mask)) | (d & mask)) & 0x7FF;
if(breakcpu) *breakcpu = 1;
break;
case 0x420: YAMSTATE->scipd = (((YAMSTATE->scipd) & (~mask)) | (d & mask)) & 0x7FF;
if(breakcpu) *breakcpu = 1;
break;
case 0x422: YAMSTATE->scipd &= ~(d & mask);
sci_recompute(YAMSTATE);
if(breakcpu) *breakcpu = 1;
break;
case 0x424: if(mask & 0x00FF) { YAMSTATE->scilv0 = d; }
break;
case 0x426: if(mask & 0x00FF) { YAMSTATE->scilv1 = d; }
break;
case 0x428: if(mask & 0x00FF) { YAMSTATE->scilv2 = d; }
break;
case 0x42A: YAMSTATE->mcieb = (((YAMSTATE->mcieb) & (~mask)) | (d & mask)) & 0x7FF;
break;
case 0x42C: YAMSTATE->mcipd = (((YAMSTATE->mcipd) & (~mask)) | (d & mask)) & 0x7FF;
break;
case 0x42E: YAMSTATE->mcipd &= ~(d & mask);
break;
}
}
uint32 EMU_CALL yam_aica_load_reg(void *state, uint32 a, uint32 mask) {
uint32 d = 0;
a &= 0xFFFC;
if(a < 0x2000) return chan_aica_load_reg(YAMSTATE, a>>7, a&0x7C) & mask;
if(a >= 0x3000) return dsp_aica_load_reg(YAMSTATE, a) & mask;
if(a < 0x2048) {
d =
((((uint32)(YAMSTATE->efsdl[(a - 0x2000) / 4])) & 0x0F) << 8) |
((((uint32)(YAMSTATE->efpan[(a - 0x2000) / 4])) & 0x1F) << 0);
return d & mask;
}
switch(a) {
case 0x2800: d = 0x0010; break; case 0x2804: d = (((uint32)(YAMSTATE->rbl)) & 3) << 13;
d |= ((YAMSTATE->rbp >> 11) & 0xFFF);
break;
case 0x2808: d = (1<<11) | (1 << 8); break; case 0x280C: d = 0; break; case 0x2810: if(YAMSTATE->out_pending > 0) yam_flush(YAMSTATE);
{ int c = (YAMSTATE->mslc) & 0x3F;
d = (((uint32)(YAMSTATE->chan[c].lp )) & 1) << 15;
if(YAMSTATE->afsel == 0) {
d |= (((uint32)(YAMSTATE->chan[c].EG.state)) & 3) << 13;
d |= (~YAMSTATE->chan[c].EG.volume >> (EG_SHIFT-3)) & 0x1FFF;
} else {
d |= (((uint32)(YAMSTATE->chan[c].lpfstate)) & 3) << 13;
d |= (YAMSTATE->chan[c].lpflevel) & 0x1FFF;
}
}
break;
case 0x2814: d = (YAMSTATE->chan[YAMSTATE->mslc].cur_addr)>>(SHIFT+12); break;
case 0x2880: d = YAMSTATE->mrwinh & 0xF; break;
case 0x2884: d = 0; break;
case 0x2888: d = 0; break;
case 0x288C: d = 0; break;
case 0x2890:
d = (((uint32)(YAMSTATE->tctl[0])) & 0x7) << 8;
d |= (((uint32)(YAMSTATE->tim[0])) & 0xFF) << 0;
break;
case 0x2894:
d = (((uint32)(YAMSTATE->tctl[1])) & 0x7) << 8;
d |= (((uint32)(YAMSTATE->tim[1])) & 0xFF) << 0;
break;
case 0x2898:
d = (((uint32)(YAMSTATE->tctl[2])) & 0x7) << 8;
d |= (((uint32)(YAMSTATE->tim[2])) & 0xFF) << 0;
break;
case 0x289C: d = YAMSTATE->scieb & 0x07FF; break;
case 0x28A0: d = YAMSTATE->scipd & 0x07FF; break;
case 0x28A4: d = 0; break;
case 0x28A8: d = YAMSTATE->scilv0 & 0xFF; break;
case 0x28AC: d = YAMSTATE->scilv1 & 0xFF; break;
case 0x28B0: d = YAMSTATE->scilv2 & 0xFF; break;
case 0x28B4: d = YAMSTATE->mcieb & 0x07FF; break;
case 0x28B8: d = YAMSTATE->mcipd & 0x07FF; break;
case 0x28BC: d = 0; break;
case 0x2C00: d = 0; break;
case 0x2D00: d = YAMSTATE->intreq & 7; break;
case 0x2D04: d = 0; break;
case 0x2E00: d = YAMSTATE->rtc >> 16; break;
case 0x2E04: d = YAMSTATE->rtc; break;
}
return d & mask;
}
void EMU_CALL yam_aica_store_reg(void *state, uint32 a, uint32 d, uint32 mask, uint8 *breakcpu) {
a &= 0xFFFC;
d &= 0xFFFF & mask;
if(a < 0x2000) { chan_aica_store_reg(YAMSTATE, a>>7, a&0x7C, d, mask); return; }
if(a >= 0x3000) { dsp_aica_store_reg(YAMSTATE, a, d, mask); return; }
if(a < 0x2048) {
if(mask & 0x00FF) { YAMSTATE->efpan[(a - 0x2000) / 4] = d & 0x1F; }
if(mask & 0xFF00) { YAMSTATE->efsdl[(a - 0x2000) / 4] = (d >> 8) & 0x0F; }
return;
}
switch(a) {
case 0x2800: yam_flush(YAMSTATE);
if(mask & 0x00FF) {
YAMSTATE->mvol = d & 0xF;
}
if(mask & 0xFF00) {
YAMSTATE->mono = (d >> 15) & 1;
}
break;
case 0x2804: { uint32 oldrbp = YAMSTATE->rbp;
uint8 oldrbl = YAMSTATE->rbl;
if(mask & 0x00FF) {
YAMSTATE->rbp >>= 11;
YAMSTATE->rbp &= 0xF00;
YAMSTATE->rbp |= d & 0x0FF;
YAMSTATE->rbp <<= 11;
}
if(mask & 0xFF00) {
YAMSTATE->rbp >>= 11;
YAMSTATE->rbp &= 0x0FF;
YAMSTATE->rbp |= d & 0xF00;
YAMSTATE->rbp <<= 11;
YAMSTATE->rbl = (d >> 13) & 3;
}
if((oldrbp != YAMSTATE->rbp) || (oldrbl != YAMSTATE->rbl)) {
uint32 newrbp = YAMSTATE->rbp;
uint8 newrbl = YAMSTATE->rbl;
YAMSTATE->rbp = oldrbp;
YAMSTATE->rbl = oldrbl;
yam_flush(YAMSTATE);
#ifdef ENABLE_DYNAREC
YAMSTATE->dsp_dyna_valid = 0;
#endif
YAMSTATE->rbp = newrbp;
YAMSTATE->rbl = newrbl;
}
}
break;
case 0x2808: break;
case 0x280C: if(mask & 0x00FF) {
}
if(mask & 0xFF00) {
YAMSTATE->mslc = (d >> 8) & 0x3F;
YAMSTATE->afsel = (d >> 14) & 1;
}
break;
case 0x2810: break; case 0x2814: break; case 0x2880: if(mask & 0x00FF) {
YAMSTATE->mrwinh = d & 0xF;
}
break;
case 0x2884: break; case 0x2888: break; case 0x288C: break; case 0x2890: if(mask & 0x00FF) { YAMSTATE->tim[0] = d & 0xFF; }
if(mask & 0xFF00) { YAMSTATE->tctl[0] = (d >> 8) & 7; }
if(breakcpu) *breakcpu = 1;
break;
case 0x2894: if(mask & 0x00FF) { YAMSTATE->tim[1] = d & 0xFF; }
if(mask & 0xFF00) { YAMSTATE->tctl[1] = (d >> 8) & 7; }
if(breakcpu) *breakcpu = 1;
break;
case 0x2898: if(mask & 0x00FF) { YAMSTATE->tim[2] = d & 0xFF; }
if(mask & 0xFF00) { YAMSTATE->tctl[2] = (d >> 8) & 7; }
if(breakcpu) *breakcpu = 1;
break;
case 0x289C: YAMSTATE->scieb = (((YAMSTATE->scieb) & (~mask)) | (d & mask)) & 0x7FF;
if(breakcpu) *breakcpu = 1;
break;
case 0x28A0: YAMSTATE->scipd = (((YAMSTATE->scipd) & (~mask)) | (d & mask)) & 0x7FF;
if(breakcpu) *breakcpu = 1;
break;
case 0x28A4: YAMSTATE->scipd &= ~(d & mask);
if(breakcpu) *breakcpu = 1;
break;
case 0x28A8: if(mask & 0x00FF) { YAMSTATE->scilv0 = d; }
break;
case 0x28AC: if(mask & 0x00FF) { YAMSTATE->scilv1 = d; }
break;
case 0x28B0: if(mask & 0x00FF) { YAMSTATE->scilv2 = d; }
break;
case 0x28B4: YAMSTATE->mcieb = (((YAMSTATE->mcieb) & (~mask)) | (d & mask)) & 0x7FF;
break;
case 0x28B8: YAMSTATE->mcipd = (((YAMSTATE->mcipd) & (~mask)) | (d & mask)) & 0x7FF;
break;
case 0x28BC: YAMSTATE->mcipd &= ~(d & mask);
break;
case 0x2C00: break;
case 0x2D00: break;
case 0x2D04: sci_recompute(YAMSTATE);
if(breakcpu) *breakcpu = 1;
break;
case 0x2E00: break;
case 0x2E04: break;
}
}
static uint32 yamrand16(struct YAM_STATE *state) {
state->randseed = 1103515245 * state->randseed + 12345;
return state->randseed >> 16;
}
static uint32 env_adjustrate(struct YAM_CHAN *chan, uint32 rate) {
sint32 effrate = rate * 2;
if(chan->krs < 0xF) {
effrate += (chan->fns >> 9) & 1;
effrate += chan->krs * 2;
effrate = (effrate - 8) + (chan->oct ^ 8);
}
if(effrate <= 0) return 0;
if(effrate >= 0x3C) return 0x3C;
return effrate;
}
static int env_needstep(uint32 effrate, uint32 odometer) {
uint32 shift;
uint32 pattern;
uint32 bitplace;
if(effrate <= 0x01) return 0;
if(effrate >= 0x30) return ((odometer & 1) == 0);
shift = 12 - ((effrate - 1) >> 2);
pattern = (effrate - 1) & 3;
if(odometer & ((1<<shift)-1)) return 0;
bitplace = (odometer >> shift) & 7;
return (0xFFFDDDD5 >> (pattern * 8 + bitplace)) & 1;
}
static sint32 AICA_UpdateSlot(struct YAM_STATE *state, struct YAM_CHAN *chan)
{
sint32 sample, fpart;
int cur_sample; int nxt_sample; int step=chan->step;
uint32 addr1,addr2,addr_select; uint32 *addr[2] = {&addr1, &addr2}; uint32 *slot_addr[2] = {&(chan->cur_addr), &(chan->nxt_addr)};
if(chan->ssctl!=0) return 0;
if(chan->plfos!=0) {
step=step*PLFO_Step(&(chan->PLFO));
step>>=SHIFT;
}
if(chan->pcms == 0) {
addr1=(chan->cur_addr>>(SHIFT-1))&state->ram_mask&~1;
addr2=(chan->nxt_addr>>(SHIFT-1))&state->ram_mask&~1;
}
else {
addr1=chan->cur_addr>>SHIFT;
addr2=chan->nxt_addr>>SHIFT;
}
if(state->version == 1 && (chan->mdl!=0 || chan->mdxsl!=0 || chan->mdysl!=0))
{
sint32 smp=(state->ringbuf[(state->bufptr-64+chan->mdxsl)&(32*RINGMAX-1)]+state->ringbuf[(state->bufptr-64+chan->mdysl)&(32*RINGMAX-1)])/2;
smp<<=0xA; smp>>=0x1A-chan->mdl; if(chan->pcms == 0) smp<<=1;
addr1+=smp; addr2+=smp;
}
if(chan->pcms == 1) {
sint8 *p1=(signed char *) (((uint8*)state->ram_ptr)+(((chan->sampleaddr+addr1)^state->mem_byte_address_xor)&state->ram_mask));
sint8 *p2=(signed char *) (((uint8*)state->ram_ptr)+(((chan->sampleaddr+addr2)^state->mem_byte_address_xor)&state->ram_mask));
cur_sample = (p1[0] << 8) ^ chan->sampler_invert;
nxt_sample = (p2[0] << 8) ^ chan->sampler_invert;
}
else if (chan->pcms == 0) {
sint16 *p1=(signed short *) (((uint8*)state->ram_ptr)+(((chan->sampleaddr+addr1)^state->mem_word_address_xor)&state->ram_mask&~1));
sint16 *p2=(signed short *) (((uint8*)state->ram_ptr)+(((chan->sampleaddr+addr2)^state->mem_word_address_xor)&state->ram_mask&~1));
cur_sample = p1[0] ^ chan->sampler_invert;
nxt_sample = p2[0] ^ chan->sampler_invert;
}
else {
uint32 adbase = chan->adbase;
uint8 *base;
uint32 steps_to_go = addr2, curstep = chan->curstep;
if(adbase) {
base = ((uint8*)state->ram_ptr);
cur_sample = chan->cur_sample;
while (curstep < steps_to_go) {
int shift1, delta1;
shift1 = 4*((curstep&1));
delta1 = (base[adbase]>>shift1)&0xf;
DecodeADPCM(&(chan->cur_sample),delta1,&(chan->cur_quant));
curstep++;
if (!(curstep & 1)) {
adbase = (adbase + 1) & state->ram_mask;
}
if (curstep == addr1)
cur_sample = chan->cur_sample;
}
nxt_sample = chan->cur_sample;
chan->adbase = adbase;
chan->curstep = curstep;
}
else {
cur_sample = nxt_sample = 0;
}
}
fpart = chan->cur_addr & ((1<<SHIFT)-1);
sample=cur_sample*((1<<SHIFT)-fpart)+nxt_sample*fpart;
sample>>=SHIFT;
chan->prv_addr=chan->cur_addr;
if(chan->Backwards)
chan->cur_addr-=step;
else
chan->cur_addr+=step;
chan->nxt_addr=chan->cur_addr+(1<<SHIFT);
addr1=chan->cur_addr>>SHIFT;
addr2=chan->nxt_addr>>SHIFT;
if(addr1>=chan->loopstart && !(chan->Backwards)) {
if(chan->link && chan->EG.state==ATTACK)
chan->EG.state = DECAY1;
}
for (addr_select=0;addr_select<2;addr_select++)
{
sint32 rem_addr;
switch(chan->sampler_looptype)
{
case 0: if(*addr[addr_select]>=chan->loopstart && *addr[addr_select]>=chan->loopend) {
keyoff(chan, 0);
}
break;
case 1: if(*addr[addr_select]>=chan->loopend) {
rem_addr = *slot_addr[addr_select] - (chan->loopend<<SHIFT);
*slot_addr[addr_select]=(chan->loopstart<<SHIFT) + rem_addr;
if(chan->pcms>=2) {
chan->adbase = (chan->sampleaddr+(chan->loopstart/2))&state->ram_mask;
chan->curstep = chan->loopstart;
if (chan->pcms == 2) {
chan->cur_sample = chan->cur_lpsample;
chan->cur_quant = chan->cur_lpquant;
}
}
}
break;
case 2: if((*addr[addr_select]>=chan->loopstart) && !(chan->Backwards)) {
rem_addr = *slot_addr[addr_select] - (chan->loopstart<<SHIFT);
*slot_addr[addr_select]=(chan->loopend<<SHIFT) - rem_addr;
chan->Backwards = 1;
}
else if((*addr[addr_select]<chan->loopstart || (*slot_addr[addr_select]&0x80000000)) && chan->Backwards) {
rem_addr = (chan->loopstart<<SHIFT) - *slot_addr[addr_select];
*slot_addr[addr_select]=(chan->loopend<<SHIFT) - rem_addr;
}
break;
case 3: if(*addr[addr_select]>=chan->loopend) {
rem_addr = *slot_addr[addr_select] - (chan->loopend<<SHIFT);
*slot_addr[addr_select]=(chan->loopend<<SHIFT) - rem_addr;
chan->Backwards = 1;
}
else if((*addr[addr_select]<chan->loopstart || (*slot_addr[addr_select]&0x80000000)) && chan->Backwards) {
rem_addr = (chan->loopstart<<SHIFT) - *slot_addr[addr_select];
*slot_addr[addr_select]=(chan->loopstart<<SHIFT) + rem_addr;
chan->Backwards = 0;
}
break;
}
}
if(chan->alfos!=0) {
sample=sample*ALFO_Step(&(chan->ALFO));
sample>>=SHIFT;
}
if(chan->EG.state==ATTACK)
sample=(sample*EG_Update(chan))>>SHIFT;
else
sample=(sample*EG_TABLE[EG_Update(chan)>>(SHIFT-10)])>>SHIFT;
if(state->version == 1 && !chan->stwinh)
{
unsigned short Enc = ((chan->tl)<<0x0)|(0x7<<0xd);
state->ringbuf[state->bufptr] = (sample * LPANTABLE_SCSP[Enc])>>(SHIFT+1);
}
return sample;
}
static uint32 generate_samples(
struct YAM_STATE *state,
struct YAM_CHAN *chan,
sint32 *buf,
uint32 odometer,
uint32 samples
) {
uint32 g;
uint32 bufptrsave = state->bufptr;
for(g = 0; g < samples; g++) {
if(chan->EG.volume <= 0) {
break;
}
if(buf) {
sint32 s = AICA_UpdateSlot(state, chan);
if(!(chan->lpoff)) {
uint32 fv = chan->lpflevel;
uint32 qv = chan->q & 0x1F;
sint32 f = (((fv & 0xFF) | 0x100) << 4) >> ((fv >> 8) ^ 0x1F);
sint32 q = qtable[qv];
s = f * s + (0x2000 - f + q) * (chan->lpp1) - q * (chan->lpp2);
s >>= 13;
chan->lpp2 = chan->lpp1;
chan->lpp1 = s;
}
buf[g] = s;
}
state->bufptr = (state->bufptr + 32) & (32*RINGMAX-1);
{ uint32 effectiverate = env_adjustrate(chan, chan->fr[chan->lpfstate]);
if(env_needstep(effectiverate, odometer)) {
uint32 d = envdecayvalue[effectiverate][odometer&3];
uint32 target = chan->flv[chan->lpfstate+1];
if(chan->lpflevel < target) {
uint32 maxd = target - chan->lpflevel;
if(d > maxd) { d = maxd; }
chan->lpflevel += d;
} else if(chan->lpflevel > target) {
uint32 maxd = chan->lpflevel - target;
if(d > maxd) { d = maxd; }
chan->lpflevel -= d;
} else {
if(chan->lpfstate < 3) { chan->lpfstate++; }
}
}
}
odometer++;
}
state->bufptr = bufptrsave;
return g;
}
static void render_and_add_channel(
struct YAM_STATE *state,
struct YAM_CHAN *chan,
sint32 *directout,
sint32 *fxout,
uint32 odometer,
uint32 samples
) {
uint32 i;
sint32 localbuf[RENDERMAX];
uint32 rendersamples;
if(chan->EG.volume <= 0) { return; }
if(!chan->disdl) { directout = NULL; }
if(!chan->dsplevel) { fxout = NULL; }
rendersamples = generate_samples(
state,
chan,
(directout || fxout || (state->version == 1 && !chan->stwinh)) ? localbuf : NULL,
odometer,
samples
);
if(directout) {
sint32 vol_l, vol_r;
convert_stereo_send_level(
chan->tl,
chan->disdl,
(state->mono) ? 0 : (chan->dipan),
&vol_l, &vol_r,
state->version
);
for(i = 0; i < rendersamples; i++) {
directout[0] += (localbuf[i]*vol_l) >> SHIFT;
directout[1] += (localbuf[i]*vol_r) >> SHIFT;
directout += 2;
}
}
if(fxout) {
sint32 vol_l, vol_r;
convert_stereo_send_level(
chan->tl,
chan->dsplevel,
0,
&vol_l, &vol_r,
state->version
);
for(i = 0; i < rendersamples; i++) {
fxout[0] += (localbuf[i]*vol_l) >> (SHIFT-2);
fxout += 16;
}
}
}
static uint32 __fastcall float16_to_int24(uint32 f) {
uint32 exponent = (f >> 11) & 0xF;
sint32 result;
result = (f & 0x8000) << 16; result >>= 1; if(exponent >= 12) { exponent = 11; } else { result ^= 0x40000000; } result |= (f & 0x7FF) << 19; result >>= exponent + 8; return result;
}
static uint32 __fastcall int24_to_float16(uint32 i) {
uint32 exponent = 0;
uint32 sign = i & 0x00800000;
if(sign) { i = ~i; }
i &= 0x7FFFFF;
if(i < 0x020000) { exponent += (6<<11); i <<= 6; }
if(i < 0x100000) { exponent += (3<<11); i <<= 3; }
if(i < 0x400000) { exponent += (1<<11); i <<= 1; }
if(i < 0x400000) { exponent += (1<<11); i <<= 1; }
if(i < 0x400000) { exponent += (1<<11); }
i >>= 11;
i &= 0x7FF;
i |= exponent;
if(sign) { i ^= 0x87FF; }
return i;
}
#define SINT32ATOFFSET(a,b) (*((sint32*)(((uint8*)(a))+(b))))
static void __fastcall dsp_sample_interpret(struct YAM_STATE *state) {
const struct MPRO *mpro = state->mpro;
uint32 i;
uint32 rbmask = (1 << ((state->rbl)+13)) - 1;
for(i = 0; i < 128; i++, mpro++) {
sint32 b, x, y, shifted;
if((mpro->__kisxzbon) & 0x80) {
x = state->temp[(state->mdec_ct)&0x7F];
state->xzbchoice[XZBCHOICE_ACC] =
((((sint64)x) * ((sint64)(state->yychoice[YYCHOICE_FRC_REG]))) >> 12) + x;
continue;
}
state->xzbchoice[XZBCHOICE_TEMP] = state->temp[((mpro->t_0rrrrrrr)+(state->mdec_ct))&0x7F];
state->yychoice[YYCHOICE_COEF] = state->coef[mpro->c_0rrrrrrr];
state->xzbchoice[XZBCHOICE_INPUTS] = state->inputs[mpro->i_00rrrrrr];
state->inputs[mpro->i_0T0wwwww] = state->mem_in_data[i & 3];
b = SINT32ATOFFSET(state->xzbchoice, (mpro->__kisxzbon) & 0x0C);
b ^= ((sint32)(mpro->negb));
b -= ((sint32)(mpro->negb));
x = SINT32ATOFFSET(state->xzbchoice, (mpro->__kisxzbon) & 0x10);
y = SINT32ATOFFSET(state->yychoice, (mpro->m_wrAFyyYh) & 0x0C);
if(mpro->m_wrAFyyYh & 2) {
sint32 inputs = state->xzbchoice[XZBCHOICE_INPUTS];
state->yychoice[YYCHOICE_Y_REG_H] = inputs >> 11;
state->yychoice[YYCHOICE_Y_REG_L] = (inputs >> 4) & 0xFFF;
}
shifted = state->xzbchoice[XZBCHOICE_ACC] << ((mpro->m_wrAFyyYh) & 1);
if((mpro->__kisxzbon) & 0x20) {
if(shifted > ( 0x7FFFFF)) { shifted = ( 0x7FFFFF); }
if(shifted < (-0x800000)) { shifted = (-0x800000); }
}
state->xzbchoice[XZBCHOICE_ACC] = ((((sint64)x) * ((sint64)y)) >> 12) + b;
if(mpro->t_Twwwwwww < 0x80) {
state->temp[((mpro->t_Twwwwwww)+(state->mdec_ct))&0x7F] = shifted;
}
if((mpro->m_wrAFyyYh) & 0x10) {
if((mpro->__kisxzbon) & 0x40) {
state->yychoice[YYCHOICE_FRC_REG] = shifted & 0xFFF;
} else {
state->yychoice[YYCHOICE_FRC_REG] = shifted >> 11;
}
}
if((mpro->m_wrAFyyYh) & 0xC0) {
sint32 tm = ((sint32)(mpro->tablemask));
uint32 a = state->madrs[mpro->m_00aaaaaa];
a += (state->adrs_reg) & ((sint32)(mpro->adrmask));
a += (mpro->__kisxzbon) & 1;
a += (state->mdec_ct) & (~tm);
a &= (rbmask | tm) & 0xFFFF;
a <<= 1;
a += state->rbp;
a &= (state->ram_mask);
a ^= state->mem_word_address_xor;
if(mpro->m_wrAFyyYh & 0x40) { sint32 memdata = *((sint16*)(((sint8*)(state->ram_ptr))+a));
if(!(mpro->__kisxzbon & 2)) { memdata = float16_to_int24(memdata); }
else { memdata <<= 8; }
state->mem_in_data[(i+2)&3] = memdata;
}
if(mpro->m_wrAFyyYh & 0x80) { sint32 memdata = shifted;
if(!(mpro->__kisxzbon & 2)) { memdata = int24_to_float16(memdata); }
else { memdata >>= 8; }
*((sint16*)(((sint8*)(state->ram_ptr))+a)) = memdata;
}
}
if((mpro->m_wrAFyyYh) & 0x20) {
if((mpro->__kisxzbon) & 0x40) {
state->adrs_reg = shifted >> 12;
} else {
state->adrs_reg = state->xzbchoice[XZBCHOICE_INPUTS] >> 16;
}
state->adrs_reg &= 0xFFF;
}
state->efreg[mpro->e_000Twwww] = shifted >> 8;
}
}
#define C(N) { *outp++ = ((uint8)(N)); }
#define C32(N) { *((uint32*)outp) = ((uint32)(N)); outp += 4; }
#define C32CALL(N) { *((uint32*)outp) = ((uint32)(N)) - (((uint32)(outp))+4); outp += 4; }
#define STRUCTOFS(thetype,thefield) ((uint32)(&(((struct thetype*)0)->thefield)))
#define STATEOFS(thefield) STRUCTOFS(YAM_STATE,thefield)
static int instruction_uses_shifted(struct MPRO *mpro) {
if((mpro->m_wrAFyyYh & 0x20) != 0) {
if((mpro->__kisxzbon & 0x40) != 0) return 1;
}
if((mpro->m_wrAFyyYh & 0x10) != 0) return 1;
if((mpro->e_000Twwww & 0x10) == 0) return 1;
if((mpro->t_Twwwwwww & 0x80) == 0) return 1;
if((mpro->m_wrAFyyYh & 0x80) != 0) return 1;
return 0;
}
#ifdef ENABLE_DYNAREC
static void dynacompile(struct YAM_STATE *state) {
uint32 rbmask = (1 << ((state->rbl)+13)) - 1;
uint8 *outp = state->dynacode;
int i;
char ins_uses_acc[129];
char ins_uses_shifted[129];
outp += DYNACODE_SLOP_SIZE;
memset(ins_uses_acc, 0, sizeof(ins_uses_acc));
memset(ins_uses_shifted, 0, sizeof(ins_uses_shifted));
ins_uses_acc[128] = 1;
ins_uses_shifted[128] = 1;
for(i = 0; i < 128; i++) {
struct MPRO *mpro = state->mpro + i;
ins_uses_shifted[i] = instruction_uses_shifted(mpro);
ins_uses_acc[i] =
(ins_uses_shifted[i]) ||
((mpro->__kisxzbon & 0x0C) == 0x04);
}
C(0x60) C(0x89) C(0xCF) C(0x8B) C(0xAF) C32(STATEOFS(mdec_ct)) C(0x8B) C(0xB7) C32(STATEOFS(xzbchoice[XZBCHOICE_ACC])) for(i = 0; i < 128; i++) {
struct MPRO *mpro = state->mpro + i;
if(ins_uses_acc[i + 1]) {
int need_tra =
((mpro->__kisxzbon & 0x10) == 0x00) ||
((mpro->__kisxzbon & 0x0C) == 0x00);
if(need_tra) {
C(0x8D) C(0x4D) C(mpro->t_0rrrrrrr) C(0x83) C(0xE1) C(0x7F) }
switch(mpro->m_wrAFyyYh & 0x0C) {
case 0x00: C(0x8B) C(0x87) C32(STATEOFS(yychoice[YYCHOICE_FRC_REG])) break;
case 0x04: { sint32 coef = state->coef[mpro->c_0rrrrrrr];
C(0xB8) C32(coef) }
break;
case 0x08: C(0x8B) C(0x87) C32(STATEOFS(yychoice[YYCHOICE_Y_REG_H])) break;
case 0x0C: C(0x8B) C(0x87) C32(STATEOFS(yychoice[YYCHOICE_Y_REG_L])) break;
}
if((mpro->__kisxzbon & 0x10) == 0) {
C(0xF7) C(0xAC) C(0x8F) C32(STATEOFS(temp)) } else {
C(0xF7) C(0xAF) C32(STATEOFS(inputs[mpro->i_00rrrrrr])) }
C(0x0F) C(0xAC) C(0xD0) C(0x0C) if((mpro->__kisxzbon & 0x08) == 0) {
if(mpro->negb == 0) {
if((mpro->__kisxzbon & 0x04) == 0) {
C(0x03) C(0x84) C(0x8F) C32(STATEOFS(temp)) } else {
C(0x01) C(0xF0) }
} else {
if((mpro->__kisxzbon & 0x04) == 0) {
C(0x2B) C(0x84) C(0x8F) C32(STATEOFS(temp)) } else {
C(0x29) C(0xF0) }
}
}
}
if(mpro->m_wrAFyyYh & 2) {
C(0x8B) C(0x97) C32(STATEOFS(inputs[mpro->i_00rrrrrr])) C(0xC1) C(0xFA) C(0x0B) C(0x89) C(0x97) C32(STATEOFS(yychoice[YYCHOICE_Y_REG_H])) C(0x8B) C(0x97) C32(STATEOFS(inputs[mpro->i_00rrrrrr])) C(0xC1) C(0xFA) C(0x04) C(0x81) C(0xE2) C32(0x00000FFF) C(0x89) C(0x97) C32(STATEOFS(yychoice[YYCHOICE_Y_REG_L])) }
if(ins_uses_shifted[i]) {
if((mpro->__kisxzbon & 0x20) == 0) { C(0x89) C(0xF2) C(0xC1) C(0xE2) C(8+(mpro->m_wrAFyyYh & 1)) C(0xC1) C(0xFA) C(0x08) } else { if((mpro->m_wrAFyyYh & 1) == 0) { C(0x8D) C(0x96) C32(0x00800000) C(0xF7) C(0xC2) C32(0xFF000000) C(0x89) C(0xF2) } else { C(0x8D) C(0x94) C(0x36) C32(0x00800000) C(0xF7) C(0xC2) C32(0xFF000000) C(0x8D) C(0x14) C(0x36) }
C(0x74) C(0x09) C(0xC1) C(0xFA) C(0x1F) C(0x81) C(0xF2) C32(0x007FFFFF) }
}
if(ins_uses_acc[i + 1]) {
C(0x89) C(0xC6) }
if(mpro->m_wrAFyyYh & 0x10) {
C(0x89) C(0xD0) if(mpro->__kisxzbon & 0x40) { C(0x25) C32(0x00000FFF) } else { C(0xC1) C(0xF8) C(0x0B) }
C(0x89) C(0x87) C32(STATEOFS(yychoice[YYCHOICE_FRC_REG])) }
if((mpro->t_Twwwwwww & 0x80) == 0) {
C(0x8D) C(0x4D) C(mpro->t_Twwwwwww) C(0x83) C(0xE1) C(0x7F) C(0x89) C(0x94) C(0x8F) C32(STATEOFS(temp)) }
if((mpro->e_000Twwww & 0x10) == 0) {
C(0x89) C(0xD0) C(0xC1) C(0xF8) C(0x08) C(0x89) C(0x87) C32(STATEOFS(efreg[mpro->e_000Twwww])) }
if((i & 1) && (mpro->m_wrAFyyYh & 0xC0)) {
uint32 madrsnx = state->madrs[mpro->m_00aaaaaa];
if(mpro->__kisxzbon & 1) { madrsnx++; }
madrsnx &= 0xFFFF;
if(mpro->tablemask == 0) {
C(0x8D) C(0x9D) C32(madrsnx) if(mpro->adrmask != 0) {
C(0x03) C(0x9F) C32(STATEOFS(adrs_reg)) }
C(0x81) C(0xE3) C32(rbmask) } else {
C(0xBB) C32(madrsnx) if(mpro->adrmask != 0) {
C(0x03) C(0x9F) C32(STATEOFS(adrs_reg)) C(0x81) C(0xE3) C32(0x0000FFFF) }
}
C(0x81) C(0xC3) C32(state->rbp / 2) C(0x81) C(0xE3) C32(state->ram_mask / 2) if((state->mem_word_address_xor / 2) != 0) {
C(0x83) C(0xF3) C(state->mem_word_address_xor / 2) }
}
if(mpro->m_wrAFyyYh & 0x20) {
if(mpro->__kisxzbon & 0x40) { C(0x89) C(0xD0) C(0xC1) C(0xF8) C(0x0C) } else {
C(0x8B) C(0x87) C32(STATEOFS(inputs[mpro->i_00rrrrrr])) C(0xC1) C(0xF8) C(0x10) }
C(0x25) C32(0x00000FFF) C(0x89) C(0x87) C32(STATEOFS(adrs_reg)) }
if((i & 1) && (mpro->m_wrAFyyYh & 0x40)) {
if((mpro->__kisxzbon & 0x02) == 0) { C(0x0F) C(0xBF) C(0x8C) C(0x1B) C32(state->ram_ptr) C(0xE8) C32CALL(float16_to_int24) } else { C(0x0F) C(0xBF) C(0x84) C(0x1B) C32(state->ram_ptr) C(0xC1) C(0xE0) C(0x08) }
C(0x89) C(0x87) C32(STATEOFS(mem_in_data[(i+2)&3])) } else if((i & 1) && (mpro->m_wrAFyyYh & 0x80)) {
if((mpro->__kisxzbon & 0x02) == 0) { C(0x89) C(0xD1) C(0xE8) C32CALL(int24_to_float16) C(0x66) C(0x89) C(0x84) C(0x1B) C32(state->ram_ptr) } else { C(0xC1) C(0xFA) C(0x08) C(0x66) C(0x89) C(0x94) C(0x1B) C32(state->ram_ptr) }
}
if((i&1) && ((mpro->i_0T0wwwww & 0x40) == 0)) {
C(0x8B) C(0x97) C32(STATEOFS(mem_in_data[i&3])) C(0x89) C(0x97) C32(STATEOFS(inputs[mpro->i_0T0wwwww])) }
}
C(0x89) C(0xB7) C32(STATEOFS(xzbchoice[XZBCHOICE_ACC])) C(0x61) C(0xC3) state->dsp_dyna_valid = 1;
}
#endif
typedef void (__fastcall *dsp_sample_t)(struct YAM_STATE *state);
static void render_effects(
struct YAM_STATE *state,
sint32 *fxbus,
sint32 *out,
uint32 samples
) {
dsp_sample_t samplefunc;
uint32 i, j;
sint32 efvol_l[16];
sint32 efvol_r[16];
#ifdef ENABLE_DYNAREC
if(state->dsp_dyna_enabled) {
if(!(state->dsp_dyna_valid)) {
dynacompile(state);
}
samplefunc = (dsp_sample_t)(((uint8*)(state->dynacode)) + DYNACODE_SLOP_SIZE);
#else
if (0) {
#endif
} else {
samplefunc = dsp_sample_interpret;
}
for(j = 0; j < 16; j++) {
convert_stereo_send_level(
0x00,
state->efsdl[j],
(state->mono) ? 0 : state->efpan[j],
efvol_l + j, efvol_r + j,
state->version
);
}
for(i = 0; i < samples; i++, fxbus += 16, out += 2) {
for(j = 0; j < 16; j++) {
sint32 t = fxbus[j];
if(t < (-0x80000)) t = (-0x80000);
if(t > ( 0x7FFFF)) t = ( 0x7FFFF);
state->inputs[0x20 + j] = t << 4;
}
samplefunc(state);
state->mdec_ct--;
for(j = 0; j < 16; j++) if(state->efsdl[j]) {
sint32 ef = (sint32)((sint16)(state->efreg[j]));
out[0] += (ef*efvol_l[j]) >> SHIFT;
out[1] += (ef*efvol_r[j]) >> SHIFT;
}
}
}
struct render_priority
{
sint32 channel_number;
sint32 priority_level;
};
int __cdecl render_priority_compare(void * a, void * b) {
struct render_priority *_a = (struct render_priority *) a;
struct render_priority *_b = (struct render_priority *) b;
return _b->priority_level - _a->priority_level;
}
static void render(struct YAM_STATE *state, uint32 odometer, uint32 samples) {
uint32 i, j;
struct render_priority priority_list[64];
sint32 outbuf[2*RENDERMAX];
sint32 fxbus[16*RENDERMAX];
sint32 *directout;
sint16 *buf;
uint32 nchannels;
uint32 bufptr_base;
int wantreverb = 0;
if(!samples) return;
buf = YAMSTATE->out_buf;
directout = (buf && (state->dry_out_enabled)) ? outbuf : NULL;
nchannels = ((YAMSTATE->version) == 1) ? 32 : 64;
if(buf && (state->dsp_emulation_enabled)) {
for(i = 0; i < 16; i++) { if(state->efsdl[i] != 0) break; }
wantreverb = (i < 16);
} else {
wantreverb = 0;
}
if(buf) {
memset(outbuf, 0, 4*2*samples);
if(wantreverb) memset(fxbus, 0, 4*16*samples);
}
for(i = 0; i < nchannels; i++) {
priority_list[i].channel_number = i;
priority_list[i].priority_level = 0;
}
if (state->version == 1) {
for(i = 0; i < nchannels; i++) {
struct YAM_CHAN *chan = state->chan + i;
sint32 priority_level = priority_list[i].priority_level + 1;
if (chan->mdxsl) priority_list[(i+chan->mdxsl)&31].priority_level = priority_level;
if (chan->mdysl) priority_list[(i+chan->mdysl)&31].priority_level = priority_level;
}
qsort(&priority_list, nchannels, sizeof(*priority_list), render_priority_compare);
}
bufptr_base = state->bufptr;
for(i = 0; i < nchannels; i++) {
struct YAM_CHAN *chan;
j = priority_list[i].channel_number;
chan = state->chan + j;
state->bufptr = bufptr_base + j;
render_and_add_channel(state, chan, directout,
wantreverb ? (fxbus + chan->dspchan) : NULL,
odometer, samples
);
}
state->bufptr = (bufptr_base + (32*samples)) & (32*RINGMAX-1);
if(wantreverb) { render_effects(state, fxbus, outbuf, samples); }
if(buf) {
sint32 vol_l, vol_r;
const sint32 shift = SHIFT + 3 + state->version;
convert_stereo_send_level(0x00, state->mvol, 0x00, &vol_l, &vol_r, 2);
for(i = 0; i < samples; i++) {
sint32 l = outbuf[2 * i + 0];
sint32 r = outbuf[2 * i + 1];
l *= vol_l; l >>= shift;
r *= vol_l; r >>= shift;
l = ICLIP16(l);
r = ICLIP16(r);
buf[2 * i + 0] = l;
buf[2 * i + 1] = r;
}
}
}
void EMU_CALL yam_flush(void *state) {
for(;;) {
uint32 n = YAMSTATE->out_pending;
if(n < 1) { break; }
if(n > RENDERMAX) { n = RENDERMAX; }
render(YAMSTATE, YAMSTATE->odometer - YAMSTATE->out_pending, n);
YAMSTATE->out_pending -= n;
if(YAMSTATE->out_buf) { YAMSTATE->out_buf += 2 * n; }
}
}
void EMU_CALL yam_prepare_dynacode(void *state) {
#ifdef ENABLE_DYNAREC
#ifdef _WIN32
DWORD i;
VirtualProtect( &YAMSTATE->dynacode, sizeof(YAMSTATE->dynacode), PAGE_EXECUTE_READWRITE, &i );
#elif defined(HAVE_MPROTECT)
unsigned long startaddr = &YAMSTATE->dynacode;
unsigned long length = sizeof(YAMSTATE->dynacode);
int psize = getpagesize();
unsigned long addr = ( startaddr & ~(psize - 1) );
mprotect( (char *) addr, length + startaddr - addr + psize, PROT_READ | PROT_WRITE | PROT_EXEC );
#endif
#endif
}
void EMU_CALL yam_unprepare_dynacode(void *state) {
#ifdef ENABLE_DYNAREC
#ifdef _WIN32
DWORD i;
VirtualProtect( &YAMSTATE->dynacode, sizeof(YAMSTATE->dynacode), PAGE_READWRITE, &i );
#elif defined(HAVE_MPROTECT)
unsigned long startaddr = &YAMSTATE->dynacode;
unsigned long length = sizeof(YAMSTATE->dynacode);
int psize = getpagesize();
unsigned long addr = ( startaddr & ~(psize - 1) );
mprotect( (char *) addr, length + startaddr - addr + psize, PROT_READ | PROT_WRITE );
#endif
#endif
}