diff --git a/AssEmbly.Test/AssEmbly.Test.csproj b/AssEmbly.Test/AssEmbly.Test.csproj
index 79728f5..ccece0d 100644
--- a/AssEmbly.Test/AssEmbly.Test.csproj
+++ b/AssEmbly.Test/AssEmbly.Test.csproj
@@ -21,4 +21,13 @@
     <ProjectReference Include="..\AssEmbly.csproj" />
   </ItemGroup>
 
+  <ItemGroup>
+    <None Update="test-invalid.dll">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="test.dll">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+
 </Project>
diff --git a/AssEmbly.Test/ProcessorTests.cs b/AssEmbly.Test/ProcessorTests.cs
index 2ba74e0..fb5553a 100644
--- a/AssEmbly.Test/ProcessorTests.cs
+++ b/AssEmbly.Test/ProcessorTests.cs
@@ -1,3 +1,4 @@
+using System.Runtime.Loader;
 using System.Text;
 
 namespace AssEmbly.Test
@@ -13685,6 +13686,729 @@ public void EXTD_BSW_Register()
                 Assert.AreEqual(0xF0DEBC9A78563412, testProcessor.Registers[(int)Register.rg7], "Instruction did not produce correct result");
                 Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
             }
+
+            [TestMethod]
+            public void ASMX_LDA_Address()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x00, 0x28, 2, 0, 0, 0, 0, 0, 0 });
+                    Encoding.UTF8.GetBytes("test.dll\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.IsNotNull(typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction did not create load context");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction did not open assembly");
+                    Assert.AreEqual(11UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x00, 0x28, 2, 0, 0, 0, 0, 0, 0 });
+                    Encoding.UTF8.GetBytes("test-invalid.dll\0").CopyTo(testProcessor.Memory, 552);
+                    _ = Assert.ThrowsException<InvalidAssemblyException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when loading invalid assembly");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x00, 0x28, 2, 0, 0, 0, 0, 0, 0 });
+                    Encoding.UTF8.GetBytes("test-missing.dll\0").CopyTo(testProcessor.Memory, 552);
+                    _ = Assert.ThrowsException<InvalidAssemblyException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when loading non-existent assembly");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_LDA_Pointer()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rg7] = 552;
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x01, (int)Register.rg7 });
+                    Encoding.UTF8.GetBytes("test.dll\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.IsNotNull(typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction did not create load context");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction did not open assembly");
+                    Assert.AreEqual(4UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rg7] = 552;
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x01, (int)Register.rg7 });
+                    Encoding.UTF8.GetBytes("test-invalid.dll\0").CopyTo(testProcessor.Memory, 552);
+                    _ = Assert.ThrowsException<InvalidAssemblyException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when loading invalid assembly");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rg7] = 552;
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x01, (int)Register.rg7 });
+                    Encoding.UTF8.GetBytes("test-missing.dll\0").CopyTo(testProcessor.Memory, 552);
+                    _ = Assert.ThrowsException<InvalidAssemblyException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when loading non-existent assembly");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_LDF_Address()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x02, 0xD2, 4, 0, 0, 0, 0, 0, 0
+                    });
+                    Encoding.UTF8.GetBytes("TestMethod\0").CopyTo(testProcessor.Memory, 1234);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(true);
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction did not open function");
+                    Assert.AreEqual(11UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x02, 0xD2, 4, 0, 0, 0, 0, 0, 0
+                    });
+                    Encoding.UTF8.GetBytes("InvalidMethod\0").CopyTo(testProcessor.Memory, 1234);
+                    _ = Assert.ThrowsException<InvalidFunctionException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when loading invalid function");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x02, 0xD2, 4, 0, 0, 0, 0, 0, 0
+                    });
+                    Encoding.UTF8.GetBytes("TestMethod3\0").CopyTo(testProcessor.Memory, 1234);
+                    _ = Assert.ThrowsException<InvalidFunctionException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when loading non-existent function");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x02, 0xD2, 4, 0, 0, 0, 0, 0, 0
+                    });
+                    Encoding.UTF8.GetBytes("TestMethod\0").CopyTo(testProcessor.Memory, 1234);
+                    _ = Assert.ThrowsException<ExternalOperationException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when used without loading an assembly");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_LDF_Pointer()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.Registers[(int)Register.rg8] = 1234;
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x03, (int)Register.rg8
+                    });
+                    Encoding.UTF8.GetBytes("TestMethod\0").CopyTo(testProcessor.Memory, 1234);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(true);
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction did not open function");
+                    Assert.AreEqual(4UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.Registers[(int)Register.rg8] = 1234;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x03, (int)Register.rg8
+                    });
+                    Encoding.UTF8.GetBytes("InvalidMethod\0").CopyTo(testProcessor.Memory, 1234);
+                    _ = Assert.ThrowsException<InvalidFunctionException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when loading invalid function");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.Registers[(int)Register.rg8] = 1234;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x03, (int)Register.rg8
+                    });
+                    Encoding.UTF8.GetBytes("TestMethod3\0").CopyTo(testProcessor.Memory, 1234);
+                    _ = Assert.ThrowsException<InvalidFunctionException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when loading non-existent function");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rg8] = 1234;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x03, (int)Register.rg8
+                    });
+                    Encoding.UTF8.GetBytes("TestMethod\0").CopyTo(testProcessor.Memory, 1234);
+                    _ = Assert.ThrowsException<ExternalOperationException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when used without loading an assembly");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_CLA()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly?.GetMethod("TestMethod", BindingFlags.Default, Processor.ExternalMethodParamTypes));
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x10
+                    });
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(true);
+                    Assert.IsNull(typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction did not remove load context");
+                    Assert.IsNull(typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction did not remove open assembly");
+                    Assert.IsNull(typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction did not remove open function");
+                    Assert.AreEqual(3UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x10
+                    });
+                    _ = Assert.ThrowsException<ExternalOperationException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when used without loading an assembly");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_CLF()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly?.GetMethod("TestMethod", BindingFlags.Default, Processor.ExternalMethodParamTypes));
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x11
+                    });
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(true);
+                    Assert.IsNotNull(typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed load context");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed open assembly");
+                    Assert.IsNull(typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction did not remove open function");
+                    Assert.AreEqual(3UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x11
+                    });
+                    _ = Assert.ThrowsException<ExternalOperationException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when used without loading a function");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_AEX_Register_Address()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x20, (int)Register.rg0, 0x28, 2, 0, 0, 0, 0, 0, 0 });
+                    Encoding.UTF8.GetBytes("test.dll\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(12UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(1UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x20, (int)Register.rg0, 0x28, 2, 0, 0, 0, 0, 0, 0 });
+                    Encoding.UTF8.GetBytes("test-invalid.dll\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(12UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x20, (int)Register.rg0, 0x28, 2, 0, 0, 0, 0, 0, 0 });
+                    Encoding.UTF8.GetBytes("test-missing.dll\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(12UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_AEX_Register_Pointer()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rg7] = 552;
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x21, (int)Register.rg0, (int)Register.rg7 });
+                    Encoding.UTF8.GetBytes("test.dll\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(5UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(1UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rg7] = 552;
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x21, (int)Register.rg0, (int)Register.rg7 });
+                    Encoding.UTF8.GetBytes("test-invalid.dll\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(5UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rg7] = 552;
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x21, (int)Register.rg0, (int)Register.rg7 });
+                    Encoding.UTF8.GetBytes("test-missing.dll\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(5UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_FEX_Register_Address()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x22, (int)Register.rg0, 0x28, 2, 0, 0, 0, 0, 0, 0 });
+                    Encoding.UTF8.GetBytes("TestMethod\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(12UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(1UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x22, (int)Register.rg0, 0x28, 2, 0, 0, 0, 0, 0, 0 });
+                    Encoding.UTF8.GetBytes("InvalidMethod\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(12UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x22, (int)Register.rg0, 0x28, 2, 0, 0, 0, 0, 0, 0 });
+                    Encoding.UTF8.GetBytes("TestMethod2\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(12UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x22, (int)Register.rg0, 0x28, 2, 0, 0, 0, 0, 0, 0 });
+                    Encoding.UTF8.GetBytes("TestMethod\0").CopyTo(testProcessor.Memory, 552);
+                    _ = Assert.ThrowsException<ExternalOperationException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when used without loading an assembly");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_FEX_Register_Pointer()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rg7] = 552;
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x23, (int)Register.rg0, (int)Register.rg7 });
+                    Encoding.UTF8.GetBytes("TestMethod\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(5UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(1UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rg7] = 552;
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x23, (int)Register.rg0, (int)Register.rg7 });
+                    Encoding.UTF8.GetBytes("InvalidMethod\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(5UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rg7] = 552;
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop"));
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x23, (int)Register.rg0, (int)Register.rg7 });
+                    Encoding.UTF8.GetBytes("TestMethod2\0").CopyTo(testProcessor.Memory, 552);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(false);
+                    Assert.AreEqual(5UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rg0], "Instruction did not produce correct result");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    testProcessor.Registers[(int)Register.rg7] = 552;
+                    testProcessor.LoadProgram(new byte[] { 0xFF, 0x04, 0x23, (int)Register.rg0, (int)Register.rg7 });
+                    Encoding.UTF8.GetBytes("TestMethod\0").CopyTo(testProcessor.Memory, 552);
+                    _ = Assert.ThrowsException<ExternalOperationException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when used without loading an assembly");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_CAL()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly?.GetMethod("TestMethod", BindingFlags.Default, Processor.ExternalMethodParamTypes));
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x30
+                    });
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(true);
+                    Assert.AreEqual(3UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0xABUL, testProcessor.Memory[1234], "Instruction did not produce correct result");
+                    Assert.AreEqual(0UL, testProcessor.Registers[(int)Register.rg8], "Instruction did not produce correct result");
+                    Assert.AreEqual(0xCDUL, testProcessor.Registers[(int)Register.rg9], "Instruction did not produce correct result");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                    Assert.IsNotNull(typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed load context");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed open assembly");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed open function");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x30
+                    });
+                    _ = Assert.ThrowsException<ExternalOperationException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when used without loading a function");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_CAL_Register()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly?.GetMethod("TestMethod", BindingFlags.Default, Processor.ExternalMethodParamTypes));
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.Registers[(int)Register.rg3] = 0x123456789ABCDEF0;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x31, (int)Register.rg3
+                    });
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(true);
+                    Assert.AreEqual(3UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0xABUL, testProcessor.Memory[1234], "Instruction did not produce correct result");
+                    Assert.AreEqual(0x123456789ABCDEF0UL, testProcessor.Registers[(int)Register.rg8], "Instruction did not produce correct result");
+                    Assert.AreEqual(0xCDUL, testProcessor.Registers[(int)Register.rg9], "Instruction did not produce correct result");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                    Assert.IsNotNull(typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed load context");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed open assembly");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed open function");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x31, (int)Register.rg3
+                    });
+                    _ = Assert.ThrowsException<ExternalOperationException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when used without loading a function");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_CAL_Literal()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly?.GetMethod("TestMethod", BindingFlags.Default, Processor.ExternalMethodParamTypes));
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x32, 0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12
+                    });
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(true);
+                    Assert.AreEqual(11UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0xABUL, testProcessor.Memory[1234], "Instruction did not produce correct result");
+                    Assert.AreEqual(0x123456789ABCDEF0UL, testProcessor.Registers[(int)Register.rg8], "Instruction did not produce correct result");
+                    Assert.AreEqual(0xCDUL, testProcessor.Registers[(int)Register.rg9], "Instruction did not produce correct result");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                    Assert.IsNotNull(typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed load context");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed open assembly");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed open function");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x32, (int)Register.rg3
+                    });
+                    _ = Assert.ThrowsException<ExternalOperationException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when used without loading a function");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_CAL_Address()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly?.GetMethod("TestMethod", BindingFlags.Default, Processor.ExternalMethodParamTypes));
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x33, 0x28, 2, 0, 0, 0, 0, 0, 0
+                    });
+                    testProcessor.WriteMemoryQWord(552, 0x123456789ABCDEF0);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(true);
+                    Assert.AreEqual(11UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0xABUL, testProcessor.Memory[1234], "Instruction did not produce correct result");
+                    Assert.AreEqual(0x123456789ABCDEF0UL, testProcessor.Registers[(int)Register.rg8], "Instruction did not produce correct result");
+                    Assert.AreEqual(0xCDUL, testProcessor.Registers[(int)Register.rg9], "Instruction did not produce correct result");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                    Assert.IsNotNull(typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed load context");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed open assembly");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed open function");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x33, 0x28, 2, 0, 0, 0, 0, 0, 0
+                    });
+                    _ = Assert.ThrowsException<ExternalOperationException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when used without loading a function");
+                }
+            }
+
+            [TestMethod]
+            public void ASMX_CAL_Pointer()
+            {
+                // "using" is used here so that the open assembly is closed without having to use closing instructions
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly?.GetMethod("TestMethod", BindingFlags.Default, Processor.ExternalMethodParamTypes));
+                    testProcessor.Registers[(int)Register.rsf] = ulong.MaxValue;
+                    testProcessor.Registers[(int)Register.rg3] = 552;
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x34, (int)Register.rg3
+                    });
+                    testProcessor.WriteMemoryQWord(552, 0x123456789ABCDEF0);
+                    // Test that no exception is thrown
+                    _ = testProcessor.Execute(true);
+                    Assert.AreEqual(4UL, testProcessor.Registers[(int)Register.rpo], "Instruction updated the rpo register by an incorrect amount");
+                    Assert.AreEqual(0xABUL, testProcessor.Memory[1234], "Instruction did not produce correct result");
+                    Assert.AreEqual(0x123456789ABCDEF0UL, testProcessor.Registers[(int)Register.rg8], "Instruction did not produce correct result");
+                    Assert.AreEqual(0xCDUL, testProcessor.Registers[(int)Register.rg9], "Instruction did not produce correct result");
+                    Assert.AreEqual(ulong.MaxValue, testProcessor.Registers[(int)Register.rsf], "Instruction updated the status flags");
+                    Assert.IsNotNull(typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed load context");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed open assembly");
+                    Assert.IsNotNull(typeof(Processor).GetField("openExtFunction", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(testProcessor), "Instruction removed open function");
+                }
+
+                using (Processor testProcessor = new(2046))
+                {
+                    AssemblyLoadContext loadContext = new("TestLoadContext", true);
+                    typeof(Processor).GetField("extLoadContext", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(testProcessor, loadContext);
+                    Type? loadedAssembly = loadContext.LoadFromAssemblyPath(Path.GetFullPath("test.dll")).GetType("AssEmblyInterop");
+                    typeof(Processor).GetField("openExtAssembly", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(
+                        testProcessor, loadedAssembly);
+                    testProcessor.LoadProgram(new byte[]
+                    {
+                        0xFF, 0x04, 0x34, (int)Register.rg3
+                    });
+                    _ = Assert.ThrowsException<ExternalOperationException>(() => testProcessor.Execute(false),
+                        "Instruction did not throw an exception when used without loading a function");
+                }
+            }
         }
 
         private class AllZeroRandom : Random
