VMCommand ReadOpCode(Stream binary, ref int didread) { int op = DataReader.Read8(binary, ref didread) & 0xff; // get unsigned if (op == 0x09) // opcode for CALL { return(null); } // check if there is a single-byte opcode foreach (var de in commands) { VMCommand cmd = de.Value; if (cmd.opcode.Length == 1 && cmd.opcode[0] == op) { return(cmd); } } // extend search to get two-byte opcodes as well int op1 = DataReader.Read8(binary, ref didread) & 0xff; foreach (var de in commands) { VMCommand cmd = de.Value; if (cmd.opcode.Length == 2 && cmd.opcode[0] == op && cmd.opcode[1] == op1) { return(cmd); } } throw new Exception("Unrecognized opcode: " + op + "(" + op1 + ")"); }
private void readByteCodeList() { StringReader reader = new StringReader(LMSAssembler.Properties.Resources.bytecodelist); String line; while ((line = reader.ReadLine()) != null) { int idx = line.IndexOf("//"); if (idx >= 0) { line = line.Substring(0, idx); } line = line.Trim(); if (line.Length > 0) { VMCommand c = new VMCommand(line); commands.Add(c.name, c); } } reader.Close(); // foreach (VMCommand c in commands.Values) // { // Console.WriteLine(c); // } }
// ---------------------------------- DISASSEMLER ---------------------------------------------- public void Disassemble(Stream binary, TextWriter writer) { Dictionary <int, String> vmobjects = new Dictionary <int, String>(); int didread = 0; // read file header and object definitions int magic = DataReader.Read32(binary, ref didread); if (magic != 0x4F47454C) { throw new Exception("Missing LEGO header"); } int imgsize = DataReader.Read32(binary, ref didread); int version = DataReader.Read16(binary, ref didread); int numobjects = DataReader.Read16(binary, ref didread); int globalbytes = DataReader.Read32(binary, ref didread); writer.WriteLine("Image size: " + imgsize); writer.WriteLine("Version: " + version); writer.WriteLine("Objects: " + numobjects); writer.WriteLine("Globals bytes: " + globalbytes); for (int i = 0; i < numobjects; i++) { int offset = DataReader.Read32(binary, ref didread); int owner = DataReader.Read16(binary, ref didread); int triggercount = DataReader.Read16(binary, ref didread); int localbytes = DataReader.Read32(binary, ref didread); if (owner == 0) { if (triggercount == 0) { vmobjects[offset] = "VMTHREAD THREAD" + (i + 1) + " ( " + localbytes + " locals)"; } else if (triggercount == 1) { vmobjects[offset] = "SUBCALL SUB" + (i + 1) + " ( " + localbytes + " locals)"; } else { throw new Exception("Encountered invalid triggercount value"); } } else { if (localbytes != 0) { throw new Exception("Can not have local bytes for object with owner"); } vmobjects[offset] = "OBJECT " + (i + 1) + " (+trigercount=" + triggercount + ", owner=" + owner + ")"; } } // read all objects while (didread < imgsize) { if (!vmobjects.ContainsKey(didread)) { throw new Exception("No object starts at position " + didread); } String o = vmobjects[didread]; vmobjects.Remove(didread); writer.WriteLine(o); // decode parameter specifier for SUBCALL if (o.StartsWith("SUBCALL")) { int localpos = 0; int numpar = DataReader.Read8(binary, ref didread) & 0xff; for (int i = 0; i < numpar; i++) { String prefix = ""; int desc = DataReader.Read8(binary, ref didread) & 0xff; if ((desc & 0x80) != 0) { prefix = "IN"; } if ((desc & 0x40) != 0) { prefix = prefix + "OUT"; } switch (desc & 0x07) { case 0: writer.WriteLine(format(localpos, 4) + " " + prefix + "_8"); localpos += 1; break; case 1: writer.WriteLine(format(localpos, 4) + " " + prefix + "_16"); localpos += 2; break; case 2: writer.WriteLine(format(localpos, 4) + " " + prefix + "_32"); localpos += 4; break; case 3: writer.WriteLine(format(localpos, 4) + " " + prefix + "_F"); localpos += 4; break; case 4: int len = DataReader.Read8(binary, ref didread) & 0xff; writer.WriteLine(format(localpos, 4) + " " + prefix + "_S " + len); localpos += len; break; default: throw new Exception("Can not decode subcall parameter list"); } } } int objectstart = didread; for (; ;) { writer.Write(format(didread - objectstart, 4) + " "); // decode bytecodes VMCommand cmd = ReadOpCode(binary, ref didread); if (cmd == null) { int n; String objid = ReadParameter(binary, ref didread); if (!int.TryParse(ReadParameter(binary, ref didread), NumberStyles.Integer, CultureInfo.InvariantCulture, out n)) { throw new Exception("Invalid specifier for number of CALL parameters"); } // special handling for CALL writer.Write("CALL SUB" + objid); for (int i = 0; i < n; i++) { writer.Write(" " + ReadParameter(binary, ref didread)); } writer.WriteLine(); } else { // normal opcodes writer.Write(cmd.name); // decode parameters int numparameters = cmd.parameters.Length; for (int i = 0; i < numparameters; i++) { String p = ReadParameter(binary, ref didread); writer.Write(" " + p); // check if this parameter is a counter to extend the parameter list if (i < cmd.parameters.Length && cmd.parameters[i] == DataType.ParameterCount) { int n; if (int.TryParse(p, NumberStyles.Integer, CultureInfo.InvariantCulture, out n)) { numparameters += (n - 1); } } } writer.WriteLine(); if (cmd.name.Equals("OBJECT_END")) { break; } } } } }