public DecodedString Decode(SpanLocation location) { var decoder = new ZStringDecoder(machine); var result = decoder.Decode(location); return(result); }
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); }
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); } }
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); }
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; }
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); }
public void NewLine(SpanLocation memory) { log.Debug("NewLine"); machine.Output.Write(Environment.NewLine); machine.SetPC(memory.Address + Size); }
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); } }
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); }
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); }
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()); }
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); }
public void PrintNum(SpanLocation location) { var number = Operands[0].SignedValue; log.Debug($"\tPrintNum {number}"); machine.Output.Write(number.ToString()); machine.SetPC(location.Address + Size); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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)); } }
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); }
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); }
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)); } }