Пример #1
0
        private DisassemblyItem DecodeInstruction(ushort address, OperationMapBase opInfo)
        {
            // --- By default, unknown codes are NOP operations
            var disassemblyItem = new DisassemblyItem(address)
            {
                OpCodes     = _currentOpCodes.ToString(),
                Instruction = "nop",
                LastAddress = (ushort)(_offset - 1)
            };

            if (opInfo == null)
            {
                return(disassemblyItem);
            }

            // --- We have a real operation, it's time to decode it
            var pragmaCount = 0;

            disassemblyItem.Instruction = opInfo.InstructionPattern;
            do
            {
                var pragmaIndex = disassemblyItem.Instruction.IndexOf("^", StringComparison.Ordinal);
                if (pragmaIndex < 0)
                {
                    break;
                }
                pragmaCount++;
                ProcessPragma(disassemblyItem, pragmaIndex);
            } while (pragmaCount < 4);

            // --- We've fully processed the instruction
            disassemblyItem.OpCodes     = _currentOpCodes.ToString();
            disassemblyItem.LastAddress = (ushort)(_offset - 1);
            return(disassemblyItem);
        }
Пример #2
0
        /// <summary>
        /// Generates byte array output for the specified section
        /// </summary>
        /// <param name="section">Section information</param>
        private void GenerateByteArray(MemorySection section)
        {
            var length = section.EndAddress - section.StartAddress + 1;

            for (var i = 0; i < length; i += 8)
            {
                var sb = new StringBuilder(200);
                sb.Append(".defb ");
                for (var j = 0; j < 8; j++)
                {
                    if (i + j >= length)
                    {
                        break;
                    }
                    if (j > 0)
                    {
                        sb.Append(", ");
                    }
                    sb.AppendFormat("#{0:X2}", MemoryContents[section.StartAddress + i + j]);
                }
                var item = new DisassemblyItem((ushort)(section.StartAddress + i))
                {
                    Instruction = sb.ToString()
                };
                _output.AddItem(item);
            }
        }
        /// <summary>
        /// Checks if the disassembler should enter into Spectrum-specific mode after
        /// the specified disassembly item.
        /// </summary>
        /// <param name="item">Item used to check the Spectrum-specific mode</param>
        /// <returns>
        /// True, to move to the Spectrum-specific mode; otherwise, false
        /// </returns>
        private bool ShouldEnterSpectrumSpecificMode(DisassemblyItem item)
        {
            // --- Check for Spectrum 48K RST #08
            if ((DisassemblyFlags & SpectrumSpecificDisassemblyFlags.Spectrum48Rst08) != 0 &&
                item?.OpCodes.Trim() == "CF")
            {
                _spectMode       = SpectrumSpecificMode.Spectrum48Rst08;
                item.HardComment = "(Report error)";
                return(true);
            }

            // --- Check for Spectrum 48K RST #28
            if ((DisassemblyFlags & SpectrumSpecificDisassemblyFlags.Spectrum48Rst28) != 0 &&
                (item?.OpCodes.Trim() == "EF" ||            // --- RST #28
                 item?.OpCodes.Trim() == "CD 5E 33" ||      // --- CALL 335E
                 item?.OpCodes.Trim() == "CD 62 33"))       // --- CALL 3362
            {
                _spectMode       = SpectrumSpecificMode.Spectrum48Rst28;
                _seriesCount     = 0;
                item.HardComment = "(Invoke Calculator)";
                return(true);
            }

            return(false);
        }
Пример #4
0
 /// <summary>
 /// Generates word array output for the specified section
 /// </summary>
 /// <param name="section">Section information</param>
 private void GenerateWordArray(MemorySection section)
 {
     var length = section.EndAddress - section.StartAddress + 1;
     for (var i = 0; i < length; i += 8)
     {
         if (i + 1 >= length) break;
         var sb = new StringBuilder(200);
         sb.Append(".defw ");
         for (var j = 0; j < 8; j += 2)
         {
             if (i + j + 1 >= length) break;
             if (j > 0)
             {
                 sb.Append(", ");
             }
             var value = (ushort)(MemoryContents[section.StartAddress + i + j * 2] +
                         (MemoryContents[section.StartAddress + i + j * 2 + 1] << 8));
             sb.AppendFormat("#{0:X4}", value);
         }
         var item = new DisassemblyItem((ushort)(section.StartAddress + i))
         {
             Instruction = sb.ToString()
         };
         _output.AddItem(item);
     }
     if (length % 2 == 1)
     {
         GenerateByteArray(new MemorySection(section.EndAddress, section.EndAddress));
     }
 }
