217 lines
14 KiB
C#
217 lines
14 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using STCompiler.Common;
|
|
using System.Collections.Generic;
|
|
|
|
class Program {
|
|
static int Main(string[] args) {
|
|
if (args.Length < 1) {
|
|
Console.WriteLine("Usage: StDisasm <file.stbc>");
|
|
return 1;
|
|
}
|
|
var path = args[0];
|
|
if (!File.Exists(path)) { Console.WriteLine("File not found: " + path); return 2; }
|
|
var data = File.ReadAllBytes(path);
|
|
try { Disasm(data); } catch(Exception ex) { Console.WriteLine("Error: " + ex.Message); return 3; }
|
|
return 0;
|
|
}
|
|
|
|
static void Disasm(byte[] data) {
|
|
using var ms = new MemoryStream(data);
|
|
using var r = new BinaryReader(ms);
|
|
|
|
string magic = Encoding.ASCII.GetString(r.ReadBytes(4));
|
|
Console.WriteLine($"Magic: {magic}");
|
|
ushort ver = r.ReadUInt16();
|
|
Console.WriteLine($"Version: {ver}");
|
|
ushort cycletime = r.ReadUInt16();
|
|
Console.WriteLine($"Cycle: {cycletime} ms");
|
|
ushort nConsts = r.ReadUInt16();
|
|
Console.WriteLine($"Consts: {nConsts}");
|
|
var consts = new List<object>();
|
|
for (int i = 0; i < nConsts; i++) {
|
|
byte t = r.ReadByte();
|
|
switch(t) {
|
|
case 1: { long v = r.ReadInt64(); consts.Add(v); Console.WriteLine($" [{i}] (long) = {v}"); break; }
|
|
case 2: { double v = r.ReadDouble(); consts.Add(v); Console.WriteLine($" [{i}] (double) = {v}"); break; }
|
|
case 3: { float v = r.ReadSingle(); consts.Add(v); Console.WriteLine($" [{i}] (float) = {v}"); break; }
|
|
case 4: { int v = r.ReadInt32(); consts.Add(v); Console.WriteLine($" [{i}] (int) = {v}"); break; }
|
|
default: { Console.WriteLine($" [{i}] Unknown const type {t}"); break; }
|
|
}
|
|
}
|
|
|
|
ushort nVars = r.ReadUInt16();
|
|
Console.WriteLine($"Vars: {nVars}");
|
|
var varTypes = new VarType[nVars];
|
|
for (int i = 0; i < nVars; i++) {
|
|
byte tb = r.ReadByte();
|
|
var vt = (VarType)tb;
|
|
varTypes[i] = vt;
|
|
|
|
if (vt == VarType.ARRAY) {
|
|
// Look ahead to find array length and element type
|
|
int arrayStart = i;
|
|
int length = 1;
|
|
VarType elementType = 0; // Initialize to INT as default
|
|
|
|
if (i + 1 < nVars) {
|
|
elementType = (VarType)varTypes[i + 1];
|
|
while (i + length < nVars && varTypes[i + length] == varTypes[i + 1]) {
|
|
length++;
|
|
}
|
|
}
|
|
|
|
Console.WriteLine($" Var[{i}] type = ARRAY[{length}] OF {elementType}");
|
|
i += length - 1; // Skip array elements
|
|
}
|
|
else if (Enum.IsDefined(typeof(VarType), vt)) {
|
|
Console.WriteLine($" Var[{i}] type = {vt}");
|
|
}
|
|
else {
|
|
Console.WriteLine($" Var[{i}] type = {tb} (unknown)");
|
|
}
|
|
}
|
|
|
|
ushort codeLen = r.ReadUInt16();
|
|
Console.WriteLine($"CodeLen: {codeLen} bytes");
|
|
var code = r.ReadBytes(codeLen);
|
|
|
|
Console.WriteLine("\n--- Disassembly ---");
|
|
int ip = 0;
|
|
while (ip < code.Length) {
|
|
int addr = ip;
|
|
byte op = code[ip++];
|
|
Console.Write($"{addr:0000}: 0x{op:X2} ");
|
|
switch (op) {
|
|
case Bytecode.OpCodes.NOP: Console.WriteLine("NOP"); break;
|
|
case Bytecode.OpCodes.PUSH_CONST: { ushort ci = ReadU16(code, ref ip); Console.WriteLine($"PUSH_CONST {ci} ({consts[ci]})"); break; }
|
|
case Bytecode.OpCodes.PUSH_REAL_CONST: { ushort ci = ReadU16(code, ref ip); Console.WriteLine($"PUSH_REAL_CONST {ci} ({consts[ci]})"); break; }
|
|
case Bytecode.OpCodes.LOAD_VAR: { ushort vi = ReadU16(code, ref ip); Console.WriteLine($"LOAD_VAR {vi}"); break; }
|
|
case Bytecode.OpCodes.STORE_VAR: { ushort vi = ReadU16(code, ref ip); Console.WriteLine($"STORE_VAR {vi}"); break; }
|
|
case Bytecode.OpCodes.JZ: { ushort target = ReadU16(code, ref ip); Console.WriteLine($"JZ addr={target:0000}"); break; }
|
|
case Bytecode.OpCodes.JMP: { ushort target = ReadU16(code, ref ip); Console.WriteLine($"JMP addr={target:0000}"); break; }
|
|
case Bytecode.OpCodes.HALT: Console.WriteLine("HALT"); break;
|
|
case Bytecode.OpCodes.ARRAY_BOUNDS_CHECK: {
|
|
Console.WriteLine("ARRAY_BOUNDS_CHECK");
|
|
// Skip the next byte as it's part of the array bounds check instruction
|
|
if (ip < code.Length) ip++;
|
|
break;
|
|
}
|
|
// Signed integer arithmetic
|
|
case Bytecode.OpCodes.ADD_SINT: Console.WriteLine("ADD_SINT"); break;
|
|
case Bytecode.OpCodes.SUB_SINT: Console.WriteLine("SUB_SINT"); break;
|
|
case Bytecode.OpCodes.MUL_SINT: Console.WriteLine("MUL_SINT"); break;
|
|
case Bytecode.OpCodes.DIV_SINT: Console.WriteLine("DIV_SINT"); break;
|
|
case Bytecode.OpCodes.ADD_INT: Console.WriteLine("ADD_INT"); break;
|
|
case Bytecode.OpCodes.SUB_INT: Console.WriteLine("SUB_INT"); break;
|
|
case Bytecode.OpCodes.MUL_INT: Console.WriteLine("MUL_INT"); break;
|
|
case Bytecode.OpCodes.DIV_INT: Console.WriteLine("DIV_INT"); break;
|
|
case Bytecode.OpCodes.ADD_DINT: Console.WriteLine("ADD_DINT"); break;
|
|
case Bytecode.OpCodes.SUB_DINT: Console.WriteLine("SUB_DINT"); break;
|
|
case Bytecode.OpCodes.MUL_DINT: Console.WriteLine("MUL_DINT"); break;
|
|
case Bytecode.OpCodes.DIV_DINT: Console.WriteLine("DIV_DINT"); break;
|
|
case Bytecode.OpCodes.ADD_LINT: Console.WriteLine("ADD_LINT"); break;
|
|
case Bytecode.OpCodes.SUB_LINT: Console.WriteLine("SUB_LINT"); break;
|
|
case Bytecode.OpCodes.MUL_LINT: Console.WriteLine("MUL_LINT"); break;
|
|
case Bytecode.OpCodes.DIV_LINT: Console.WriteLine("DIV_LINT"); break;
|
|
// Unsigned integer arithmetic
|
|
case Bytecode.OpCodes.ADD_USINT: Console.WriteLine("ADD_USINT"); break;
|
|
case Bytecode.OpCodes.SUB_USINT: Console.WriteLine("SUB_USINT"); break;
|
|
case Bytecode.OpCodes.MUL_USINT: Console.WriteLine("MUL_USINT"); break;
|
|
case Bytecode.OpCodes.DIV_USINT: Console.WriteLine("DIV_USINT"); break;
|
|
case Bytecode.OpCodes.ADD_UINT: Console.WriteLine("ADD_UINT"); break;
|
|
case Bytecode.OpCodes.SUB_UINT: Console.WriteLine("SUB_UINT"); break;
|
|
case Bytecode.OpCodes.MUL_UINT: Console.WriteLine("MUL_UINT"); break;
|
|
case Bytecode.OpCodes.DIV_UINT: Console.WriteLine("DIV_UINT"); break;
|
|
case Bytecode.OpCodes.ADD_UDINT: Console.WriteLine("ADD_UDINT"); break;
|
|
case Bytecode.OpCodes.SUB_UDINT: Console.WriteLine("SUB_UDINT"); break;
|
|
case Bytecode.OpCodes.MUL_UDINT: Console.WriteLine("MUL_UDINT"); break;
|
|
case Bytecode.OpCodes.DIV_UDINT: Console.WriteLine("DIV_UDINT"); break;
|
|
case Bytecode.OpCodes.ADD_ULINT: Console.WriteLine("ADD_ULINT"); break;
|
|
case Bytecode.OpCodes.SUB_ULINT: Console.WriteLine("SUB_ULINT"); break;
|
|
case Bytecode.OpCodes.MUL_ULINT: Console.WriteLine("MUL_ULINT"); break;
|
|
case Bytecode.OpCodes.DIV_ULINT: Console.WriteLine("DIV_ULINT"); break;
|
|
// Floating point arithmetic
|
|
case Bytecode.OpCodes.ADD_REAL: Console.WriteLine("ADD_REAL"); break;
|
|
case Bytecode.OpCodes.SUB_REAL: Console.WriteLine("SUB_REAL"); break;
|
|
case Bytecode.OpCodes.MUL_REAL: Console.WriteLine("MUL_REAL"); break;
|
|
case Bytecode.OpCodes.DIV_REAL: Console.WriteLine("DIV_REAL"); break;
|
|
case Bytecode.OpCodes.ADD_LREAL: Console.WriteLine("ADD_LREAL"); break;
|
|
case Bytecode.OpCodes.SUB_LREAL: Console.WriteLine("SUB_LREAL"); break;
|
|
case Bytecode.OpCodes.MUL_LREAL: Console.WriteLine("MUL_LREAL"); break;
|
|
case Bytecode.OpCodes.DIV_LREAL: Console.WriteLine("DIV_LREAL"); break;
|
|
// Signed integer comparisons
|
|
case Bytecode.OpCodes.LT_SINT: Console.WriteLine("LT_SINT"); break;
|
|
case Bytecode.OpCodes.GT_SINT: Console.WriteLine("GT_SINT"); break;
|
|
case Bytecode.OpCodes.LE_SINT: Console.WriteLine("LE_SINT"); break;
|
|
case Bytecode.OpCodes.GE_SINT: Console.WriteLine("GE_SINT"); break;
|
|
case Bytecode.OpCodes.EQ_SINT: Console.WriteLine("EQ_SINT"); break;
|
|
case Bytecode.OpCodes.NEQ_SINT: Console.WriteLine("NEQ_SINT"); break;
|
|
case Bytecode.OpCodes.LT_INT: Console.WriteLine("LT_INT"); break;
|
|
case Bytecode.OpCodes.GT_INT: Console.WriteLine("GT_INT"); break;
|
|
case Bytecode.OpCodes.LE_INT: Console.WriteLine("LE_INT"); break;
|
|
case Bytecode.OpCodes.GE_INT: Console.WriteLine("GE_INT"); break;
|
|
case Bytecode.OpCodes.EQ_INT: Console.WriteLine("EQ_INT"); break;
|
|
case Bytecode.OpCodes.NEQ_INT: Console.WriteLine("NEQ_INT"); break;
|
|
case Bytecode.OpCodes.LT_DINT: Console.WriteLine("LT_DINT"); break;
|
|
case Bytecode.OpCodes.GT_DINT: Console.WriteLine("GT_DINT"); break;
|
|
case Bytecode.OpCodes.LE_DINT: Console.WriteLine("LE_DINT"); break;
|
|
case Bytecode.OpCodes.GE_DINT: Console.WriteLine("GE_DINT"); break;
|
|
case Bytecode.OpCodes.EQ_DINT: Console.WriteLine("EQ_DINT"); break;
|
|
case Bytecode.OpCodes.NEQ_DINT: Console.WriteLine("NEQ_DINT"); break;
|
|
case Bytecode.OpCodes.LT_LINT: Console.WriteLine("LT_LINT"); break;
|
|
case Bytecode.OpCodes.GT_LINT: Console.WriteLine("GT_LINT"); break;
|
|
case Bytecode.OpCodes.LE_LINT: Console.WriteLine("LE_LINT"); break;
|
|
case Bytecode.OpCodes.GE_LINT: Console.WriteLine("GE_LINT"); break;
|
|
case Bytecode.OpCodes.EQ_LINT: Console.WriteLine("EQ_LINT"); break;
|
|
case Bytecode.OpCodes.NEQ_LINT: Console.WriteLine("NEQ_LINT"); break;
|
|
// Unsigned integer comparisons
|
|
case Bytecode.OpCodes.LT_USINT: Console.WriteLine("LT_USINT"); break;
|
|
case Bytecode.OpCodes.GT_USINT: Console.WriteLine("GT_USINT"); break;
|
|
case Bytecode.OpCodes.LE_USINT: Console.WriteLine("LE_USINT"); break;
|
|
case Bytecode.OpCodes.GE_USINT: Console.WriteLine("GE_USINT"); break;
|
|
case Bytecode.OpCodes.EQ_USINT: Console.WriteLine("EQ_USINT"); break;
|
|
case Bytecode.OpCodes.NEQ_USINT: Console.WriteLine("NEQ_USINT"); break;
|
|
case Bytecode.OpCodes.LT_UINT: Console.WriteLine("LT_UINT"); break;
|
|
case Bytecode.OpCodes.GT_UINT: Console.WriteLine("GT_UINT"); break;
|
|
case Bytecode.OpCodes.LE_UINT: Console.WriteLine("LE_UINT"); break;
|
|
case Bytecode.OpCodes.GE_UINT: Console.WriteLine("GE_UINT"); break;
|
|
case Bytecode.OpCodes.EQ_UINT: Console.WriteLine("EQ_UINT"); break;
|
|
case Bytecode.OpCodes.NEQ_UINT: Console.WriteLine("NEQ_UINT"); break;
|
|
case Bytecode.OpCodes.LT_UDINT: Console.WriteLine("LT_UDINT"); break;
|
|
case Bytecode.OpCodes.GT_UDINT: Console.WriteLine("GT_UDINT"); break;
|
|
case Bytecode.OpCodes.LE_UDINT: Console.WriteLine("LE_UDINT"); break;
|
|
case Bytecode.OpCodes.GE_UDINT: Console.WriteLine("GE_UDINT"); break;
|
|
case Bytecode.OpCodes.EQ_UDINT: Console.WriteLine("EQ_UDINT"); break;
|
|
case Bytecode.OpCodes.NEQ_UDINT: Console.WriteLine("NEQ_UDINT"); break;
|
|
case Bytecode.OpCodes.LT_ULINT: Console.WriteLine("LT_ULINT"); break;
|
|
case Bytecode.OpCodes.GT_ULINT: Console.WriteLine("GT_ULINT"); break;
|
|
case Bytecode.OpCodes.LE_ULINT: Console.WriteLine("LE_ULINT"); break;
|
|
case Bytecode.OpCodes.GE_ULINT: Console.WriteLine("GE_ULINT"); break;
|
|
case Bytecode.OpCodes.EQ_ULINT: Console.WriteLine("EQ_ULINT"); break;
|
|
case Bytecode.OpCodes.NEQ_ULINT: Console.WriteLine("NEQ_ULINT"); break;
|
|
// Floating point comparisons
|
|
case Bytecode.OpCodes.LT_REAL: Console.WriteLine("LT_REAL"); break;
|
|
case Bytecode.OpCodes.GT_REAL: Console.WriteLine("GT_REAL"); break;
|
|
case Bytecode.OpCodes.LE_REAL: Console.WriteLine("LE_REAL"); break;
|
|
case Bytecode.OpCodes.GE_REAL: Console.WriteLine("GE_REAL"); break;
|
|
case Bytecode.OpCodes.EQ_REAL: Console.WriteLine("EQ_REAL"); break;
|
|
case Bytecode.OpCodes.NEQ_REAL: Console.WriteLine("NEQ_REAL"); break;
|
|
case Bytecode.OpCodes.LT_LREAL: Console.WriteLine("LT_LREAL"); break;
|
|
case Bytecode.OpCodes.GT_LREAL: Console.WriteLine("GT_LREAL"); break;
|
|
case Bytecode.OpCodes.LE_LREAL: Console.WriteLine("LE_LREAL"); break;
|
|
case Bytecode.OpCodes.GE_LREAL: Console.WriteLine("GE_LREAL"); break;
|
|
case Bytecode.OpCodes.EQ_LREAL: Console.WriteLine("EQ_LREAL"); break;
|
|
case Bytecode.OpCodes.NEQ_LREAL: Console.WriteLine("NEQ_LREAL"); break;
|
|
default: Console.WriteLine($"{Bytecode.OpName(op)}"); break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static ushort ReadU16(byte[] a, ref int ip) {
|
|
ushort v = (ushort)(a[ip] | (a[ip+1] << 8));
|
|
ip += 2;
|
|
return v;
|
|
}
|
|
} |