コード例 #1
0
 void UpdateLineCounterAndIRQ(int lineNum)
 {
     _lineCounter = lineNum;
     if ((_ram.ReadIO(0xd01a, false) & 0x1) > 0)
     {
         int targetLineNum = (_ram.ReadIO(0xd011, false) & 0x80) * 2 + _ram.ReadIO(0xd012, false);
         if (_lineCounter == targetLineNum)
         {
             _processor.SetIRQ();
         }
     }
     if (_timer > 0 && (_ram.ReadIO(0xdc0e, false) & 0x1) > 0)
     {
         _timer -= VIC2.CYCLES_PER_LINE;
         if (_timer <= 0)
         {
             _timer = 0;
             if (_timerIRQEnable)
             {
                 _timerIRQFlag = true;
                 _processor.SetIRQ();
             }
         }
     }
 }
コード例 #2
0
    public void BufferSamples(int cpuCycles)
    {
        if (cpuCycles == 0)
        {
            return;
        }

        // Adjust amount of cycles to render based on buffer fill
        float multiplier = 1f + (1764 - samples.Count) / 8192f;

        // Let multiplier remain at 1 when we're executing the playroutine, to make sure ADSR behavior is accurate
        if (cpuCycles <= VIC2.CYCLES_PER_LINE * 2)
        {
            multiplier = 1f;
        }
        cpuCycles = (int)(multiplier * cpuCycles);

        for (int i = 0; i < 3; ++i)
        {
            ushort ioBase = (ushort)(0xd400 + i * 7);
            _channels[i].frequency = (ushort)(_ram.ReadIO(ioBase) | (_ram.ReadIO((ushort)(ioBase + 1)) << 8));
            _channels[i].pulse     = (ushort)(_ram.ReadIO((ushort)(ioBase + 2)) | (_ram.ReadIO((ushort)(ioBase + 3)) << 8));
            _channels[i].waveform  = _ram.ReadIO((ushort)(ioBase + 4));
            _channels[i].ad        = _ram.ReadIO((ushort)(ioBase + 5));
            _channels[i].sr        = _ram.ReadIO((ushort)(ioBase + 6));
        }

        float masterVol    = (_ram.ReadIO(0xd418) & 0xf) / 22.5f;
        byte  filterSelect = (byte)(_ram.ReadIO(0xd418) & 0x70);
        byte  filterCtrl   = _ram.ReadIO(0xd417);

        // Filter cutoff & resonance
        // Adjusted to be slightly darker than jsSID
        float cutoff = _ram.ReadIO(0xd416) + 0.2f;

        cutoff = 1f - 1.463f * Mathf.Exp(cutoff * _cutoffRatio);
        if (cutoff < 0.035f)
        {
            cutoff = 0.035f;
        }
        float resonance = (filterCtrl > 0x5f) ? 8f / (filterCtrl >> 4) : 1.41f;

        for (int i = 0; i < cpuCycles; ++i)
        {
            for (int j = 0; j < 3; ++j)
            {
                _channels[j].Clock();
            }
            for (int j = 0; j < 3; ++j)
            {
                if (_channels[j].doSync && (_channels[j].syncTarget.waveform & 0x2) != 0)
                {
                    _channels[j].syncTarget.ResetAccumulator();
                }
            }

            ++_cycleAccumulator;
            if (_cycleAccumulator >= _cyclesPerSample)
            {
                _cycleAccumulator -= _cyclesPerSample;

                float output      = 0f;
                float filterInput = 0f;

                if ((filterCtrl & 1) == 0)
                {
                    output += _channels[0].GetOutput();
                }
                else
                {
                    filterInput += _channels[0].GetOutput();
                }

                if ((filterCtrl & 2) == 0)
                {
                    output += _channels[1].GetOutput();
                }
                else
                {
                    filterInput += _channels[1].GetOutput();
                }

                if ((filterCtrl & 4) == 0)
                {
                    output += _channels[2].GetOutput();
                }
                else
                {
                    filterInput += _channels[2].GetOutput();
                }

                // Highpass
                float temp = filterInput + _prevBandPass * resonance + _prevLowPass;
                if ((filterSelect & 0x40) != 0)
                {
                    output -= temp;
                }
                // Bandpass
                temp          = _prevBandPass - temp * cutoff;
                _prevBandPass = temp;
                if ((filterSelect & 0x20) != 0)
                {
                    output -= temp;
                }
                // Lowpass
                temp         = _prevLowPass + temp * cutoff;
                _prevLowPass = temp;
                if ((filterSelect & 0x10) != 0)
                {
                    output += temp;
                }

                output *= masterVol;
                newSamples.Add(output);
            }
        }

        lock (samplesLock)
        {
            samples.AddRange(newSamples);
            newSamples.Clear();
        }
    }