Пример #5
0
 /// <summary>
 /// Generates skip output for the specified section
 /// </summary>
 /// <param name="section">Section information</param>
 private void GenerateSkipOutput(MemorySection section)
 {
     var item = new DisassemblyItem(section.StartAddress)
     {
         Instruction = $".skip {section.EndAddress - section.StartAddress + 1:X4}H"
     };
     _output.AddItem(item);
 }
Пример #6
0
        /// <summary>
        /// Generates byte array output for the specified section
        /// </summary>
        /// <param name="section">Section information</param>
        /// <param name="rowBytes">Number of bytes to add to a .DEFG row</param>
        private void GenerateDefgArray(MemorySection section, int rowBytes)
        {
            var length    = section.EndAddress - section.StartAddress + 1;
            var sb        = new StringBuilder(200);
            var opCodes   = new StringBuilder();
            var byteInRow = 0;
            var startAddr = section.StartAddress;

            for (var i = 0; i < length; i++)
            {
                if (byteInRow == 0)
                {
                    sb.Append(".defg");
                }

                var content = MemoryContents[section.StartAddress + i];
                opCodes.Append($"{content:X2} ");
                sb.Append(" ");
                for (var j = 0; j < 8; j++)
                {
                    sb.Append((content & 0x80) == 0 ? "." : "X");
                    content <<= 1;
                }

                byteInRow++;
                if (byteInRow >= rowBytes)
                {
                    byteInRow = 0;
                    var item = new DisassemblyItem(startAddr)
                    {
                        Instruction = sb.ToString(),
                        OpCodes     = opCodes.ToString()
                    };
                    _output.AddItem(item);
                    startAddr = (ushort)(section.StartAddress + i + 1);
                    sb.Clear();
                    opCodes.Clear();
                }
            }

            if (byteInRow == 0)
            {
                return;
            }
            var lastItem = new DisassemblyItem(startAddr)
            {
                Instruction = sb.ToString(),
                OpCodes     = opCodes.ToString()
            };

            _output.AddItem(lastItem);
        }
