From ee27ce78284323d75a279804e0aab0194f6eff37 Mon Sep 17 00:00:00 2001 From: saxxonpike Date: Thu, 8 Nov 2012 00:09:20 +0000 Subject: [PATCH] commodore64: added SID waveform generators (no sound output yet) --- .../Computers/Commodore64/Sid.cs | 195 +++++++++++++++++- .../Computers/Commodore64/VicII.cs | 6 +- 2 files changed, 190 insertions(+), 11 deletions(-) diff --git a/BizHawk.Emulation/Computers/Commodore64/Sid.cs b/BizHawk.Emulation/Computers/Commodore64/Sid.cs index dea6d750e2..a9009bbe05 100644 --- a/BizHawk.Emulation/Computers/Commodore64/Sid.cs +++ b/BizHawk.Emulation/Computers/Commodore64/Sid.cs @@ -5,6 +5,14 @@ using System.Text; namespace BizHawk.Emulation.Computers.Commodore64 { + public enum SidEnvelopeState + { + Disabled, + Attack, + Decay, + Release + } + public enum SidMode { Sid6581, @@ -17,7 +25,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 public bool BP; public bool D3; public int[] DCY = new int[3]; - public int ENV3; + public int[] ENV = new int[3]; public int[] F = new int[3]; public int FC; public bool[] FILT = new bool[3]; @@ -26,7 +34,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 public bool HP; public bool LP; public bool[] NOISE = new bool[3]; - public int OSC3; + public int[] OSC = new int[3]; public int POTX; public int POTY; public int[] PW = new int[3]; @@ -34,6 +42,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 public int[] RLS = new int[3]; public bool[] RMOD = new bool[3]; public bool[] SAW = new bool[3]; + public int[] SR = new int[3]; public bool[] SQU = new bool[3]; public int[] STN = new int[3]; public bool[] SYNC = new bool[3]; @@ -44,6 +53,9 @@ namespace BizHawk.Emulation.Computers.Commodore64 public SidRegs() { // power on state + SR[0] = 0x7FFFFF; + SR[1] = 0x7FFFFF; + SR[2] = 0x7FFFFF; } public byte this[int addr] @@ -131,10 +143,10 @@ namespace BizHawk.Emulation.Computers.Commodore64 result = POTY; break; case 0x1B: - result = OSC3; + result = OSC[2] >> 4; break; case 0x1C: - result = ENV3; + result = ENV[2]; break; default: result = 0; @@ -234,10 +246,10 @@ namespace BizHawk.Emulation.Computers.Commodore64 POTY = val; break; case 0x1B: - OSC3 = val; + OSC[2] = val << 4; break; case 0x1C: - ENV3 = val; + ENV[2] = val; break; } } @@ -247,12 +259,28 @@ namespace BizHawk.Emulation.Computers.Commodore64 public class Sid { + private int[] envRateIndex = { + 9, 32, 63, 95, + 149, 220, 267, 313, + 392, 977, 1954, 3126, + 3907, 11720, 19532, 31251 + }; + + private int[] syncIndex = { 2, 0, 1 }; + public Func ReadPotX; public Func ReadPotY; + public int clock; + public bool[] envEnable = new bool[3]; + public int[] envExpCounter = new int[3]; + public int[] envRate = new int[3]; + public int[] envRateCounter = new int[3]; + public SidEnvelopeState[] envState = new SidEnvelopeState[3]; + public bool[] gateLastCycle = new bool[3]; public int output; - public int potCycle; public SidRegs regs; + public int[] waveClock = new int[3]; public Sid() { @@ -273,13 +301,144 @@ namespace BizHawk.Emulation.Computers.Commodore64 public void PerformCycle() { - output = 0; - if (potCycle == 0) + // accumulator is 24 bits + clock = (clock + 1) & 0xFFFFFF; + + ProcessVoice(0); + ProcessVoice(1); + ProcessVoice(2); + + // query pots every 512 cycles + if ((clock & 0x1FF) == 0x000) { regs.POTX = ReadPotX() & 0xFF; regs.POTY = ReadPotY() & 0xFF; } - potCycle = (potCycle + 1) & 0x1FF; + } + + private void ProcessEnvelope(int index) + { + // envelope counter is 15 bits + envRateCounter[index] &= 0x7FFF; + + if (!gateLastCycle[index] && regs.GATE[index]) + { + envState[index] = SidEnvelopeState.Attack; + envEnable[index] = true; + } + else if (gateLastCycle[index] && !regs.GATE[index]) + { + envState[index] = SidEnvelopeState.Release; + } + + if (envRateCounter[index] == envRate[index]) + { + envExpCounter[index] = 0; + if (envEnable[index]) + { + + } + } + + gateLastCycle[index] = regs.GATE[index]; + } + + private void ProcessShiftRegister(int index) + { + int newBit = ((regs.SR[index] >> 22) ^ (regs.SR[index] >> 17)) & 0x1; + regs.SR[index] = ((regs.SR[index] << 1) | newBit) & 0x7FFFFF; + } + + private void ProcessVoice(int index) + { + int triOutput; + int sawOutput; + int squOutput; + int noiseOutput; + int finalOutput = 0xFFFFFF; + bool outputEnabled = false; + + // triangle waveform + if (regs.TRI[index]) + { + triOutput = waveClock[index] >> 12; + if (regs.SYNC[index]) + triOutput ^= regs.OSC[syncIndex[index]] & 0x800; + + if ((triOutput & 0x800) != 0x000) + triOutput &= 0xFFF; + + triOutput <<= 1; + finalOutput &= triOutput; + outputEnabled = true; + } + + // saw waveform + if (regs.SAW[index]) + { + sawOutput = waveClock[index] >> 12; + finalOutput &= sawOutput; + outputEnabled = true; + } + + // square waveform + if (regs.SQU[index]) + { + if (regs.TEST[index]) + { + squOutput = 0xFFF; + } + else + { + if (regs.PW[index] >= (waveClock[index] >> 12)) + squOutput = 0xFFF; + else + squOutput = 0x000; + } + finalOutput &= squOutput; + outputEnabled = true; + } + + // noise waveform + if (regs.NOISE[index]) + { + int sr = regs.SR[index]; + noiseOutput = sr & 0x100000 >> 9; + noiseOutput |= sr & 0x040000 >> 8; + noiseOutput |= sr & 0x004000 >> 5; + noiseOutput |= sr & 0x000800 >> 3; + noiseOutput |= sr & 0x000200 >> 2; + noiseOutput |= sr & 0x000020 << 1; + noiseOutput |= sr & 0x000004 << 3; + noiseOutput |= sr & 0x000001 << 4; + finalOutput &= noiseOutput; + outputEnabled = true; + } + + // test bit resets the oscillator and silences output + if (regs.TEST[index]) + { + waveClock[index] = 0x000000; + outputEnabled = false; + } + else + { + // shift register for generating noise + if ((waveClock[index] & 0x7FFFF) == 0x00000) + ProcessShiftRegister(index); + + // increment wave clock + waveClock[index] = (waveClock[index] + regs.F[index]) & 0xFFFFFF; + } + + // process the envelope generator + //ProcessEnvelope(index); + + // write to internal reg + if (outputEnabled) + regs.OSC[index] = finalOutput; + else + regs.OSC[index] = 0x000000; } public byte Read(ushort addr) @@ -298,6 +457,22 @@ namespace BizHawk.Emulation.Computers.Commodore64 } } + private void UpdateEnvelopeRateCounter(int index) + { + switch (envState[index]) + { + case SidEnvelopeState.Attack: + envRate[index] = envRateIndex[regs.ATK[index]]; + break; + case SidEnvelopeState.Decay: + envRate[index] = envRateIndex[regs.DCY[index]]; + break; + case SidEnvelopeState.Release: + envRate[index] = envRateIndex[regs.RLS[index]]; + break; + } + } + public void Write(ushort addr, byte val) { addr &= 0x1F; diff --git a/BizHawk.Emulation/Computers/Commodore64/VicII.cs b/BizHawk.Emulation/Computers/Commodore64/VicII.cs index d7c1a9dcc4..220930243b 100644 --- a/BizHawk.Emulation/Computers/Commodore64/VicII.cs +++ b/BizHawk.Emulation/Computers/Commodore64/VicII.cs @@ -827,7 +827,11 @@ namespace BizHawk.Emulation.Computers.Commodore64 if (!idle && cycle >= 16 && cycle < 56) { // todo: implement XSCROLL properly - if (regs.XSCROLL == (rasterOffsetX & 0x7)) + // comparing to (rasterOffsetX & 0x7) seems to align + // properly but smooth scrolling is not possible + // comparing to i works but then the screen + // is not aligned anymore... + if (regs.XSCROLL == i) { characterColumn = 0; characterData = characterMemory[regs.VMLI];