コード例 #3
0
    public void RenderNextLine()
    {
        if (_lineNum >= 200)
        {
            return;
        }

        int   pixelStart  = _lineNum * 320;
        Color black       = _palette[0];
        Color bgColor     = _palette[_ram.ReadIO(0xd021) & 0xf];
        Color borderColor = _palette[_ram.ReadIO(0xd020) & 0xf];

        byte control       = _ram.ReadIO(0xd011);
        int  yScroll       = control & 0x7;
        int  xScroll       = _ram.ReadIO(0xd016) & 0x7;
        bool hBorders      = (_ram.ReadIO(0xd016) & 0x8) == 0;
        bool vBorders      = (control & 0x8) == 0;
        bool displayEnable = (control & 0x10) != 0;
        bool bitmapMode    = (control & 0x20) != 0;
        bool multiColor    = (_ram.ReadIO(0xd016) & 0x10) != 0;
        bool ebcMode       = (control & 0x40) != 0;

        ushort videoBank     = (ushort)(0xc000 - (_ram.ReadIO(0xdd00) & 0x3) * 0x4000);
        ushort charData      = (ushort)(videoBank + (_ram.ReadIO(0xd018) & 0xe) * 0x400);
        ushort bitmapData    = (ushort)(videoBank + (_ram.ReadIO(0xd018) & 0x8) * 0x400);
        ushort screenAddress = (ushort)(videoBank + (_ram.ReadIO(0xd018) & 0xf0) * 0x40);

        Color mc1 = _palette[_ram.ReadIO(0xd022) & 0xf];
        Color mc2 = _palette[_ram.ReadIO(0xd023) & 0xf];
        Color mc3 = _palette[_ram.ReadIO(0xd024) & 0xf];

        if ((_lineNum == 0 && ((_lineNum + 3) & 0x7) >= yScroll) || (((_lineNum + 3) & 0x7) == yScroll && _lineNum >= _nextBadlineLineNum))
        {
            DoBadLine(yScroll);
        }

        // HACK for Hessian scrolling: actually get chars & colors every line
        if (!_idleState)
        {
            for (int i = 0; i < 40; ++i)
            {
                _lineChars[i]  = _ram.ReadRAM((ushort)(screenAddress + _currentCharRow * 40 + i));
                _lineColors[i] = (byte)(_ram.ReadIO((ushort)(0xd800 + _currentCharRow * 40 + i)) & 0xf);
            }
        }

        int charIndex = 0;
        int charRow   = (_lineNum + 3 - yScroll) & 0x7;
        int bit       = 0x80 << xScroll;

        bool renderSprites = true;

        // V-border or display off
        if (!displayEnable || (vBorders && (_lineNum < 4 || _lineNum >= 196)))
        {
            for (int i = 0; i < 320; ++i)
            {
                _pixels[pixelStart + i] = borderColor;
            }
            renderSprites = false;
        }
        else
        // Idle state or illegal mode (render just black)
        if (_idleState || (ebcMode && multiColor))
        {
            for (int i = 0; i < 320; ++i)
            {
                _pixels[pixelStart + i] = black;
            }
        }
        // Charmode
        else if (!bitmapMode)
        {
            byte charByte = ebcMode ? _ram.ReadRAM((ushort)(charData + (_lineChars[charIndex] & 0x3f) * 8 + charRow)) :
                            _ram.ReadRAM((ushort)(charData + _lineChars[charIndex] * 8 + charRow));

            // Singlecolor
            if (!multiColor)
            {
                for (int i = 0; i < 320; ++i)
                {
                    if (hBorders && (i < 7 || i >= 311))
                    {
                        _pixels[pixelStart + i] = borderColor;
                    }
                    else
                    {
                        if (bit > 0x80 || charByte == 0 || (charByte & bit) == 0)
                        {
                            if (!ebcMode)
                            {
                                _pixels[pixelStart + i] = bgColor;
                            }
                            else
                            {
                                switch (_lineChars[charIndex] >> 6)
                                {
                                case 0:
                                    _pixels[pixelStart + i] = bgColor;
                                    break;

                                case 1:
                                    _pixels[pixelStart + i] = mc1;
                                    break;

                                case 2:
                                    _pixels[pixelStart + i] = mc2;
                                    break;

                                case 3:
                                    _pixels[pixelStart + i] = mc3;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            _pixels[pixelStart + i] = _palette[_lineColors[charIndex]];
                        }
                    }

                    bit >>= 1;
                    if (bit == 0)
                    {
                        bit = 0x80;
                        ++charIndex;
                        if (charIndex < 40)
                        {
                            charByte = ebcMode ? _ram.ReadRAM((ushort)(charData + (_lineChars[charIndex] & 0x3f) * 8 + charRow)) :
                                       _ram.ReadRAM((ushort)(charData + _lineChars[charIndex] * 8 + charRow));
                        }
                    }
                }
            }
            // Multicolor
            else
            {
                int bitPairShift = 0x7 + xScroll;

                for (int i = 0; i < 320; ++i)
                {
                    if (hBorders && (i < 7 || i >= 311))
                    {
                        _pixels[pixelStart + i] = borderColor;
                    }
                    else
                    {
                        if (bit > 0x80 || charByte == 0)
                        {
                            _pixels[pixelStart + i] = bgColor;
                        }
                        else
                        {
                            if (_lineColors[charIndex] < 0x8)
                            {
                                if ((charByte & bit) != 0)
                                {
                                    _pixels[pixelStart + i] = _palette[_lineColors[charIndex]];
                                }
                                else
                                {
                                    _pixels[pixelStart + i] = bgColor;
                                }
                            }
                            else
                            {
                                byte bitPair = (byte)((charByte >> (bitPairShift & 0x6)) & 0x3);
                                switch (bitPair)
                                {
                                case 0:
                                    _pixels[pixelStart + i] = bgColor;
                                    break;

                                case 1:
                                    _pixels[pixelStart + i] = mc1;
                                    break;

                                case 2:
                                    _pixels[pixelStart + i] = mc2;
                                    break;

                                case 3:
                                    _pixels[pixelStart + i] = _palette[_lineColors[charIndex] & 0x7];
                                    break;
                                }
                            }
                        }
                    }

                    bit >>= 1;
                    --bitPairShift;
                    if (bit == 0)
                    {
                        bit          = 0x80;
                        bitPairShift = 0x7;
                        ++charIndex;
                        if (charIndex < 40)
                        {
                            charByte = _ram.ReadRAM((ushort)(charData + _lineChars[charIndex] * 8 + charRow));
                        }
                    }
                }
            }
        }
        else if (bitmapMode)
        {
            byte charByte = _ram.ReadRAM((ushort)(bitmapData + _bitmapRow * 320 + charIndex * 8 + charRow));

            // Singlecolor
            if (!multiColor)
            {
                for (int i = 0; i < 320; ++i)
                {
                    if (hBorders && (i < 7 || i >= 311))
                    {
                        _pixels[pixelStart + i] = borderColor;
                    }
                    else
                    {
                        if (bit > 0x80 || charByte == 0)
                        {
                            _pixels[pixelStart + i] = bgColor;
                        }
                        else
                        {
                            if ((charByte & bit) != 0)
                            {
                                _pixels[pixelStart + i] = _palette[_lineChars[charIndex] >> 4];
                            }
                            else
                            {
                                _pixels[pixelStart + i] = _palette[_lineChars[charIndex] & 0xf];
                            }
                        }
                    }

                    bit >>= 1;
                    if (bit == 0)
                    {
                        bit = 0x80;
                        ++charIndex;
                        if (charIndex < 40)
                        {
                            charByte = _ram.ReadRAM((ushort)(bitmapData + _bitmapRow * 320 + charIndex * 8 + charRow));
                        }
                    }
                }
            }
            // Multicolor
            else
            {
                int bitPairShift = 0x7 + xScroll;

                for (int i = 0; i < 320; ++i)
                {
                    if (hBorders && (i < 7 || i >= 311))
                    {
                        _pixels[pixelStart + i] = borderColor;
                    }
                    else
                    {
                        if (bit > 0x80 || charByte == 0)
                        {
                            _pixels[pixelStart + i] = bgColor;
                        }
                        else
                        {
                            byte bitPair = (byte)((charByte >> (bitPairShift & 0x6)) & 0x3);
                            switch (bitPair)
                            {
                            case 0:
                                _pixels[pixelStart + i] = bgColor;
                                break;

                            case 1:
                                _pixels[pixelStart + i] = _palette[_lineChars[charIndex] >> 4];
                                break;

                            case 2:
                                _pixels[pixelStart + i] = _palette[_lineChars[charIndex] & 0xf];
                                break;

                            case 3:
                                _pixels[pixelStart + i] = _palette[_lineColors[charIndex] & 0xf];
                                break;
                            }
                        }
                    }

                    bit >>= 1;
                    --bitPairShift;
                    if (bit == 0)
                    {
                        bit          = 0x80;
                        bitPairShift = 0x7;
                        ++charIndex;
                        if (charIndex < 40)
                        {
                            charByte = _ram.ReadRAM((ushort)(bitmapData + _bitmapRow * 320 + charIndex * 8 + charRow));
                        }
                    }
                }
            }
        }

        byte spriteFlags        = _ram.ReadIO(0xd015);
        byte spriteMCFlags      = _ram.ReadIO(0xd01c);
        byte spriteXMSBFlags    = _ram.ReadIO(0xd010);
        byte spriteXExpandFlags = _ram.ReadIO(0xd01d);

        Color sprMc1 = _palette[_ram.ReadIO(0xd025) & 0xf];
        Color sprMc2 = _palette[_ram.ReadIO(0xd026) & 0xf];

        for (int i = 7; i >= 0; --i)
        {
            byte spriteY = _ram.ReadIO((ushort)(0xd001 + i * 2));
            if (!_spriteActive[i] && (spriteFlags & bitValues[i]) != 0)
            {
                if (_lineNum == spriteY - 50 || (_lineNum == 0 && spriteY >= 30 && spriteY < 50))
                {
                    _spriteActive[i] = true;
                    _spriteRow[i]    = (byte)(_lineNum + 50 - spriteY);
                }
            }

            if (_spriteActive[i])
            {
                // TODO: Y expansion, background priority
                if (renderSprites)
                {
                    int startX = _ram.ReadIO((ushort)(0xd000 + i * 2));
                    if ((spriteXMSBFlags & bitValues[i]) != 0)
                    {
                        startX += 256;
                    }
                    bool xExpand = (spriteXExpandFlags & bitValues[i]) != 0;
                    if (xExpand && startX >= 480 && startX < 504)
                    {
                        startX -= 504;
                    }

                    ushort spriteData  = (ushort)(videoBank + _ram.ReadRAM((ushort)(screenAddress + 0x3f8 + i)) * 0x40 + _spriteRow[i] * 3);
                    Color  spriteColor = _palette[_ram.ReadIO((ushort)(0xd027 + i)) & 0xf];

                    for (int j = 0; j < 24; ++j)
                    {
                        int  k          = xExpand ? (startX + j * 2 - 24) : (startX + j - 24);
                        byte spriteByte = _ram.ReadRAM((ushort)(spriteData + (j >> 3)));

                        for (int l = 0; l < (xExpand ? 2 : 1); ++l)
                        {
                            if (k >= 0 && k <= 320 && (!hBorders || (k >= 7 && k < 311)) && spriteByte != 0)
                            {
                                if ((spriteMCFlags & bitValues[i]) != 0)
                                {
                                    byte bitPair = (byte)((spriteByte >> (6 - (j & 0x6))) & 0x3);
                                    switch (bitPair)
                                    {
                                    case 1:
                                        _pixels[pixelStart + k] = sprMc1;
                                        break;

                                    case 2:
                                        _pixels[pixelStart + k] = spriteColor;
                                        break;

                                    case 3:
                                        _pixels[pixelStart + k] = sprMc2;
                                        break;
                                    }
                                }
                                else
                                {
                                    if ((spriteByte & bitValues[7 - (j & 0x7)]) != 0)
                                    {
                                        _pixels[pixelStart + k] = spriteColor;
                                    }
                                }
                            }
                            ++k;
                        }
                    }
                }

                ++_spriteRow[i];
                if (_spriteRow[i] >= 21)
                {
                    _spriteActive[i] = false;
                }
            }
        }

        // Done, increment linecount
        ++_lineNum;
    }