sencha: track changes to MpactCheriotCPU.cs

- MpactCheriotPeripheral is now bundled with and bound to the
  MpactCherioCPU class; this includes combining the code in one file
- no more need to setup ram_smc; mpact sim is not shared any more
- CliPort -> CLIPort and WaitForCli -> WaitForCLI
- renode LoadELF now works (LoadBinary should too but not tested)
- constructors changed; adjust the c# code to match
- massive style changes to MpactCheriotCPU.cs

NB: this requires an update cheriot toolchain

Change-Id: I9034e06c7ffecf78312b38b59ef971256f78107d
diff --git a/platforms/sencha_smc.repl b/platforms/sencha_smc.repl
index c457b35..94937c5 100644
--- a/platforms/sencha_smc.repl
+++ b/platforms/sencha_smc.repl
@@ -25,11 +25,11 @@
     memoryBase: 0x80000000
     memorySize: 0x04000000
     revocationMemoryBase: 0x83000000 // Shadow bitmap
-    clintMMRBase: 0 // NB: disables simulator built-in impl
 
-ram_smc: MpactPeripheral.MpactCheriotPeripheral @ sysbus 0x80000000
+ram_smc: MpactCPU.MpactCheriotPeripheral @ sysbus 0x80000000
     size: 0x04000000
-    id: 1  // NB: must match MpactCheriotCPU.id
+    baseAddress: 0x80000000
+    mpactCpu: cpu1
 
 // Control block for the SMC, lets us pause/restart the core at an arbitrary PC.
 smc_control: MpactCPU.SmcCheriot_ControlBlock @ sysbus 0x54020000
diff --git a/sencha.resc b/sencha.resc
index b77b779..ceae2c4 100644
--- a/sencha.resc
+++ b/sencha.resc
@@ -21,8 +21,7 @@
 
 include @sim/config/shodan_infrastructure/MpactCheriotCPU.cs
 EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.MpactCPU.MpactCheriotCPU"
-include @sim/config/shodan_infrastructure/MpactCheriotPeripheral.cs
-EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.MpactPeripheral.MpactCheriotPeripheral"
+EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.MpactCPU.MpactCheriotPeripheral"
 EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.CPU.RiscV32"
 include @sim/config/shodan_infrastructure/KelvinCPU.cs
 EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.CPU.KelvinCPU"
@@ -62,12 +61,8 @@
 
 # Override cli_port to enable the command line interface on the specified port.
 $cli_port?= -1
-sysbus.cpu1 CliPort $cli_port
-sysbus.cpu1 WaitForCli true
-
-# Setup ram_smc to coordinate with cpu1
-sysbus.ram_smc CpuLibraryPath $cheriotLibrary
-sysbus.ram_smc Start
+sysbus.cpu1 CLIPort $cli_port
+sysbus.cpu1 WaitForCLI true
 
 $tar ?= @out/cantrip/shodan/release/ext_flash.tar
 $spi_flash_load_address ?= 0x44000000
diff --git a/shodan_infrastructure/MpactCheriotCPU.cs b/shodan_infrastructure/MpactCheriotCPU.cs
index 072ddaa..b814cd6 100644
--- a/shodan_infrastructure/MpactCheriotCPU.cs
+++ b/shodan_infrastructure/MpactCheriotCPU.cs
@@ -38,518 +38,758 @@
 
 namespace Antmicro.Renode.Peripherals.MpactCPU
 {
-	// Declare some additional function signatures.
-	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-	public delegate Int32 FuncInt32Int32ActionInt32(Int32 param0, ActionInt32 param1);
-	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-	public delegate Int32 FuncInt32Int32Int32FuncInt32UInt64IntPtrInt32FuncInt32UInt64IntPtrInt32(Int32 param0, Int32 param1, FuncInt32UInt64IntPtrInt32 param2,
-			FuncInt32UInt64IntPtrInt32 param3);
-	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-	public delegate Int32 FuncInt32Int32FuncInt32UInt64IntPtrInt32FuncInt32UInt64IntPtrInt32(Int32 param0, FuncInt32UInt64IntPtrInt32 param1,
-			FuncInt32UInt64IntPtrInt32 param2);
-	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-	public delegate Int32 FuncInt32Int32StringArrStringArrInt32(Int32 param0, string[] param1, string[] param2, Int32 param3);
-	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-	public delegate Int32 FuncInt32Int32Int32Bool(Int32 param0, Int32 param1, bool param2);
 
-	public class MpactCheriotCPU : BaseCPU, ICpuSupportingGdb, ICPUWithRegisters, ICPUWithHooks, IGPIOReceiver, ITimeSink, IDisposable {
-		[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 1)]
-		private struct RegInfo {
-			[FieldOffset(0)]
-			public Int32 index;
-			[FieldOffset(4)]
-			public Int32 width;
-			[FieldOffset(8)]
-			public bool isGeneral;
-			[FieldOffset(9)]
-			public bool isReadOnly;
-		}
+// This interface is implemented by MpactCheriotCPU and used by
+// MpactCheriotPeripheral to access memory in mpact_cheriot simulator
+public interface IMpactPeripheral :  IBytePeripheral, IWordPeripheral,
+                                     IDoubleWordPeripheral,
+                                     IQuadWordPeripheral,
+                                     IMultibyteWritePeripheral {}
 
-		public MpactCheriotCPU(uint id, UInt64 memoryBase, UInt64 memorySize,
-				       UInt64 revocationMemoryBase, UInt64 clintMMRBase,
-				       string cpuType, IMachine machine, Endianess endianness,
-				       CpuBitness bitness = CpuBitness.Bits32)
-		: base(id, cpuType, machine, endianness, bitness)
-		{
-			this.memoryBase = memoryBase;
-			this.memorySize = memorySize;
-			revocationMemBase = revocationMemoryBase;
-			clintBase = clintMMRBase;
-			error_ptr = Marshal.AllocHGlobal(4);
-			value_ptr = Marshal.AllocHGlobal(8);
-			reg_info_ptr = Marshal.AllocHGlobal(Marshal.SizeOf<RegInfo>());
-			string_ptr = Marshal.AllocHGlobal(maxStringLen);
-			read_sysmem_delegate = new FuncInt32UInt64IntPtrInt32(ReadSysMemory);
-			write_sysmem_delegate = new FuncInt32UInt64IntPtrInt32(WriteSysMemory);
-			cpuLibraryRegistered = false;
-		}
 
-		~MpactCheriotCPU() {
-			Marshal.FreeHGlobal(error_ptr);
-			Marshal.FreeHGlobal(value_ptr);
-			Marshal.FreeHGlobal(reg_info_ptr);
-			Marshal.FreeHGlobal(string_ptr);
-		}
+// Struct containing info for loading binary image files.
+public struct BinFileLoadInfo {
+    public string file_name;
+    public UInt64 load_address;
+    public UInt64 entry_point;
+}
 
-		public override string Architecture { get { return "MpactCheriot";} }
+// The MpactCheriotCPU class. This class derives from BaseCPU, which implements
+// a CPU in ReNode. It is the interface between ReNode and the mpact_cheriot
+// simulator library.
+public class MpactCheriotCPU : BaseCPU, ICpuSupportingGdb, ICPUWithRegisters,
+                               ICPUWithHooks, IGPIOReceiver, ITimeSink,
+                               IDisposable, IMpactPeripheral {
 
-		public override void Start()
-		{
-			if (!cpuLibraryRegistered)
-			{
-					LogAndThrowRE("Failed to register cpu library");
-					return;
-			}
-			base.Start();
+    // Structure for ReNode register information that is obtained from the
+    // simulator.
+    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 1)]
+    private struct RegInfo {
+        [FieldOffset(0)]
+        public Int32 index;
+        [FieldOffset(4)]
+        public Int32 width;
+        [FieldOffset(8)]
+        public bool isGeneral;
+        [FieldOffset(9)]
+        public bool isReadOnly;
+    }
 
-			// Simulator initialization code goes here.
-			mpact_id = connect_with_sysbus((Int32)Id, maxStringLen, read_sysmem_delegate, write_sysmem_delegate);
-			if (mpact_id < 0) {
-				LogAndThrowRE("Failed to create simulator instance");
-				return;
-			}
-			// Set up configuration array.
-			var config_names = new List<string>();
-			var config_values = new List<string>();
-			config_names.Add("memoryBase");
-			config_names.Add("memorySize");
-			config_names.Add("revocationMemoryBase");
-			config_names.Add("clintMMRBase");
-			config_values.Add("0x" + memoryBase.ToString("X"));
-			config_values.Add("0x" + memorySize.ToString("X"));
-			config_values.Add("0x" + revocationMemBase.ToString("X"));
-			config_values.Add("0x" + clintBase.ToString("X"));
+    public MpactCheriotCPU(uint id, UInt64 memoryBase, UInt64 memorySize,
+		           UInt64 revocationMemoryBase, string cpuType,
+			   IMachine machine, Endianess endianness,
+                           CpuBitness bitness = CpuBitness.Bits32)
+        : base(id, cpuType, machine, endianness, bitness) {
+        this.memoryBase = memoryBase;
+        this.memorySize = memorySize;
+        revocationMemBase = revocationMemoryBase;
+        // Allocate space for marshaling data to/from simulator.
+        error_ptr = Marshal.AllocHGlobal(4);
+        value_ptr = Marshal.AllocHGlobal(8);
+        reg_info_ptr = Marshal.AllocHGlobal(Marshal.SizeOf<RegInfo>());
+        string_ptr = Marshal.AllocHGlobal(maxStringLen);
+    }
 
-			if (cli_port != -1) {
-				config_names.Add("cliPort");
-				config_values.Add("0x" + cli_port.ToString("X"));
-				config_names.Add("waitForCLI");
-				config_values.Add("0x" + Convert.ToInt32(wait_for_cli).ToString("X"));
-			}
+    ~MpactCheriotCPU() {
+        Marshal.FreeHGlobal(error_ptr);
+        Marshal.FreeHGlobal(value_ptr);
+        Marshal.FreeHGlobal(reg_info_ptr);
+        Marshal.FreeHGlobal(string_ptr);
+    }
 
-			Int32 cfg_res = set_config(mpact_id, config_names.ToArray(), config_values.ToArray(), config_names.Count);
-			if (cfg_res < 0) {
-				LogAndThrowRE("Failed to set configuration information");
-			}
-		}
 
