Exemple #1
0
        public DecodedString Decode(SpanLocation location)
        {
            var decoder = new ZStringDecoder(machine);
            var result  = decoder.Decode(location);

            return(result);
        }
Exemple #2
0
        public override void Prepare(SpanLocation memory)
        {
            operandResolver.AddOperands(Operands, memory.Bytes.Slice(1));

            Size      = 2 + Operands.Size;
            OpCode    = Bits.BottomFive(memory.Bytes[0]);
            Operation = OpCode switch
            {
                0x00 => new Operation(nameof(Call), Call, hasStore: true),
                0x01 => new Operation(nameof(StoreW), StoreW),
                0x03 => new Operation(nameof(PutProp), PutProp),
                0x04 => new Operation(nameof(Read), Read),
                0x05 => new Operation(nameof(PrintChar), PrintChar),
                0x06 => new Operation(nameof(PrintNum), PrintNum),
                0x08 => new Operation(nameof(Push), Push),
                0x09 => new Operation(nameof(Pull), Pull),
                _ => throw new InvalidOperationException($"Unknown VAR opcode {OpCode:X}")
            };
            if (Operation.HasStore)
            {
                StoreResult = memory.Bytes[Size];
                Size       += 1;
            }
            if (Operation.HasBranch)
            {
                Size += Branch.Size;
                throw new NotImplementedException("Do this");
            }

            DumpToLog(memory, Size);
        }
Exemple #3
0
        public void Call(SpanLocation memory)
        {
            var callAddress = machine.Memory.Unpack(Operands[0].Value);

            if (callAddress == 0)
            {
                machine.SetVariable(StoreResult, 0);
                log.Debug($"\tCall {callAddress:X} -> {StoreResult}");
                machine.SetPC(memory.Address + Size);
            }
            else
            {
                var methodMemory = machine.Memory.SpanAt(callAddress);
                var method       = new MethodDescriptor(methodMemory, machine);
                var capturedArgs = Operands.Skip(1).Select(o => o.Value).ToList();

                var newFrame = new StackFrame(memory.Address + Size,
                                              method.LocalsCount, StoreResult);
                machine.StackFrames.PushFrame(newFrame);

                for (var i = 1; i <= method.InitialValues.Count; i++)
                {
                    machine.SetVariable(i, method.InitialValues[i - 1]);
                }

                for (var i = 1; i <= capturedArgs.Count; i++)
                {
                    machine.SetVariable(i, capturedArgs[i - 1]);
                }

                log.Debug($"\tCall {callAddress:X} with {capturedArgs.Aggregate(new StringBuilder(), (sb, v) => sb.Append(v.ToString("X") + " "), sb => sb)}");
                machine.SetPC(callAddress + method.HeaderSize);
            }
        }
Exemple #4
0
        public void GetProp(SpanLocation location)
        {
            var objecNumber    = Operands[0].Value;
            var propertyNumber = Operands[1].Value;
            var gameObject     = machine.ObjectTable.GetObject(objecNumber);

            if (gameObject.Properties.ContainsKey(propertyNumber))
            {
                var propertyValue = gameObject.Properties[propertyNumber];
                if (propertyValue.Size == 1)
                {
                    log.Debug($"\tGetProp for {objecNumber}[{propertyNumber}] found {propertyValue.Value.Span[0]:X} => {StoreResult}");
                    machine.SetVariable(StoreResult, propertyValue.Value.Span[0]);
                }
                else if (propertyValue.Size == 2)
                {
                    log.Debug($"\tGetProp for {objecNumber}[{propertyNumber}] found {Bits.MakeWord(propertyValue.Value.Span)} => {StoreResult}");
                    machine.SetVariable(StoreResult, Bits.MakeWord(propertyValue.Value.Span));
                }
                else
                {
                    throw new InvalidOperationException($"GetProp should look for property with length of 1 or 2, not {propertyValue.Size}. Looking at prop {propertyNumber} on {objecNumber}");;
                }
            }
            else
            {
                var propertyValue = machine.ObjectTable.GetDefault(propertyNumber);
                log.Debug($"\tGetProp for {objecNumber}[{propertyNumber}] took default {propertyValue} => {StoreResult}");

                machine.SetVariable(StoreResult, propertyValue);
            }

            machine.SetPC(location.Address + Size);
        }
