Ejemplo n.º 1
0
 SetupSpritePalletes(DisplayDefinition disDef, Memory memory, MMR pallete)
 {
     if (pallete == MMR.OBP0)
     {
         byte obp0 = memory.LowLevelRead((ushort)MMR.OBP0);
         disDef.SpritePallete0[0] = 0x00000000; // Sprite colors are trasparent
         for (int color = 1; color < 4; ++color)
         {
             int down  = (obp0 >> (2 * color)) & 1;
             int up    = (obp0 >> (2 * color + 1)) & 1;
             int index = (up << 1) | down;
             disDef.SpritePallete0[color] = disDef.SpriteColors[index];
         }
     }
     else if (pallete == MMR.OBP1)
     {
         byte obp1 = memory.LowLevelRead((ushort)MMR.OBP1);
         disDef.SpritePallete1[1] = 0x00000000; // Sprite colors are trasparent
         for (int color = 1; color < 4; ++color)
         {
             int down  = (obp1 >> (2 * color)) & 1;
             int up    = (obp1 >> (2 * color + 1)) & 1;
             int index = (up << 1) | down;
             disDef.SpritePallete1[color] = disDef.SpriteColors[index];
         }
     }
     else
     {
         throw new InvalidProgramException("Invalid pallete register given");
     }
 }
Ejemplo n.º 2
0
        public void GetMeetsWithVenueName()
        {
            //Setup
            var listOfMeets = new List <Meet>
            {
                new Meet()
                {
                    MeetDate   = DateTime.Now,
                    MeetName   = "Test Meet 1",
                    MeetId     = 1,
                    MeetVenue  = "Test Venue 1",
                    PoolLength = "11"
                },
                new Meet()
                {
                    MeetDate   = DateTime.Now,
                    MeetName   = "Test Meet 2",
                    MeetId     = 2,
                    MeetVenue  = "Test Venue 1",
                    PoolLength = "21"
                }
            };
            var mockMeetsRepo = new Mock <IMeetRepo>();

            mockMeetsRepo.Setup(MMR => MMR.GetMeets("Test Venue 1")).Returns(listOfMeets);
            var sut = new MeetsController(mockMeetsRepo.Object);

            //Action
            var res = sut.GetMeets("Test Venue 1");

            //Assert
            res.Should().BeOfType <OkNegotiatedContentResult <List <Meet> > >();
            res.As <OkNegotiatedContentResult <List <Meet> > >().Content.Should().BeEquivalentTo(listOfMeets);
        }
Ejemplo n.º 3
0
        public void GetMeetsFormattedByStartAndEndDateReturnsMeetsWithinStartAndEndDate()
        {
            //Setup
            var listOfMeets = new List <Meet>
            {
                new Meet()
                {
                    MeetDate   = new DateTime(2019, 04, 14),
                    MeetName   = "Test Meet 1",
                    MeetId     = 1,
                    MeetVenue  = "Test Venue 1",
                    PoolLength = "11"
                },
                new Meet()
                {
                    MeetDate   = new DateTime(2019, 04, 13),
                    MeetName   = "Test Meet 2",
                    MeetId     = 2,
                    MeetVenue  = "Test Venue 1",
                    PoolLength = "21"
                }
            };
            var mockMeetsRepo = new Mock <IMeetRepo>();

            mockMeetsRepo.Setup(MMR => MMR.GetMeets(new DateTime(2019, 04, 12), new DateTime(2019, 04, 15))).Returns(listOfMeets);
            var sut = new MeetsController(mockMeetsRepo.Object);

            //Action
            var res = sut.GetMeetsFormatted(new DateTime(2019, 04, 12), new DateTime(2019, 04, 15));

            //Assert
            res.Should().BeOfType <OkNegotiatedContentResult <List <string> > >();
            res.As <OkNegotiatedContentResult <List <string> > >().Content.Should().BeEquivalentTo(FormatMeets(listOfMeets));
        }