-		public override void Reset()
-		{
-			base.Reset();
-			instructionsExecutedThisRound = 0;
-			totalExecutedInstructions = 0;
-			// Call simulator to reset.
-			reset(mpact_id);
-		}
+    public override string Architecture { get { return "MpactCheriot";} }
 
-		public override void Dispose()
-		{
-			base.Dispose();
-			destruct(mpact_id);
-		}
+    public override void Start() {
+        base.Start();
 
-		public string CpuLibraryPath
-		{
-				get
-				{
-						return cpuLibraryPath;
-				}
-				set
-				{
-						if (!String.IsNullOrWhiteSpace(value))
-						{
-								if (cpuLibraryRegistered)
-								{
-										this.WarningLog("cpu library already registerd and " +
-																		"should not be updated again.");
-										return;
-								}
-								cpuLibraryPath = value;
-								try
-								{
-										binder = new NativeBinder(this, cpuLibraryPath);
-								}
-								catch (System.Exception e)
-								{
-										LogAndThrowRE("Failed to load CPU library: " + e.Message);
-								}
-								cpuLibraryRegistered = true;
-						}
-						else
-						{
-								return;
-						}
-				}
-		}
+        // Set up configuration array.
+        var config_names = new List<string>();
+        var config_values = new List<string>();
+        config_names.Add("memoryBase");
+        config_names.Add("memorySize");
+        config_names.Add("revocationMemoryBase");
+        config_values.Add("0x" + memoryBase.ToString("X"));
+        config_values.Add("0x" + memorySize.ToString("X"));
+        config_values.Add("0x" + revocationMemBase.ToString("X"));
+        if (cli_port > 0) {
+                            this.Log(LogLevel.Info, "Adding cli port");
+            config_names.Add("cliPort");
+            config_values.Add("0x" + cli_port.ToString("X"));
+                config_names.Add("waitForCLI");
+            config_values.Add("0x" + (wait_for_cli ? 1 : 0).ToString("X"));
+        }
+        Int32 cfg_res = set_config(mpact_id, config_names.ToArray(),
+                                   config_values.ToArray(), config_names.Count);
+        if (cfg_res < 0) {
+            LogAndThrowRE("Failed to set configuration information");
+        }
+        if (mpact_id < 0) {
+            LogAndThrowRE("Failed to create simulator instance");
+            return;
+        }
+        // Load executable file or bin file if specified. Otherwise it is
+        // handled by the system.
+        if (!executable_file.Equals("")) {
+            var entry_point = load_executable(mpact_id, executable_file,
+                                              error_ptr);
+            Int32 result = Marshal.ReadInt32(error_ptr);
+            if (result < 0) {
+                LogAndThrowRE("Failed to load executable");
+            }
+            PC = entry_point;
+        } else if (!bin_file_info.file_name.Equals("")) {
+            Int32 res = load_image(mpact_id, bin_file_info.file_name,
+                                   bin_file_info.load_address);
+            if (res < 0) {
+                LogAndThrowRE("Failed to load binary image");
+            }
+            PC = bin_file_info.entry_point;
+        }
+    }
 
-		public int CliPort { get => cli_port; set => cli_port = value; }
-		public bool WaitForCli
-		{
-			get => wait_for_cli;
-			set => wait_for_cli = value;
-		}
+    public override void Reset() {
+        base.Reset();
+        instructionsExecutedThisRound = 0;
+        totalExecutedInstructions = 0;
+        // Call simulator to reset.
+        reset(mpact_id);
+    }
 
-		public override ulong ExecutedInstructions => totalExecutedInstructions;
+    public override void Dispose() {
+        base.Dispose();
+        // Cleanup: simulator and any unmanaged resources.
+        this.Log(LogLevel.Info, "destruct mpact");
+        destruct(mpact_id);
+        this.Log(LogLevel.Info, "done");
+    }
 