Exemple #5
0
        public void PutProp(SpanLocation location)
        {
            // Writes the given value to the given property of the given object.If the property
            // does not exist for that object, the interpreter should halt with a suitable error message.
            // If the property length is 1, then the interpreter should store only the least
            // significant byte of the value. (For instance, storing - 1 into a 1 - byte property
            // results in the property value 255.) As with get_prop the property length must not be more
            // than 2: if it is, the behaviour of the opcode is undefined.

            var objectNumber = Operands[0].Value;
            var gameObject   = machine.ObjectTable.GetObject(objectNumber);

            var propertyNumber = Operands[1].Value;
            var gameProperty   = gameObject.Properties[propertyNumber];
            var value          = Operands[2].Value;

            if (gameProperty.Value.Length > 2)
            {
                throw new InvalidOperationException("Illegal to PutProp on a property larger than 2 bytes");
            }

            log.Debug($"\tPutProp obj {objectNumber} prop {propertyNumber} value {value}");

            gameProperty.SetValue(Operands[2].Value);
            machine.SetPC(location.Address + Size);
        }
        public MethodDescriptor(SpanLocation memory, Machine machine)
        {
            if (machine == null)
            {
                throw new ArgumentNullException(nameof(machine));
            }

            LocalsCount = memory.Bytes[0];

            if (LocalsCount < 0 || LocalsCount > 15)
            {
                throw new InvalidOperationException($"Invalid numer of locals {LocalsCount}");
            }

            if (machine.Version < 5)
            {
                var values = new int[LocalsCount];
                for (var i = 0; i < LocalsCount; i++)
                {
                    var offset = 1 + (i * 2);
                    values[i] = Bits.MakeWord(memory.Bytes.Slice(offset, 2));
                }
                InitialValues = values;
                HeaderSize    = (1 + (LocalsCount * 2));
            }
            else
            {
                HeaderSize    = 1;
                InitialValues = Empty;
            }
            StartAddress = memory.Address + HeaderSize;
        }
Exemple #7
0
        public override void Prepare(SpanLocation memory)
        {
            Size      = 1;
            OpCode    = Bits.BottomFour(memory.Bytes[0]);
            Operation = OpCode switch
            {
                0x00 => new Operation(nameof(RetTrue), RetTrue),
                0x01 => new Operation(nameof(RetFalse), RetFalse),
                0x02 => new Operation(nameof(Print), Print, hasText: true),
                0x08 => new Operation(nameof(RetPopped), RetPopped),
                0x0B => new Operation(nameof(NewLine), NewLine),
                _ => throw new InvalidOperationException($"Unknown OP0 opcode {OpCode:X}")
            };

            if (Operation.HasText)
            {
                var decoded = textResolver.Decode(memory.Forward(1));
                Size += decoded.BytesConsumed;
                Text  = decoded.Text;
            }
            if (Operation.HasStore)
            {
                StoreResult = memory.Bytes[Size];
                Size       += 1;
            }
            if (Operation.HasBranch)
            {
                var branchData = machine.Memory.SpanAt(memory.Address + Size);
                Branch = branchResolver.ResolveBranch(branchData);
                Size  += Branch.Size;
            }

            DumpToLog(memory, Size);
        }
Exemple #8
0
        public void NewLine(SpanLocation memory)
        {
            log.Debug("NewLine");

            machine.Output.Write(Environment.NewLine);
            machine.SetPC(memory.Address + Size);
        }