Ejemplo n.º 4
0
        internal void HandleMemoryChange(MMR mappedRegister, byte value)
        {
            switch (mappedRegister)
            {
            case MMR.LCDC:
                // We set all the LCDC bits
                for (int i = 0; i < 8; ++i)
                {
                    _state.LCDCBits[i] = (value & (1 << i)) != 0;
                }
                break;

            case MMR.STAT:
                _state.STAT = value;
                break;

            case MMR.SCY:
                _state.SCY = value;
                break;

            case MMR.SCX:
                _state.SCX = value;
                break;

            case MMR.LY:
                _state.CurrentLine = 0;
                break;

            case MMR.LYC:
                _state.LYC = value;
                break;

            case MMR.DMA:
                LoadSprites();
                break;

            case MMR.BGP:
                DisFuncs.SetupTilePallete(_disDef, _memory);
                break;

            case MMR.OBP0:
                DisFuncs.SetupSpritePalletes(_disDef, _memory, MMR.OBP0);
                break;

            case MMR.OBP1:
                DisFuncs.SetupSpritePalletes(_disDef, _memory, MMR.OBP1);
                break;

            case MMR.WY:
                _state.WY = value;
                break;

            case MMR.WX:
                _state.WX = value;
                break;

            default:
                throw new InvalidProgramException("All cases should be handled...");
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Creates a DiscordEmbed to represent the profile
        /// </summary>
        /// <returns></returns>
        public DiscordEmbed CreateEmbed()
        {
            var main = TopOperators.FirstOrDefault();

            StringBuilder desc = new StringBuilder();

            desc.AppendLine($"**Level {Level}**");
            desc.AppendLine($"**{main.Key} Main**");

            DiscordEmbedBuilder builder = new DiscordEmbedBuilder();

            builder.WithAuthor(this.Name, this.URL, this.Avatar).WithDescription(desc.ToString());

            if (Rank != Rank.Unranked)
            {
                builder.WithColor(Rank.GetColor())
                .AddField("MMR", MMR.ToString(), true).AddField("Best", BestMMR.ToString(), true).AddField("Rank", RankText, true);
            }

            builder.AddField("=== Casual Time", CasualStatistics.TimePlayed)
            .AddField("Kills", CasualStatistics.Kills.ToString(), true).AddField("Deaths", CasualStatistics.Deaths.ToString(), true).AddField("KD", CasualStatistics.KD.ToString("F2"), true)
            .AddField("Wins", CasualStatistics.Wins.ToString(), true).AddField("Loss", CasualStatistics.Losses.ToString(), true).AddField("Win%", CasualStatistics.WinPercent.ToString("F2"), true)
            .WithThumbnailUrl(main.Value);

            if (Rank != Rank.Unranked)
            {
                builder.AddField("=== Ranked Time", RankedStatistics.TimePlayed)
                .AddField("Kills", RankedStatistics.Kills.ToString(), true).AddField("Deaths", RankedStatistics.Deaths.ToString(), true).AddField("KD", RankedStatistics.KD.ToString("F2"), true)
                .AddField("Wins", RankedStatistics.Wins.ToString(), true).AddField("Loss", RankedStatistics.Losses.ToString(), true).AddField("Win%", RankedStatistics.WinPercent.ToString("F2"), true);
            }

            return(builder.Build());
        }
Ejemplo n.º 6
0
        internal void HandleMemoryChange(MMR register, byte value)
        {
            switch (register)
            {
            case MMR.TIMA:
                _state.TimaCounter = value;
                this._memory.LowLevelWrite((ushort)MMR.TIMA, value);
                break;

            case MMR.TMA:
                _state.TmaValue = value;
                this._memory.LowLevelWrite((ushort)MMR.TMA, value);
                break;

            case MMR.TAC:
                // Clock select is the bits 0 and 1 of the TAC register
                byte clockSelect = (byte)(value & 0x03);
                switch (clockSelect)
                {
                case 1:
                    _state.TacMask = 0x000F;         // f/2^4  0000 0000 0000 1111, (262144 Hz)
                    break;

                case 2:
                    _state.TacMask = 0x003F;         // f/2^6  0000 0000 0011 1111, (65536 Hz)
                    break;

                case 3:
                    _state.TacMask = 0x00FF;         // f/2^8  0000 0000 1111 1111, (16384 Hz)
                    break;

                default:
                    _state.TacMask = 0x03FF;         // f/2^10 0000 0011 1111 1111, (4096 Hz)
                    break;
                }
                // We restart the counter
                _state.TacCounter = 0;
                // TAC has a 0xF8 mask (only lower 3 bits are useful)
                this._memory.LowLevelWrite((ushort)MMR.TAC, (byte)(0xF8 | value));
                break;
            }
        }
Ejemplo n.º 7
0
        public void UpdateMeetValidMeetAndDbSuccessfulReturnsOk()
        {
            //Setup
            var mockMeetsRepo = new Mock <IMeetRepo>();
            var meet          = new Meet()
            {
                MeetDate   = new DateTime(),
                MeetName   = "Test Meet",
                MeetId     = 1,
                MeetVenue  = "Test Venue",
                PoolLength = "11"
            };

            mockMeetsRepo.Setup(MMR => MMR.UpdateMeet(meet)).Returns(true);
            var sut = new MeetsController(mockMeetsRepo.Object);

            //Action
            var res = sut.UpdateMeet(meet);

            //Assert
            res.Should().BeOfType <OkResult>();
        }
Ejemplo n.º 8
0
        public void UpdateMeetValidMeetAndDbUnSuccessfulReturnsBadRequest()
        {
            //Setup
            var mockMeetsRepo = new Mock <IMeetRepo>();
            var meet          = new Meet()
            {
                MeetDate   = new DateTime(),
                MeetName   = "Test Meet",
                MeetId     = 1,
                MeetVenue  = "Test Venue",
                PoolLength = "11"
            };

            mockMeetsRepo.Setup(MMR => MMR.UpdateMeet(meet)).Returns(false);
            var sut = new MeetsController(mockMeetsRepo.Object);

            //Action
            var res = sut.UpdateMeet(meet);

            //Assert
            res.Should().BeOfType <BadRequestErrorMessageResult>();
            res.As <BadRequestErrorMessageResult>().Message.Should().Be("Meet failed to be updated");
        }
Ejemplo n.º 9
0
        internal SquareChannel(Memory memory, FrameSequencer frameSequencer,
                               int sampleRate, int numChannels, int sampleSize, int channelIndex,
                               MMR sweepRegister, MMR wavePatternDutyRegister, MMR volumeEnvelopeRegister,
                               MMR freqLowRegister, MMR freqHighRegister)
        {
            _memory         = memory;
            _frameSequencer = frameSequencer;

            SampleRate    = sampleRate;
            _msSampleRate = SampleRate / 1000;
            NumChannels   = numChannels;
            SampleSize    = sampleSize;
            _buffer       = new short[SampleRate * NumChannels * SampleSize * _milliseconds / 1000];

            _channelIndex    = channelIndex;
            _soundEventQueue = new SoundEventQueue(1000);

            // Register setup
            _sweepRegister           = sweepRegister;
            _wavePatternDutyRegister = wavePatternDutyRegister;
            _volumeEnvelopeRegister  = volumeEnvelopeRegister;
            _freqLowRegister         = freqLowRegister;
            _freqHighRegister        = freqHighRegister;
        }
Ejemplo n.º 10
0
        internal SquareChannel(Memory memory, FrameSequencer frameSequencer,
                           int sampleRate, int numChannels, int sampleSize, int channelIndex,
                           MMR sweepRegister, MMR wavePatternDutyRegister, MMR volumeEnvelopeRegister,
                           MMR freqLowRegister, MMR freqHighRegister)
        {
            _memory = memory;
              _frameSequencer = frameSequencer;

              SampleRate = sampleRate;
              _msSampleRate = SampleRate / 1000;
              NumChannels = numChannels;
              SampleSize = sampleSize;
              _buffer = new short[SampleRate * NumChannels * SampleSize * _milliseconds / 1000];

              _channelIndex = channelIndex;
              _soundEventQueue = new SoundEventQueue(1000);

              // Register setup
              _sweepRegister = sweepRegister;
              _wavePatternDutyRegister = wavePatternDutyRegister;
              _volumeEnvelopeRegister = volumeEnvelopeRegister;
              _freqLowRegister = freqLowRegister;
              _freqHighRegister = freqHighRegister;
        }
Ejemplo n.º 11
0
        internal void HandleMemoryChange(MMR register, byte value, bool updatedEnabledFlag = true)
        {
            if (!_state.Enabled)
              {
            // When powered off, the internal length can be changed (DMG only)
            switch (register)
            {
              case MMR.NR11:
            _channel1.ChangeLength(value);
            break;
              case MMR.NR21:
            _channel2.ChangeLength(value);
            break;
              case MMR.NR31:
            _channel3.ChangeLength(value);
            break;
              case MMR.NR41:
            _channel4.ChangeLength(value);
            break;
            }

            // Other than turning on, all other writes are ignored
            if (register != MMR.NR52) { return; }
              }

              // We store previous channel status
              bool channel1Enabled = _channel1.Enabled;
              bool channel2Enabled = _channel2.Enabled;
              bool channel3Enabled = _channel3.Enabled;
              bool channel4Enabled = _channel4.Enabled;
              bool prevEnabled = _state.Enabled;

              switch (register)
              {
            case MMR.NR10:
            case MMR.NR11:
            case MMR.NR12:
            case MMR.NR13:
            case MMR.NR14:
              _channel1.HandleMemoryChange(register, value);
              break;
            case MMR.NR21:
            case MMR.NR22:
            case MMR.NR23:
            case MMR.NR24:
              _channel2.HandleMemoryChange(register, value);
              break;
            case MMR.NR30:
            case MMR.NR31:
            case MMR.NR32:
            case MMR.NR33:
            case MMR.NR34:
              _channel3.HandleMemoryChange(register, value);
              break;
            case MMR.NR41:
            case MMR.NR42:
            case MMR.NR43:
            case MMR.NR44:
              _channel4.HandleMemoryChange(register, value);
              break;
            case MMR.NR50:
              // NOTE(Cristian): No Vin support
              _memory.LowLevelWrite((ushort)register, value);
              break;
            case MMR.NR51:
              // TODO(Cristian): Implement this logic
              _state.OutputChannel1Left = ((value & 0x01) != 0);
              _state.OutputChannel2Left = ((value & 0x02) != 0);
              _state.OutputChannel3Left = ((value & 0x04) != 0);
              _state.OutputChannel4Left = ((value & 0x08) != 0);
              _state.OutputChannel1Right = ((value & 0x10) != 0);
              _state.OutputChannel2Right = ((value & 0x20) != 0);
              _state.OutputChannel3Right = ((value & 0x40) != 0);
              _state.OutputChannel4Right = ((value & 0x80) != 0);
              _memory.LowLevelWrite((ushort)register, value);
              break;
            case MMR.NR52:
              bool apuEnabled = (Utils.UtilFuncs.TestBit(value, 7) != 0);
              if (!apuEnabled)
              {
            // Powering down the APU should power down all the registers
            //for (ushort r = (ushort)MMR.NR10; r < (ushort)MMR.NR52; ++r)
            //{
            //  HandleMemoryChange((MMR)r, 0, false);
            //}
            _channel1.PowerOff();
            _channel1.SetEnabled(false);
            _channel2.PowerOff();
            _channel2.SetEnabled(false);
            _channel3.PowerOff();
            _channel3.SetEnabled(false);
            _channel4.PowerOff();
            _channel4.SetEnabled(false);

            _memory.LowLevelWrite((ushort)MMR.NR50, 0);
            _memory.LowLevelWrite((ushort)MMR.NR51, 0);
              }
              else if (!_state.Enabled)
              {
            _frameSequencer.Reset();
              }
              // We update at the end because otherwise the recursive calls would
              // be rejected by the guard
              _state.Enabled = apuEnabled;
              break;
              }

              // NOTE(Cristian): This is an "optimization" for when NR52 is disabled,
              //                 All the registers are set to 0. A normal recursive call
              //                 would write the NR52 memory several times unnecessarily
              if (!updatedEnabledFlag) { return; }

              // We compare to see if we have to change the NR52 byte
              if ((channel1Enabled != _channel1.Enabled) ||
              (channel2Enabled != _channel2.Enabled) ||
              (channel3Enabled != _channel3.Enabled) ||
              (channel4Enabled != _channel4.Enabled) ||
              (prevEnabled != _state.Enabled))
              {
            byte nr52 = 0x70;
            if (_state.Enabled)
            {
              nr52 = (byte)((_channel1.Enabled ? 0x1 : 0) |  // bit 0
                        (_channel2.Enabled ? 0x2 : 0) |  // bit 1
                        (_channel3.Enabled ? 0x4 : 0) |  // bit 2
                        (_channel4.Enabled ? 0x8 : 0) |  // bit 3
                        0xF0);                           // bit 4-7 are 1
            }

            // We know bit 7 is 1 because otherwise the whole register is 0x70
            _memory.LowLevelWrite((ushort)MMR.NR52, nr52);
              }
        }
Ejemplo n.º 12
0
        public void HandleMemoryChange(MMR register, byte value)
        {
            byte before = _memory.LowLevelRead((ushort)register);
            #if SoundTiming
              //Timeline[TimelineCount++] = (long)register;
              //Timeline[TimelineCount++] = value;
            #endif

              if (register == _sweepRegister)
              {
            // Sweep Shift Number (Bits 0-2)
            _state.SweepShifts = value & 0x07;

            // Sweep Direction (Bit 3)
            bool prevSweepUp = _state.SweepUp;
            _state.SweepUp = ((value & 0x08) == 0);
            // Going from neg->pos after a calc has occurred disabled the channel
            if (_state.SweepCalcOcurred && !prevSweepUp && _state.SweepUp)
            {
              SetEnabled(false);
            }
            _state.SweepCalcOcurred = false;

            // Sweep Time (Bits 4-6)
            _state.SweepLength = ((value >> 4) & 0x07);

            // Bit 7 is always 1
            _memory.LowLevelWrite((ushort)register, (byte)(value | 0x80));
              }
              else if (register == _wavePatternDutyRegister)
              {
            // TODO(Cristian): Wave Pattern Duty
            _state.SoundLengthCounter = 0x3F - (value & 0x3F);

            _memory.LowLevelWrite((ushort)register, value);
              }
              else if (register == _volumeEnvelopeRegister)
              {
            _state.EnvelopeTicks = value & 0x7;
            _state.EnvelopeUp = (value & 0x8) != 0;
            _state.EnvelopeDefaultValue = value >> 4;

            // Putting volume 0 disables the channel
            if ((_state.EnvelopeDefaultValue == 0) && !_state.EnvelopeUp)
            {
              _state.EnvelopeDACOn = false;
              SetEnabled(false);
            }
            else
            {
              _state.EnvelopeDACOn = true;
            }

            _memory.LowLevelWrite((ushort)register, value);
              }
              else if (register == _freqLowRegister)
              {
            ushort newFreqFactor = (ushort)(((_state.HighFreqByte & 0x7) << 8) | value);
            SetFrequencyFactor(newFreqFactor);
            _memory.LowLevelWrite((ushort)register, value);
              }
              else if (register == _freqHighRegister)
              {
            ushort newFreqFactor = (ushort)(((value & 0x7) << 8) | _state.LowFreqByte);
            SetFrequencyFactor(newFreqFactor);

            bool prevContinuousOutput = _state.ContinuousOutput;
            _state.ContinuousOutput = (Utils.UtilFuncs.TestBit(value, 6) == 0);
            // Only enabling sound length (disabled -> enabled) could trigger a clock
            if ((!_state.ContinuousOutput) &&
            (prevContinuousOutput != _state.ContinuousOutput))
            {
              // If the next frameSequencer WON'T trigger the length period,
              // the counter is somehow decremented...
              if ((_frameSequencer.Value & 0x01) == 0)
              {
            ClockLengthCounter();
              }
            }

            // Bit 7 is called a channel INIT. On this event the following occurs:
            // * The Volume Envelope values value are changed
            bool init = (Utils.UtilFuncs.TestBit(value, 7) != 0);
            // INIT triggers only if the DAC (volume) is on
            if (init)
            {
              if(_state.EnvelopeDACOn)
              {
            SetEnabled(true);
              }

              // FREQUENCY SWEEP
              _state.SweepFrequencyRegister = _state.FrequencyFactor;
              _state.SweepCounter = _state.SweepLength;

              if (_state.SweepLength == 0) { _state.SweepCounter = 8; }
              _state.SweepEnabled = ((_state.SweepLength > 0) || (_state.SweepShifts > 0));
              // We create immediate frequency calculation
              if (_state.SweepShifts > 0)
              {
            CalculateSweepChange(updateValue: false, redoCalculation: false);
            _state.SweepCalcOcurred = true;
              }

              // NOTE(Cristian): If the length counter is empty at INIT,
              //                 it's reloaded with full length
              if(_state.SoundLengthCounter < 0)
              {
            _state.SoundLengthCounter = 0x3F;

            // If INIT on an zerioed empty enabled length channel
            // AND the next frameSequencer tick WON'T tick the length period
            // The lenght counter is somehow decremented
            if (!_state.ContinuousOutput &&
                ((_frameSequencer.Value & 0x01) == 0))
            {
              ClockLengthCounter();
            }
              }

              // Envelope is reloaded
              _state.EnvelopeTickCounter = _state.EnvelopeTicks;
              _state.EnvelopeCurrentUp = _state.EnvelopeUp;
              SetEnvelopeCurrentValue(_state.EnvelopeDefaultValue);
            }

            // Bits 3-5 are always 1
            _memory.LowLevelWrite((ushort)register, (byte)(value | 0x38));
              }
              else if (register == MMR.NR52)
              {
            SetEnabled((Utils.UtilFuncs.TestBit(value, _channelIndex) != 0));
              }

            #if SoundTiming
              //Timeline[TimelineCount++] = before;
              //Timeline[TimelineCount++] = _memory.LowLevelRead((ushort)register);
            #endif
        }
Ejemplo n.º 13
0
        public void HandleMemoryChange(MMR register, byte value)
        {
            switch (register)
            {
            case MMR.NR41: // Sound Length
                _state.SoundLengthCounter = 0x3F - (value & 0x3F);
                _memory.LowLevelWrite((ushort)register, value);
                break;

            case MMR.NR42:
                _state.EnvelopeTicks        = value & 0x07;
                _state.EnvelopeUp           = (value & 0x8) != 0;
                _state.EnvelopeDefaultValue = value >> 4;

                // Putting volume 0 disables the channel
                if ((_state.EnvelopeDefaultValue == 0) && !_state.EnvelopeUp)
                {
                    _state.EnvelopeDACOn = false;
                    SetEnabled(false);
                }
                else
                {
                    _state.EnvelopeDACOn = true;
                }

                _memory.LowLevelWrite((ushort)register, value);
                break;

            case MMR.NR43:
                AddSoundEvent(NoiseChannelEvents.NR43_WRITE, value);
                _memory.LowLevelWrite((ushort)register, value);
                break;

            case MMR.NR44:

                bool prevContinuousOutput = _state.ContinuousOutput;
                _state.ContinuousOutput = (Utils.UtilFuncs.TestBit(value, 6) == 0);
                // Only enabling sound length (disabled -> enabled) could trigger a clock
                if ((!_state.ContinuousOutput) &&
                    (prevContinuousOutput != _state.ContinuousOutput))
                {
                    // If the next frameSequencer WON'T trigger the length period,
                    // the counter is somehow decremented...
                    if ((_frameSequencer.Value & 0x01) == 0)
                    {
                        ClockLengthCounter();
                    }
                }

                bool init = (Utils.UtilFuncs.TestBit(value, 7) != 0);
                if (init)
                {
                    AddSoundEvent(NoiseChannelEvents.INIT, 0);
                    if (_state.EnvelopeDACOn)
                    {
                        SetEnabled(true);
                    }

                    // NOTE(Cristian): If the length counter is empty at INIT,
                    //                 it's reloaded with full length
                    if (_state.SoundLengthCounter < 0)
                    {
                        _state.SoundLengthCounter = 0x3F;

                        // If INIT on an zerioed empty enabled length channel
                        // AND the next frameSequencer tick WON'T tick the length period
                        // The lenght counter is somehow decremented
                        if (!_state.ContinuousOutput &&
                            ((_frameSequencer.Value & 0x01) == 0))
                        {
                            ClockLengthCounter();
                        }
                    }

                    // Envelope is reloaded
                    _state.EnvelopeTickCounter = _state.EnvelopeTicks;
                    _state.EnvelopeCurrentUp   = _state.EnvelopeUp;
                    SetEnvelopeCurrentValue(_state.EnvelopeDefaultValue);
                }

                _memory.LowLevelWrite((ushort)register, value);
                break;
            }
        }
 public MemoryMappedRegisterViewModel(string name, MMR register, IGameBoy gameBoy)
 {
     _name = name;
       _register = register;
       _gameBoy = gameBoy;
 }
Ejemplo n.º 15
0
 public MemoryMappedRegisterViewModel(string name, MMR register, IGameBoy gameBoy)
 {
     _name     = name;
     _register = register;
     _gameBoy  = gameBoy;
 }
Ejemplo n.º 16
0
        internal static void SetupSpritePalletes(DisplayDefinition disDef, Memory memory, MMR pallete)
        {
            if (pallete == MMR.OBP0)
              {

            byte obp0 = memory.LowLevelRead((ushort)MMR.OBP0);
            disDef.SpritePallete0[0] = 0x00000000; // Sprite colors are trasparent
            for (int color = 1; color < 4; ++color)
            {
              int down = (obp0 >> (2 * color)) & 1;
              int up = (obp0 >> (2 * color + 1)) & 1;
              int index = (up << 1) | down;
              disDef.SpritePallete0[color] = disDef.SpriteColors[index];
            }
              }
              else if (pallete == MMR.OBP1)
              {
            byte obp1 = memory.LowLevelRead((ushort)MMR.OBP1);
            disDef.SpritePallete1[1] = 0x00000000; // Sprite colors are trasparent
            for (int color = 1; color < 4; ++color)
            {
              int down = (obp1 >> (2 * color)) & 1;
              int up = (obp1 >> (2 * color + 1)) & 1;
              int index = (up << 1) | down;
              disDef.SpritePallete1[color] = disDef.SpriteColors[index];
            }
              }
              else
              {
            throw new InvalidProgramException("Invalid pallete register given");
              }
        }
Ejemplo n.º 17
0
        public void HandleMemoryChange(MMR register, byte value)
        {
            switch (register)
              {
            case MMR.NR41:  // Sound Length
              _state.SoundLengthCounter = 0x3F - (value & 0x3F);
              _memory.LowLevelWrite((ushort)register, value);
              break;
            case MMR.NR42:
              _state.EnvelopeTicks = value & 0x07;
              _state.EnvelopeUp = (value & 0x8) != 0;
              _state.EnvelopeDefaultValue = value >> 4;

              // Putting volume 0 disables the channel
              if ((_state.EnvelopeDefaultValue == 0) && !_state.EnvelopeUp)
              {
            _state.EnvelopeDACOn = false;
            SetEnabled(false);
              }
              else
              {
            _state.EnvelopeDACOn = true;
              }

              _memory.LowLevelWrite((ushort)register, value);
              break;
            case MMR.NR43:
              AddSoundEvent(NoiseChannelEvents.NR43_WRITE, value);
              _memory.LowLevelWrite((ushort)register, value);
              break;
            case MMR.NR44:

              bool prevContinuousOutput = _state.ContinuousOutput;
              _state.ContinuousOutput = (Utils.UtilFuncs.TestBit(value, 6) == 0);
              // Only enabling sound length (disabled -> enabled) could trigger a clock
              if ((!_state.ContinuousOutput) &&
              (prevContinuousOutput != _state.ContinuousOutput))
              {
            // If the next frameSequencer WON'T trigger the length period,
            // the counter is somehow decremented...
            if ((_frameSequencer.Value & 0x01) == 0)
            {
              ClockLengthCounter();
            }
              }

              bool init = (Utils.UtilFuncs.TestBit(value, 7) != 0);
              if (init)
              {
            AddSoundEvent(NoiseChannelEvents.INIT, 0);
            if(_state.EnvelopeDACOn)
            {
              SetEnabled(true);
            }

            // NOTE(Cristian): If the length counter is empty at INIT,
            //                 it's reloaded with full length
            if(_state.SoundLengthCounter < 0)
            {
              _state.SoundLengthCounter = 0x3F;

              // If INIT on an zerioed empty enabled length channel
              // AND the next frameSequencer tick WON'T tick the length period
              // The lenght counter is somehow decremented
              if (!_state.ContinuousOutput &&
                  ((_frameSequencer.Value & 0x01) == 0))
              {
                ClockLengthCounter();
              }
            }

            // Envelope is reloaded
            _state.EnvelopeTickCounter = _state.EnvelopeTicks;
            _state.EnvelopeCurrentUp = _state.EnvelopeUp;
            SetEnvelopeCurrentValue(_state.EnvelopeDefaultValue);
              }

              _memory.LowLevelWrite((ushort)register, value);
              break;
              }
        }
Ejemplo n.º 18
0
 internal void HandleMemoryChange(MMR register, byte value)
 {
     switch (register)
     {
         case MMR.TIMA:
             _state.TimaCounter = value;
             this._memory.LowLevelWrite((ushort)MMR.TIMA, value);
             break;
         case MMR.TMA:
             _state.TmaValue = value;
             this._memory.LowLevelWrite((ushort)MMR.TMA, value);
             break;
         case MMR.TAC:
             // Clock select is the bits 0 and 1 of the TAC register
             byte clockSelect = (byte)(value & 0x03);
             switch (clockSelect)
             {
                 case 1:
                     _state.TacMask = 0x000F; // f/2^4  0000 0000 0000 1111, (262144 Hz)
                     break;
                 case 2:
                     _state.TacMask = 0x003F; // f/2^6  0000 0000 0011 1111, (65536 Hz)
                     break;
                 case 3:
                     _state.TacMask = 0x00FF; // f/2^8  0000 0000 1111 1111, (16384 Hz)
                     break;
                 default:
                     _state.TacMask = 0x03FF; // f/2^10 0000 0011 1111 1111, (4096 Hz)
                     break;
             }
             // We restart the counter
             _state.TacCounter = 0;
             // TAC has a 0xF8 mask (only lower 3 bits are useful)
             this._memory.LowLevelWrite((ushort)MMR.TAC, (byte)(0xF8 | value));
             break;
     }
 }
Ejemplo n.º 19
0
        public void HandleMemoryChange(MMR register, byte value)
        {
            switch(register)
              {
            case MMR.NR30:  // Sound on/off
              // Last bit determines sound on/off
              _state.ChannelDACOn = (Utils.UtilFuncs.TestBit(value, 7) != 0);
              // When DAC re-enabled, the channel doesn't enables itself
              if (!_state.ChannelDACOn)
              {
            SetEnabled(false);
              }

              _memory.LowLevelWrite((ushort)register, value);
              break;
            case MMR.NR31:  // Sound Length
              _state.SoundLengthCounter = 0xFF - value;
              //_memory.LowLevelWrite((ushort)register, 0xFF);
              _memory.LowLevelWrite((ushort)register, value);
              break;
            case MMR.NR32:  // Output Level (volume)
              // Basically, we shift by this amount.
              // If the amount is 0, it means we mute
              SetVolumeRightShift(((value >> 5) & 0x3) - 1);
              // We reload the sample
              //_outputValue = (short)Volume;

              _memory.LowLevelWrite((ushort)register, value);
              break;
            case MMR.NR33:  // FrequencyFactor lower
              {
            ushort newFreqFactor = (ushort)(((_state.HighFreqByte & 0x7) << 8) | value);
            SetFrequencyFactor(newFreqFactor);

            _memory.LowLevelWrite((ushort)register, value);
            break;
              }
            case MMR.NR34:  // FrequencyFactor higher
              {
            ushort newFreqFactor = (ushort)(((value & 0x7) << 8) | _state.LowFreqByte);
            SetFrequencyFactor(newFreqFactor);

            bool prevContinuousOutput = _state.ContinuousOutput;
            _state.ContinuousOutput = (Utils.UtilFuncs.TestBit(value, 6) == 0);
            // Only enabling sound length (disabled -> enabled) could trigger a clock
            if ((!_state.ContinuousOutput) &&
                (prevContinuousOutput != _state.ContinuousOutput))
            {
              // If the next frameSequencer WON'T trigger the length period,
              // the counter is somehow decremented...
              if ((_frameSequencer.Value & 0x01) == 0)
              {
                ClockLengthCounter();
              }
            }

            bool init = (Utils.UtilFuncs.TestBit(value, 7) != 0);
            if (init)
            {
              AddSoundEvent(WaveChannelEvents.INIT, value);
              _state.TickCounter = _state.TickThreshold;
              _state.CurrentSampleIndex = 0;

              // NOTE(Cristian): If the length counter is empty at INIT,
              //                 it's reloaded with full length
              if (_state.SoundLengthCounter < 0)
              {
                _state.SoundLengthCounter = 0xFF;

                // If INIT on an zerioed empty enabled length channel
                // AND the next frameSequencer tick WON'T tick the length period
                // The lenght counter is somehow decremented
                if (!_state.ContinuousOutput &&
                    ((_frameSequencer.Value & 0x01) == 0))
                {
                  ClockLengthCounter();
                }
              }

              if (_state.ChannelDACOn)
              {
                SetEnabled(true);
              }
            }

            _memory.LowLevelWrite((ushort)register, value);
            break;
              }
              }
        }
Ejemplo n.º 20
0
        public void HandleMemoryChange(MMR register, byte value)
        {
            byte before = _memory.LowLevelRead((ushort)register);

#if SoundTiming
            //Timeline[TimelineCount++] = (long)register;
            //Timeline[TimelineCount++] = value;
#endif

            if (register == _sweepRegister)
            {
                // Sweep Shift Number (Bits 0-2)
                _state.SweepShifts = value & 0x07;

                // Sweep Direction (Bit 3)
                bool prevSweepUp = _state.SweepUp;
                _state.SweepUp = ((value & 0x08) == 0);
                // Going from neg->pos after a calc has occurred disabled the channel
                if (_state.SweepCalcOcurred && !prevSweepUp && _state.SweepUp)
                {
                    SetEnabled(false);
                }
                _state.SweepCalcOcurred = false;

                // Sweep Time (Bits 4-6)
                _state.SweepLength = ((value >> 4) & 0x07);

                // Bit 7 is always 1
                _memory.LowLevelWrite((ushort)register, (byte)(value | 0x80));
            }
            else if (register == _wavePatternDutyRegister)
            {
                // TODO(Cristian): Wave Pattern Duty
                _state.SoundLengthCounter = 0x3F - (value & 0x3F);

                _memory.LowLevelWrite((ushort)register, value);
            }
            else if (register == _volumeEnvelopeRegister)
            {
                _state.EnvelopeTicks        = value & 0x7;
                _state.EnvelopeUp           = (value & 0x8) != 0;
                _state.EnvelopeDefaultValue = value >> 4;

                // Putting volume 0 disables the channel
                if ((_state.EnvelopeDefaultValue == 0) && !_state.EnvelopeUp)
                {
                    _state.EnvelopeDACOn = false;
                    SetEnabled(false);
                }
                else
                {
                    _state.EnvelopeDACOn = true;
                }

                _memory.LowLevelWrite((ushort)register, value);
            }
            else if (register == _freqLowRegister)
            {
                ushort newFreqFactor = (ushort)(((_state.HighFreqByte & 0x7) << 8) | value);
                SetFrequencyFactor(newFreqFactor);
                _memory.LowLevelWrite((ushort)register, value);
            }
            else if (register == _freqHighRegister)
            {
                ushort newFreqFactor = (ushort)(((value & 0x7) << 8) | _state.LowFreqByte);
                SetFrequencyFactor(newFreqFactor);

                bool prevContinuousOutput = _state.ContinuousOutput;
                _state.ContinuousOutput = (Utils.UtilFuncs.TestBit(value, 6) == 0);
                // Only enabling sound length (disabled -> enabled) could trigger a clock
                if ((!_state.ContinuousOutput) &&
                    (prevContinuousOutput != _state.ContinuousOutput))
                {
                    // If the next frameSequencer WON'T trigger the length period,
                    // the counter is somehow decremented...
                    if ((_frameSequencer.Value & 0x01) == 0)
                    {
                        ClockLengthCounter();
                    }
                }

                // Bit 7 is called a channel INIT. On this event the following occurs:
                // * The Volume Envelope values value are changed
                bool init = (Utils.UtilFuncs.TestBit(value, 7) != 0);
                // INIT triggers only if the DAC (volume) is on
                if (init)
                {
                    if (_state.EnvelopeDACOn)
                    {
                        SetEnabled(true);
                    }

                    // FREQUENCY SWEEP
                    _state.SweepFrequencyRegister = _state.FrequencyFactor;
                    _state.SweepCounter           = _state.SweepLength;

                    if (_state.SweepLength == 0)
                    {
                        _state.SweepCounter = 8;
                    }
                    _state.SweepEnabled = ((_state.SweepLength > 0) || (_state.SweepShifts > 0));
                    // We create immediate frequency calculation
                    if (_state.SweepShifts > 0)
                    {
                        CalculateSweepChange(updateValue: false, redoCalculation: false);
                        _state.SweepCalcOcurred = true;
                    }

                    // NOTE(Cristian): If the length counter is empty at INIT,
                    //                 it's reloaded with full length
                    if (_state.SoundLengthCounter < 0)
                    {
                        _state.SoundLengthCounter = 0x3F;

                        // If INIT on an zerioed empty enabled length channel
                        // AND the next frameSequencer tick WON'T tick the length period
                        // The lenght counter is somehow decremented
                        if (!_state.ContinuousOutput &&
                            ((_frameSequencer.Value & 0x01) == 0))
                        {
                            ClockLengthCounter();
                        }
                    }

                    // Envelope is reloaded
                    _state.EnvelopeTickCounter = _state.EnvelopeTicks;
                    _state.EnvelopeCurrentUp   = _state.EnvelopeUp;
                    SetEnvelopeCurrentValue(_state.EnvelopeDefaultValue);
                }

                // Bits 3-5 are always 1
                _memory.LowLevelWrite((ushort)register, (byte)(value | 0x38));
            }
            else if (register == MMR.NR52)
            {
                SetEnabled((Utils.UtilFuncs.TestBit(value, _channelIndex) != 0));
            }

#if SoundTiming
            //Timeline[TimelineCount++] = before;
            //Timeline[TimelineCount++] = _memory.LowLevelRead((ushort)register);
#endif
        }
Ejemplo n.º 21
0
        public void HandleMemoryChange(MMR register, byte value)
        {
            switch (register)
            {
            case MMR.NR30: // Sound on/off
                // Last bit determines sound on/off
                _state.ChannelDACOn = (Utils.UtilFuncs.TestBit(value, 7) != 0);
                // When DAC re-enabled, the channel doesn't enables itself
                if (!_state.ChannelDACOn)
                {
                    SetEnabled(false);
                }

                _memory.LowLevelWrite((ushort)register, value);
                break;

            case MMR.NR31: // Sound Length
                _state.SoundLengthCounter = 0xFF - value;
                //_memory.LowLevelWrite((ushort)register, 0xFF);
                _memory.LowLevelWrite((ushort)register, value);
                break;

            case MMR.NR32: // Output Level (volume)
                // Basically, we shift by this amount.
                // If the amount is 0, it means we mute
                SetVolumeRightShift(((value >> 5) & 0x3) - 1);
                // We reload the sample
                //_outputValue = (short)Volume;

                _memory.LowLevelWrite((ushort)register, value);
                break;

            case MMR.NR33: // FrequencyFactor lower
            {
                ushort newFreqFactor = (ushort)(((_state.HighFreqByte & 0x7) << 8) | value);
                SetFrequencyFactor(newFreqFactor);

                _memory.LowLevelWrite((ushort)register, value);
                break;
            }

            case MMR.NR34: // FrequencyFactor higher
            {
                ushort newFreqFactor = (ushort)(((value & 0x7) << 8) | _state.LowFreqByte);
                SetFrequencyFactor(newFreqFactor);

                bool prevContinuousOutput = _state.ContinuousOutput;
                _state.ContinuousOutput = (Utils.UtilFuncs.TestBit(value, 6) == 0);
                // Only enabling sound length (disabled -> enabled) could trigger a clock
                if ((!_state.ContinuousOutput) &&
                    (prevContinuousOutput != _state.ContinuousOutput))
                {
                    // If the next frameSequencer WON'T trigger the length period,
                    // the counter is somehow decremented...
                    if ((_frameSequencer.Value & 0x01) == 0)
                    {
                        ClockLengthCounter();
                    }
                }

                bool init = (Utils.UtilFuncs.TestBit(value, 7) != 0);
                if (init)
                {
                    AddSoundEvent(WaveChannelEvents.INIT, value);
                    _state.TickCounter        = _state.TickThreshold;
                    _state.CurrentSampleIndex = 0;

                    // NOTE(Cristian): If the length counter is empty at INIT,
                    //                 it's reloaded with full length
                    if (_state.SoundLengthCounter < 0)
                    {
                        _state.SoundLengthCounter = 0xFF;

                        // If INIT on an zerioed empty enabled length channel
                        // AND the next frameSequencer tick WON'T tick the length period
                        // The lenght counter is somehow decremented
                        if (!_state.ContinuousOutput &&
                            ((_frameSequencer.Value & 0x01) == 0))
                        {
                            ClockLengthCounter();
                        }
                    }

                    if (_state.ChannelDACOn)
                    {
                        SetEnabled(true);
                    }
                }

                _memory.LowLevelWrite((ushort)register, value);
                break;
            }
            }
        }
Ejemplo n.º 22
0
        internal void HandleMemoryChange(MMR register, byte value, bool updatedEnabledFlag = true)
        {
            if (!_state.Enabled)
            {
                // When powered off, the internal length can be changed (DMG only)
                switch (register)
                {
                case MMR.NR11:
                    _channel1.ChangeLength(value);
                    break;

                case MMR.NR21:
                    _channel2.ChangeLength(value);
                    break;

                case MMR.NR31:
                    _channel3.ChangeLength(value);
                    break;

                case MMR.NR41:
                    _channel4.ChangeLength(value);
                    break;
                }

                // Other than turning on, all other writes are ignored
                if (register != MMR.NR52)
                {
                    return;
                }
            }

            // We store previous channel status
            bool channel1Enabled = _channel1.Enabled;
            bool channel2Enabled = _channel2.Enabled;
            bool channel3Enabled = _channel3.Enabled;
            bool channel4Enabled = _channel4.Enabled;
            bool prevEnabled     = _state.Enabled;

            switch (register)
            {
            case MMR.NR10:
            case MMR.NR11:
            case MMR.NR12:
            case MMR.NR13:
            case MMR.NR14:
                _channel1.HandleMemoryChange(register, value);
                break;

            case MMR.NR21:
            case MMR.NR22:
            case MMR.NR23:
            case MMR.NR24:
                _channel2.HandleMemoryChange(register, value);
                break;

            case MMR.NR30:
            case MMR.NR31:
            case MMR.NR32:
            case MMR.NR33:
            case MMR.NR34:
                _channel3.HandleMemoryChange(register, value);
                break;

            case MMR.NR41:
            case MMR.NR42:
            case MMR.NR43:
            case MMR.NR44:
                _channel4.HandleMemoryChange(register, value);
                break;

            case MMR.NR50:
                // NOTE(Cristian): No Vin support
                _memory.LowLevelWrite((ushort)register, value);
                break;

            case MMR.NR51:
                // TODO(Cristian): Implement this logic
                _state.OutputChannel1Left  = ((value & 0x01) != 0);
                _state.OutputChannel2Left  = ((value & 0x02) != 0);
                _state.OutputChannel3Left  = ((value & 0x04) != 0);
                _state.OutputChannel4Left  = ((value & 0x08) != 0);
                _state.OutputChannel1Right = ((value & 0x10) != 0);
                _state.OutputChannel2Right = ((value & 0x20) != 0);
                _state.OutputChannel3Right = ((value & 0x40) != 0);
                _state.OutputChannel4Right = ((value & 0x80) != 0);
                _memory.LowLevelWrite((ushort)register, value);
                break;

            case MMR.NR52:
                bool apuEnabled = (Utils.UtilFuncs.TestBit(value, 7) != 0);
                if (!apuEnabled)
                {
                    // Powering down the APU should power down all the registers
                    //for (ushort r = (ushort)MMR.NR10; r < (ushort)MMR.NR52; ++r)
                    //{
                    //  HandleMemoryChange((MMR)r, 0, false);
                    //}
                    _channel1.PowerOff();
                    _channel1.SetEnabled(false);
                    _channel2.PowerOff();
                    _channel2.SetEnabled(false);
                    _channel3.PowerOff();
                    _channel3.SetEnabled(false);
                    _channel4.PowerOff();
                    _channel4.SetEnabled(false);

                    _memory.LowLevelWrite((ushort)MMR.NR50, 0);
                    _memory.LowLevelWrite((ushort)MMR.NR51, 0);
                }
                else if (!_state.Enabled)
                {
                    _frameSequencer.Reset();
                }
                // We update at the end because otherwise the recursive calls would
                // be rejected by the guard
                _state.Enabled = apuEnabled;
                break;
            }

            // NOTE(Cristian): This is an "optimization" for when NR52 is disabled,
            //                 All the registers are set to 0. A normal recursive call
            //                 would write the NR52 memory several times unnecessarily
            if (!updatedEnabledFlag)
            {
                return;
            }

            // We compare to see if we have to change the NR52 byte
            if ((channel1Enabled != _channel1.Enabled) ||
                (channel2Enabled != _channel2.Enabled) ||
                (channel3Enabled != _channel3.Enabled) ||
                (channel4Enabled != _channel4.Enabled) ||
                (prevEnabled != _state.Enabled))
            {
                byte nr52 = 0x70;
                if (_state.Enabled)
                {
                    nr52 = (byte)((_channel1.Enabled ? 0x1 : 0) | // bit 0
                                  (_channel2.Enabled ? 0x2 : 0) | // bit 1
                                  (_channel3.Enabled ? 0x4 : 0) | // bit 2
                                  (_channel4.Enabled ? 0x8 : 0) | // bit 3
                                  0xF0);                          // bit 4-7 are 1
                }

                // We know bit 7 is 1 because otherwise the whole register is 0x70
                _memory.LowLevelWrite((ushort)MMR.NR52, nr52);
            }
        }
Ejemplo n.º 23
0
 internal void HandleMemoryChange(MMR mappedRegister, byte value)
 {
     switch (mappedRegister)
       {
     case MMR.LCDC:
       // We set all the LCDC bits
       for (int i = 0; i < 8; ++i)
       {
     _state.LCDCBits[i] = (value & (1 << i)) != 0;
       }
       break;
     case MMR.STAT:
       _state.STAT = value;
       break;
     case MMR.SCY:
       _state.SCY = value;
       break;
     case MMR.SCX:
       _state.SCX = value;
       break;
     case MMR.LY:
       _state.CurrentLine = 0;
       break;
     case MMR.LYC:
       _state.LYC = value;
       break;
     case MMR.DMA:
       LoadSprites();
       break;
     case MMR.BGP:
       DisFuncs.SetupTilePallete(_disDef, _memory);
       break;
     case MMR.OBP0:
       DisFuncs.SetupSpritePalletes(_disDef, _memory, MMR.OBP0);
       break;
     case MMR.OBP1:
       DisFuncs.SetupSpritePalletes(_disDef, _memory, MMR.OBP1);
       break;
     case MMR.WY:
       _state.WY = value;
       break;
     case MMR.WX:
       _state.WX = value;
       break;
     default:
       throw new InvalidProgramException("All cases should be handled...");
       }
 }