Esempio n. 1
0
        public bool Tick()
        {
            var spriteAddress = 0xfe00 + 4 * _i;

            switch (_state)
            {
            case State.ReadingY:
                _spriteY = _oemRam.GetByte(spriteAddress);
                _state   = State.ReadingX;
                break;

            case State.ReadingX:
                _spriteX = _oemRam.GetByte(spriteAddress + 1);
                if (_spritePosIndex < _sprites.Length && Between(_spriteY, _registers.Get(GpuRegister.Ly) + 16,
                                                                 _spriteY + _lcdc.GetSpriteHeight()))
                {
                    _sprites[_spritePosIndex++] = new SpritePosition(_spriteX, _spriteY, spriteAddress);
                }

                _i++;
                _state = State.ReadingY;
                break;
            }

            return(_i < 40);
        }
 private void DisplayProgress()
 {
     if (_cpu.State == State.OPCODE && _mem.GetByte(_registers.PC) == 0x22 && _registers.HL >= 0x9800 &&
         _registers.HL < 0x9c00)
     {
         if (_registers.A != 0)
         {
             _os.Write(_registers.A);
         }
     }
     else if (IsByteSequenceAtPc(0x7d, 0xe6, 0x1f, 0xee, 0x1f))
     {
         _os.Write('\n');
     }
 }
Esempio n. 3
0
 private static void CopyValues(IAddressSpace addressSpace, int from, int to, int length)
 {
     for (var i = length - 1; i >= 0; i--)
     {
         var b = addressSpace.GetByte(0xfe00 + from + i) % 0xff;
         addressSpace.SetByte(0xfe00 + to + i, b);
     }
 }
Esempio n. 4
0
        private int GetTestResult(Gameboy gb)
        {
            IAddressSpace mem = gb.Mmu;

            if (!_testStarted)
            {
                var i = 0xa000;
                foreach (var v in new[] { 0x80, 0xde, 0xb0, 0x61 })
                {
                    if (mem.GetByte(i++) != v)
                    {
                        return(0x80);
                    }
                }

                _testStarted = true;
            }

            int status = mem.GetByte(0xa000);

            if (gb.Cpu.State != State.OPCODE)
            {
                return(status);
            }

            var reg = gb.Cpu.Registers;

            int ii = reg.PC;

            foreach (int v in new int[] { 0xe5, 0xf5, 0xfa, 0x83, 0xd8 })
            {
                if (mem.GetByte(ii++) != v)
                {
                    return(status);
                }
            }

            var c = (char)reg.A;

            _text.Append(c);
            _os?.Write(c);

            reg.PC += 0x19;
            return(status);
        }
        public static bool IsInfiniteLoop(Gameboy gb)
        {
            Cpu cpu = gb.Cpu;

            if (cpu.State != State.OPCODE)
            {
                return(false);
            }

            Registers     regs = cpu.Registers;
            IAddressSpace mem  = gb.Mmu;

            int  i     = regs.PC;
            bool found = true;

            foreach (int v in new int[] { 0x18, 0xfe })
            {
                // jr fe
                if (mem.GetByte(i++) != v)
                {
                    found = false;
                    break;
                }
            }

            if (found)
            {
                return(true);
            }

            i = regs.PC;
            foreach (int v in new int[] { 0xc3, BitUtils.GetLsb(i), BitUtils.GetMsb(i) })
            {
                // jp pc
                if (mem.GetByte(i++) != v)
                {
                    return(false);
                }
            }

            return(true);
        }
Esempio n. 6
0
        public int GetByte(int address)
        {
            switch (_dmgBootstrap)
            {
            case 0 when !Gbc && (address >= 0x0000 && address < 0x0100):
                return(BootRom.GameboyClassic[address]);

            case 0 when Gbc && address >= 0x000 && address < 0x0100:
                return(BootRom.GameboyColor[address]);

            case 0 when Gbc && address >= 0x200 && address < 0x0900:
                return(BootRom.GameboyColor[address - 0x0100]);
            }

            return(address == 0xff50 ? 0xff : _addressSpace.GetByte(address));
        }
