private int stackPtr; //Pointer to next address to write to #endregion Fields #region Constructors /// <summary> /// Creates a new z processor /// </summary> /// <param name="buf">memory buffer</param> /// <param name="ui">interface with the rest of the world</param> protected ZProcessor(MemoryBuffer buf, IUserInterface ui) { //Validate params if (buf == null) { throw new ArgumentNullException("buf"); } else if (ui == null) { throw new ArgumentNullException("ui"); } //Cache global vars offset globalVarsOffset = buf.GetUShort(0xC) - 0x10; //Globals vars must be higher than the header (security) if (globalVarsOffset + 0x10 < 64) { throw new ZMachineException("global variables table must not reside in the header"); } //Set dynamic limit buf.DynamicLimit = Math.Min((int) buf.GetUShort(0xE), 64); //Store memory buffer and ui memBuf = buf; zUi = ui; //Create encoder and object tree zEncoder = new ZTextEncoder(buf); objectTree = new ZObjectTree(buf); }
/// <summary> /// Creates a new version 1 z processor /// </summary> /// <param name="buf">memory buffer</param> /// <param name="ui">interface with the rest of the world</param> public MachineV1(MemoryBuffer buf, IUserInterface ui) : base(buf, ui) { InstructionFunc[] ops; //2OP instructions ops = Instructions2OP; ops[0x1] = Je; ops[0x2] = Jl; ops[0x3] = Jg; ops[0x4] = DecChk; ops[0x5] = IncChk; ops[0x6] = Jin; ops[0x7] = Test; ops[0x8] = Or; ops[0x9] = And; ops[0xA] = TestAttr; ops[0xB] = SetAttr; ops[0xC] = ClearAttr; ops[0xD] = Store; ops[0xE] = InsertObj; ops[0xF] = LoadW; ops[0x10] = LoadB; ops[0x11] = GetProp; ops[0x12] = GetPropAddr; ops[0x13] = GetNextProp; ops[0x14] = Add; ops[0x15] = Sub; ops[0x16] = Mul; ops[0x17] = Div; ops[0x18] = Mod; //1OP Instructions ops = Instructions1OP; ops[0x0] = Jz; ops[0x1] = GetSibling; ops[0x2] = GetChild; ops[0x3] = GetParent; ops[0x4] = GetPropLen; ops[0x5] = Inc; ops[0x6] = Dec; ops[0x7] = PrintAddr; ops[0x9] = RemoveObj; ops[0xA] = PrintObj; ops[0xB] = Ret; ops[0xC] = Jump; ops[0xD] = PrintPAddr; ops[0xE] = Load; ops[0xF] = Not; //0OP Instructions ops = Instructions0OP; ops[0x0] = RTrue; ops[0x1] = RFalse; ops[0x2] = Print; ops[0x3] = PrintRet; ops[0x4] = Nop; ops[0x5] = Save; ops[0x6] = Restore; ops[0x7] = Restart; ops[0x8] = RetPopped; ops[0x9] = Pop; ops[0xA] = Quit; ops[0xB] = NewLine; //VAR Instructions ops = InstructionsVAR; ops[0x0] = GenericCall; ops[0x0] = StoreW; ops[0x0] = StoreB; ops[0x0] = PutProp; ops[0x0] = Read; ops[0x0] = PrintChar; ops[0x0] = PrintNum; ops[0x0] = RandomFunc; ops[0x0] = Push; ops[0x0] = Pull; }
/// <summary> /// Creates a new z machine character encoder /// </summary> /// <param name="buf">game memory buffer</param> public ZTextEncoder(MemoryBuffer buf) { //Store buffer this.buf = buf; //Get version this.machineVersion = buf.GetByte(0); //Find unicode table address int unicodeTable = 0; if (machineVersion >= 5) { //Search the extension header table ushort extensionHdr = buf.GetUShort(0x36); if (extensionHdr != 0 && buf.GetUShort(extensionHdr) >= 3) { unicodeTable = buf.GetUShort(extensionHdr + 6); } } //Create unicode cache this.unicodeCache = CreateUnicodeCache(unicodeTable); //Create reverse cache // Go in reverse so that ASCII takes priority over custom unicode for(int i = 255; i > 0; i--) { //Add character if (unicodeCache[i] != InvalidChar) { reverseUnicodeCache[unicodeCache[i]] = (byte) i; } } //Create alphabet cache if (machineVersion >= 5 && buf.GetUShort(0x34) != 0) { this.alphabetCache = CreateAlphabetCache(buf.GetUShort(0x34)); } else { //Use default alphabet this.alphabetCache = machineVersion == 1 ? DEFAULT_ALPHABET_TABLE_V1 : DEFAULT_ALPHABET_TABLE; } //Create reverse alphabet cache for (int i = 0; i < 78; i++) { reverseAlphabetCache[reverseUnicodeCache[alphabetCache[i]]] = (byte) (i + 1); } //Create abbreviation cache if (machineVersion >= 2 && buf.GetUShort(0x18) != 0) { this.abbreviationCache = CreateAbbreviationCache(buf.GetUShort(0x18)); } //Cache dictionary information mainDictionaryAddress = buf.GetUShort(0x8); mainDictionary = GetDictionaryInfo(mainDictionaryAddress); }