Exemple #9
0
        public void Go(bool result, Machine machine, int instructionSize, SpanLocation currentLocation)
        {
            if (machine == null)
            {
                throw new ArgumentNullException(nameof(machine));
            }

            if (Offset == 0 && BranchOnTrue == result)
            {
                var frame = machine.StackFrames.PopFrame();
                machine.SetVariable(frame.StoreVariable, 0);
                machine.SetPC(frame.ReturnPC);
            }
            else if (Offset == 1 && BranchOnTrue == result)
            {
                var frame = machine.StackFrames.PopFrame();
                machine.SetVariable(frame.StoreVariable, 1);
                machine.SetPC(frame.ReturnPC);
            }
            else if (BranchOnTrue == result)
            {
                var newPC = currentLocation.Address + instructionSize + Offset - 2;
                machine.SetPC(newPC);
            }
            else
            {
                machine.SetPC(currentLocation.Address + instructionSize);
            }
        }
Exemple #10
0
        public override void Prepare(SpanLocation memory)
        {
            operandResolver.AddOperands(Operands, memory.Bytes);

            Size      = 1 + Operands.Size;
            OpCode    = Bits.BottomFour(memory.Bytes[0]);
            Operation = OpCode switch
            {
                0x00 => new Operation(nameof(JZ), JZ, hasBranch: true),
                0x01 => new Operation(nameof(GetSibling), GetSibling, hasBranch: true, hasStore: true),
                0x02 => new Operation(nameof(GetChild), GetChild, hasStore: true, hasBranch: true),
                0x03 => new Operation(nameof(GetParent), GetParent, hasStore: true),
                0x05 => new Operation(nameof(Inc), Inc),
                0x06 => new Operation(nameof(Dec), Dec),
                0x0A => new Operation(nameof(PrintObj), PrintObj),
                0x0B => new Operation(nameof(Ret), Ret),
                0x0C => new Operation(nameof(Jump), Jump),
                0x0d => new Operation(nameof(PrintPaddr), PrintPaddr),
                _ => throw new InvalidOperationException($"Unknown OP1 opcode {OpCode:X}")
            };
            if (Operation.HasStore)
            {
                StoreResult = memory.Bytes[Size];
                Size       += 1;
            }
            if (Operation.HasBranch)
            {
                var branchData = machine.Memory.SpanAt(memory.Address + Size);
                Branch = branchResolver.ResolveBranch(branchData);
                Size  += Branch.Size;
            }

            DumpToLog(memory, Size);
        }
Exemple #11
0
        public void JZ(SpanLocation location)
        {
            var value  = Operands[0].Value;
            var result = value == 0;

            log.Debug($"\tJZ {value:X} is {result}");

            Branch.Go(result, machine, Size, location);
        }
Exemple #12
0
        public void DumpToLog(SpanLocation memory, int size)
        {
            var sb = new StringBuilder();

            sb.Append($"\t{ToString()}");
            sb.Append($"\t{memory.ToString(size)}");

            log.Verbose(sb.ToString());
        }
Exemple #13
0
        public void PrintChar(SpanLocation location)
        {
            var character = (char)Operands[0].Value;

            log.Debug($"\tPrintChar {character}");

            machine.Output.Write(character.ToString());
            machine.SetPC(location.Address + Size);
        }
Exemple #14
0
        public void PrintNum(SpanLocation location)
        {
            var number = Operands[0].SignedValue;

            log.Debug($"\tPrintNum {number}");

            machine.Output.Write(number.ToString());
            machine.SetPC(location.Address + Size);
        }
