Exemple #1
0
        private void IncrementOamAddrAndCheckOverflow(int increment)
        {
            byte temp = (byte)(this.oamAddr + increment);

            if (temp < this.oamAddr)
            {
                this.currentState = SpriteEvaluationState.EvaluationComplete;
            }
            else
            {
                this.oamAddr = temp;
            }
        }
Exemple #2
0
        private void DoSpriteEvaluation()
        {
            if (this.cycle == 0)
            {
                this.currentState             = SpriteEvaluationState.EvaluateYCoord;
                this.spritesFound             = 0;
                this.spriteZeroOnNextScanline = false;
            }
            else if (this.cycle <= 64)
            {
                this.overrideOamRead = true;

                if ((this.cycle & 0x01) == 0x01)
                {
                    // Odd cycle - write 0xFF to secondary OAM
                    this.secondaryOam[this.cycle >> 1] = 0xFF;
                }
            }
            else if (this.cycle <= 256)
            {
                this.overrideOamRead = false;

                if ((this.cycle & 0x01) == 0x01)
                {
                    // Odd cycle - read data for the current sprite from primary OAM
                    // NOTE: This assumes OAMADDR was reset to 0 as expected during ticks 257-320 of the previous
                    //  scanline.  If game code modifies OAMADDR afterwards, lots of weird stuff can happen.
                    this.spriteEvalTemp = this.primaryOam[this.oamAddr];
                }
                else
                {
                    // Even cycle - write to secondary OAM
                    switch (this.currentState)
                    {
                    case SpriteEvaluationState.EvaluateYCoord:
                        this.secondaryOam[this.spritesFound * 4] = spriteEvalTemp;

                        // If the Y coordinate of the sprite is in range, we need to copy the rest of its data
                        //  from primary OAM.  Ignore results on line 239, as no sprites are shown on line 0.
                        if (this.scanline >= this.spriteEvalTemp && this.scanline < (this.spriteEvalTemp + (this.tallSprites ? 16 : 8)) && this.scanline != 239)
                        {
                            if (!this.spriteZeroOnNextScanline)
                            {
                                this.spriteZeroOnNextScanline = this.cycle == 66;
                            }

                            currentState = SpriteEvaluationState.CopyTileIndex;
                            this.oamAddr++;
                        }
                        else
                        {
                            // Sprite was not in range, check the next one
                            this.IncrementOamAddrAndCheckOverflow(4);
                        }
                        break;

                    case SpriteEvaluationState.CopyTileIndex:
                        this.secondaryOam[(this.spritesFound * 4) + 1] = spriteEvalTemp;
                        this.currentState = SpriteEvaluationState.CopyAttributes;
                        this.IncrementOamAddrAndCheckOverflow(1);
                        break;

                    case SpriteEvaluationState.CopyAttributes:
                        this.secondaryOam[(this.spritesFound * 4) + 2] = spriteEvalTemp;
                        this.currentState = SpriteEvaluationState.CopyXCoord;
                        this.IncrementOamAddrAndCheckOverflow(1);
                        break;

                    case SpriteEvaluationState.CopyXCoord:
                        this.secondaryOam[(this.spritesFound * 4) + 3] = spriteEvalTemp;

                        this.spritesFound++;
                        if (this.spritesFound == 8)
                        {
                            // Found 8 sprites for this line - continue processing to check for overflow
                            this.currentState = SpriteEvaluationState.OverflowCheck;
                        }
                        else
                        {
                            // Look for another sprite on this line
                            this.currentState = SpriteEvaluationState.EvaluateYCoord;
                        }

                        this.IncrementOamAddrAndCheckOverflow(1);
                        break;

                    case SpriteEvaluationState.OverflowCheck:
                        if (this.scanline >= this.spriteEvalTemp && this.scanline < (this.spriteEvalTemp + 8))
                        {
                            // Found another sprite on a full scanline
                            this.spriteOverflow = true;
                            this.IncrementOamAddrAndCheckOverflow(4);
                        }
                        else
                        {
                            // Sprite isn't on this scanline, check the next one
                            // 2C02 BUG: The OAM address is incremented by 5 in this case, so the Y coordinate
                            //  evaluated for further sprites won't actually be the Y coordinate
                            this.IncrementOamAddrAndCheckOverflow(5);
                        }

                        break;

                    case SpriteEvaluationState.EvaluationComplete:
                        // Do nothing
                        break;
                    }
                }
            }
            else if (this.cycle <= 320)
            {
                this.oamAddr = 0;
            }
        }