diff --git a/Exceptions.cs b/Exceptions.cs
index adc71a3..cbbfd92 100644
--- a/Exceptions.cs
+++ b/Exceptions.cs
@@ -196,6 +196,18 @@ public InvalidFunctionException(string message, string consoleMessage) : base(me
         public InvalidFunctionException(string message, string consoleMessage, Exception inner) : base(message, consoleMessage, inner) { }
     }
 
+    /// <summary>
+    /// The exception that is thrown when an instruction is used without an external assembly or function loaded when one is required.
+    /// </summary>
+    public class ExternalOperationException : RuntimeException
+    {
+        public ExternalOperationException() : base() { }
+        public ExternalOperationException(string message) : base(message) { }
+        public ExternalOperationException(string message, Exception inner) : base(message, inner) { }
+        public ExternalOperationException(string message, string consoleMessage) : base(message, consoleMessage) { }
+        public ExternalOperationException(string message, string consoleMessage, Exception inner) : base(message, consoleMessage, inner) { }
+    }
+
     /// <summary>
     /// The exception that is thrown when there is not enough free memory remaining to perform the requested allocation.
     /// </summary>
diff --git a/Processor.cs b/Processor.cs
index c1afff0..761aafa 100644
--- a/Processor.cs
+++ b/Processor.cs
@@ -1,5 +1,7 @@
 using System.Buffers.Binary;
 using System.Globalization;
