Beispiel #1
0
        public override void FormatInstruction(TextWriter writer, Context ctx, Instruction inst)
        {
            // label or indent
            if (inst.Parent == null)
            {
                writer.Write(INDENT);
            }
            else
            {
                writer.Write(INST_LABEL, inst.PC);
            }

            ZOpAttribute attr = ctx.GetOpcodeInfo(inst.Op);

            // instruction name
            writer.Write('@');
            writer.Write(attr.InformName);

            // regular operands
            ushort[]      operands = inst.Operands;
            OperandType[] otypes   = inst.OperandTypes;

            for (int i = 0; i < otypes.Length; i++)
            {
                switch (otypes[i])
                {
                case OperandType.Word:
                case OperandType.Byte:
                    writer.Write(' ');
                    writer.Write((short)operands[i]);
                    break;

                case OperandType.Variable:
                    writer.Write(' ');
                    writer.Write(FormatVariable(operands[i]));
                    break;
                }
            }

            // text
            ushort[] text = inst.EncodedText;
            if (text != null)
            {
                writer.Write(" \"");

                foreach (char c in ctx.DecodeText(text))
                {
                    switch (c)
                    {
                    case '\n':
                        writer.Write('^');
                        break;

                    case '"':
                        writer.Write('\"');
                        break;

                    default:
                        //XXX handle @ and other characters that need escaping
                        writer.Write(c);
                        break;
                    }
                }

                writer.Write('"');
            }

            // store target
            if (inst.StoreTarget != null)
            {
                writer.Write(" -> ");
                writer.Write(FormatVariable(inst.StoreTarget.Value));
            }

            // branch target
            if (inst.BranchType != BranchType.None)
            {
                writer.Write(" ?");
                switch (inst.BranchType)
                {
                case BranchType.LongNegative:
                case BranchType.ShortNegative:
                    writer.Write('~');
                    break;
                }

                switch (inst.BranchOffset)
                {
                case 0:
                    writer.Write("rfalse");
                    break;

                case 1:
                    writer.Write("rtrue");
                    break;

                default:
                    writer.Write("zc_{0:x5}", inst.PC + inst.Length + inst.BranchOffset - 2);
                    break;
                }
            }

            // done
            writer.WriteLine(';');
        }
Beispiel #2
0
        public static Instruction Decode(Context ctx, BinaryReader rdr, int pc)
        {
            int length = 1;

            // read opcode number and look up opcode info
            ushort op = rdr.ReadByte();

            if (op == 190 && ctx.ZVersion >= 5)
            {
                op = (ushort)(256 + rdr.ReadByte());
                length++;
            }

            // canonicalize opcode number and decode operand types
            OperandType[] otypes;

            if (op < 128)
            {
                // long, 2OP
                otypes = new OperandType[2];

                if ((op & 0x40) == 0)
                {
                    otypes[0] = OperandType.Byte;
                }
                else
                {
                    otypes[0] = OperandType.Variable;
                }

                if ((op & 0x20) == 0)
                {
                    otypes[1] = OperandType.Byte;
                }
                else
                {
                    otypes[1] = OperandType.Variable;
                }

                op &= 0x1f;     // clear operand type bits
            }
            else if (op < 192)
            {
                // short
                if (op < 176)
                {
                    // 1OP
                    otypes = new[] { (OperandType)((op >> 4) & 3) };
                    op    &= 0xcf;  // clear operand type bits
                }
                else
                {
                    // 0OP
                    otypes = new OperandType[] { };
                }
            }
            else
            {
                // variable
                if (op == 236 || op == 250)
                {
                    otypes = new OperandType[8];
                }
                else
                {
                    otypes = new OperandType[4];
                }

                if (op < 224)
                {
                    // 2OP
                    op &= 0x1f;      // translate to 2OP opcode number
                }
                // otherwise VAR (op < 256) or EXT

                for (int i = 0; 4 * i < otypes.Length; i++)
                {
                    byte b = rdr.ReadByte();
                    length++;
                    otypes[4 * i]     = (OperandType)((b >> 6) & 3);
                    otypes[4 * i + 1] = (OperandType)((b >> 4) & 3);
                    otypes[4 * i + 2] = (OperandType)((b >> 2) & 3);
                    otypes[4 * i + 3] = (OperandType)(b & 3);
                }
            }

            // look up opcode info
            ZOpAttribute attr = ctx.GetOpcodeInfo(op);

            if (attr == null)
            {
                return(null);
            }

            // read operand values
            ushort[] operands = new ushort[otypes.Length];

            for (int i = 0; i < otypes.Length; i++)
            {
                switch (otypes[i])
                {
                case OperandType.Word:
                    operands[i] = rdr.ReadZWord();
                    length     += 2;
                    break;

                case OperandType.Byte:
                case OperandType.Variable:
                    operands[i] = rdr.ReadByte();
                    length++;
                    break;
                }
            }

            // read store/branch targets
            byte?storeTarget = null;

            if ((attr.Flags & ZOpFlags.Store) != 0)
            {
                storeTarget = rdr.ReadByte();
                length++;
            }

            BranchType branchType;
            short      branchOffset = 0;

            if ((attr.Flags & ZOpFlags.Branch) != 0)
            {
                byte b = rdr.ReadByte();
                length++;
                branchType = (BranchType)(b & 0xc0);

                switch (branchType)
                {
                case BranchType.LongNegative:
                case BranchType.LongPositive:
                    // signed 14-bit offset: last 6 bits of b followed by all 8 of the next byte
                    // we shift right by 2 to extend the sign from 14 to 16 bits
                    short s = (short)(((b & 0x3f) << 10) | (rdr.ReadByte() << 2));
                    length++;
                    branchOffset = (short)(s >> 2);
                    break;

                case BranchType.ShortNegative:
                case BranchType.ShortPositive:
                    // unsigned 6-bit offset: last 6 bits of b
                    branchOffset = (short)(b & 0x3f);
                    break;
                }
            }
            else
            {
                branchType = BranchType.None;
            }

            // read text
            ushort[] encodedText = null;
            if ((attr.Flags & ZOpFlags.String) != 0)
            {
                List <ushort> list = new List <ushort>();
                ushort        w;
                do
                {
                    w       = rdr.ReadZWord();
                    length += 2;
                    list.Add(w);
                } while ((w & 0x8000) == 0);

                encodedText = list.ToArray();
            }

            // done
            var result = new Instruction(pc, length)
            {
                branchOffset = branchOffset,
                branchType   = branchType,
                encodedText  = encodedText,
                op           = op,
                operandTypes = otypes,
                operands     = operands,
                storeTarget  = storeTarget
            };

            return(result);
        }