-		public override ExecutionMode ExecutionMode
-		{
-			get
-			{
-				return executionMode;
-			}
-			set
-			{
-				lock(singleStepSynchronizer.Guard)
-				{
-					if (executionMode == value)
-					{
-						return;
-					}
-
-					executionMode = value;
-
-					singleStepSynchronizer.Enabled = IsSingleStepMode;
-					UpdateHaltedState();
-				}
-			}
-		}
-
-		[Register]
-		public override RegisterValue PC
-		{
-			get
-			{
-				Int32 error = read_register(mpact_id, PC_ID, value_ptr);
-				// TODO(torerik): Check for error.
-				if (error < 0) {
-					this.Log(LogLevel.Error, "Failed to read PC");
-				}
-				Int64 value = Marshal.ReadInt64(value_ptr);
-				return Convert.ToUInt64(value);
-			}
-
-			set
-			{
-				Int32 error = write_register(mpact_id, PC_ID, value);
-				// TODO(torerik): Check for error.
-				if (error < 0) {
-					this.Log(LogLevel.Error, "Failed to write PC");
-				}
-			}
-		}
-
-		protected override ExecutionResult ExecuteInstructions(ulong numberOfInstructionsToExecute, out ulong numberOfExecutedInstructions)
-		{
-			UInt64 instructionsExecutedThisRound = 0UL;
-			ExecutionResult result = ExecutionResult.Ok;
-			try
-			{
-				// Invoke simulator for the number of instructions.
-				instructionsExecutedThisRound = step(mpact_id, numberOfInstructionsToExecute, error_ptr);
-				// Parse the result.
-				Int32 step_result = Marshal.ReadInt32(error_ptr);
-				switch (step_result) {
-					case -1:
-						result = ExecutionResult.Aborted;
-						break;
-					case 0:
-						result = ExecutionResult.Ok;
-						break;
-					case 1:
-						result = ExecutionResult.Interrupted;
-						break;
-					case 2:
-						result = ExecutionResult.WaitingForInterrupt;
-						break;
-					case 3:
-						result = ExecutionResult.StoppedAtBreakpoint;
-						break;
-					case 4:
-						result = ExecutionResult.StoppedAtWatchpoint;
-						break;
-					case 5:
-						result = ExecutionResult.ExternalMmuFault;
-						break;
-					default:
-						LogAndThrowRE("Unknown return value from step - " + step_result);
-						break;
-				}
-			}
-			catch (Exception)
-			{
-				this.NoisyLog("CPU exception detected, halting.");
-				InvokeHalted(new HaltArguments(HaltReason.Abort, Id));
-				return ExecutionResult.Aborted;
-			}
-			finally
-			{
-				numberOfExecutedInstructions = instructionsExecutedThisRound;
-				totalExecutedInstructions += instructionsExecutedThisRound;
-			}
-
-			return result;
-		}
-
-		// ICPUWithRegisters methods implementations.
-		public  void SetRegisterUnsafe(int register, RegisterValue value) {
-			var status = write_register((Int32)mpact_id, (Int32)register, (UInt64)value);
-			if (status < 0) {
-				LogAndThrowRE("Failed to write register " + register);
-			}
-		}
-
-		public  RegisterValue GetRegisterUnsafe(int register) {
-			var status = read_register(mpact_id, register, value_ptr);
-			if (status < 0) {
-				LogAndThrowRE("Failed to read register " + register);
-			}
-			Int64 value = Marshal.ReadInt64(value_ptr);
-			return (UInt64)value;
-		}
-
-		private void GetMpactRegisters() {
-			if (registerMap.Count != 0) return;
-			Int32 num_regs = get_reg_info_size(mpact_id);
-			for (Int32 i = 0; i < num_regs; i++) {
-				Int32 result = get_reg_info(mpact_id, i, string_ptr, reg_info_ptr);
-				if (result < 0) {
-					this.Log(LogLevel.Error, "Failed to get register info for index " + i);
-					continue;
-				}
-				var reg_info = Marshal.PtrToStructure<RegInfo>(reg_info_ptr);
-				var cpu_reg = new CPURegister(reg_info.index, reg_info.width, reg_info.isGeneral, reg_info.isReadOnly);
-				var reg_name = Marshal.PtrToStringAuto(string_ptr);
-				registerMap.Add(reg_info.index, cpu_reg);
-				registerNamesMap.Add(reg_name, reg_info.index);
-			}
-		}
-
-		public  IEnumerable<CPURegister> GetRegisters() {
-			if (registerMap.Count == 0) {
-				GetMpactRegisters();
-			}
-			return registerMap.Values.OrderBy(x => x.Index);
-		}
-
-		public new string[,] GetRegistersValues() {
-			if (registerMap.Count == 0) {
-				GetMpactRegisters();
-			}
-			var result = new Dictionary<string, ulong>();
-			foreach (var reg in registerNamesMap) {
-				var status = read_register(mpact_id, reg.Value, value_ptr);
-				if (status < 0) continue;
-				Int64 value = Marshal.ReadInt64(value_ptr);
-				result.Add(reg.Key, Convert.ToUInt64(value));
-			}
-			var table = new Table().AddRow("Name", "Value");
-			table.AddRows(result, x=> x.Key, x=> "0x{0:X}".FormatWith(x.Value));
-			return table.ToArray();
-		}
-
-		private void LogAndThrowRE(string info)
-		{
-				this.Log(LogLevel.Error, info);
-				throw new RecoverableException(info);
-		}
-
-	public Int32 LoadImageFile(String file_name, UInt64 address) {
-		return load_image(mpact_id, file_name, address);
+    public string CpuLibraryPath {
+        get {
+	  return cpu_library_path;
 	}
+	set {
+		this.Log(LogLevel.Info, "Lib: " + value);
+	    if (String.IsNullOrWhiteSpace(value)) {
+                cpu_library_path = value;
+                return;
+            }
+	    if (cpu_library_bound) {
+	        LogAndThrowRE("CPU library already bound to: "
+		              + cpu_library_path);
+	    }
+	    cpu_library_path = value;
+	    try {
+	        binder = new NativeBinder(this, cpu_library_path);
+            }
+	    catch (System.Exception e) {
+	        LogAndThrowRE("Failed to load CPU library: " + e.Message);
+            }
+	    cpu_library_bound = true;
 
-	public void OnGPIO(int number, bool value) {
+            // Instantiate the simulator, passing in callbacks to read and write
+            // from/to the system bus.
+            read_sysmem_delegate =
+	            new FuncInt32UInt64IntPtrInt32(ReadSysMemory);
+            write_sysmem_delegate =
+	            new FuncInt32UInt64IntPtrInt32(WriteSysMemory);
+            mpact_id = construct_with_sysbus(maxStringLen,
+			                     read_sysmem_delegate,
+                                             write_sysmem_delegate);
+        }
+    }
+
+    public string ExecutableFile {
+        get => executable_file;
+        set => executable_file = value;
+    }
+
+    public BinFileLoadInfo BinFileInfo {
+        get => bin_file_info;
+        set => bin_file_info = value;
+    }
+
+    public int CLIPort { get => cli_port; set => cli_port = value; }
+
+    public bool WaitForCLI { get => wait_for_cli; set => wait_for_cli = value; }
+
+    public override ulong ExecutedInstructions => totalExecutedInstructions;
+
+    public override ExecutionMode ExecutionMode {
+        get { return executionMode; }
+        set {
+            lock(singleStepSynchronizer.Guard) {
+                if (executionMode == value) return;
+
+                executionMode = value;
+
+                singleStepSynchronizer.Enabled = IsSingleStepMode;
+                UpdateHaltedState();
+            }
+        }
+    }
+
+    [Register]
+    public override RegisterValue PC {
+        get {
+            Int32 error = read_register(mpact_id, PC_ID, value_ptr);
+            if (error < 0) {
+                this.Log(LogLevel.Error, "Failed to read PC");
+            }
+            Int64 value = Marshal.ReadInt64(value_ptr);
+            return Convert.ToUInt64(value);
+        }
+
+        set {
+            Int32 error = write_register(mpact_id, PC_ID, value);
+            if (error < 0) {
+                this.Log(LogLevel.Error, "Failed to write PC");
+            }
+        }
+    }
+
+    protected override ExecutionResult ExecuteInstructions(
+                    ulong numberOfInstructionsToExecute,
+                    out ulong numberOfExecutedInstructions) {
+        UInt64 instructionsExecutedThisRound = 0UL;
+        ExecutionResult result = ExecutionResult.Ok;
+        try {
+            // Invoke simulator for the number of instructions.
+            instructionsExecutedThisRound =
+                    step(mpact_id, numberOfInstructionsToExecute, error_ptr);
+            // Parse the result.
+            Int32 step_result = Marshal.ReadInt32(error_ptr);
+            switch (step_result) {
+                case -1:
+                    result = ExecutionResult.Aborted;
+                    break;
+                case 0:
+                    result = ExecutionResult.Ok;
+                    break;
+                case 1:
+                    result = ExecutionResult.Interrupted;
+                    break;
+                case 2:
+                    result = ExecutionResult.WaitingForInterrupt;
+                    break;
+                case 3:
+                    result = ExecutionResult.StoppedAtBreakpoint;
+                    break;
+                case 4:
+                    result = ExecutionResult.StoppedAtWatchpoint;
+                    break;
+                case 5:
+                    result = ExecutionResult.ExternalMmuFault;
+                    break;
+                default:
+                    LogAndThrowRE("Unknown return value from step - "
+                                  + step_result);
+                    break;
+                }
+        }
+        catch (Exception) {
+            this.NoisyLog("CPU exception detected, halting.");
+            InvokeHalted(new HaltArguments(HaltReason.Abort, Id));
+            return ExecutionResult.Aborted;
+            }
+        finally {
+            numberOfExecutedInstructions = instructionsExecutedThisRound;
+            totalExecutedInstructions += instructionsExecutedThisRound;
+        }
+        return result;
+    }
+
+    // ICPUWithRegisters methods implementations.
+    public  void SetRegisterUnsafe(int register, RegisterValue value) {
+        var status = write_register((Int32)mpact_id, (Int32)register,
+                                    (UInt64)value);
+        if (status < 0) {
+            LogAndThrowRE("Failed to write register " + register);
+        }
+    }
+
+    public  RegisterValue GetRegisterUnsafe(int register) {
+        var status = read_register(mpact_id, register, value_ptr);
+        if (status < 0) {
+            LogAndThrowRE("Failed to read register " + register);
+        }
+        Int64 value = Marshal.ReadInt64(value_ptr);
+        return (UInt64)value;
+    }
+
+    private void GetMpactRegisters() {
+        if (registerMap.Count != 0) return;
+        Int32 num_regs = get_reg_info_size(mpact_id);
+        for (Int32 i = 0; i < num_regs; i++) {
+            Int32 result = get_reg_info(mpact_id, i, string_ptr, reg_info_ptr);
+            if (result < 0) {
+                this.Log(LogLevel.Error,
+                         "Failed to get register info for index " + i);
+                continue;
+            }
+            var reg_info = Marshal.PtrToStructure<RegInfo>(reg_info_ptr);
+            var cpu_reg = new CPURegister(reg_info.index, reg_info.width,
+                                          reg_info.isGeneral,
+                                          reg_info.isReadOnly);
+            var reg_name = Marshal.PtrToStringAuto(string_ptr);
+            registerMap.Add(reg_info.index, cpu_reg);
+            registerNamesMap.Add(reg_name, reg_info.index);
+        }
+    }
+
+    public  IEnumerable<CPURegister> GetRegisters() {
+        if (registerMap.Count == 0) {
+            GetMpactRegisters();
+        }
+        return registerMap.Values.OrderBy(x => x.Index);
+    }
+
+    public new string[,] GetRegistersValues() {
+        if (registerMap.Count == 0) {
+            GetMpactRegisters();
+        }
+        var result = new Dictionary<string, ulong>();
+        foreach (var reg in registerNamesMap) {
+            var status = read_register(mpact_id, reg.Value, value_ptr);
+            if (status < 0) continue;
+            Int64 value = Marshal.ReadInt64(value_ptr);
+            result.Add(reg.Key, Convert.ToUInt64(value));
+        }
+        var table = new Table().AddRow("Name", "Value");
+        table.AddRows(result, x=> x.Key, x=> "0x{0:X}".FormatWith(x.Value));
+        return table.ToArray();
+    }
+
+    private void LogAndThrowRE(string info) {
+        this.Log(LogLevel.Error, info);
+        throw new RecoverableException(info);
+    }
+
+    public Int32 LoadImageFile(String file_name, UInt64 address) {
+        return load_image(mpact_id, file_name, address);
+    }
+
+    public void OnGPIO(int number, bool value) {
 		if (mpact_id <= 0) {
 			this.Log(LogLevel.Noisy, "OnGPIO: no simulator, discard gpio {0}:{1}", number, value);
 			return;
 		}
-		Int32 status = set_irq_value(mpact_id, number, value);
-		if (status < 0) {
-			Console.Error.WriteLine("Failure in setting irq value");
-		}
-	}
+        Int32 status = set_irq_value(mpact_id, number, value);
+        if (status < 0) {
+            Console.Error.WriteLine("Failure in setting irq value");
+        }
+    }
 
-	public Int32 ReadSysMemory(UInt64 address, IntPtr buffer, Int32 length) {
-		// Read from System Bus.
-		switch (length) {
-			case 1:
-				var data8 = new byte[length];
-				data8[0] = machine.SystemBus.ReadByte(address, this);
-				Marshal.Copy(data8, 0, buffer, length);
-				break;
-			case 2:
-				var data16 = new Int16[1];
-				data16[0] = (Int16) machine.SystemBus.ReadWord(address, this);
-				Marshal.Copy(data16, 0, buffer, 1);
-				break;
-			case 4:
-				var data32 = new Int32[1];
-				data32[0] = (Int32) machine.SystemBus.ReadDoubleWord(address, this);
-				Marshal.Copy(data32, 0, buffer, 1);
-				break;
-			case 8:
-				var data64 = new Int64[1];
-				data64[0] = (Int64) machine.SystemBus.ReadQuadWord(address, this);
-				Marshal.Copy(data64, 0, buffer, 1);
-				break;
-			default:
-				var dataN = new byte[length];
-				machine.SystemBus.ReadBytes(address, length, dataN, 0, false, this);
-				Marshal.Copy(dataN, 0, buffer, length);
-				break;
-		}
-		return length;
-	}
+    public Int32 ReadSysMemory(UInt64 address, IntPtr buffer, Int32 length) {
+        // Read from System Bus.
+        switch (length) {
+            case 1:
+                var data8 = new byte[length];
+                data8[0] = machine.SystemBus.ReadByte(address, this);
+                Marshal.Copy(data8, 0, buffer, length);
+                break;
+            case 2:
+                var data16 = new Int16[1];
+                data16[0] = (Int16) machine.SystemBus.ReadWord(address, this);
+                Marshal.Copy(data16, 0, buffer, 1);
+                break;
+            case 4:
+                var data32 = new Int32[1];
+                data32[0] = (Int32) machine.SystemBus.ReadDoubleWord(address,
+                                                                     this);
+                Marshal.Copy(data32, 0, buffer, 1);
+                break;
+            case 8:
+                var data64 = new Int64[1];
+                data64[0] = (Int64) machine.SystemBus.ReadQuadWord(address,
+                                                                   this);
+                Marshal.Copy(data64, 0, buffer, 1);
+                break;
+            default:
+                var dataN = new byte[length];
+                machine.SystemBus.ReadBytes(address, length, dataN, 0, false,
+                                            this);
+                Marshal.Copy(dataN, 0, buffer, length);
+                break;
+        }
+        return length;
+    }
 
-	public Int32 WriteSysMemory(UInt64 address, IntPtr buffer, Int32 length) {
-		// Create a managed buffer for the store data.
-		// Copy the store data to the managed buffer.
-		// Write the data to the system bus.
-		switch (length) {
-			case 1:
-				var data8 = new byte[1];
-				Marshal.Copy(buffer, data8, 0, 1);
-				machine.SystemBus.WriteByte(address, data8[0], this);
-				break;
-			case 2:
-				var data16 = new Int16[1];
-				Marshal.Copy(buffer, data16, 0, 1);
-				machine.SystemBus.WriteWord(address, (ushort)data16[0], this);
-				break;
-			case 4:
-				var data32 = new Int32[1];
-				Marshal.Copy(buffer, data32, 0, 1);
-				machine.SystemBus.WriteDoubleWord(address, (uint)data32[0], this);
-				break;
-			case 8:
-				var data64 = new Int64[1];
-				Marshal.Copy(buffer, data64, 0, 1);
-				machine.SystemBus.WriteQuadWord(address, (ulong)data64[0], this);
-				break;
-			default:
-				var dataN = new byte[length];
-				Marshal.Copy(buffer, dataN, 0, length);
-				machine.SystemBus.WriteBytes(dataN, address);
-				break;
-		}
-		return length;
-	}
+    public Int32 WriteSysMemory(UInt64 address, IntPtr buffer, Int32 length) {
+        switch (length) {
+            case 1:
+                var data8 = new byte[1];
+                Marshal.Copy(buffer, data8, 0, 1);
+                machine.SystemBus.WriteByte(address, data8[0], this);
+                break;
+            case 2:
+                var data16 = new Int16[1];
+                Marshal.Copy(buffer, data16, 0, 1);
+                machine.SystemBus.WriteWord(address, (ushort)data16[0], this);
+                break;
+            case 4:
+                var data32 = new Int32[1];
+                Marshal.Copy(buffer, data32, 0, 1);
+                machine.SystemBus.WriteDoubleWord(address, (uint)data32[0],
+                                                  this);
+                break;
+            case 8:
+                var data64 = new Int64[1];
+                Marshal.Copy(buffer, data64, 0, 1);
+                machine.SystemBus.WriteQuadWord(address, (ulong)data64[0],
+                                                this);
+                break;
+            default:
+                var dataN = new byte[length];
+                Marshal.Copy(buffer, dataN, 0, length);
+                machine.SystemBus.WriteBytes(dataN, address);
+                break;
+        }
+        return length;
+    }
 
-		// ICPUWithHooks methods.
+    // ICPUWithHooks methods.
 
-		public void AddHookAtInterruptBegin(Action<ulong> hook) {
-			throw new RecoverableException("Interrupt hooks not currently supported");
-		}
-		public void AddHookAtInterruptEnd(Action<ulong> hook) {
-			throw new RecoverableException("Interrupt hooks not currently supported");
-		}
-		public void AddHookAtWfiStateChange(Action<bool> hook) {
-			throw new RecoverableException("Wfi state change hook not currently supported");
-		}
+    public void AddHookAtInterruptBegin(Action<ulong> hook) {
+        throw new RecoverableException(
+                        "Interrupt hooks not currently supported");
+    }
+    public void AddHookAtInterruptEnd(Action<ulong> hook) {
+        throw new RecoverableException(
+                        "Interrupt hooks not currently supported");
+    }
+    public void AddHookAtWfiStateChange(Action<bool> hook) {
+        throw new RecoverableException(
+			"Wfi state change hook not currently supported");
+    }
 
-		public void AddHook(ulong addr, Action<ICpuSupportingGdb, ulong> hook) {
-			throw new RecoverableException("Hooks not currently supported");
-		}
-		public void RemoveHook(ulong addr, Action<ICpuSupportingGdb, ulong> hook) {
-		}
-		public void RemoveHooksAt(ulong addr) {
-		}
-		public void RemoveAllHooks() {
-		}
+    public void AddHook(ulong addr, Action<ICpuSupportingGdb, ulong> hook) {
+        throw new RecoverableException("Hooks not currently supported");
+    }
+    public void RemoveHook(ulong addr, Action<ICpuSupportingGdb, ulong> hook) {
+        /* empty */
+    }
+    public void RemoveHooksAt(ulong addr) { /* empty */ }
+    public void RemoveAllHooks() { /* empty */ }
 
-		// ICpuSuportingGdb methods.
+    // ICpuSuportingGdb methods.
 
-		public void EnterSingleStepModeSafely(HaltArguments args, bool? blocking = null) {
-			CheckCpuThreadId();
-			ChangeExecutionModeToSingleStep(blocking);
-			UpdateHaltedState();
-			InvokeHalted(args);
-		}
+    public void EnterSingleStepModeSafely(HaltArguments args,
+		                          bool? blocking = null) {
+        CheckCpuThreadId();
+        ChangeExecutionModeToSingleStep(blocking);
+        UpdateHaltedState();
+        InvokeHalted(args);
+    }
 
-		public string GDBArchitecture { get { return "riscv:cheriot"; } }
+    public string GDBArchitecture { get { return "riscv:cheriot"; } }
 
-		public List<GDBFeatureDescriptor> GDBFeatures {
-			get {
-				if (gdbFeatures.Any()) return gdbFeatures;
+    public List<GDBFeatureDescriptor> GDBFeatures {
+        get {
+            if (gdbFeatures.Any()) return gdbFeatures;
 
-				// Populate the register map if it hasn't been done yet.
-				if (registerNamesMap.Count == 0) {
-					GetMpactRegisters();
-				}
-				var cpuGroup = new GDBFeatureDescriptor("org.gnu.gdb.riscv.cpu");
-				var intType = $"uint32";
-				var c0_index = registerNamesMap["c0"];
-				for (var i = 0u; i < 16; ++i) {
-					cpuGroup.Registers.Add(new GDBRegisterDescriptor((uint)c0_index + i, 32u, $"c{i}", intType, "general"));
-				}
-				var pcc_index = registerNamesMap["pcc"];
-				cpuGroup.Registers.Add(new GDBRegisterDescriptor((uint)pcc_index, 32u, "pcc", "code_ptr", "general"));
-				gdbFeatures.Add(cpuGroup);
+            // Populate the register map if it hasn't been done yet.
+            if (registerNamesMap.Count == 0) {
+                GetMpactRegisters();
+            }
+            var cpuGroup = new GDBFeatureDescriptor("org.gnu.gdb.riscv.cpu");
+            var intType = $"uint32";
+            var c0_index = registerNamesMap["c0"];
+            for (var i = 0u; i < 16; ++i) {
+                cpuGroup.Registers.Add(
+		        new GDBRegisterDescriptor((uint)c0_index + i, 32u,
+				                  $"c{i}", intType, "general"));
+            }
+            var pcc_index = registerNamesMap["pcc"];
+            cpuGroup.Registers.Add(
+		        new GDBRegisterDescriptor((uint)pcc_index, 32u, "pcc",
+				                  "code_ptr", "general"));
+            gdbFeatures.Add(cpuGroup);
 
-				return gdbFeatures;
-			}
-		}
+            return gdbFeatures;
+        }
+    }
 
-		// End of ICpuSupportingGdb methods.
+    // End of ICpuSupportingGdb methods.
 
-		private List<GDBFeatureDescriptor> gdbFeatures = new List<GDBFeatureDescriptor>();
-		private UInt64 memoryBase;
-		private UInt64 memorySize;
-		private UInt64 revocationMemBase;
-		private UInt64 clintBase;
-		private Dictionary<Int32, CPURegister> registerMap = new Dictionary<Int32, CPURegister>();
-		private Dictionary<string, Int32> registerNamesMap = new Dictionary<string, Int32>();
-		private string cpuLibraryPath;
-    private bool cpuLibraryRegistered;
-		private int cli_port = -1;
-		private bool wait_for_cli = false;
-		private NativeBinder binder;
-		private readonly object nativeLock;
-		private readonly Int32 maxStringLen = 32;
-		private IntPtr value_ptr {get; set;}
-		private IntPtr error_ptr {get; set;}
-		private IntPtr reg_info_ptr {get; set;}
-		private IntPtr string_ptr {get; set;}
-		private FuncInt32UInt64IntPtrInt32 read_sysmem_delegate;
-		private FuncInt32UInt64IntPtrInt32 write_sysmem_delegate;
+    // IMpactPeripheral methods.
+    public void WriteByte(long address, byte value) {
+        var data8 = new byte[1];
+        data8[0] = (byte) value;
+        Marshal.Copy(data8, 0, value_ptr, 1);
+        write_memory(mpact_id, (UInt64) address + base_address, value_ptr, 1);
+    }
+
+    public byte ReadByte(long address) {
+        var data8 = new byte[1];
+        read_memory(mpact_id, (UInt64) address + base_address, value_ptr, 1);
+        Marshal.Copy(value_ptr, data8, 0, 1);
+        return (byte) data8[0];
+    }
+
+    public void WriteWord(long address, ushort value) {
+        var data16 = new Int16[1];
+        data16[0] = (Int16) value;
+        Marshal.Copy(data16, 0, value_ptr, 1);
+        write_memory(mpact_id, (UInt64) address + base_address, value_ptr, 2);
+    }
+
+    public ushort ReadWord(long address) {
+        var data16 = new Int16[1];
+        read_memory(mpact_id, (UInt64) address + base_address, value_ptr, 2);
+        Marshal.Copy(value_ptr, data16, 0, 1);
+        return (ushort) data16[0];
+    }
+
+    public void WriteDoubleWord(long address, uint value) {
+        var data32 = new Int32[1];
+        data32[0] = (Int32) value;
+        Marshal.Copy(data32, 0, value_ptr, 1);
+        write_memory(mpact_id, (UInt64) address + base_address, value_ptr, 4);
+    }
+
+    public uint ReadDoubleWord(long address) {
+        var data32 = new Int32[1];
+        read_memory(mpact_id, (UInt64) address + base_address, value_ptr, 4);
+        Marshal.Copy(value_ptr, data32, 0, 1);
+        return (uint) data32[0];
+    }
+
+    public void WriteQuadWord(long address, ulong value) {
+        var data64 = new Int64[1];
+        data64[0] = (Int64) value;
+        Marshal.Copy(data64, 0, value_ptr, 1);
+        write_memory(mpact_id, (UInt64) address + base_address, value_ptr, 8);
+    }
+
+    public ulong ReadQuadWord(long address) {
+        var data64 = new Int64[1];
+        read_memory(mpact_id, (UInt64) address + base_address, value_ptr, 8);
+        Marshal.Copy(value_ptr, data64, 0, 1);
+        return (ulong) data64[0];
+    }
+
+    public byte[] ReadBytes(long offset, int count, ICPU context = null) {
+        var bytes = new byte[count];
+        var byte_array_ptr = Marshal.AllocHGlobal(count);
+        read_memory(mpact_id, (UInt64) offset + base_address, byte_array_ptr,
+                    count);
+        Marshal.Copy(value_ptr, bytes, 0, count);
+        Marshal.FreeHGlobal(byte_array_ptr);
+        return bytes;
+    }
+
+    public void WriteBytes(long offset, byte[] array, int startingIndex,
+                           int count, ICPU context = null) {
+        var byte_array_ptr = Marshal.AllocHGlobal(count);
+        Marshal.Copy(array, startingIndex, byte_array_ptr, count);
+        write_memory(mpact_id, (UInt64) offset + base_address, byte_array_ptr,
+		     count);
+        Marshal.FreeHGlobal(byte_array_ptr);
+    }
+
+    // End of IMpactPeripheral methods.
+
+    private int cli_port = -1;
+    private bool wait_for_cli = false;
+    private UInt64 base_address = 0;
+    private UInt64 size = 0;
+    private List<GDBFeatureDescriptor>
+	        gdbFeatures = new List<GDBFeatureDescriptor>();
+    private UInt64 memoryBase;
+    private UInt64 memorySize;
+    private UInt64 revocationMemBase;
+    private Dictionary<Int32, CPURegister>
+	        registerMap = new Dictionary<Int32, CPURegister>();
+    private Dictionary<string, Int32>
+	        registerNamesMap = new Dictionary<string, Int32>();
+    private string executable_file = "";
+    private BinFileLoadInfo
+	        bin_file_info = new BinFileLoadInfo {file_name = "",
+			                             load_address = 0,
+					  	     entry_point = 0};
+    private string cpu_library_path = "";
+    private bool cpu_library_bound = false;
+    private NativeBinder binder;
+    private readonly object nativeLock;
+    private readonly Int32 maxStringLen = 32;
+
+    // Pointers used in marshaling data to/from the simulator library.
+    private IntPtr value_ptr {get; set;}
+    private IntPtr error_ptr {get; set;}
+    private IntPtr reg_info_ptr {get; set;}
+    private IntPtr string_ptr {get; set;}
+
+    // Declare some additional function signatures.
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+    public delegate Int32 ConnectWithSysbus(Int32 param0, Int32 param1,
+                                            FuncInt32UInt64IntPtrInt32 param2,
+                                            FuncInt32UInt64IntPtrInt32 param3);
+
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+    public delegate Int32 ConstructWithSysbus(Int32 param0,
+                                              FuncInt32UInt64IntPtrInt32 param1,
+                                              FuncInt32UInt64IntPtrInt32 param2);
+
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+    public delegate Int32 SetConfig(Int32 param0, string[] param1,
+		                    string[] param2, Int32 param3);
+
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+    public delegate Int32 SetIrqValue(Int32 param0, Int32 param1, bool param2);
+
+    // Int32 read_sysmem_delegate(UInt64 address, IntPtr buffer, Int32 size)
+    private FuncInt32UInt64IntPtrInt32 read_sysmem_delegate;
+    // Int32 write_sysmem_delegate(UInt64 address, IntPtr buffer, Int32 size)
+    private FuncInt32UInt64IntPtrInt32 write_sysmem_delegate;
+
+    // Functions that are imported from the mpact sim library.
 #pragma warning disable 649
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32FuncInt32UInt64IntPtrInt32FuncInt32UInt64IntPtrInt32 construct_with_sysbus; // (Int32 id, Int32 callback(Uint64, IntPtr, Int32), Int32 callback(Uint64, IntPtr, Int32));
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32Int32FuncInt32UInt64IntPtrInt32FuncInt32UInt64IntPtrInt32 connect_with_sysbus; // (Int32 id, Int32 callback(Uint64, IntPtr, Int32), Int32 callback(Uint64, IntPtr, Int32));
-		[Import(UseExceptionWrapper = false)]
-		private ActionInt32 destruct;  // (Int32 id);
-		[Import(UseExceptionWrapper = false)]
-		private ActionInt32 reset;  // (Int32 id);
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32 get_reg_info_size; // (Int32 id)
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32Int32IntPtrIntPtr get_reg_info; // (Int32 id, IntPtr *name, IntPtr *struct);
-		[Import(UseExceptionWrapper = false)]
-		private FuncUInt64Int32StringIntPtr load_executable;  // (Int32 id, String file_name);
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32StringUInt64 load_image; // (Int32 id, String file_name, UInt64 address);
-		[Import(UseExceptionWrapper = false)]
-        	private FuncUInt64Int32UInt64IntPtr step;  // (Int32 id, UInt64 step, IntPtr *error);
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32Int32IntPtr read_register;  // (Int32 id, Int32 reg_id, IntPtr *value);
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32Int32UInt64 write_register;  // (Int32 id, Int32 reg_id, UInt64 value);
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32UInt64IntPtrInt32 read_memory; // (Int32 id, UInt64 address, IntPtr buffer, Int32 size);
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32UInt64IntPtrInt32 write_memory; // (Int32 id, UInt64 address, IntPtr buffer, Int32 size);
-		// Set config.
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32StringArrStringArrInt32 set_config; // Int32 set_config(Int32 id, string[] names string[] values, Int32 size);
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32Int32Bool set_irq_value; // Int32 set_irq_value(Int32 id, Int32 irq_no, bool value);
+    [Import(UseExceptionWrapper = false)]
+    // Int32 construct_with_sysbus(Int32 id,
+    //                             Int32 read_callback(UInt64, IntPtr, Int32),
+    //                             Int32 write_callback(UInt64, IntPtr, Int32));
+    private ConstructWithSysbus construct_with_sysbus;
+
+    [Import(UseExceptionWrapper = false)]
+    // Int32 connect_with_sybsus(Int32 id,
+    //                           Int32 read_callback(UInt64, IntPtr, Int32),
+    //                           Int32 write_callback(UInt64, IntPtr, Int32));
+    private ConnectWithSysbus connect_with_sysbus;
+
+    [Import(UseExceptionWrapper = false)]
+    // void destruct(Int32 id);
+    private ActionInt32 destruct;
+
+    [Import(UseExceptionWrapper = false)]
+    // void reset(Int32 id);
+    private ActionInt32 reset;
+
+    [Import(UseExceptionWrapper = false)]
+    // Int32 get_reg_info_size(Int32 id)
+    private FuncInt32Int32 get_reg_info_size;
+
+    [Import(UseExceptionWrapper = false)]
+    // Int32 get_reg_info(Int32 id, IntPtr *name, IntPtr *struct);
+    private FuncInt32Int32Int32IntPtrIntPtr get_reg_info;
+
+    [Import(UseExceptionWrapper = false)]
+    // UInt64 load_executable(Int32 id, String file_name);
+    private FuncUInt64Int32StringIntPtr load_executable;
+
+    [Import(UseExceptionWrapper = false)]
+    // Int32 load_image(Int32 id, String file_name, UInt64 address);
+    private FuncInt32Int32StringUInt64 load_image;
+
+    [Import(UseExceptionWrapper = false)]
+    // UInt64 step(Int32 id, UInt64 step, IntPtr *error);
+    private FuncUInt64Int32UInt64IntPtr step;
+
+    [Import(UseExceptionWrapper = false)]
+    // Int32 read_register(Int32 id, Int32 reg_id, IntPtr *value);
+    private FuncInt32Int32Int32IntPtr read_register;
+
+    [Import(UseExceptionWrapper = false)]
+    // Int32 write_register(Int32 id, Int32 reg_id, UInt64 value);
+    private FuncInt32Int32Int32UInt64 write_register;
+
+    [Import(UseExceptionWrapper = false)]
+    // Int32 read_memory(Int32 id, UInt64 address, IntPtr buffer, Int32 size);
+    private FuncInt32Int32UInt64IntPtrInt32 read_memory;
+
+    [Import(UseExceptionWrapper = false)]
+    // Int32 write_memory(Int32 id, UInt64 address, IntPtr buffer, Int32 size);
+    private FuncInt32Int32UInt64IntPtrInt32 write_memory;
+
+    [Import(UseExceptionWrapper = false)]
+    // Int32 set_config(Int32 id, string[] names string[] values, Int32 size);
+    private SetConfig set_config;
+
+    [Import(UseExceptionWrapper = false)]
+    // Int32 set_irq_value(Int32 id, Int32 irq_no, bool value);
+    private SetIrqValue set_irq_value;
 
 #pragma warning restore 649
 
-		private Int32 mpact_id {get; set;}
-		private ulong instructionsExecutedThisRound {get; set;}
-		private ulong totalExecutedInstructions {get; set;}
-		private const int PC_ID = 0x07b1;
+    private Int32 mpact_id {get; set;}
+    private ulong instructionsExecutedThisRound {get; set;}
+    private ulong totalExecutedInstructions {get; set;}
+    private const int PC_ID = 0x07b1;
+}  // class MpactCheriotCPU
+
+
+// Peripheral interface class.
+public class MpactCheriotPeripheral : IKnownSize, IBytePeripheral,
+	                              IWordPeripheral, IDoubleWordPeripheral,
+				      IQuadWordPeripheral,
+				      IMultibyteWritePeripheral, IDisposable {
+
+    public MpactCheriotPeripheral(IMachine machine, long baseAddress,
+		                  long size, IMpactPeripheral mpactCpu) {
+        if (size == 0) {
+	    throw new ConstructionException("Memory size cannot be 0");
 	}
-}
+        this.machine = machine;
+        this.size = size;
+        this.base_address = baseAddress;
+        this.mpact_cpu = mpactCpu;
+    }
+
+    public void Reset() {}
+
+    public void Dispose() {}
+
+    // All memory accesses are forwarded to the mpactCpu with the base_address
+    // added to the address field.
+    public void WriteByte(long address, byte value) {
+        mpact_cpu.WriteByte(address + base_address, value);
+    }
+
+    public byte ReadByte(long address) {
+        return mpact_cpu.ReadByte(address + base_address);
+    }
+
+    public void WriteWord(long address, ushort value) {
+        mpact_cpu.WriteWord(address + base_address, value);
+    }
+
+    public ushort ReadWord(long address) {
+        return mpact_cpu.ReadWord(address + base_address);
+    }
+
+    public void WriteDoubleWord(long address, uint value) {
+        mpact_cpu.WriteDoubleWord(address + base_address, value);
+    }
+
+    public uint ReadDoubleWord(long address) {
+        return mpact_cpu.ReadDoubleWord(address + base_address);
+    }
+
+    public void WriteQuadWord(long address, ulong value) {
+        mpact_cpu.WriteQuadWord(address + base_address, value);
+    }
+
+    public ulong ReadQuadWord(long address) {
+        return mpact_cpu.ReadQuadWord(address + base_address);
+    }
+
+    public byte[] ReadBytes(long offset, int count, ICPU context = null) {
+        return mpact_cpu.ReadBytes(offset + base_address, count, context);
+    }
+
+    public void WriteBytes(long offset, byte[] array, int startingIndex,
+		           int count, ICPU context = null) {
+        mpact_cpu.WriteBytes(offset + base_address, array, startingIndex,
+			     count, context);
+    }
+
+    public long Size { get { return size;} }
+    private IMpactPeripheral mpact_cpu;
+    private long size;
+    private long base_address = 0;
+    private IMachine machine;
+
+}  // class MpactCheriotPeripheral
+
+}  // namespace Antmicro.Renode.Peripherals.MpactCPU
 
