Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 99 additions & 55 deletions emu/cores/vsu.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ typedef struct
UINT8 ModData[0x20];

INT32 EffFreq[6];
INT32 Envelope[6];
INT32 EnvelopeValue[6];
INT32 EnvelopeReload[6];

UINT8 WavePos[6];
UINT8 ModWavePos;
Expand All @@ -128,6 +129,10 @@ typedef struct
INT32 EnvelopeClockDivider[6];
INT32 SweepModClockDivider;

INT32 EnvelopeModMask[6];
INT32 ModState;
INT32 ModLock;

INT32 NoiseLatcherClockDivider;
UINT8 NoiseLatcher;

Expand Down Expand Up @@ -155,6 +160,8 @@ static void VSU_Power(vsu_state* chip)
chip->SweepControl = 0;
chip->SweepModCounter = 0;
chip->SweepModClockDivider = 1;
chip->ModState = 0;
chip->ModLock = 0;

for(ch = 0; ch < 6; ch++)
{
Expand All @@ -166,7 +173,9 @@ static void VSU_Power(vsu_state* chip)
chip->RAMAddress[ch] = 0;

chip->EffFreq[ch] = 0;
chip->Envelope[ch] = 0;
chip->EnvelopeReload[ch] = 0;
chip->EnvelopeValue[ch] = 0;
chip->EnvelopeModMask[ch] = 0;
chip->WavePos[ch] = 0;
chip->FreqCounter[ch] = 0;
chip->IntervalCounter[ch] = 0;
Expand Down Expand Up @@ -196,15 +205,25 @@ static void VSU_Write(void* info, UINT16 A, UINT8 V)
A <<= 2;
A &= 0x7FF;

chip->ModLock = 0;

//printf("VSU Write: %d, %08x %02x\n", timestamp, A, V);

if(A < 0x280)
chip->WaveData[A >> 7][(A >> 2) & 0x1F] = V & 0x3F;
{
bool cancel_write = false;
for(int i = 0; i < 6; i++)
if(chip->IntlControl[i] & 0x80)
cancel_write = true;
if(!cancel_write)
chip->WaveData[A >> 7][(A >> 2) & 0x1F] = V & 0x3F;
}
else if(A < 0x400)
{
//if(A >= 0x300)
// printf("Modulation mirror write? %08x %02x\n", A, V);
chip->ModData[(A >> 2) & 0x1F] = V;
if(!(chip->IntlControl[4] & 0x80))
chip->ModData[(A >> 2) & 0x1F] = V;
}
else if(A < 0x600)
{
Expand All @@ -231,7 +250,6 @@ static void VSU_Write(void* info, UINT16 A, UINT8 V)

if(V & 0x80)
{
chip->EffFreq[ch] = chip->Frequency[ch];
if(ch == 5)
chip->FreqCounter[ch] = 10 * (2048 - chip->EffFreq[ch]);
else
Expand All @@ -244,15 +262,21 @@ static void VSU_Write(void* info, UINT16 A, UINT8 V)
chip->SweepModCounter = (chip->SweepControl >> 4) & 7;
chip->SweepModClockDivider = (chip->SweepControl & 0x80) ? 8 : 1;
chip->ModWavePos = 0;
chip->ModState = 0;
}

chip->WavePos[ch] = 0;

if(ch == 5)
chip->lfsr = 1;

//if(!(chip->IntlControl[ch] & 0x80))
// chip->Envelope[ch] = (chip->EnvControl[ch] >> 4) & 0xF;
chip->EnvelopeModMask[ch] = 0;
if(!(chip->EnvControl[ch] & 0x200) && (
(chip->EnvelopeValue[ch] == 0 && !(chip->EnvControl[ch] & 0x0008)) ||
(chip->EnvelopeValue[ch] == 0xF && (chip->EnvControl[ch] & 0x0008))))
{
chip->EnvelopeModMask[ch] = 1;
}

chip->EffectsClockDivider[ch] = 4800;
chip->IntervalClockDivider[ch] = 4;
Expand All @@ -270,30 +294,48 @@ static void VSU_Write(void* info, UINT16 A, UINT8 V)
chip->Frequency[ch] |= V << 0;
chip->EffFreq[ch] &= 0xFF00;
chip->EffFreq[ch] |= V << 0;
chip->ModLock = 1;
break;

case 0x3:
chip->Frequency[ch] &= 0x00FF;
chip->Frequency[ch] |= (V & 0x7) << 8;
chip->EffFreq[ch] &= 0x00FF;
chip->EffFreq[ch] |= (V & 0x7) << 8;
chip->ModLock = 2;
break;

case 0x4:
chip->EnvControl[ch] &= 0xFF00;
chip->EnvControl[ch] |= V << 0;

chip->Envelope[ch] = (V >> 4) & 0xF;
chip->EnvelopeReload[ch] = (V >> 4) & 0xF;
chip->EnvelopeValue[ch] = (V >> 4) & 0xF;

if(chip->EnvelopeModMask[ch] == 1)
{
chip->EnvelopeModMask[ch] = 2;
}
break;

case 0x5:
chip->EnvControl[ch] &= 0x00FF;
if(ch == 4)
chip->EnvControl[ch] |= (V & 0x73) << 8;
else if(ch == 5)
{
chip->EnvControl[ch] |= (V & 0x73) << 8;
chip->lfsr = 1;
}
else
chip->EnvControl[ch] |= (V & 0x03) << 8;

if(chip->EnvelopeModMask[ch] == 0 && !(chip->EnvControl[ch] & 0x200) && (
(chip->EnvelopeValue[ch] == 0 && !(chip->EnvControl[ch] & 0x0008)) ||
(chip->EnvelopeValue[ch] == 0xF && (chip->EnvControl[ch] & 0x0008))))
{
chip->EnvelopeModMask[ch] = 1;
}
break;

case 0x6:
Expand Down Expand Up @@ -327,14 +369,14 @@ INLINE void VSU_CalcCurrentOutput(vsu_state* chip, int ch, DEV_SMPL* left, DEV_S
else
WD = chip->WaveData[chip->RAMAddress[ch]][chip->WavePos[ch]];
}
l_ol = chip->Envelope[ch] * chip->LeftLevel[ch];
l_ol = chip->EnvelopeValue[ch] * chip->LeftLevel[ch];
if(l_ol)
{
l_ol >>= 3;
l_ol += 1;
}

r_ol = chip->Envelope[ch] * chip->RightLevel[ch];
r_ol = chip->EnvelopeValue[ch] * chip->RightLevel[ch];
if(r_ol)
{
r_ol >>= 3;
Expand Down Expand Up @@ -396,7 +438,7 @@ static void VSU_Update(vsu_state* chip, UINT32 clocks, DEV_SMPL* outleft, DEV_SM
{
if(ch == 5)
{
int feedback = ((chip->lfsr >> 7) & 1) ^ ((chip->lfsr >> Tap_LUT[(chip->EnvControl[5] >> 12) & 0x7]) & 1);
int feedback = ((chip->lfsr >> 7) & 1) ^ ((chip->lfsr >> Tap_LUT[(chip->EnvControl[5] >> 12) & 0x7]) & 1) ^ 1;
chip->lfsr = ((chip->lfsr << 1) & 0x7FFF) | feedback;

chip->FreqCounter[ch] += 10 * (2048 - chip->EffFreq[ch]);
Expand Down Expand Up @@ -446,23 +488,27 @@ static void VSU_Update(vsu_state* chip, UINT32 clocks, DEV_SMPL* outleft, DEV_SM
{
chip->EnvelopeClockDivider[ch] += 4;

INT32 new_envelope = chip->EnvelopeValue[ch];
if(chip->EnvelopeValue[ch] < 0xF &&(chip->EnvControl[ch] & 0x0008))
new_envelope++;
else if(chip->EnvelopeValue[ch] > 0 && !(chip->EnvControl[ch] & 0x0008))
new_envelope--;
else if((chip->EnvControl[ch] & 0x200) && chip->EnvelopeModMask[ch] != 2)
{
new_envelope = chip->EnvelopeReload[ch];
chip->EnvelopeModMask[ch] = 0;
}
else if(chip->EnvelopeModMask[ch] == 0)
chip->EnvelopeModMask[ch] = 1;

if(chip->EnvControl[ch] & 0x0100) // Enveloping enabled?
{
chip->EnvelopeCounter[ch]--;
if(!chip->EnvelopeCounter[ch])
{
chip->EnvelopeCounter[ch] = (chip->EnvControl[ch] & 0x7) + 1;

if(chip->EnvControl[ch] & 0x0008) // Grow
{
if(chip->Envelope[ch] < 0xF || (chip->EnvControl[ch] & 0x200))
chip->Envelope[ch] = (chip->Envelope[ch] + 1) & 0xF;
}
else // Decay
{
if(chip->Envelope[ch] > 0 || (chip->EnvControl[ch] & 0x200))
chip->Envelope[ch] = (chip->Envelope[ch] - 1) & 0xF;
}
if(chip->EnvelopeModMask[ch] == 0)
chip->EnvelopeValue[ch] = new_envelope;
}
}

Expand All @@ -471,6 +517,18 @@ static void VSU_Update(vsu_state* chip, UINT32 clocks, DEV_SMPL* outleft, DEV_SM

if(ch == 4)
{
// Calculate sweep early
INT32 delta = chip->EffFreq[ch] >> (chip->SweepControl & 0x7);
INT32 NewSweepFreq = chip->EffFreq[ch] + ((chip->SweepControl & 0x8) ? delta : -delta);

if(!(chip->EnvControl[ch] & 0x1000))
{
if(NewSweepFreq < 0)
NewSweepFreq = 0;
else if(NewSweepFreq > 0x7FF)
chip->IntlControl[ch] &= ~0x80;
}

chip->SweepModClockDivider--;
while(chip->SweepModClockDivider <= 0)
{
Expand All @@ -487,41 +545,27 @@ static void VSU_Update(vsu_state* chip, UINT32 clocks, DEV_SMPL* outleft, DEV_SM

if(chip->EnvControl[ch] & 0x1000) // Modulation
{
if(chip->ModWavePos < 32 || (chip->EnvControl[ch] & 0x2000))
{
chip->ModWavePos &= 0x1F;

chip->EffFreq[ch] = (chip->EffFreq[ch] + (INT8)chip->ModData[chip->ModWavePos]);
if(chip->EffFreq[ch] < 0)
{
//puts("Underflow");
chip->EffFreq[ch] = 0;
}
else if(chip->EffFreq[ch] > 0x7FF)
{
//puts("Overflow");
chip->EffFreq[ch] = 0x7FF;
}
chip->ModWavePos++;
}
//puts("Mod");
if(chip->ModState == 0 || (chip->EnvControl[ch] & 0x2000))
chip->EffFreq[ch] = (chip->Frequency[ch] + (INT8)chip->ModData[chip->ModWavePos]) & 0x7FF;
if(chip->ModState == 1)
chip->ModState = 2;

// Hardware bug: writing to S5FQ* locks the relevant byte when modulating
if(chip->ModLock == 1)
chip->EffFreq[ch] = (chip->EffFreq[ch] & 0x700) | (chip->Frequency[ch] & 0xFF);
else if(chip->ModLock == 2)
chip->EffFreq[ch] = (chip->EffFreq[ch] & 0xFF) | (chip->Frequency[ch] & 0x700);
}
else // Sweep
else if(chip->ModState < 2) // Sweep
{
chip->EffFreq[ch] = NewSweepFreq;
}

if(++chip->ModWavePos >= 32)
{
INT32 delta = chip->EffFreq[ch] >> (chip->SweepControl & 0x7);
INT32 NewFreq = chip->EffFreq[ch] + ((chip->SweepControl & 0x8) ? delta : -delta);

//printf("Sweep(%d): Old: %d, New: %d\n", ch, EffFreq[ch], NewFreq);

if(NewFreq < 0)
chip->EffFreq[ch] = 0;
else if(NewFreq > 0x7FF)
{
//chip->EffFreq[ch] = 0x7FF;
chip->IntlControl[ch] &= ~0x80;
}
else
chip->EffFreq[ch] = NewFreq;
if(chip->ModState == 0)
chip->ModState = 1;
chip->ModWavePos = 0;
}
}
}
Expand Down
Loading