Пример #1
0
        /// <summary>
        /// Drop extra source words outside of the update region when searching for
        /// the first edge of a new scan line.  Updates _srcNeedsAligned when found.
        /// To avoid some overhead, is only called in Idle state if _srcNeedsAligned
        /// is true and the _srcFifo is not empty.  [could just inline this in Clock()
        /// and save a funtion call]
        /// </summary>
        private void ClearLeadingSrcWords()
        {
            // We only need to align the first edge in a Begin phase; else no-op
            if (_phase == Phase.Begin || _phase == Phase.BeginEnd || _phase == Phase.BeginEndClear)
            {
                ROpWord w = _srcFifo.Peek();
                w.Mask = SrcWordMask(w.Index);

                if ((w.Mask == CombinerFlags.Both) ||
                    (_direction == Direction.LeftToRight && w.Mask == CombinerFlags.LeftEdge) ||
                    (_direction == Direction.RightToLeft && w.Mask == CombinerFlags.RightEdge))
                {
                    _srcNeedsAligned = false;   // Found our first edge
                    _halfPipe        = w;       // Prime the half-pipeline register
                }

                if (_srcNeedsAligned)
                {
#if TRACING_ENABLED
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.RasterOp, "RasterOp: --> Dropping leading word ({0})", w.Mask);
                    }
#endif
                    _srcFifo.Dequeue();
                }
            }
        }
Пример #2
0
        private RasterOp()
        {
            _ropShifter = new Shifter();            // Our own private Idaho
            _srcFifo    = new Queue <ROpWord>(16);  // 4 quads (hardware limit)
            _destFifo   = new Queue <ROpWord>(4);   // 1 quad
            _halfPipe   = new ROpWord();            // 1 word, for overlap
            _rdsTable   = new CombinerFlags[512];   // 9 bit index
            _rscTable   = new EdgeStrategy[128];    // 7 bit index

            LoadRasterOpROMs();
        }
