From 4fb80fe158f07c13c188795a7a54ec082841dc23 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Sun, 12 May 2024 04:21:17 +0200
Subject: [PATCH] add disassembly & display functions

---
 src/assembler.rs | 34 +++++++++++++++++++++++++++++++++-
 src/linker.rs    | 15 +++++++++++++++
 src/vm.rs        | 14 ++++++++++++++
 3 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/src/assembler.rs b/src/assembler.rs
index 74a3049..4e1f560 100644
--- a/src/assembler.rs
+++ b/src/assembler.rs
@@ -5,7 +5,7 @@ use {
     }
 };
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub enum AssemblyWord {
     Symbol( LinkAddr ),
     Lit( VM_Word )
@@ -25,6 +25,38 @@ impl AssemblyWord {
     }
 }
 
+pub fn disassemble(bytecode: &Vec< AssemblyWord >) -> Vec< String > {
+    let mut words = bytecode.iter();
+    let mut result = Vec::new();
+
+    let mut remaining_params = 0;
+
+    while let Some(w) = words.next() {
+        match w {
+            AssemblyWord::Symbol( addr ) => {
+                result.push( format!("{}", addr) );
+                remaining_params -= 1;
+            }
+            AssemblyWord::Lit(w) => {
+                if remaining_params == 0 {
+                    if *w < 18 {
+                        let inst : VM_Instruction = unsafe { std::mem::transmute(*w) };
+                        result.push(format!("{:?}", inst));
+                        remaining_params = inst.param_length();
+                    } else {
+                        result.push(format!("invalid opcode {}", w));
+                    }
+                } else {
+                    remaining_params -= 1;
+                    result.push(format!("{}", w));
+                }
+            }
+        }
+    }
+
+    result
+}
+
 pub struct Assembler {
     words: Vec< AssemblyWord >,
 }
diff --git a/src/linker.rs b/src/linker.rs
index 1095954..5c48f5b 100644
--- a/src/linker.rs
+++ b/src/linker.rs
@@ -12,6 +12,21 @@ pub enum LinkAddr {
     }
 }
 
+impl std::fmt::Display for LinkAddr {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+        match self {
+            LinkAddr::Absolute(addr) =>
+                write!(f, "{:x}", addr),
+            LinkAddr::Relative{ symbol, offset } =>
+                if *offset == 0 {
+                    write!(f, "{}", symbol)
+                } else {
+                    write!(f, "{}+{:x}", symbol, offset)
+                }
+        }
+    }
+}
+
 pub struct Section {
     addr: VM_Word,
     data: Vec< AssemblyWord >
diff --git a/src/vm.rs b/src/vm.rs
index 1e27a86..0d71434 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -12,6 +12,20 @@ pub enum VM_Instruction {
     BitwiseNot,
 }
 
+impl VM_Instruction {
+    pub fn param_length(&self) -> usize {
+        match self {
+            VM_Instruction::Jmp |
+            VM_Instruction::Call |
+            VM_Instruction::Branch |
+            VM_Instruction::Lit => {
+                1
+            },
+            _ => 0
+        }
+    }
+}
+
 pub struct VM {
     pub data_stack: Vec< VM_Word >,
     pub call_stack: Vec< VM_Word >,