Exemple #1
0
        public MemoryController(string name)
        {
            _name     = name;
            _bkmTable = new BookmarkEntry[256];

            LoadBookmarkROM();

            Reset();
        }
Exemple #2
0
        /// <summary>
        /// Load the BKM16 ROM image from disk.
        /// </summary>
        private void LoadBookmarkROM()
        {
            // BKM is a lookup table with an 8-bit index, returning an 8-bit value
            FileStream fs = new FileStream(Paths.BuildPROMPath("bkm16emu.rom"), FileMode.Open);

            for (int i = 0; i < 256; i++)
            {
                // Split the result byte into fields once, rather than on every lookup :-)
                _bkmTable[i] = new BookmarkEntry((byte)fs.ReadByte());
            }
            fs.Close();

#if TRACING_ENABLED
            if (Trace.TraceOn)
            {
                Trace.Log(LogType.EmuState, "Initialized BKM ROM lookup table.");
            }
#endif
        }
Exemple #3
0
        /// <summary>
        /// Sets bookmarks for the next cycle, and modifies the current one if necessary.
        /// WARNING: THIS IS WHERE THE SAUSAGE IS MADE.
        /// </summary>
        private void UpdateBookmarks(MemoryCycle nextCycle)
        {
            if (nextCycle == MemoryCycle.None)
            {
                // If no active or pending op, reset our bookmark
                if (!_current.Active && !_pending.Active)
                {
                    _bookmark = 0;
                }
            }
            else
            {
                // This microinstruction specifies a new memory request: initialize
                // the next bookmark value based on the request type
                int book = (int)nextCycle;

                //
                // Special cases for RasterOp
                //
                if (RasterOp.Instance.Enabled)
                {
                    if (Tstate == 0)
                    {
                        // First: we're allowed to issue Store4/4R in T0, ahead of the
                        // usual T3.  So we tweak the cycle type to index the bookmark
                        // ROM with the modified timings.
                        if (nextCycle == MemoryCycle.Store4R)
                        {
                            book = 0x2;         // "RopStore4R"
                        }
                        else if (nextCycle == MemoryCycle.Store4)
                        {
                            book = 0x4;         // "RopStore4"
                        }
                    }
                    else if (Tstate == 3)
                    {
                        //
                        // Second: Fetch4/4Rs are issued back-to-back (in the correct t3)
                        // but must NOT introduce the possible CPU abort of a WaitT2 state;
                        // MDI must remain valid AND the index values must count down correctly
                        // for the operation in progress, so that after the t0,t1 complete the
                        // next op's four words arrive in the four subsequent Tstates.  This
                        // introduces two additional fake cycle types, as with the case above.  Ugh..
                        //
                        if (_current.CycleType == MemoryCycle.Fetch4R && nextCycle == MemoryCycle.Fetch4R)
                        {
                            _bookmark = book = 0x1;     // "RopFetch4R"
                        }
                        else if (_current.CycleType == MemoryCycle.Fetch4 && nextCycle == MemoryCycle.Fetch4)
                        {
                            _bookmark = book = 0x3;     // "RopFetch4"
                        }
                    }
                }

                // For RasterOp special cases, use the modified bookmark for the entire cycle
                _nextBookmark = book;

                //
                // Special cases for indirect or overlapped Fetches (non-RasterOp)
                //
                if (MemoryBoard.Instance.IsFetch(nextCycle))
                {
                    //
                    // Back-to-back Fetch or Fetch2 requests present unique timing challenges
                    // (and allow a small performance boost by eliminating some wait states).
                    // To accommodate this with as little embarrassment as possible, we use a
                    // transitional bookmark value to cover the overlap. For a Fetch, this may
                    // terminate the op early, invalidating one or more time slots where MDI is
                    // valid (and forcing a CPU wait so that incorrect data is not returned).
                    // In other cases we have to let the current op retire normally but drop
                    // immediately into a WaitT2 (rather than WaitT3) for the new op.  There's
                    // no pretty way to deal with this...
                    //
                    // Gory details in the comments below.  Look away now for "plausible deniability".
                    //
                    if (_current.CycleType == MemoryCycle.Fetch || _current.CycleType == MemoryCycle.Fetch2)
                    {
                        book          = 0x6;            // "IndFetch" covers the overlap...
                        _bookmark     = book;           // ...force immediate switch for the (t2,t3)...
                        _nextBookmark = (int)nextCycle; // ...but switch back to the real cycle type in Request()
                    }
                    else if (_current.CycleType == MemoryCycle.Fetch4 && !RasterOp.Instance.Enabled)
                    {
                        book          = 0x7;            // "IndFetch4" is for the specific case of a RefillOp
                        _bookmark     = book;           // followed immediately by another Fetch; can't clobber the
                        _nextBookmark = (int)nextCycle; // last index word, or the last two OpFile bytes are screwed
                    }
                }

                // Get a new set of flags -- these may modify the current cycle!
                BookmarkEntry flags = GetBookmarkEntry(book, _nextState);

#if DEBUG
                // If the Recognize flag is not set, we're really out in left field...
                // ... but all of this can go away entirely once things are fully debugged.
                if (!flags.Recognize)
                {
                    Console.WriteLine("-->\t{0} queue: Recognize not set for new {1} request in T{2}!", _name, nextCycle, Tstate);

                    // If the Abort flag isn't set either, our BKM16 ROM is buggy; force an
                    // abort and just hope for the best?
                    if (!flags.Abort)
                    {
                        Console.WriteLine("-->\tForced abort in T{0} due to new request in wrong cycle.", Tstate);
                        Console.WriteLine("\tFlags: {0}", flags);
                        DumpQueue();
                        flags.Abort = true;
                        // PERQSystem.Instance.Break();
                    }
                }
#endif

                // If the done flag is set, retire the current op (may be early,
                // if a Fetch is overlapped)
                if (flags.Complete)
                {
#if TRACING_ENABLED
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.MemoryState, "{0} queue: Terminated {1}", _name, _current);
                    }
#endif
                    _current.Clear();
                }

                // Set the wait and next state based on the new flags
                _wait      = flags.Abort;
                _nextState = flags.NextState;
            }
        }