Пример #1
0
        public void WriteByte(int address, byte value)
        {
            if (address <= 0x7FFF)
            {
                mbc.WriteByte(address, value);
            }
            else if (address <= 0x9FFF)
            {
                Video.WriteVRAM(address - 0x8000, value);
            }
            else if (address <= 0xBFFF)
            {
                mbc.WriteByte(address, value);
            }
            else if (address <= 0xCFFF)
            {
                wram[0, address - 0xC000] = value;
            }
            else if (address <= 0xDFFF)
            {
                wram[wrambank, address - 0xD000] = value;
            }
            else if (address <= 0xEFFF)
            {
                wram[0, address - 0xE000] = value;
            }
            else if (address <= 0xFDFF)
            {
                wram[wrambank, address - 0xF000] = value;
            }
            else if (address <= 0xFE9F)
            {
                Video.WriteOAM(address - 0xFE00, value);
            }
            else if (address <= 0xFEFF)
            {
                // Not usable
            }
            else if (address <= 0xFF7F)
            {
                switch (address - 0xFF00)
                {
                case 0x00:     // Joypad
                    Joypad.SelectButtonKeys    = ((value >> 5) & 1) == 0;
                    Joypad.SelectDirectionKeys = ((value >> 4) & 1) == 0;
                    break;

                case 0x01:     // SB Serial transfer data
                    serial.Write(value);
                    break;

                case 0x02:     // SC Serial Transfer Control
                    if ((value & 0x80) == 0x80)
                    {
                        serial.Start();
                    }
                    break;

                case 0x04:     // Divider Register
                    Timer.DIV = 0;
                    break;

                case 0x05:     // Timer Counter
                    Timer.TIMA = value;
                    break;

                case 0x06:     // Timer Modulo
                    Timer.TMA = value;
                    break;

                case 0x07:     // Timer Control
                    Timer.TAC = value;
                    break;

                case 0x0F:     // Interrupt Flag
                    Interrupt.IF = value;
                    break;

                case 0x10:     // NR10 Channel 1 Sweep register
                    Audio.Channel1.SweepShift     = value & 7;
                    Audio.Channel1.SweepDirection = (SweepMode)((value >> 3) & 1);
                    Audio.Channel1.SweepTime      = (value >> 4) & 7;
                    break;

                case 0x11:     // NR11 Channel 1 Sound length/Wave pattern duty
                    Audio.Channel1.SoundLengthRaw  = value & 0x3F;
                    Audio.Channel1.WavePatternDuty = (value >> 6) & 3;
                    break;

                case 0x12:     // NR12 Channel 1 Volume Envelope
                    Audio.Channel1.EnvelopeSweep     = value & 7;
                    Audio.Channel1.EnvelopeDirection = (EnvelopeMode)((value >> 3) & 1);
                    Audio.Channel1.Volume            = (value >> 4) & 0xF;
                    break;

                case 0x13:     // NR13 Channel 1 Frequency lo
                    Audio.Channel1.Frequency = (Audio.Channel1.Frequency & 0x700) | value;
                    break;

                case 0x14:     // NR14 Channel 1 Frequency hi
                    Audio.Channel1.Frequency           = (Audio.Channel1.Frequency & 0xFF) | ((value & 7) << 8);
                    Audio.Channel1.StopOnLengthExpired = (value & 0x40) == 0x40;
                    if ((value & 0x80) == 0x80)
                    {
                        Audio.Channel1.Restart();
                    }
                    break;

                case 0x16:     // NR16 Channel 2 Sound length/Wave pattern duty
                    Audio.Channel2.SoundLengthRaw  = value & 0x3F;
                    Audio.Channel2.WavePatternDuty = (value >> 6) & 3;
                    break;

                case 0x17:     // NR17 Channel 2 Volume Envelope
                    Audio.Channel2.EnvelopeSweep     = value & 7;
                    Audio.Channel2.EnvelopeDirection = (EnvelopeMode)((value >> 3) & 1);
                    Audio.Channel2.Volume            = (value >> 4) & 0xF;
                    break;

                case 0x18:     // NR18 Channel 2 Frequency lo
                    Audio.Channel2.Frequency = (Audio.Channel2.Frequency & 0x700) | value;
                    break;

                case 0x19:     // NR19 Channel 2 Frequency hi
                    Audio.Channel2.Frequency           = (Audio.Channel2.Frequency & 0xFF) | ((value & 7) << 8);
                    Audio.Channel2.StopOnLengthExpired = (value & 0x40) == 0x40;
                    if ((value & 0x80) == 0x80)
                    {
                        Audio.Channel2.Restart();
                    }
                    break;

                case 0x1A:     // NR30 Channel 3 Sound on / off
                    Audio.Channel3.On = (value & 0x80) == 0x80;
                    break;

                case 0x1B:     // NR31 Channel 3 Sound Length
                    Audio.Channel3.SoundLengthRaw = value;
                    break;

                case 0x1c:     // NR32 Channel 3 Select output level
                    Audio.Channel3.OutputLevel = (value >> 5) & 3;
                    break;

                case 0x1D:     // NR33 Channel 3 Frequency lo
                    Audio.Channel3.FrequencyRaw = (Audio.Channel3.FrequencyRaw & 0x700) | value;
                    break;

                case 0x1E:     // NR34 Channel 3 Frequency hi
                    Audio.Channel3.FrequencyRaw        = (Audio.Channel3.FrequencyRaw & 0xFF) | ((value & 7) << 8);
                    Audio.Channel3.StopOnLengthExpired = (value & 0x40) == 0x40;
                    if ((value & 0x80) == 0x80)
                    {
                        Audio.Channel3.Restart();
                    }
                    break;

                case 0x20:     // NR41 Channel 4 Sound Length
                    Audio.Channel4.SoundLengthRaw = value;
                    break;

                case 0x21:     // NR42 Channel 4 Volume Envelope
                    Audio.Channel4.EnvelopeSweep     = value & 7;
                    Audio.Channel4.EnvelopeDirection = (EnvelopeMode)((value >> 3) & 1);
                    Audio.Channel4.Volume            = (value >> 4) & 0xF;
                    break;

                case 0x22:     // NR43 Channel 4 Polynomial Counter
                    Audio.Channel4.ClockFrequency = value >> 4;
                    Audio.Channel4.CounterStep    = (value & 8) == 8;
                    Audio.Channel4.Counter        = Audio.Channel4.CounterStep ? 0x7F : 0x7FFF;
                    Audio.Channel4.DividingRatio  = value & 7;
                    break;

                case 0x23:     // NR44 Channel 4 Counter/consecutive; Initial
                    Audio.Channel4.StopOnLengthExpired = (value & 0x40) == 0x40;
                    if ((value & 0x80) == 0x80)
                    {
                        Audio.Channel4.Restart();
                    }
                    break;

                // FF30-FF3F Wave Pattern RAM
                case 0x30:
                case 0x31:
                case 0x32:
                case 0x33:
                case 0x34:
                case 0x35:
                case 0x36:
                case 0x37:
                case 0x38:
                case 0x39:
                case 0x3A:
                case 0x3B:
                case 0x3C:
                case 0x3D:
                case 0x3E:
                case 0x3F:
                    Audio.Channel3.WaveRAM[(address & 0xF) * 2]     = (byte)(value >> 4);
                    Audio.Channel3.WaveRAM[(address & 0xF) * 2 + 1] = (byte)(value & 0xF);
                    break;

                case 0x40:     // LCDC
                    Video.LCDEnable               = ((value >> 7) & 1) == 1;
                    Video.WindowTileMapSelect     = ((value >> 6) & 1) == 1;
                    Video.WindowEnable            = ((value >> 5) & 1) == 1;
                    Video.TileDataSelect          = ((value >> 4) & 1) == 1;
                    Video.BackgroundTileMapSelect = ((value >> 3) & 1) == 1;
                    Video.ObjectSize              = ((value >> 2) & 1) == 1;
                    Video.ObjectEnable            = ((value >> 1) & 1) == 1;
                    Video.BackgroundEnable        = (value & 1) == 1;
                    break;

                case 0x41:     // LCDC STAT
                    Video.CoincidenceInterrupt = ((value >> 6) & 1) == 1;
                    Video.OAMInterrupt         = ((value >> 5) & 1) == 1;
                    Video.VBlankInterrupt      = ((value >> 4) & 1) == 1;
                    Video.HBlankInterrupt      = ((value >> 3) & 1) == 1;
                    Video.CoincidenceFlag      = ((value >> 2) & 1) == 1;
                    Video.ModeFlag             = value & 3;
                    break;

                case 0x42:     // SCY
                    Video.SCY = value;
                    break;

                case 0x43:     // SCX
                    Video.SCX = value;
                    break;

                case 0x45:     // LYC
                    Video.LYC = value;
                    break;

                case 0x46:     // OAM DMA
                    int address2 = value << 8;
                    for (int i = 0; i < 0x9F; i++)
                    {
                        WriteByte(0xFE00 + i, ReadByte(address2 + i));
                    }
                    break;

                case 0x47:     // BGP
                    Video.BGP = value;
                    break;

                case 0x48:     // OBP0
                    Video.OBP0 = value;
                    break;

                case 0x49:     // OBP1
                    Video.OBP1 = value;
                    break;

                case 0x4A:     // WY
                    Video.WY = value;
                    break;

                case 0x4B:     // WX
                    Video.WX = value;
                    break;

                case 0x4D:     // Prepare Speed Switch
                    cpu.PrepareSpeedSwitch = (value & 1) == 1;
                    break;

                case 0x4F:     // VRAM bank
                    if (rom.HasColorFeatures)
                    {
                        Video.VRAMBank = value & 1;
                    }
                    break;

                case 0x51:     // HDMA Source, High
                    hdma.SourceAddress = hdma.SourceAddress & 0xFF | (value << 8);
                    break;

                case 0x52:     // HDMA Source, Low
                    hdma.SourceAddress = hdma.SourceAddress & 0xFF00 | (value & 0xF0);
                    break;

                case 0x53:     // HDMA Destination, High
                    hdma.DestinationAddress = hdma.DestinationAddress & 0xFF | ((value & 0x1F) << 8);
                    break;

                case 0x54:     // HDMA Destination, Low
                    hdma.DestinationAddress = hdma.DestinationAddress & 0xFF00 | (value & 0xF0);
                    break;

                case 0x55:     // HDMA Length/Mode/Start
                    hdma.Length   = ((value & 0x7F) + 1) * 0x10;
                    hdma.IsHBlank = (value & 0x80) == 0x80;
                    if (!hdma.IsHBlank)
                    {
                        hdma.PerformGeneralPurpose();
                    }
                    break;

                case 0x68:     // Background Palette Index
                    Video.BackgroundPaletteIndex = value & 0x3F;
                    Video.BackgroundPaletteAI    = (value & 0x80) == 0x80;
                    break;

                case 0x69:     // Background Palette Data
                    Video.WritePRAM(0, value);
                    break;

                case 0x6A:     // Object Palette Index
                    Video.ObjectPaletteIndex = value & 0x3F;
                    Video.ObjectPaletteAI    = (value & 0x80) == 0x80;
                    break;

                case 0x6B:     // Object Palette Data
                    Video.WritePRAM(1, value);
                    break;

                case 0x70:     // WRAM bank
                    if (rom.HasColorFeatures)
                    {
                        if (value == 0)
                        {
                            value = 1;
                        }
                        wrambank = value & 7;
                    }
                    break;

                default:
                    //throw new Exception(string.Format("Unknown IO port at 0x{0:X} (WRITE)", address));
                    break;
                }
            }
            else if (address <= 0xFFFE)
            {
                hram[address - 0xFF80] = value;
            }
            else
            {
                Interrupt.IE = value;
            }
        }