Beispiel #3
0
        public override void FormatInstruction(TextWriter writer, Context ctx, Instruction inst)
        {
            // label or indent
            if (inst.Parent == null)
            {
                writer.Write(INDENT);
            }
            else
            {
                writer.Write(INST_LABEL, inst.PC);
            }

            ZOpAttribute attr = ctx.GetOpcodeInfo(inst.Op);

            // instruction name
            writer.Write(attr.ClassicName);

            // regular operands
            ushort[]      operands = inst.Operands;
            OperandType[] otypes   = inst.OperandTypes;

            bool any = false;

            for (int i = 0; i < otypes.Length; i++)
            {
                switch (otypes[i])
                {
                case OperandType.Word:
                case OperandType.Byte:
                    if (!any)
                    {
                        writer.Write(' ');
                        any = true;
                    }
                    else
                    {
                        writer.Write(',');
                    }
                    if (i == 0)
                    {
                        if ((attr.Flags & ZOpFlags.Call) != 0)
                        {
                            writer.Write("ZR${0:X4}", operands[i]);
                            continue;
                        }
                        if ((attr.Flags & ZOpFlags.Label) != 0)
                        {
                            writer.Write("ZC${0:X5}", inst.PC + inst.Length + (short)operands[i] - 2);
                            continue;
                        }
                        if ((attr.Flags & ZOpFlags.IndirectVar) != 0)
                        {
                            writer.Write('\'');
                            writer.Write(FormatVariable(operands[i]));
                            continue;
                        }
                    }
                    writer.Write((short)operands[i]);
                    break;

                case OperandType.Variable:
                    if (!any)
                    {
                        writer.Write(' ');
                        any = true;
                    }
                    else
                    {
                        writer.Write(',');
                    }
                    writer.Write(FormatVariable(operands[i]));
                    break;
                }
            }

            // text
            ushort[] text = inst.EncodedText;
            if (text != null)
            {
                writer.Write(" \"");

                foreach (char c in ctx.DecodeText(text))
                {
                    switch (c)
                    {
                    case '"':
                        writer.Write("\"\"");
                        break;

                    default:
                        writer.Write(c);
                        break;
                    }
                }

                writer.Write('"');
            }

            // store target
            if (inst.StoreTarget != null)
            {
                writer.Write(" >");
                writer.Write(FormatVariable(inst.StoreTarget.Value));
            }

            // branch target
            if (inst.BranchType != BranchType.None)
            {
                switch (inst.BranchType)
                {
                case BranchType.LongNegative:
                case BranchType.ShortNegative:
                    writer.Write(" \\");
                    break;

                case BranchType.LongPositive:
                case BranchType.ShortPositive:
                    writer.Write(" /");
                    break;
                }

                switch (inst.BranchOffset)
                {
                case 0:
                    writer.Write("FALSE");
                    break;

                case 1:
                    writer.Write("TRUE");
                    break;

                default:
                    writer.Write("ZC${0:X5}", inst.PC + inst.Length + inst.BranchOffset - 2);
                    break;
                }
            }

            writer.WriteLine();
        }