Пример #3
0
        /// <summary>
        /// Drop extra words from the Source FIFO that are outside the update region.
        /// Called in SrcFetch if _leftOver is true.
        /// </summary>
        private void ClearExtraSrcWords()
        {
            // We only need to clear after the second edge in an End/Clear phase
            if (_phase == Phase.EndClear || _phase == Phase.BeginEndClear)
            {
                if (_srcFifo.Count == 0)
                {
                    // We've completed our DestFetch and used up all the source words; obviously
                    // there ain't no more to clear, so reset for the start of the next line.
                    _leftOver        = false;
                    _srcNeedsAligned = true;
#if TRACING_ENABLED
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.RasterOp, "RasterOp: --> Reset for first edge");
                    }
#endif
                }
                else
                {
                    // We're here when there are still extra source words left over from the previous
                    // scan line.  We only want to drop words through the end of the current quad.
                    ROpWord w = _srcFifo.Peek();

                    if ((_direction == Direction.LeftToRight && w.Index == 3) ||
                        (_direction == Direction.RightToLeft && w.Index == 0))
                    {
                        _leftOver        = false;
                        _srcNeedsAligned = true;
#if TRACING_ENABLED
                        if (Trace.TraceOn)
                        {
                            Trace.Log(LogType.RasterOp, "RasterOp: --> End of scan line, reset for first edge ({0})", w.Mask);
                        }
#endif
                        _srcFifo.Dequeue();
                    }

                    if (_leftOver)
                    {
#if TRACING_ENABLED
                        if (Trace.TraceOn)
                        {
                            Trace.Log(LogType.RasterOp, "RasterOp: --> Clearing extra word ({0})", w.Mask);
                        }
#endif
                        _srcFifo.Dequeue();
                    }
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Populates and returns a ROpWord with the address, index and data
        /// of the current memory word (but throws an error if MDI is invalid).
        /// </summary>
        private ROpWord FetchNextWord()
        {
            ROpWord w = new ROpWord();

            if (MemoryBoard.Instance.MDIValid)
            {
                // The microcode calculates the addresses and initiates fetches;
                // we just pluck the next incoming word off the MDI.
                w.Address = MemoryBoard.Instance.MADR;
                w.Index   = MemoryBoard.Instance.MIndex;
                w.Data    = MemoryBoard.Instance.MDI;
            }
            else
            {
#if DEBUG
                // For debugging we just try to continue, but we're pretty hosed at this point...
                Console.WriteLine("RasterOp: FetchNextWord in {0} while MDI was invalid!", _state);
                w.Clear();
#else
                throw new InvalidOperationException("RasterOp: FetchNextWord while MDI was invalid!");
#endif
            }
            return(w);
        }
Пример #5
0
        /// <summary>
        /// Aligns and combines the Source and Destination words to produce a RasterOp
        /// result word.  Called during DestFetch as each word arrives to avoid
        /// complications from the delay in the overlapped Fetch/Store cycle.
        /// </summary>
        private ROpWord ComputeResult(ROpWord dest)
        {
            ROpWord      src = dest;                    // init to silence the Xamarin compiler...
            EdgeStrategy e = EdgeStrategy.NoPopNoPeek;  // assume nothing!  n/a in non-edge cases anyway
            ushort       aligned, combined;

#if TRACING_ENABLED
            if (Trace.TraceOn)
            {
                Trace.Log(LogType.RasterOp, "RasterOp: Result dest word: {0}", dest);
            }
#endif

            #region Align Words

            // The Emperor has made a critical error, and the time for our word
            // alignment has come.  Admiral Ackbar will explain the plan of attack:
            //
            // 1.   At the start of a scanline, our source FIFO is aligned and the
            //      half-pipeline register is "primed".  This means we should be
            //      guaranteed to have at least the first edge word in the FIFO;
            // 2.   If the source spans the quad but the destination doesn't (or
            //      vice versa), we have to account for the "two edges into one"
            //      problem - pull in the extra source word (source L+R -> dest B)
            //      or hold the source word one extra cycle (dest L+R <- source B);
            // 3.   In all other modes, we should be able to just pop the next word
            //      so the FIFOs move in lock step (while in the source region), he
            //      said, handwaving furiously.
            //
            // The RSC03 ROM tells the hardware how to cope with the source FIFO; here
            // we use a lookup table to deal with all the complicated edge alignment
            // rules outlined above.
            //
            // Many Bothans died to bring us this information...

            // Look at the destination word to find our edges and set the _leftOver flag
            switch (dest.Mask)
            {
            // Outside the first edge: return dest unmodified, don't touch the source FIFO
            case CombinerFlags.DontMask:
                return(dest);

            // Outside the second edge: return dest unmodified, but pop the source word too.
            // In some cases we do legitimately clear the last source word, so test for that.
            case CombinerFlags.Leftover:
                if (_srcFifo.Count > 0)
                {
                    src = _srcFifo.Dequeue();
#if DEBUG
                    src.Mask = SrcWordMask(src.Index);      // for debugging, not necessary otherwise
#endif
#if TRACING_ENABLED
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.RasterOp, "RasterOp: Dropped src word: {0}", src);
                    }
#endif
                }
                return(dest);

            // Full word (any phase): should always have a matching source word
            case CombinerFlags.FullWord:
                try
                {
                    src = _srcFifo.Dequeue();
#if DEBUG
                    src.Mask = SrcWordMask(src.Index);      // for debugging, not necessary otherwise
#endif
                }
                catch (InvalidOperationException)
                {
#if DEBUG
                    Console.WriteLine("Source FIFO empty at Full word!");       // continuing will probably fail...
#else
                    throw new InvalidOperationException("Source FIFO empty and Result expected");
#endif
                }
                break;

            // Left edge: flag the beginning or end of the update region
            // Right edge: opposite of left, flag the other end :-)
            case CombinerFlags.LeftEdge:
            case CombinerFlags.RightEdge:
                _leftOver = (dest.Mask == CombinerFlags.LeftEdge && _direction == Direction.RightToLeft) ||
                            (dest.Mask == CombinerFlags.RightEdge && _direction == Direction.LeftToRight);

                if (_srcFifo.Count > 0)
                {
                    src      = _srcFifo.Peek();
                    src.Mask = SrcWordMask(src.Index);
                    e        = GetEdgeStrategy(dest.Mask, src.Mask);
                }
                else if (_leftOver && (_extraSrcWord || _xOffset > 0))
                {
                    // At the end of a line (either direction) we are peeking forward
                    // but have run out of source words.  In this case we copy the half-
                    // pipeline register (in essence, not popping the second edge word)
                    // to provide enough bits to complete the line.
                    src = _halfPipe;
                }
                else
                {
#if DEBUG
                    Console.WriteLine("Source FIFO empty at {0} word!", dest.Mask);       // continuing will probably fail...
#else
                    throw new InvalidOperationException("Source FIFO empty and Result expected");
#endif
                }
                break;

            // Both edges in one word
            case CombinerFlags.Both:
                _leftOver = true;           // But... but... it's false too!  Ow, my head.

                try
                {
                    src      = _srcFifo.Peek();
                    src.Mask = SrcWordMask(src.Index);
                    e        = GetEdgeStrategy(dest.Mask, src.Mask);
                }
                catch (InvalidOperationException)
                {
#if DEBUG
                    Console.WriteLine("Source FIFO empty at Both edges word!");        // continuing will probably fail..
#else
                    throw new InvalidOperationException("Source FIFO empty and Result expected");
#endif
                }
                break;

            // Should never happen if our RDS00 ROM table is correct!
            case CombinerFlags.Invalid:
                throw new InvalidOperationException("RasterOp Destination result word has Invalid mask");
            }

            // Pop the current word?
            if (e == EdgeStrategy.PopPeek || e == EdgeStrategy.PopNoPeek)
            {
                _srcFifo.Dequeue();
                // Mask was already set
            }

            // Peek ahead to the next?
            if (e == EdgeStrategy.PopPeek || e == EdgeStrategy.NoPopPeek)
            {
                src      = _srcFifo.Dequeue();
                src.Mask = SrcWordMask(src.Index);
            }