Esempio n. 7
0
        public void Tick()
        {
            if (!_transferInProgress)
            {
                return;
            }
            if (++_ticks < 648 / _speedMode.GetSpeedMode())
            {
                return;
            }

            _transferInProgress = false;
            _restarted          = false;
            _ticks = 0;

            for (var i = 0; i < 0xa0; i++)
            {
                _oam.SetByte(0xfe00 + i, _addressSpace.GetByte(_from + i));
            }
        }
 public int GetByte(int address) => _addressSpace.GetByte(Translate(address));
Esempio n. 9
0
        public void Tick()
        {
            _clockCycle++;
            var speed = _speedMode.GetSpeedMode();

            if (_clockCycle >= (4 / speed))
            {
                _clockCycle = 0;
            }
            else
            {
                return;
            }

            if (State == State.OPCODE || State == State.HALTED || State == State.STOPPED)
            {
                if (_interruptManager.IsIme() && _interruptManager.IsInterruptRequested())
                {
                    if (State == State.STOPPED)
                    {
                        _display.Enabled = true;
                    }

                    State = State.IRQ_READ_IF;
                }
            }

            switch (State)
            {
            case State.IRQ_READ_IF:
            case State.IRQ_READ_IE:
            case State.IRQ_PUSH_1:
            case State.IRQ_PUSH_2:
            case State.IRQ_JUMP:
                HandleInterrupt();
                return;

            case State.HALTED when _interruptManager.IsInterruptRequested():
                State = State.OPCODE;

                break;
            }

            if (State == State.HALTED || State == State.STOPPED)
            {
                return;
            }

            var accessedMemory = false;

            while (true)
            {
                var pc = Registers.PC;
                switch (State)
                {
                case State.OPCODE:
                    ClearState();
                    _opcode1       = _addressSpace.GetByte(pc);
                    accessedMemory = true;
                    if (_opcode1 == 0xcb)
                    {
                        State = State.EXT_OPCODE;
                    }
                    else if (_opcode1 == 0x10)
                    {
                        CurrentOpcode = _opcodes.Commands[_opcode1];
                        State         = State.EXT_OPCODE;
                    }
                    else
                    {
                        State         = State.OPERAND;
                        CurrentOpcode = _opcodes.Commands[_opcode1];
                        if (CurrentOpcode == null)
                        {
                            throw new InvalidOperationException($"No command for 0x{_opcode1:X2}");
                        }
                    }

                    if (!_haltBugMode)
                    {
                        Registers.IncrementPc();
                    }
                    else
                    {
                        _haltBugMode = false;
                    }

                    break;

                case State.EXT_OPCODE:
                    if (accessedMemory)
                    {
                        return;
                    }

                    accessedMemory = true;
                    _opcode2       = _addressSpace.GetByte(pc);
                    CurrentOpcode ??= _opcodes.ExtCommands[_opcode2];

                    if (CurrentOpcode == null)
                    {
                        throw new InvalidOperationException($"No command for {_opcode2:X}cb 0x{_opcode2:X2}");
                    }

                    State = State.OPERAND;
                    Registers.IncrementPc();
                    break;

                case State.OPERAND:
                    while (_operandIndex < CurrentOpcode.Length)
                    {
                        if (accessedMemory)
                        {
                            return;
                        }

                        accessedMemory            = true;
                        _operand[_operandIndex++] = _addressSpace.GetByte(pc);
                        Registers.IncrementPc();
                    }

                    _ops  = CurrentOpcode.Ops.ToList();
                    State = State.RUNNING;
                    break;

                case State.RUNNING:
                    if (_opcode1 == 0x10)
                    {
                        if (_speedMode.OnStop())
                        {
                            State = State.OPCODE;
                        }
                        else
                        {
                            State            = State.STOPPED;
                            _display.Enabled = false;
                        }

                        return;
                    }
                    else if (_opcode1 == 0x76)
                    {
                        if (_interruptManager.IsHaltBug())
                        {
                            State        = State.OPCODE;
                            _haltBugMode = true;
                            return;
                        }
                        else
                        {
                            State = State.HALTED;
                            return;
                        }
                    }

                    if (_opIndex < _ops.Count)
                    {
                        var op = _ops[_opIndex];
                        var opAccessesMemory = op.ReadsMemory() || op.WritesMemory();
                        if (accessedMemory && opAccessesMemory)
                        {
                            return;
                        }

                        _opIndex++;

                        var corruptionType = op.CausesOemBug(Registers, _opContext);
                        if (corruptionType != null)
                        {
                            HandleSpriteBug(corruptionType.Value);
                        }

                        _opContext = op.Execute(Registers, _addressSpace, _operand, _opContext);
                        op.SwitchInterrupts(_interruptManager);

                        if (!op.Proceed(Registers))
                        {
                            _opIndex = _ops.Count;
                            break;
                        }

                        if (op.ForceFinishCycle())
                        {
                            return;
                        }

                        if (opAccessesMemory)
                        {
                            accessedMemory = true;
                        }
                    }

                    if (_opIndex >= _ops.Count)
                    {
                        State         = State.OPCODE;
                        _operandIndex = 0;
                        _interruptManager.OnInstructionFinished();
                        return;
                    }

                    break;

                case State.HALTED:
                case State.STOPPED:
                    return;
                }
            }
        }