diff --git a/shodan_infrastructure/MpactCheriotPeripheral.cs b/shodan_infrastructure/MpactCheriotPeripheral.cs
deleted file mode 100644
index e885bfa..0000000
--- a/shodan_infrastructure/MpactCheriotPeripheral.cs
+++ /dev/null
@@ -1,180 +0,0 @@
-using System;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Collections.Generic;
-using System.Collections.Concurrent;
-using Antmicro.Renode.Core;
-using Antmicro.Renode.Debugging;
-using Antmicro.Renode.Exceptions;
-using Antmicro.Renode.Hooks;
-using Antmicro.Renode.Logging;
-using Antmicro.Renode.Peripherals;
-using Antmicro.Renode.Peripherals.Bus;
-using Antmicro.Renode.Peripherals.CPU;
-using Antmicro.Renode.Peripherals.Timers;
-using Antmicro.Renode.Peripherals.CPU.Disassembler;
-using Antmicro.Renode.Peripherals.CPU.Registers;
-using Antmicro.Renode.Utilities;
-using Antmicro.Renode.Time;
-using Antmicro.Renode.Utilities.Binding;
-
-namespace Antmicro.Renode.Peripherals.MpactPeripheral {
-
-				[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-				public delegate Int32 FuncInt32Int32Int32FuncInt32UInt64IntPtrInt32FuncInt32UInt64IntPtrInt32(Int32 param0, Int32 param1,
-			FuncInt32UInt64IntPtrInt32 param2, FuncInt32UInt64IntPtrInt32 param3);
-
-	public class MpactCheriotPeripheral : IKnownSize, IBytePeripheral, IWordPeripheral, IDoubleWordPeripheral, IQuadWordPeripheral, IMultibyteWritePeripheral, IDisposable {
-
-		public MpactCheriotPeripheral(IMachine machine, long size, int id) {
-			if (size == 0) throw new ConstructionException("Memory size cannot be 0");
-			this.machine = machine;
-			this.size = size;
-			this.id = id;
-			cpuLibraryRegistered = false;
-			error_ptr = Marshal.AllocHGlobal(4);
-			value_ptr = Marshal.AllocHGlobal(8);
-			string_ptr = Marshal.AllocHGlobal(maxStringLen);
-		}
-
-		public string CpuLibraryPath {
-			get {
-				return cpuLibraryPath;
-			}
-			set {
-				if (!String.IsNullOrWhiteSpace(value)) {
-					if (cpuLibraryRegistered) {
-						this.WarningLog("cpu library already registerd and " +
-														"should not be updated again.");
-						return;
-					}
-					cpuLibraryPath = value;
-					try {
-						binder = new NativeBinder(this, cpuLibraryPath);
-					} catch (System.Exception e) {
-						LogAndThrowRE("Failed to load CPU library: " + e.Message);
-					}
-					cpuLibraryRegistered = true;
-				} else {
-					return;
-				}
-			}
-		}
-
-		public void Start() {
-			if (!cpuLibraryRegistered) {
-				LogAndThrowRE("Failed to register cpu library");
-				return;
-			}
-			this.Log(LogLevel.Noisy, "Start simulator with id {0}", id);
-			mpact_id = connect_with_sysbus(id, maxStringLen, null, null);
-			if (mpact_id < 0) {
-				LogAndThrowRE("Failed to create simulator instance");
-				return;
-			}
-		}
-
-		public void Reset() {}
-		public void Dispose() {}
-
-		public void WriteByte(long address, byte value) {
-			var data8 = new byte[1];
-			data8[0] = (byte) value;
-			Marshal.Copy(data8, 0, value_ptr, 1);
-			write_memory(mpact_id, (UInt64) address, value_ptr, 1);
-		}
-
-		public byte ReadByte(long address) {
-			var data8 = new byte[1];
-			read_memory(mpact_id, (UInt64) address, value_ptr, 1);
-			Marshal.Copy(value_ptr, data8, 0, 1);
-			return (byte) data8[0];
-		}
-
-		public void WriteWord(long address, ushort value) {
-			var data16 = new Int16[1];
-			data16[0] = (Int16) value;
-			Marshal.Copy(data16, 0, value_ptr, 1);
-			write_memory(mpact_id, (UInt64) address, value_ptr, 2);
-		}
-
-		public ushort ReadWord(long address) {
-			var data16 = new Int16[1];
-			read_memory(mpact_id, (UInt64) address, value_ptr, 2);
-			Marshal.Copy(value_ptr, data16, 0, 1);
-			return (ushort) data16[0];
-		}
-
-		public void WriteDoubleWord(long address, uint value) {
-			var data32 = new Int32[1];
-			data32[0] = (Int32) value;
-			Marshal.Copy(data32, 0, value_ptr, 1);
-			write_memory(mpact_id, (UInt64) address, value_ptr, 4);
-		}
-
-		public uint ReadDoubleWord(long address) {
-			var data32 = new Int32[1];
-			read_memory(mpact_id, (UInt64) address, value_ptr, 4);
-			Marshal.Copy(value_ptr, data32, 0, 1);
-			return (uint) data32[0];
-		}
-
-		public void WriteQuadWord(long address, ulong value) {
-			var data64 = new Int64[1];
-			data64[0] = (Int64) value;
-			Marshal.Copy(data64, 0, value_ptr, 1);
-			write_memory(mpact_id, (UInt64) address, value_ptr, 8);
-		}
-
-		public ulong ReadQuadWord(long address) {
-			var data64 = new Int64[1];
-			read_memory(mpact_id, (UInt64) address, value_ptr, 8);
-			Marshal.Copy(value_ptr, data64, 0, 1);
-			return (ulong) data64[0];
-		}
-
-		public byte[] ReadBytes(long offset, int count, ICPU context = null) {
-			var bytes = new byte[count];
-			var byte_array_ptr = Marshal.AllocHGlobal(count);
-			read_memory(mpact_id, (UInt64) offset, byte_array_ptr, count);
-			Marshal.Copy(value_ptr, bytes, 0, count);
-			Marshal.FreeHGlobal(byte_array_ptr);
-			return bytes;
-		}
-
-		public void WriteBytes(long offset, byte[] array, int startingIndex, int count, ICPU context = null) {
-			var byte_array_ptr = Marshal.AllocHGlobal(count);
-			Marshal.Copy(array, startingIndex, byte_array_ptr, count);
-			write_memory(mpact_id, (UInt64) offset, byte_array_ptr, count);
-			Marshal.FreeHGlobal(byte_array_ptr);
-		}
-
-		public long Size { get { return size;} }
-		private Int32 mpact_id;
-		private Int32 id {get; set;}
-		private long size;
-		private NativeBinder binder;
-		private string cpuLibraryPath;
-		private bool cpuLibraryRegistered;
-		private IMachine machine;
-		private readonly Int32 maxStringLen = 32;
-		private IntPtr value_ptr {get; set;}
-		private IntPtr error_ptr {get; set;}
-		private IntPtr string_ptr {get; set;}
-
-		private void LogAndThrowRE(string info) {
-			this.Log(LogLevel.Error, info);
-			throw new RecoverableException(info);
-		}
-
-	#pragma warning disable 649
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32Int32FuncInt32UInt64IntPtrInt32FuncInt32UInt64IntPtrInt32 connect_with_sysbus; // (Int32 id, Int32 callback(Uint64, IntPtr, Int32), Int32 callback(Uint64, IntPtr, Int32));
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32UInt64IntPtrInt32 read_memory; // (Int32 id, UInt64 address, IntPtr buffer, Int32 size);
-		[Import(UseExceptionWrapper = false)]
-		private FuncInt32Int32UInt64IntPtrInt32 write_memory; // (Int32 id, UInt64 address, IntPtr buffer, Int32 size);
-	}
-
-}  // namespace Antmicro.Renode.Peripherals.MpactPeripheral