#if TRACING_ENABLED
            if (Trace.TraceOn)
            {
                Trace.Log(LogType.RasterOp, "RasterOp: Next source word: {0}", src);
            }
#endif

            #endregion

            #region Align Bits

            // The destination word is in the update region and our source word is aligned.
            // If bit alignment is needed, feed the saved word from the half pipe to the
            // shifter with the current word.  Note that the MSB of the combined shifter
            // inputs is always the leftmost pixel in the update region (so, dependent upon
            // the direction of transfer).
            if (_xOffset != 0)
            {
                if (_direction == Direction.LeftToRight)
                {
#if TRACING_ENABLED
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.RasterOp, "RasterOp: Result xtra (hi): {0:x4}", _halfPipe);
                    }
#endif
                    _ropShifter.Shift(src.Data, _halfPipe.Data);
                }
                else
                {
#if TRACING_ENABLED
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.RasterOp, "RasterOp: Result xtra (lo): {0:x4}", _halfPipe);
                    }
#endif
                    _ropShifter.Shift(_halfPipe.Data, src.Data);
                }

                // Save the current source word
                _halfPipe = src;

                // Grab the aligned source word from the shifter
                aligned = _ropShifter.ShifterOutput;
            }
            else
            {
                // Already in alignment
                aligned = src.Data;
            }

#if TRACING_ENABLED
            if (Trace.TraceOn)
            {
                Trace.Log(LogType.RasterOp, "RasterOp: Result aligned:  {0:x4}", aligned);
            }
#endif
            #endregion

            #region Combine 'em

            // Finally! Combine source & dest words using the appropriate mask
            switch (dest.Mask)
            {
            case CombinerFlags.LeftEdge:
                combined = Combine(dest.Data, aligned, _leftEdgeMask);
                break;

            case CombinerFlags.RightEdge:
                combined = Combine(dest.Data, aligned, _rightEdgeMask);
                break;

            case CombinerFlags.Both:
                combined = Combine(dest.Data, aligned, _bothEdgesMask);
                break;

            case CombinerFlags.FullWord:
                combined = Combine(dest.Data, aligned, 0xffff);
                break;

            default:
                combined = dest.Data;       // This can't actually happen (silence a warning)
                break;
            }

#if TRACING_ENABLED
            if (Trace.TraceOn)
            {
                Trace.Log(LogType.RasterOp, "RasterOp: Result combined: {0:x4} (func={1})", combined, _function);
            }
#endif

            #endregion


            // For debugging, we return the ROpWord, updated with the combined result.
            // At some point when this is fully debugged, the dest FIFO could be a
            // simple queue of ushorts, which could improve efficiency.
            dest.Data = combined;
            return(dest);
        }