Esempio n. 10
0
        public void Tick()
        {
            if (_fetchingDisabled && _state == State.ReadTileId)
            {
                if (_fifo.GetLength() <= 8)
                {
                    _fifo.Enqueue8Pixels(EmptyPixelLine, _tileAttributes);
                }

                return;
            }

            if (--_divider == 0)
            {
                _divider = 2;
            }
            else
            {
                return;
            }

stateSwitch:

            switch (_state)
            {
            case State.ReadTileId:
                _tileId = _videoRam0.GetByte(_mapAddress + _xOffset);

                _tileAttributes = _gbc
                            ? TileAttributes.ValueOf(_videoRam1.GetByte(_mapAddress + _xOffset))
                            : TileAttributes.Empty;

                _state = State.ReadData1;
                break;

            case State.ReadData1:
                _tileData1 = GetTileData(_tileId, _tileLine, 0, _tileDataAddress, _tileIdSigned, _tileAttributes, 8);
                _state     = State.ReadData2;
                break;

            case State.ReadData2:
                _tileData2 = GetTileData(_tileId, _tileLine, 1, _tileDataAddress, _tileIdSigned, _tileAttributes, 8);
                _state     = State.Push;
                goto stateSwitch;     // Sorry mum

            case State.Push:
                if (_fifo.GetLength() <= 8)
                {
                    _fifo.Enqueue8Pixels(Zip(_tileData1, _tileData2, _tileAttributes.IsXFlip()), _tileAttributes);
                    _xOffset = (_xOffset + 1) % 0x20;
                    _state   = State.ReadTileId;
                }

                break;

            case State.ReadSpriteTileId:
                _tileId = _oemRam.GetByte(_sprite.GetAddress() + 2);
                _state  = State.ReadSpriteFlags;
                break;

            case State.ReadSpriteFlags:
                _spriteAttributes = TileAttributes.ValueOf(_oemRam.GetByte(_sprite.GetAddress() + 3));
                _state            = State.ReadSpriteData1;
                break;

            case State.ReadSpriteData1:
                if (_lcdc.GetSpriteHeight() == 16)
                {
                    _tileId &= 0xfe;
                }

                _tileData1 = GetTileData(_tileId, _spriteTileLine, 0, 0x8000, false, _spriteAttributes,
                                         _lcdc.GetSpriteHeight());
                _state = State.ReadSpriteData2;
                break;

            case State.ReadSpriteData2:
                _tileData2 = GetTileData(_tileId, _spriteTileLine, 1, 0x8000, false, _spriteAttributes,
                                         _lcdc.GetSpriteHeight());
                _state = State.PushSprite;
                break;

            case State.PushSprite:
                _fifo.SetOverlay(Zip(_tileData1, _tileData2, _spriteAttributes.IsXFlip()), _spriteOffset,
                                 _spriteAttributes, _spriteOamIndex);
                _state = State.ReadTileId;
                break;
            }
        }