Esempio n. 1
0
        private void FormatParameterBlock(int offset, Param[] parms)
        {
            int blockAddr = Util.GetWord(mFileData, offset + 4, 2, false);

            // Try to format the parameter block.  Start by figuring out how long it is.
            int blockLen = 0;

            foreach (Param parm in parms)
            {
                blockLen += parm.Length;
            }

            // Locate it and verify that the entire thing fits in the file.
            int blockOff = mAddrTrans.AddressToOffset(offset, blockAddr);

            if (Util.IsInBounds(mFileData, blockOff, blockLen))
            {
                if (VERBOSE)
                {
                    mAppRef.DebugLog("Formatting P8 block at +" + blockOff.ToString("x6"));
                }

                foreach (Param parm in parms)
                {
                    // We could try to dereference pathname buffers to see if it's a
                    // fixed value and not an empty buffer, but it's hard for us to
                    // reliably tell the difference between a length-limited pathname
                    // and junk.  If the length byte is bad, we run the risk of lumping
                    // a bunch of stuff into the pathname buffer.
                    mAppRef.SetInlineDataFormat(blockOff, parm.Length, parm.Type,
                                                parm.SubType, null);
                    blockOff += parm.Length;
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Converts a JSR/JMP operand to a file offset.
        /// </summary>
        /// <param name="vaddr">AVG address operand.</param>
        /// <param name="baseAddr">Base address of vector memory.</param>
        /// <param name="offset">File offset of instruction.</param>
        /// <returns>False if the target address is outside the file bounds.</returns>
        private bool Branch(int vaddr, int baseAddr, ref int offset)
        {
            int fileAddr   = baseAddr + vaddr * 2;
            int fileOffset = mAddrTrans.AddressToOffset(offset, fileAddr);

            if (fileOffset < 0)
            {
                mAppRef.ReportError("JMP/JSR to " + vaddr.ToString("x4") + " invalid");
                return(false);
            }
            offset = fileOffset;
            return(true);
        }
Esempio n. 3
0
        // IPlugin_SymbolList
        public void UpdateSymbolList(List <PlSymbol> plSyms)
        {
            // reset this every time, in case they remove the symbol
            mChrRomOffset = -1;

            foreach (PlSymbol sym in plSyms)
            {
                if (sym.Label == CHR_ROM)
                {
                    int addr = sym.Value;
                    mChrRomOffset = mAddrTrans.AddressToOffset(0, addr);
                    break;
                }
            }
            mAppRef.DebugLog(CHR_ROM + " @ +" + mChrRomOffset.ToString("x6"));
        }
Esempio n. 4
0
        private IVisualization2d GenerateScreen(ReadOnlyDictionary <string, object> parms)
        {
            //const int RAW_IMAGE_SIZE = 0x1ff8;
            const int HR_WIDTH      = 280;
            const int HR_BYTE_WIDTH = HR_WIDTH / 7;
            const int HR_HEIGHT     = 192;

            int  offset  = Util.GetFromObjDict(parms, P_OFFSET, 0);
            bool isColor = Util.GetFromObjDict(parms, P_IS_COLOR, true);

            if (offset < 0 || offset >= mFileData.Length)
            {
                // should be caught by editor
                mAppRef.ReportError("Invalid parameter");
                return(null);
            }

            //int lastOffset = offset + RAW_IMAGE_SIZE - 1;
            //if (lastOffset >= mFileData.Length) {
            //    mAppRef.ReportError("Bitmap runs off end of file (last offset +" +
            //        lastOffset.ToString("x6") + ")");
            //    return null;
            //}

            // Linearize the data.  To handle programs that move themselves around before
            // executing we use the address translator (e.g. the title screen in Space Eggs
            // is contiguous in memory but split in half in the file).  This is slower, but
            // mAddrTrans is a local (not proxy) object, so it's not too bad.
            byte[] buf      = new byte[HR_BYTE_WIDTH * HR_HEIGHT];
            int    outIdx   = 0;
            int    baseAddr = mAddrTrans.OffsetToAddress(offset);

            for (int row = 0; row < HR_HEIGHT; row++)
            {
                // If row is ABCDEFGH, we want pppFGHCD EABAB000 (where p would be $20/$40).
                int low     = ((row & 0xc0) >> 1) | ((row & 0xc0) >> 3) | ((row & 0x08) << 4);
                int high    = ((row & 0x07) << 2) | ((row & 0x30) >> 4);
                int rowAddr = baseAddr + ((high << 8) | low);

                // Not expecting the data to wrap around, but it's possible.
                rowAddr = (baseAddr & 0xff0000) | (rowAddr & 0xffff);

                for (int col = 0; col < HR_BYTE_WIDTH; col++)
                {
                    int srcOffset = mAddrTrans.AddressToOffset(offset, rowAddr + col);
                    if (srcOffset < 0)
                    {
                        mAppRef.ReportError("Address $" + (rowAddr + col).ToString("x4") +
                                            " is outside of file");
                        return(null);
                    }
                    buf[outIdx++] = mFileData[srcOffset];
                }
            }

            VisBitmap8 vb = new VisBitmap8(HR_WIDTH, HR_HEIGHT);

            SetHiResPalette(vb);
            RenderBitmap(buf, 0, HR_BYTE_WIDTH, HR_HEIGHT, 1, HR_BYTE_WIDTH,
                         isColor ? ColorMode.SimpleColor : ColorMode.Mono, false, false,
                         vb, 0, 0);
            return(vb);
        }
        public void CheckBrk(int offset, bool twoByteBrk, out bool noContinue)
        {
            noContinue = true;

            // need BRK, function byte, and two-byte address
            if (!Util.IsInBounds(mFileData, offset, 4))
            {
                return;
            }
            byte func = mFileData[offset + 1];

            if (func != 0x85 && (func < 0x01 || func > 0x02))
            {
                return;
            }

            Util.FormatBrkByte(mAppRef, twoByteBrk, offset, DataSubType.Hex, null);
            mAppRef.SetInlineDataFormat(offset + 2, 2, DataType.NumericLE,
                                        DataSubType.Address, null);
            noContinue = false;

            int structAddr = Util.GetWord(mFileData, offset + 2, 2, false);
            int structOff  = mAddrTrans.AddressToOffset(offset, structAddr);

            if (structOff < 0)
            {
                mAppRef.DebugLog("Unable to get offset for address $" + structAddr.ToString("x6"));
                return;
            }

            switch (func)
            {
            case 0x01:
                if (!Util.IsInBounds(mFileData, structOff, 27))
                {
                    mAppRef.DebugLog("Struct doesn't fit in file");
                    return;
                }
                mAppRef.SetInlineDataFormat(structOff + 0, 2, DataType.NumericLE,
                                            DataSubType.Decimal, null);
                mAppRef.SetInlineDataFormat(structOff + 2, 2, DataType.NumericBE,
                                            DataSubType.Hex, null);
                mAppRef.SetInlineDataFormat(structOff + 4, 4, DataType.NumericLE,
                                            DataSubType.Hex, null);
                mAppRef.SetInlineDataFormat(structOff + 8, 4, DataType.NumericBE,
                                            DataSubType.Hex, null);
                mAppRef.SetInlineDataFormat(structOff + 12, 1, DataType.NumericLE,
                                            DataSubType.Ascii, null);
                mAppRef.SetInlineDataFormat(structOff + 13, 1, DataType.NumericLE,
                                            DataSubType.HighAscii, null);
                mAppRef.SetInlineDataFormat(structOff + 14, 8, DataType.StringDci,
                                            DataSubType.Ascii, null);
                mAppRef.SetInlineDataFormat(structOff + 22, 3, DataType.NumericLE,
                                            DataSubType.Address, null);
                mAppRef.SetInlineDataFormat(structOff + 25, 2, DataType.NumericLE,
                                            DataSubType.Symbol, "data02");
                break;

            case 0x02:
                if (!Util.IsInBounds(mFileData, structOff, 2))
                {
                    mAppRef.DebugLog("Struct doesn't fit in file");
                    return;
                }
                mAppRef.SetInlineDataFormat(structOff, 2, DataType.NumericLE,
                                            DataSubType.Address, null);
                int nextAddr = Util.GetWord(mFileData, structOff + 2, 2, false);
                int nextOff  = mAddrTrans.AddressToOffset(structOff, nextAddr);
                if (!Util.IsInBounds(mFileData, nextOff, 1))
                {
                    mAppRef.DebugLog("Struct doesn't fit in file");
                    return;
                }
                mAppRef.SetInlineDataFormat(nextOff, 8, DataType.StringGeneric,
                                            DataSubType.HighAscii, null);
                break;

            case 0x85:
                // do nothing further
                break;
            }
        }
Esempio n. 6
0
        // IPlugin_InlineJsr
        public void CheckJsr(int offset, int operand, out bool noContinue)
        {
            noContinue = false;

            // Do a quick test on the target address.
            int unused;

            if (!mInlineAddrs.TryGetValue(operand, out unused))
            {
                // JSR destination address not special.
                return;
            }

            // Address matched.  Translate the target address to the actual offset.  This is
            // important when multiple offsets have the same address.
            int targetOffset = mAddrTrans.AddressToOffset(offset, operand);

            if (targetOffset < 0)
            {
                mAppRef.DebugLog("Failed to map address $" + operand.ToString("x4") + " to offset");
                return;
            }
            InlineKind kind;

            if (!mInlineOffsets.TryGetValue(targetOffset, out kind))
            {
                // Actual call target doesn't have a matching label.
                return;
            }

            offset += 3;    // move past JSR

            switch (kind)
            {
            case InlineKind.InAZ:
                // Null-terminated ASCII string.
                FormatNullTermString(offset, false);
                break;

            case InlineKind.InA1:
                // Length-delimited ASCII string
                FormatL1String(offset, false);
                break;

            case InlineKind.InPZ:
                // Null-terminated PETSCII string.
                FormatNullTermString(offset, true);
                break;

            case InlineKind.InP1:
                // Length-delimited PETSCII string
                FormatL1String(offset, true);
                break;

            case InlineKind.InW:
            case InlineKind.InWA:
                // 16-bit value. Start by confirming next two bytes are inside the file bounds.
                if (!Util.IsInBounds(mFileData, offset, 2))
                {
                    return;
                }

                if (kind == InlineKind.InW)
                {
                    // Format 16-bit value as default (hex).
                    mAppRef.SetInlineDataFormat(offset, 2,
                                                DataType.NumericLE, DataSubType.None, null);
                }
                else
                {
                    // Format 16-bit value as an address.
                    mAppRef.SetInlineDataFormat(offset, 2,
                                                DataType.NumericLE, DataSubType.Address, null);
                }
                break;

            case InlineKind.InNR:
                // Non-returning call.
                noContinue = true;
                break;
            }
        }
Esempio n. 7
0
        private void FormatParameterBlock(int offset, ParamSet pset)
        {
            if (VERBOSE)
            {
                mAppRef.DebugLog("SOSPARM: trying to format SOS at +" + offset.ToString("x6"));
            }
            int blockAddr = Util.GetWord(mFileData, offset + 2, 2, false);

            // Try to format the parameter block.  Start by figuring out how long the
            // required portion is.
            int blockLen = 0;

            foreach (Param parm in pset.Required)
            {
                blockLen += parm.Length;
            }

            int optionListAddr = -1;
            int optionListLen  = -1;

            // Locate it and verify that the entire thing fits in the file.
            int blockOff = mAddrTrans.AddressToOffset(offset, blockAddr);

            if (VERBOSE)
            {
                mAppRef.DebugLog("SOSPARM:  checking addr=$" + blockAddr.ToString("x4") +
                                 " off=+" + blockOff.ToString("x6") + " len=" + blockLen);
            }
            if (Util.IsInBounds(mFileData, blockOff, blockLen))
            {
                if (VERBOSE)
                {
                    mAppRef.DebugLog("SOSPARM:  formatting block at +" + blockOff.ToString("x6"));
                }

                foreach (Param parm in pset.Required)
                {
                    // Watch for option list parameters.
                    if (parm == OPTION_LIST)
                    {
                        optionListAddr = Util.GetWord(mFileData, blockOff, 2, false);
                    }
                    else if (parm == OPTION_LENGTH)
                    {
                        optionListLen = mFileData[blockOff];
                    }

                    // We could try to dereference pathname buffers to see if it's a
                    // fixed value and not an empty buffer, but it's hard for us to
                    // reliably tell the difference between a length-limited pathname
                    // and junk.  If the length byte is bad, we run the risk of lumping
                    // a bunch of stuff into the pathname buffer.

                    mAppRef.SetInlineDataFormat(blockOff, parm.Length, parm.Type,
                                                parm.SubType, null);
                    blockOff += parm.Length;
                }
            }
            else
            {
                if (VERBOSE)
                {
                    mAppRef.DebugLog("SOSPARM:  NOT in bounds");
                }
            }

            if (optionListAddr >= 0 && optionListLen > 0)
            {
                if (VERBOSE)
                {
                    mAppRef.DebugLog("SOSPARM:  format optionList addr=$" +
                                     optionListAddr.ToString("x4") + " len=" + optionListLen);
                }
                blockOff = mAddrTrans.AddressToOffset(offset, optionListAddr);
                if (Util.IsInBounds(mFileData, blockOff, optionListLen))
                {
                    // Format the parts of the option list that are present.
                    int usedLen = 0;

                    foreach (Param parm in pset.Optional)
                    {
                        if (usedLen + parm.Length > optionListLen)
                        {
                            // This parameter was not provided.
                            break;
                        }

                        mAppRef.SetInlineDataFormat(blockOff, parm.Length, parm.Type,
                                                    parm.SubType, null);
                        blockOff += parm.Length;
                        usedLen  += parm.Length;
                    }
                }
            }
        }
Esempio n. 8
0
        public void CheckJsr(int offset, int operand, out bool noContinue)
        {
            const int MLI_ENTRY = 0xbf00;

            noContinue = false;
            if (offset + 6 < mFileData.Length && operand == MLI_ENTRY)
            {
                // match!

                byte req       = mFileData[offset + 3];
                int  blockAddr = Util.GetWord(mFileData, offset + 4, 2, false);
                if (VERBOSE)
                {
                    mAppRef.DebugLog("P8 MLI call detected at +" + offset.ToString("x6") +
                                     ", cmd=$" + req.ToString("x2") + " addr=$" + blockAddr.ToString("x4"));
                }

                PlSymbol sym;
                if (mFunctionList.TryGetValue(req, out sym))
                {
                    mAppRef.SetInlineDataFormat(offset + 3, 1, DataType.NumericLE,
                                                DataSubType.Symbol, sym.Label);
                }
                else
                {
                    mAppRef.SetInlineDataFormat(offset + 3, 1, DataType.NumericLE,
                                                DataSubType.None, null);
                }
                mAppRef.SetInlineDataFormat(offset + 4, 2, DataType.NumericLE,
                                            DataSubType.Address, null);

                Param[] parms;
                if (ParamDescrs.TryGetValue(req, out parms))
                {
                    // Try to format the parameter block.  Start by figuring out how long it is.
                    int blockLen = 0;
                    foreach (Param parm in parms)
                    {
                        blockLen += parm.Length;
                    }

                    // Locate it and verify that the entire thing fits in the file.
                    int blockOff = mAddrTrans.AddressToOffset(offset, blockAddr);
                    if (Util.IsInBounds(mFileData, blockOff, blockLen))
                    {
                        if (VERBOSE)
                        {
                            mAppRef.DebugLog("Formatting P8 block at +" + blockOff.ToString("x6"));
                        }

                        foreach (Param parm in parms)
                        {
                            // We could try to dereference pathname buffers to see if it's a
                            // fixed value and not an empty buffer, but it's hard for us to
                            // reliably tell the difference between a length-limited pathname
                            // and junk.  If the length byte is bad, we run the risk of lumping
                            // a bunch of stuff into the pathname buffer.
                            mAppRef.SetInlineDataFormat(blockOff, parm.Length, parm.Type,
                                                        parm.SubType, null);
                            blockOff += parm.Length;
                        }
                    }
                }

                if (req == 0x65)            // QUIT call
                {
                    noContinue = true;
                }
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Attempts to format the parameter block that is passed into the GS/OS call.
        /// </summary>
        /// <remarks>
        /// All "class 1" GS/OS calls have a parameter block that begins with a parameter
        /// count.  The count indicates how many parameters are provided after the pCount
        /// field.  This is a field count, not a byte count, and may be zero.
        ///
        /// Sometimes different calls will overlap, e.g GET_FILE_INFO and SET_FILE_INFO.  This
        /// is generally only done when the parameters line up, so I'm not expecting things
        /// to come out weird, but it's possible.
        /// </remarks>
        private void FormatParameterBlock(int offset, int req, int blockAddr)
        {
            Param[] parms;
            if (!ParamDescrs.TryGetValue(req, out parms))
            {
                // We don't have a parameter list for this call.
                return;
            }

            int blockOff = mAddrTrans.AddressToOffset(offset, blockAddr);

            int paramCount;

            if (req < 0x0100)
            {
                // ProDOS-16 parameter blocks are fixed-length.
                paramCount = parms.Length;
            }
            else
            {
                // Confirm we can at least get the parameter count.
                if (!Util.IsInBounds(mFileData, blockOff, 2))
                {
                    return;
                }
                int pCount = Util.GetWord(mFileData, blockOff, 2, false);
                if (pCount >= parms.Length)
                {
                    // Might be an uninitialized value.  Just format the pCount.
                    pCount = 1;
                }

                paramCount = pCount + 1;    // add 1 for pCount itself
            }

            // Compute parameter block length in bytes.
            int blockLen = 0;

            for (int i = 0; i < paramCount; i++)
            {
                blockLen += parms[i].Length;
            }

            // Confirm that the entire thing fits in the file.
            if (!Util.IsInBounds(mFileData, blockOff, blockLen))
            {
                return;
            }

            if (VERBOSE)
            {
                mAppRef.DebugLog("Formatting GS/OS call block at +" + blockOff.ToString("x6") +
                                 ", count=" + paramCount);
            }

            // Format each entry.
            for (int i = 0; i < paramCount; i++)
            {
                Param parm = parms[i];
                mAppRef.SetInlineDataFormat(blockOff, parm.Length, parm.Type,
                                            parm.SubType, null);
                blockOff += parm.Length;
            }
        }