Exemple #15
0
        public override void Prepare(SpanLocation memory)
        {
            OpCode    = Bits.BottomFive(memory.Bytes[0]);
            Operation = OpCode switch
            {
                0x01 => new Operation(nameof(JE), JE, hasBranch: true),
                0x02 => new Operation(nameof(JL), JL, hasBranch: true),
                0x03 => new Operation(nameof(JG), JG, hasBranch: true),
                0x04 => new Operation(nameof(DecChk), DecChk, hasBranch: true),
                0x05 => new Operation(nameof(IncChk), IncChk, hasBranch: true),
                0x06 => new Operation(nameof(Jin), Jin, hasBranch: true),
                0x09 => new Operation(nameof(And), And, hasStore: true),
                0x0A => new Operation(nameof(TestAttr), TestAttr, hasBranch: true),
                0x0B => new Operation(nameof(SetAttr), SetAttr),
                0x0D => new Operation(nameof(StoreB), StoreB),
                0x0E => new Operation(nameof(InsertObj), InsertObj),
                0x0F => new Operation(nameof(LoadW), LoadW, hasStore: true),
                0x10 => new Operation(nameof(LoadB), LoadB, hasStore: true),
                0x11 => new Operation(nameof(GetProp), GetProp, hasStore: true),
                0x14 => new Operation(nameof(Add), Add, hasStore: true),
                0x15 => new Operation(nameof(Sub), Sub, hasStore: true),
                _ => throw new InvalidOperationException($"Unknown OP2 opcode {OpCode:X}")
            };

            if (OpCode == 0x05)
            {
                // 😒 seven Z-machine opcodes access variables but by their numbers ...
                // inc, dec, inc_chk, dec_chk, store, pull, load. 😒
                indirectOperandResolver.AddOperands(Operands, memory.Bytes.Slice(1));
                Size = 1 + Operands.Size;
            }
            else if (Bits.SevenSixSet(memory.Bytes[0]) == true &&
                     Bits.FiveSet(memory.Bytes[0]) == false)
            {
                // 😒 2OPS, but VAR operands 😒
                varOperandResolver.AddOperands(Operands, memory.Bytes.Slice(1));
                Size = 2 + Operands.Size;
            }
            else
            {
                op2OperandResolver.AddOperands(Operands, memory.Bytes);
                Size = 1 + Operands.Size;
            }
            if (Operation.HasStore)
            {
                StoreResult = memory.Bytes[Size];
                Size       += 1;
            }
            if (Operation.HasBranch)
            {
                var branchData = machine.Memory.SpanAt(memory.Address + Size);
                Branch = branchResolver.ResolveBranch(branchData);
                Size  += Branch.Size;
            }

            DumpToLog(memory, Size);
        }
Exemple #16
0
        public void PrintObj(SpanLocation location)
        {
            var number     = Operands[0].Value;
            var gameObject = machine.ObjectTable.GetObject(number);

            log.Debug($"\tPrintObj {number}");
            machine.Output.Write(gameObject.Description);
            machine.SetPC(location.Address + Size);
        }
Exemple #17
0
        public void Push(SpanLocation location)
        {
            var value = Operands[0].Value;

            log.Debug($"\tPush {value} => 0");

            machine.StackFrames.RoutineStack.Push(value);
            machine.SetPC(location.Address + Size);
        }
Exemple #18
0
        public void InsertObj(SpanLocation location)
        {
            var target      = Operands[0].Value;
            var destination = Operands[1].Value;

            log.Debug($"\tInsertObj {target} to {destination}");

            machine.ObjectTable.InsertObject(target, destination);
            machine.SetPC(location.Address + Size);
        }
Exemple #19
0
        public void RetTrue(SpanLocation memory)
        {
            var returnValue = 1;
            var frame       = machine.StackFrames.PopFrame();

            log.Debug($"RetTrue to {frame.ReturnPC:X}");

            machine.SetVariable(frame.StoreVariable, returnValue);
            machine.SetPC(frame.ReturnPC);
        }
Exemple #20
0
        public void RetPopped(SpanLocation location)
        {
            var returnValue = machine.StackFrames.RoutineStack.Pop();
            var frame       = machine.StackFrames.PopFrame();

            log.Debug($"RetPopped {returnValue} to {frame.ReturnPC:X}");

            machine.SetVariable(frame.StoreVariable, returnValue);
            machine.SetPC(frame.ReturnPC);
        }