+using System.Reflection;
+using System.Runtime.Loader;
 using System.Text;
 using AssEmbly.Resources.Localization;
 
@@ -10,6 +12,9 @@ namespace AssEmbly
     /// </summary>
     public class Processor : IDisposable
     {
+        public static readonly Type[] ExternalMethodParamTypes =
+            new Type[3] { typeof(byte[]), typeof(byte[]), typeof(ulong?) };
+
         public readonly byte[] Memory;
         public readonly ulong[] Registers;
         public readonly bool UseV1CallStack;
@@ -23,6 +28,10 @@ public class Processor : IDisposable
         private BinaryWriter? fileWrite;
         private long openFileSize;
 
+        private AssemblyLoadContext? extLoadContext;
+        private Type? openExtAssembly;
+        private MethodInfo? openExtFunction;
+
         private readonly Random rng = new();
 
         // Because C#'s console methods work with potentially multi-byte characters at a time,
@@ -53,9 +62,12 @@ public Processor(ulong memorySize, ulong entryPoint = 0, bool useV1CallStack = f
 
         public void Dispose()
         {
+            extLoadContext?.Unload();
+
             openFile?.Dispose();
             fileRead?.Dispose();
             fileWrite?.Dispose();
+
             GC.SuppressFinalize(this);
         }