Пример #7
0
        /// <summary>
        /// Checks if the disassembler should enter into Spectrum-specific mode after
        /// the specified disassembly item.
        /// </summary>
        /// <param name="item">Item used to check the Spectrum-specific mode</param>
        /// <returns>
        /// True, to move to the Spectrum-specific mode; otherwise, false
        /// </returns>
        private bool ShouldEnterSpectrumSpecificMode(DisassemblyItem item)
        {
            // --- Check if we find flags for the bank of the disassembly item
            var bank = item.Address >> 14;

            if (!DisassemblyFlags.TryGetValue(bank, out var flags) ||
                flags == SpectrumSpecificDisassemblyFlags.None)
            {
                return(false);
            }

            // --- Check for Spectrum 48K RST #08
            if ((flags & SpectrumSpecificDisassemblyFlags.Spectrum48Rst08) != 0 &&
                item.OpCodes.Trim() == "CF")
            {
                _spectMode       = SpectrumSpecificMode.Spectrum48Rst08;
                item.HardComment = "(Report error)";
                return(true);
            }

            // --- Check for Spectrum 48K RST #28
            if ((flags & SpectrumSpecificDisassemblyFlags.Spectrum48Rst28) != 0 &&
                (item.OpCodes.Trim() == "EF" ||            // --- RST #28
                 item.OpCodes.Trim() == "CD 5E 33" ||      // --- CALL 335E
                 item.OpCodes.Trim() == "CD 62 33"))       // --- CALL 3362
            {
                _spectMode       = SpectrumSpecificMode.Spectrum48Rst28;
                _seriesCount     = 0;
                item.HardComment = "(Invoke Calculator)";
                return(true);
            }

            // --- Check for Spectrum 128K RST #28
            if ((flags & SpectrumSpecificDisassemblyFlags.Spectrum128Rst28) != 0 &&
                item.OpCodes.Trim() == "EF")
            {
                _spectMode       = SpectrumSpecificMode.Spectrum128Rst8;
                item.HardComment = "(Call Spectrum 48 ROM)";
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Disassembles the subsequent operation as Spectrum-specific
        /// </summary>
        /// <param name="carryOn">
        /// True, if the disassembler still remains in Spectrum-specific mode;
        /// otherwise, false
        /// </param>
        /// <returns>Disassembled operation</returns>
        private DisassemblyItem DisassembleSpectrumSpecificOperation(out bool carryOn)
        {
            if (_spectMode == SpectrumSpecificMode.None)
            {
                carryOn = false;
                return(null);
            }

            DisassemblyItem item = null;

            carryOn = false;

            // --- Handle Spectrum 48 Rst08
            if (_spectMode == SpectrumSpecificMode.Spectrum48Rst08)
            {
                // --- The next byte is the operation code
                var address   = (ushort)_offset;
                var errorCode = Fetch();
                _spectMode = SpectrumSpecificMode.None;
                item       = new DisassemblyItem(address)
                {
                    OpCodes     = $"{errorCode:X2}",
                    Instruction = $".defb #{errorCode:X2}",
                    HardComment = $"(error code: #{errorCode:X2})",
                    LastAddress = (ushort)(_offset - 1)
                };
            }

            // --- Handle Spectrum 48 Rst08
            if (_spectMode == SpectrumSpecificMode.Spectrum48Rst28)
            {
                var address  = (ushort)_offset;
                var calcCode = Fetch();
                item = DisassembleCalculatorEntry(address, calcCode, out carryOn);
            }

            if (!carryOn)
            {
                _spectMode = SpectrumSpecificMode.None;
            }
            return(item);
        }
Пример #9
0
 /// <summary>
 /// Adds a new item to the output
 /// </summary>
 /// <param name="item">Disassembly item to add</param>
 public void AddItem(DisassemblyItem item)
 {
     _outputItems.Add(item);
     _outputByAddress.Add(item.Address, item);
 }
Пример #10
0
        private void ProcessPragma(DisassemblyItem disassemblyItem, int pragmaIndex)
        {
            var instruction = disassemblyItem.Instruction;

            if (pragmaIndex >= instruction.Length)
            {
                return;
            }

            var pragma        = instruction[pragmaIndex + 1];
            var replacement   = "";
            var symbolPresent = false;
            var symbolValue   = (ushort)0x000;

            switch (pragma)
            {
            case '8':
                // --- #8: 8-bit value defined on bit 3, 4 and 5 ($00, $10, ..., $38)
                var val = (byte)(_opCode & 0x38);
                replacement = ByteToString(val);
                break;

            case 'b':
                // --- #b: bit index defined on bit 3, 4 and 5 in bit operations
                var bit = (byte)((_opCode & 0x38) >> 3);
                replacement = bit.ToString();
                break;

            case 'r':
                // --- #r: relative label (8 bit offset)
                var distance  = Fetch();
                var labelAddr = (ushort)(_opOffset + 2 + (sbyte)distance);
                _output.CreateLabel(labelAddr, (ushort)_opOffset);
                replacement   = GetLabelName(labelAddr);
                symbolPresent = true;
                disassemblyItem.HasLabelSymbol = true;
                symbolValue = labelAddr;
                break;

            case 'L':
                // --- #L: absolute label (16 bit address)
                var target = FetchWord();
                disassemblyItem.TargetAddress = target;
                _output.CreateLabel(target, (ushort)_opOffset);
                replacement   = GetLabelName(target);
                symbolPresent = true;
                disassemblyItem.HasLabelSymbol = true;
                symbolValue = target;
                break;

            case 'q':
                // --- #q: 8-bit registers named on bit 3, 4 and 5 (B, C, ..., (HL), A)
                var regqIndex = (_opCode & 0x38) >> 3;
                replacement = s_Q8Regs[regqIndex];
                break;

            case 's':
                // --- #q: 8-bit registers named on bit 0, 1 and 2 (B, C, ..., (HL), A)
                var regsIndex = _opCode & 0x07;
                replacement = s_Q8Regs[regsIndex];
                break;

            case 'Q':
                // --- #Q: 16-bit register pair named on bit 4 and 5 (BC, DE, HL, SP)
                var regQIndex = (_opCode & 0x30) >> 4;
                replacement = s_Q16Regs[regQIndex];
                break;

            case 'R':
                // --- #Q: 16-bit register pair named on bit 4 and 5 (BC, DE, HL, AF)
                var regRIndex = (_opCode & 0x30) >> 4;
                replacement = s_R16Regs[regRIndex];
                break;

            case 'B':
                // --- #B: 8-bit value from the code
                var value = Fetch();
                replacement   = ByteToString(value);
                symbolPresent = true;
                symbolValue   = value;
                break;

            case 'W':
                // --- #W: 16-bit word from the code
                var word = FetchWord();
                replacement   = WordToString(word);
                symbolPresent = true;
                symbolValue   = word;
                break;

            case 'X':
                // --- #X: Index register (IX or IY) according to current index mode
                replacement = _indexMode == 1 ? "ix": "iy";
                break;

            case 'l':
                // --- #l: Lowest 8 bit index register (XL or YL) according to current index mode
                replacement = _indexMode == 1 ? "xl" : "yl";
                break;

            case 'h':
                // --- #h: Highest 8 bit index register (XH or YH) according to current index mode
                replacement = _indexMode == 1 ? "xh" : "yh";
                break;

            case 'D':
                // --- #D: Index operation displacement
                if (_displacement.HasValue)
                {
                    replacement = (sbyte)_displacement < 0
                            ? $"-{ByteToString((byte) (0x100 - _displacement.Value))}"
                            : $"+{ByteToString(_displacement.Value)}";
                }
                break;
            }

            if (symbolPresent && !string.IsNullOrEmpty(replacement))
            {
                disassemblyItem.TokenPosition = pragmaIndex;
                disassemblyItem.TokenLength   = replacement.Length;
                disassemblyItem.HasSymbol     = true;
                disassemblyItem.SymbolValue   = symbolValue;
            }
            disassemblyItem.Instruction = instruction.Substring(0, pragmaIndex)
                                          + (replacement ?? "")
                                          + instruction.Substring(pragmaIndex + 2);
        }
Пример #11
0
        /// <summary>
        /// Disassembles the subsequent operation as Spectrum-specific
        /// </summary>
        /// <param name="carryOn">
        /// True, if the disassembler still remains in Spectrum-specific mode;
        /// otherwise, false
        /// </param>
        /// <returns>Disassembled operation</returns>
        private DisassemblyItem DisassembleSpectrumSpecificOperation(out bool carryOn)
        {
            if (_spectMode == SpectrumSpecificMode.None)
            {
                carryOn = false;
                return(null);
            }

            DisassemblyItem item = null;

            carryOn = false;

            // --- Handle Spectrum 48 RST #08
            if (_spectMode == SpectrumSpecificMode.Spectrum48Rst08)
            {
                // --- The next byte is the operation code
                var address   = (ushort)_offset;
                var errorCode = Fetch();
                _spectMode = SpectrumSpecificMode.None;
                item       = new DisassemblyItem(address)
                {
                    Instruction = $".defb #{errorCode:X2}",
                    HardComment = $"(error code: #{errorCode:X2})",
                    LastAddress = (ushort)(_offset - 1)
                };
            }

            // --- Handle Spectrum 48 RST #28
            if (_spectMode == SpectrumSpecificMode.Spectrum48Rst28)
            {
                var address  = (ushort)_offset;
                var calcCode = Fetch();
                item = DisassembleCalculatorEntry(address, calcCode, out carryOn);
            }

            // --- Handle Spectrum 128 RST #08
            if (_spectMode == SpectrumSpecificMode.Spectrum128Rst8)
            {
                // --- The next byte is the operation code
                var address     = (ushort)_offset;
                var callAddress = FetchWord();
                _spectMode = SpectrumSpecificMode.None;
                item       = new DisassemblyItem(address)
                {
                    Instruction = $".defw #{callAddress:X4}",
                    LastAddress = (ushort)(_offset - 1)
                };
                var provider = GetProvider <ISpectrum48RomLabelProvider>();
                var label    = provider?.GetSpectrum48Label(callAddress);
                if (label != null)
                {
                    item.HardComment = $"({label})";
                }
            }

            if (!carryOn)
            {
                _spectMode = SpectrumSpecificMode.None;
            }
            return(item);
        }
Пример #12
0
        /// <summary>
        /// Disassemble a calculator entry
        /// </summary>
        private DisassemblyItem DisassembleCalculatorEntry(ushort address, byte calcCode, out bool carryOn)
        {
            // --- Create the default disassembly item
            var item = new DisassemblyItem(address)
            {
                LastAddress = (ushort)(_offset - 1),
                Instruction = $".defb #{calcCode:X2}"
            };

            var opCodes = new List <byte> {
                calcCode
            };

            carryOn = true;

            // --- If we're in series mode, obtain the subsequent series value
            if (_seriesCount > 0)
            {
                var lenght = (calcCode >> 6) + 1;
                if ((calcCode & 0x3F) == 0)
                {
                    lenght++;
                }
                for (var i = 0; i < lenght; i++)
                {
                    var nextByte = Fetch();
                    opCodes.Add(nextByte);
                }
                item.Instruction = ".defb " + string.Join(", ", opCodes.Select(o => $"#{o:X2}"));
                item.HardComment = $"({FloatNumber.FromCompactBytes(opCodes)})";
                _seriesCount--;
                return(item);
            }

            // --- Generate the output according the calculation op code
            switch (calcCode)
            {
            case 0x00:
            case 0x33:
            case 0x35:
                var jump = Fetch();
                opCodes.Add(jump);
                var jumpAddr = (ushort)(_offset - 1 + (sbyte)jump);
                _output.CreateLabel(jumpAddr, null);
                item.Instruction = $".defb #{calcCode:X2}, #{jump:X2}";
                item.HardComment = $"({s_CalcOps[calcCode]}: {GetLabelName(jumpAddr)})";
                carryOn          = calcCode != 0x33;
                break;

            case 0x34:
                _seriesCount     = 1;
                item.HardComment = "(stk-data)";
                break;

            case 0x38:
                item.HardComment = "(end-calc)";
                carryOn          = false;
                break;

            case 0x86:
            case 0x88:
            case 0x8C:
                _seriesCount     = calcCode - 0x80;
                item.HardComment = $"(series-0{calcCode-0x80:X1})";
                break;

            case 0xA0:
            case 0xA1:
            case 0xA2:
            case 0xA3:
            case 0xA4:
                var constNo = calcCode - 0xA0;
                item.HardComment = GetIndexedCalcOp(0x3F, constNo);
                break;

            case 0xC0:
            case 0xC1:
            case 0xC2:
            case 0xC3:
            case 0xC4:
            case 0xC5:
                var stNo = calcCode - 0xC0;
                item.HardComment = GetIndexedCalcOp(0x40, stNo);
                break;

            case 0xE0:
            case 0xE1:
            case 0xE2:
            case 0xE3:
            case 0xE4:
            case 0xE5:
                var getNo = calcCode - 0xE0;
                item.HardComment = GetIndexedCalcOp(0x41, getNo);
                break;

            default:
                var comment = s_CalcOps.ContainsKey(calcCode)
                        ? s_CalcOps[calcCode]
                        : $"calc code: #{calcCode:X2}";
                item.HardComment = $"({comment})";
                break;
            }
            return(item);
        }