Exemple #21
0
        public void JE(SpanLocation location)
        {
            var a      = Operands[0].Value;
            var b      = Operands[1].Value;
            var result = a == b;

            log.Debug($"\tJE: {a:X} {b:X} is {result} go {Branch.Offset} on {Branch.BranchOnTrue}");

            Branch.Go(result, machine, Size, location);
        }
Exemple #22
0
        public void GetParent(SpanLocation location)
        {
            var objectNumber = Operands[0].Value;
            var gameObject   = machine.ObjectTable.GetObject(objectNumber);
            var parentNumber = gameObject.Parent;

            log.Debug($"\tGetParent for {objectNumber} is {parentNumber} => {StoreResult}");
            machine.SetVariable(StoreResult, parentNumber);
            machine.SetPC(location.Address + Size);
        }
Exemple #23
0
        public void SetAttr(SpanLocation location)
        {
            var objectNumber = Operands[0].Value;
            var attribute    = Operands[1].Value;

            log.Debug($"\tSetAttr {attribute} on {objectNumber} to true");

            machine.ObjectTable.GetObject(objectNumber).SetAttribute(attribute, true);
            machine.SetPC(location.Address + Size);
        }
Exemple #24
0
        public void JL(SpanLocation location)
        {
            var a      = Operands[0].SignedValue;
            var b      = Operands[1].SignedValue;
            var result = a < b;

            log.Debug($"\tJL {result} to {Branch.Offset} on {Branch.BranchOnTrue}");

            Branch.Go(result, machine, Size, location);
        }
Exemple #25
0
        public void Ret(SpanLocation location)
        {
            var returnValue = Operands[0].Value;
            var frame       = machine.StackFrames.PopFrame();

            log.Debug($"\tRet to {frame.ReturnPC:X}");

            machine.SetVariable(frame.StoreVariable, returnValue);
            machine.SetPC(frame.ReturnPC);
        }
 private Instruction DecodeShort(SpanLocation memory)
 {
     if (Bits.FiveFourSet(memory.Bytes[0]))
     {
         return(new Op0Instruction(machine));
     }
     else
     {
         return(new Op1Instruction(machine));
     }
 }
Exemple #27
0
        public void Dec(SpanLocation location)
        {
            var variable = Operands[0].RawValue;
            var value    = (short)machine.ReadVariable(variable);

            value -= 1;

            log.Debug($"\tDec {value} => {variable}");
            machine.SetVariable(variable, value);
            machine.SetPC(location.Address + Size);
        }
Exemple #28
0
        public void GetChild(SpanLocation location)
        {
            var objectNumber = Operands[0].Value;
            var gameObject   = machine.ObjectTable.GetObject(objectNumber);
            var childNumber  = gameObject.Child;
            var hasChild     = childNumber != 0;

            log.Debug($"\tGetChild for {objectNumber} is {childNumber} => {StoreResult}");
            machine.SetVariable(StoreResult, childNumber);
            Branch.Go(hasChild, machine, Size, location);
        }
Exemple #29
0
        public void GetSibling(SpanLocation location)
        {
            var objectNumber  = Operands[0].Value;
            var gameObject    = machine.ObjectTable.GetObject(objectNumber);
            var siblingNumber = gameObject.Sibling;
            var hasSibling    = siblingNumber != 0;

            log.Debug($"\tGetSibling for {objectNumber} is {siblingNumber} => {StoreResult}");
            machine.SetVariable(StoreResult, siblingNumber);
            Branch.Go(hasSibling, machine, Size, location);
        }
 private Instruction DecodeVar(SpanLocation memory)
 {
     if (Bits.FiveSet(memory.Bytes[0]))
     {
         return(new VarInstruction(machine));
     }
     else
     {
         return(new Op2Instruction(machine));
     }
 }