diff --git a/src/leon3_dsu.c b/src/leon3_dsu.c
index e449064bd70d0cddcd88cf2b6247fbccbf44909c..531dc6b22945fc683505e6bd0dd3c0c295403c4e 100644
--- a/src/leon3_dsu.c
+++ b/src/leon3_dsu.c
@@ -96,6 +96,9 @@ static uint32_t dsu_get_local_reg_addr(uint32_t cpu, uint32_t n, uint32_t cwp)
 }
 
 
+
+
+
 /**
  * @brief calculate address of input register %in for a window
  * @see GR712-UM v2.3 pp. 81
@@ -415,6 +418,133 @@ uint32_t dsu_get_reg_trap(uint32_t cpu)
 }
 
 
+
+/**
+ * @brief get input register of current window pointer
+ *
+ * @param cpu the cpu number
+ *
+ * @param buffer point to array where values will be written
+ */
+void dsu_get_input_reg(uint32_t cpu, uint32_t *buffer)
+{
+	uint32_t psr_reg = dsu_get_reg_psr(cpu);
+	uint32_t cwp = psr_reg & 0x1F;
+
+	ioread32(DSU_REG_IN(cpu, cwp), buffer, 8);
+}
+
+
+/**
+ * @brief get local register of current window pointer
+ *
+ * @param cpu the cpu number
+ *
+ * @param buffer pointer to array where values will be written
+ */
+void dsu_get_local_reg(uint32_t cpu, uint32_t *buffer)
+{
+	uint32_t psr_reg = dsu_get_reg_psr(cpu);
+	uint32_t cwp = psr_reg & 0x1F;
+
+	ioread32(DSU_REG_LOCAL(cpu, cwp), buffer, 8);
+}
+
+/**
+ * @brief get output register of current window pointer
+ *
+ * @param cpu the cpu number
+ *
+ * @param buffer point to array where values will be written
+ */
+void dsu_get_output_reg(uint32_t cpu, uint32_t *buffer)
+{
+	uint32_t psr_reg = dsu_get_reg_psr(cpu);
+	uint32_t cwp = psr_reg & 0x1F;
+
+	ioread32(DSU_REG_OUT(cpu, cwp), buffer, 8);
+}
+
+/**
+ * @brief get gloabl register
+ *
+ * @param cpu the cpu number
+ *
+ * @param buffer point to array where values will be written
+ */
+void dsu_get_global_reg(uint32_t cpu, uint32_t *buffer)
+{
+	ioread32(DSU_REG_GLOBAL(cpu), buffer, 8);
+}
+
+void dsu_get_local_reg_window(uint32_t cpu, uint32_t window, uint32_t *buffer)
+{
+	ioread32(DSU_REG_LOCAL(cpu, window), buffer, 8);
+}
+
+
+void dsu_get_input_reg_window(uint32_t cpu, uint32_t window, uint32_t *buffer)
+{
+	ioread32(DSU_REG_IN(cpu, window), buffer, 8);
+}
+
+
+void dsu_get_output_reg_window(uint32_t cpu, uint32_t window, uint32_t *buffer)
+{
+	ioread32(DSU_REG_OUT(cpu, window), buffer, 8);
+}
+
+
+uint32_t dsu_get_local_reg_single(uint32_t cpu, uint32_t cwp, uint32_t reg_num)
+{
+	return ioread32(dsu_get_local_reg_addr(cpu, reg_num, cwp));
+}
+
+uint32_t dsu_get_input_reg_single(uint32_t cpu, uint32_t cwp, uint32_t reg_num)
+{
+	return ioread32(dsu_get_input_reg_addr(cpu, reg_num, cwp));
+}
+
+uint32_t dsu_get_output_reg_single(uint32_t cpu, uint32_t cwp, uint32_t reg_num)
+{
+	return ioread32(dsu_get_output_reg_addr(cpu, reg_num, cwp));
+}
+
+uint32_t dsu_get_global_reg_single(uint32_t cpu, uint32_t reg_num)
+{
+	return ioread32(dsu_get_global_reg_addr(cpu, reg_num));
+}
+
+
+union float_value dsu_get_float_reg(uint32_t cpu, uint32_t reg_num)
+{
+	union float_value val = {0};
+
+	if (reg_num > 31)
+		return val;
+	
+	val.u = ioread32(DSU_BASE(cpu) + DSU_FPU_REG + reg_num * 4);
+	return val;
+}
+
+
+union double_value dsu_get_double_reg(uint32_t cpu, uint32_t reg_num)
+{
+	uint32_t address = DSU_BASE(cpu) + DSU_FPU_REG + 32 * 4 + reg_num * 8;
+	union double_value val = {0};
+
+	if (reg_num > 12)
+		return val;
+
+	val.u = (uint64_t)ioread32(address);
+	val.u = val.u << 32;
+	val.u += (uint64_t)ioread32(address + 4);
+	
+	return val;
+}
+
+
+
 /**
  * @brief check if cpu is in debug mode
  *
@@ -921,6 +1051,20 @@ void dsu_set_reg_fp(uint32_t cpu, uint32_t cwp, uint32_t val)
 }
 
 
+/**
+ * @brief  get frame pointer register (%i6) in a window of a cpu
+ *
+ * @param cpu the cpu number
+ * @param cwp the window number
+ */   
+uint32_t dsu_get_reg_fp(uint32_t cpu, uint32_t cwp)
+{
+	uint32_t reg = dsu_get_input_reg_addr(cpu, 6, cwp);
+
+	return ioread32(reg);
+}
+
+
 
 /**
  * @brief get the last line_count lines from the instruction trace buffer
@@ -980,5 +1124,59 @@ void dsu_get_instr_trace_buffer(uint32_t cpu, struct instr_trace_buffer_line *bu
 		}
 	}
 
-	free(data);	
+	free(data);
+}
+
+
+void dsu_set_local_reg(uint32_t cpu, uint32_t cwp, uint32_t reg_num, uint32_t value)
+{
+	uint32_t address = dsu_get_local_reg_addr(cpu, reg_num, cwp);
+
+	iowrite32(address, value);
+}
+
+
+void dsu_set_input_reg(uint32_t cpu, uint32_t cwp, uint32_t reg_num, uint32_t value)
+{
+	uint32_t address = dsu_get_input_reg_addr(cpu, reg_num, cwp);
+
+	iowrite32(address, value);
+}
+
+
+void dsu_set_output_reg(uint32_t cpu, uint32_t cwp, uint32_t reg_num, uint32_t value)
+{
+	uint32_t address = dsu_get_output_reg_addr(cpu, reg_num, cwp);
+
+	iowrite32(address, value);
+}
+
+
+void dsu_set_global_reg(uint32_t cpu, uint32_t reg_num, uint32_t value)
+{
+	uint32_t address = dsu_get_global_reg_addr(cpu, reg_num);
+
+	iowrite32(address, value);
+}
+
+
+void dsu_set_float_reg(uint32_t cpu, uint32_t reg_num, union float_value value)
+{
+	uint32_t address = DSU_BASE(cpu) + DSU_FPU_REG + reg_num * 4;
+	if (reg_num > 31)
+		return;
+
+	iowrite32(address, value.u);	
+}
+
+
+void dsu_set_double_reg(uint32_t cpu, uint32_t reg_num, union double_value value)
+{
+	uint32_t address = DSU_BASE(cpu) + DSU_FPU_REG + 32 * 4 + reg_num * 8;
+
+	if (reg_num > 12)
+		return;
+
+	iowrite32(address, (uint32_t)(value.u >> 32));
+	iowrite32(address + 4, (uint32_t)(value.u & 0xFFFFFFFF));
 }
diff --git a/src/leon3_dsu.h b/src/leon3_dsu.h
index 680e8eba2d777ac21ffb4b5b4159a6e9adab94db..cded64baa8bdb70729c001a804c0fbd76094cfaa 100644
--- a/src/leon3_dsu.h
+++ b/src/leon3_dsu.h
@@ -91,6 +91,8 @@
 #define DSU_REG_TRAP	0x400020
 
 
+
+
 // TODO: this needs to be refactored
 #define DSU_CTRL ADDRESSES[get_connected_cpu_type()][DSU]
 #define DSU_OFFSET_CPU(x)	((x & 0x07) << 24)
@@ -98,6 +100,12 @@
 
 //#define DSU_BASE(x)		(ADDRESSES[get_connected_cpu_type()][DSU] + DSU_OFFSET_CPU(x))
 
+#define DSU_REG_OUT(cpu, cwp) DSU_BASE(cpu) + DSU_IU_REG + ((cwp * 64 + 32) % (NWINDOWS * 64))
+#define DSU_REG_LOCAL(cpu, cwp) DSU_BASE(cpu) + DSU_IU_REG + ((cwp * 64 + 64) % (NWINDOWS * 64))
+#define DSU_REG_IN(cpu, cwp) DSU_BASE(cpu) + DSU_IU_REG + ((cwp * 64 + 96) % (NWINDOWS * 64))
+#define DSU_REG_GLOBAL(cpu) DSU_BASE(cpu) + DSU_IU_REG + (NWINDOWS * 64)
+
+
 
 /**
  * @see GR712-UM v2.3 p. 82
@@ -232,6 +240,18 @@ struct ahb_trace_buffer_line {
 }__attribute__((packed));
 
 
+
+union float_value {
+	uint32_t u;
+	float f;
+};
+
+union double_value {
+	uint64_t u;
+	double d;
+};
+
+
 /**
  * maps the AHB trace buffer, must be pointed to DSU_AHB_TRCE_BUF_START
  */
@@ -261,7 +281,27 @@ uint32_t dsu_get_global_reg(uint32_t cpu, uint32_t n);
 uint32_t dsu_get_dsu_ctrl(uint32_t cpu);
 uint32_t dsu_get_reg_psr(uint32_t cpu);
 uint32_t dsu_get_reg_tbr(uint32_t cpu);
+uint32_t dsu_get_reg_y(uint32_t cpu);
 uint32_t dsu_get_reg_trap(uint32_t cpu);
+
+void dsu_get_local_reg(uint32_t cpu, uint32_t *buffer);
+void dsu_get_input_reg(uint32_t cpu, uint32_t *buffer);
+void dsu_get_output_reg(uint32_t cpu, uint32_t *buffer);
+void dsu_get_global_reg(uint32_t cpu, uint32_t *buffer);
+
+void dsu_get_local_reg_window(uint32_t cpu, uint32_t cwp, uint32_t *buffer);
+void dsu_get_input_reg_window(uint32_t cpu, uint32_t cwp, uint32_t *buffer);
+void dsu_get_output_reg_window(uint32_t cpu, uint32_t cwp, uint32_t *buffer);
+
+uint32_t dsu_get_local_reg_single(uint32_t cpu, uint32_t cwp, uint32_t reg_num);
+uint32_t dsu_get_input_reg_single(uint32_t cpu, uint32_t cwp, uint32_t reg_num);
+uint32_t dsu_get_output_reg_single(uint32_t cpu, uint32_t cwp, uint32_t reg_num);
+uint32_t dsu_get_global_reg_single(uint32_t cpue, uint32_t cwp, uint32_t reg_num);
+
+union float_value dsu_get_float_reg(uint32_t cpu, uint32_t reg_num);
+union double_value dsu_get_double_reg(uint32_t cpu, uint32_t reg_num);
+
+
 void dsu_set_reg_psr(uint32_t cpu, uint32_t val);
 
 /* line_start is relative with 0 being the last executed line */
@@ -270,6 +310,7 @@ void dsu_get_instr_trace_buffer(uint32_t cpu, struct instr_trace_buffer_line *bu
 uint32_t dsu_get_reg_wim(uint32_t cpu);
 uint32_t dsu_get_reg_pc(uint32_t cpu);
 uint32_t dsu_get_reg_sp(uint32_t cpu, uint32_t cwp);
+uint32_t dsu_get_reg_fp(uint32_t cpu, uint32_t cwp);
 uint32_t dsu_get_reg_fsr(uint32_t cpu);
 
 
@@ -294,4 +335,14 @@ void dsu_set_reg_fsr(uint32_t cpu, uint32_t val);
 void dsu_set_reg_sp(uint32_t cpu, uint32_t cwp, uint32_t val);
 void dsu_set_reg_fp(uint32_t cpu, uint32_t cwp, uint32_t val);
 
+void dsu_set_local_reg(uint32_t cpu, uint32_t cwp, uint32_t reg_num, uint32_t value);
+void dsu_set_input_reg(uint32_t cpu, uint32_t cwp, uint32_t reg_num, uint32_t value);
+void dsu_set_output_reg(uint32_t cpu, uint32_t cwp, uint32_t reg_num, uint32_t value);
+void dsu_set_global_reg(uint32_t cpu, uint32_t reg_num, uint32_t value);
+
+void dsu_set_float_reg(uint32_t cpu, uint32_t reg_num, union float_value value);
+void dsu_set_double_reg(uint32_t cpu, uint32_t reg_num, union double_value value);
+
+
+
 #endif /* LEON3_DSU_H */
diff --git a/src/uviemon_cli.cpp b/src/uviemon_cli.cpp
index 8594fa5c3bd8181b822f0bfeff89b933c4e6886c..b43c860a629a3bd1a64ffb4dcb51ca13621533ed 100644
--- a/src/uviemon_cli.cpp
+++ b/src/uviemon_cli.cpp
@@ -12,6 +12,7 @@
 #include "uviemon_cli.hpp"
 
 #include "address_map.h"
+#include "uviemon_reg.h"
 
 #include <iostream> // cout & cerr
 #include <iomanip>	// Used for setfill and setw (cout formatting)
@@ -20,6 +21,28 @@
 
 #include <stdlib.h>
 
+#ifndef PACKAGE
+  #define PACKAGE
+  #ifndef PACKAGE_VERSION
+    #define PACKAGE_VERSION
+    #include <bfd.h>
+    #undef PACKAGE_VERSION
+  #else
+    #include <bfd.h>
+  #endif
+  #undef PACKAGE
+#else
+  #ifndef PACKAGE_VERSION
+    #define PACKAGE_VERSION
+    #include <bfd.h>
+    #undef PACKAGE_VERSION
+  #else 
+    #include <bfd.h>
+  #endif
+#endif
+
+#include <dis-asm.h>
+
 #include "leon3_dsu.h"
 
 
@@ -27,7 +50,7 @@ using namespace std;
 
 //static int command_count;
 
-#define COMMAND_COUNT 14
+#define COMMAND_COUNT 16
 
 static command commands[COMMAND_COUNT] =  {
 	{ "help", &help },
@@ -45,6 +68,9 @@ static command commands[COMMAND_COUNT] =  {
 	{ "bdump", &bdump },
 
 	{ "inst", &inst },
+	{ "reg", &reg },
+
+	{ "wash", &washc },
 
 	{ "load", &load },
 	{ "verify", &verify },
@@ -56,8 +82,14 @@ static command commands[COMMAND_COUNT] =  {
 static DWORD parse_parameter(char *param);
 
 static void parse_opcode(char *buffer, uint32_t opcode, uint32_t address);
+static void print_register_error_msg(const char * const reg);
+static void print_value_error_msg(const char * const value);
+//static int parse_register_number(const char * const reg, uint32_t * const reg_num, uint32_t highest_register);
+static const char * const get_tt_error_desc(uint32_t error_code);
+
+#define TT_ERROR_COUNT 32
 
-std::unordered_map<int, std::string> tt_errors = {
+struct tt_error tt_errors[] = {
 	{0x0, "[reset]: Power-on reset"},
 	{0x2b, "[write_error]: write buffer error"},
 	{0x01, "[instruction_access_error]: Error during instruction fetch"},
@@ -90,7 +122,7 @@ std::unordered_map<int, std::string> tt_errors = {
 	{0x1E, "[interrupt_level_14]: Asynchronous interrupt 14"},
 	{0x1F, "[interrupt_level_15]: Asynchronous interrupt 15"},
 	{0x80, "[trap_instruction]: OK"}
-	// Anything larger than 0x80 will be some other Software trap instruction (TA)
+	/* Anything larger than 0x80 will be some other Software trap instruction (TA) */
 };
 
 
@@ -259,7 +291,9 @@ void help(const char *command, int param_count, char params[MAX_PARAMETERS][MAX_
 
 	printf("  bdump:\t Read <length#2> BYTEs of data from memory starting at an <address#1>, saving the data to a <filePath#1>\n\n");
 
-	printf("  isnt:\t Prints the last <instruction_cnt#1> instruction to stdout\n\n");
+	printf("  inst:\t Prints the last <instruction_cnt#1> instruction to stdout\n\n");
+
+	printf("  reg:\t Prints or sets registers\n\n");
 
 	printf("  load: \t Write a file with <filePath#1> to the device memory\n");
 	printf("  verify: \t Verify a file written to the device memory with <filePath#1>\n");
@@ -284,26 +318,33 @@ void run(const char *command, int param_count, char params[MAX_PARAMETERS][MAX_P
 
 	if (tt < 0x80) // Hardware traps
 	{
-		cerr << " => Error: Hardware trap!" << endl;
-		cerr << endl;
-		cerr << "tt 0x" << hex << (unsigned int)tt << ", " << tt_errors[tt] << endl;
+		printf(" => Error: Hardware trap!\n\n");
+		printf("tt 0x%02x, %s\n", (uint8_t)tt, get_tt_error_desc(tt));
 	}
 	else if (tt == 0x80) // Successfull trap
 	{
-		cout << " => OK!" << endl;
+		printf(" => OK!\n");	
 	}
 	else if (tt > 0x80 && tt <= 0xFF) // Software trap
 	{
-		cerr << " => Error: Software trap!" << endl;
-		cerr << endl;
-		cerr << "tt 0x" << hex << (unsigned int)tt << ", [trap_instruction]: Software trap instruction (TA)" << endl;
+		printf(" => Error: Software trap!\n\n");
+		printf("tt 0x%02x, [trap_instruction]: Software trap instruction (TA)\n", (uint8_t)tt);
 	}
 	else // Something else that's not documented
 	{
-		cerr << " => Error!" << endl;
-		cerr << endl;
-		cerr << "tt 0x" << hex << (unsigned int)tt << ", [unknown]: unknown trap!" << endl;
+		printf(" => Error!\n\n");
+		printf("tt 0x%02x, [unknown]: unknown trap!", (uint8_t)tt);
+	}
+}
+
+static const char * const get_tt_error_desc(uint32_t error_code)
+{
+	for (int i = 0; i < TT_ERROR_COUNT; i++) {
+		if (tt_errors[i].error_code == error_code)
+			return tt_errors[i].error_desc;
 	}
+
+	return "Error code not found";
 }
 
 void reset(const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH])
@@ -355,7 +396,7 @@ void verify(const char *command, int param_count, char params[MAX_PARAMETERS][MA
 	verify(params[0]);
 }
 
-void wash(const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH])
+void washc(const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH])
 {
 	WORD size = 16;
 	// was 0x40000000
@@ -410,11 +451,11 @@ void memx(const char *command, int param_count, char params[MAX_PARAMETERS][MAX_
 	}
 
 	if (strcmp(command, "memh") == 0) {
-		param_count == 1 ? memh(param_1) : memh(param_1, param_2);
+		param_count == 1 ? memh(param_1, 32) : memh(param_1, param_2);
 	} else if(strcmp(command, "memb") == 0) {
-		param_count == 1 ? memb(param_1) : memb(param_1, param_2);
+		param_count == 1 ? memb(param_1, 64) : memb(param_1, param_2);
 	} else if (strcmp(command, "mem") == 0) {
-		param_count == 1 ? mem(param_1) : mem(param_1, param_2);
+		param_count == 1 ? mem(param_1, 16) : mem(param_1, param_2);
 	}
 }
 
@@ -427,13 +468,14 @@ void wmemx(const char *command, int param_count, char params[MAX_PARAMETERS][MAX
 		return;
 	}
 
-	if ( (param_1 = strtol(params[0], NULL, 10)) == 0) {
-		printf("Parameter 1 must be a positive integer");
+	if ( (param_1 = parse_parameter(params[0])) == 0) {
+		printf("Parameter 1 must be a positive integer\n");
 		return;
 	}
 
-	if ( (param_2 = strtol(params[1], NULL, 10)) == 0) {
-		printf("Parameter 2 must be a positive integer");
+	param_2 = parse_parameter(params[1]);
+	if (errno != 0) {
+		printf("Parameter 2 a 32 bit int\n");
 		return;
 	}
 
@@ -450,6 +492,7 @@ void wmemx(const char *command, int param_count, char params[MAX_PARAMETERS][MAX
 void inst(const char* command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH])
 {
 	uint32_t instr_count = 11;
+	uint32_t cpu = 0;
 
 	if (param_count > 1) {
 		printf("Inst only needs 1 parameter: the number of lines");
@@ -467,7 +510,7 @@ void inst(const char* command, int param_count, char params[MAX_PARAMETERS][MAX_
 	struct instr_trace_buffer_line *buffer = (instr_trace_buffer_line*) malloc(sizeof(instr_trace_buffer_line) * instr_count * 2);
 
 	/* TODO: manage active cpu */
-	dsu_get_instr_trace_buffer(0, buffer, instr_count * 2, 0);
+	dsu_get_instr_trace_buffer(cpu, buffer, instr_count * 2, 0);
 
 
 	uint32_t i_cntr = 0;
@@ -487,7 +530,7 @@ void inst(const char* command, int param_count, char params[MAX_PARAMETERS][MAX_
 
 		if (i_cntr < instr_count) {
 			page++;
-			dsu_get_instr_trace_buffer(0, buffer, instr_count * 2, page * instr_count * 2);
+			dsu_get_instr_trace_buffer(cpu, buffer, instr_count * 2, page * instr_count * 2);
 		}
 	}
 
@@ -508,10 +551,10 @@ void inst(const char* command, int param_count, char params[MAX_PARAMETERS][MAX_
 				 * second is program counter with last two bits set to zero
 				 */
 				parse_opcode(operation, buffer[j].field[3], buffer[j].field[2] & 0xFFFFFFFC); 
-				printf("    %9u  %08x  %-30s  [",
+				printf("    %9u  %08x  ",
 					   buffer[j].field[0] & 0x3FFFFFFF,
-					   buffer[j].field[2] & 0xFFFFFFFC,
-					   operation);
+					   buffer[j].field[2] & 0xFFFFFFFC);
+				printf(" [");
 
 
 				/* Check for instruction trap bit 2 is set */
@@ -537,9 +580,166 @@ void inst(const char* command, int param_count, char params[MAX_PARAMETERS][MAX_
 	free(buffer);
 }
 
+void reg (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH])
+{
+	uint32_t cpu = 0;
+	uint32_t input, reg_value;
+	int base;
+	char *input_str;
+
+	union float_value reg_value_float, float_input;
+	union double_value reg_value_double, double_input;
+
+	struct register_desc desc;
+	struct register_func *func_handler;
+
+	if (param_count == 0) {
+		uint32_t cwp = dsu_get_reg_psr(cpu) & 0x1F;
+		register_print_summary(cpu, cwp);
+
+	} else {
+		desc = parse_register(params[0], cpu);
+
+		/* Register could not be parsed */
+		if (strcmp(desc.name, "inv") == 0) {
+			print_register_error_msg(params[0]);
+			return;
+		}
+
+		/*  Print register summary for the requested window */
+		if (strcmp(desc.name, "w") == 0) {
+			register_print_summary(cpu, desc.window);
+			return;
+		}
+
+		/* Get function pointer for getting and setting requsted register */
+		func_handler = get_register_functions(desc);
+
+		if (strcmp(func_handler->name, "inv") == 0) {
+			print_register_error_msg(params[0]);
+			return;
+		}
+
+		/* Parse value from second parameter if available */
+		if (param_count == 2) {
+			input_str = params[1];
+			base = 10;
+			errno = 0;
+			
+			switch(desc.type) {
+			case standard_reg:
+				if (input_str[0] == '0' && input_str[1] == 'x') {
+					base = 16;
+					input_str = input_str + 2;
+				}
+
+				input = strtol(input_str, NULL, base);
+
+				if (errno != 0) {
+					print_value_error_msg(params[1]);
+					return;
+				}
+
+				((register_func_standard*)func_handler)->set_value(desc, input);
+				break;
+
+			case float_reg:
+				float_input.f = strtof(input_str, NULL);
+
+				if (errno != 0) {
+					print_value_error_msg(params[1]);
+					return;
+				}
+
+				((register_func_float*)func_handler)->set_value(desc, float_input);
+				break;
+
+			case double_reg:
+				double_input.d = strtod(input_str, NULL);
+
+				if (errno != 0) {
+					print_value_error_msg(params[1]);
+					return;
+				}
+
+				((register_func_double*)func_handler)->set_value(desc, double_input);
+				break;
+				
+			default:
+				break;
+			}
+		}
+
+		switch(desc.type) {
+		case standard_reg:
+			reg_value = ((register_func_standard*)func_handler)->get_value(desc);
+			printf("   %3s = %d (0x%08x)\n", params[0], reg_value, reg_value);
+			break;
+
+		case float_reg:
+			reg_value_float = ((register_func_float*)func_handler)->get_value(desc);
+			printf("   %3s = %f (0x%08x)\n", params[0], reg_value_float.f, reg_value_float.u);
+			break;
+
+		case double_reg:
+			reg_value_double = ((register_func_double*)func_handler)->get_value(desc);
+			printf("   %3s = %lf (0x%016lx)\n", params[0], reg_value_double.d, reg_value_double.u);
+			break;
+
+		case none:
+			print_register_error_msg(params[0]);
+			break;
+		}
+	}
+
+}
+
+static void print_register_error_msg(const char * const reg)
+{
+	printf("No such register %s\n", reg);
+}
+
+static void print_value_error_msg(const char * const value)
+{
+	printf("Could not parse value: %s\n", value);
+}
+
 
 static void parse_opcode(char *buffer, uint32_t opcode, uint32_t address)
 {
+	/* list supported arch */
+	/*const char **arch_list = bfd_arch_list();
+	const char **a;
+
+	for (a = arch_list; *a; a++) {
+		printf("\t%s\n", *a);
+	}
+
+	free(arch_list);
+
+	
+	static bool disassembler_initialized = false;
+	static disassembler_ftype disassembler_p;
+	static disassemble_info info;
+
+	if (!disassembler_initialized) {
+		disassembler_p = disassembler(bfd_arch_sparc, true, bfd_mach_sparc, NULL);
+
+		init_disassemble_info(&info, stdout, (fprintf_ftype)fprintf, (fprintf_styled_ftype)fprintf);
+		info.read_memory_func = buffer_read_memory;
+		info.buffer_vma = address;
+		info.arch = bfd_arch_sparc;
+		info.mach = bfd_mach_sparc_v8plus;
+		disassemble_init_for_target(&info);
+
+		disassembler_initialized = true;
+	}
+
+	info.buffer = (bfd_byte *)&opcode;
+	info.buffer_length = 1;
+	
+	disassembler_p(0, &info);*/
+	
 	struct opcode op;
 	op.opcode_raw = opcode;
 
diff --git a/src/uviemon_cli.hpp b/src/uviemon_cli.hpp
index 0e9931dbce65913dd006a5eacb99f7d156b1a18e..40ca86e9082929734f6b75d68a48a44a1beea5c5 100644
--- a/src/uviemon_cli.hpp
+++ b/src/uviemon_cli.hpp
@@ -30,12 +30,8 @@ typedef struct {
 	void (*function)(const char *, int, char [MAX_PARAMETERS][MAX_PARAM_LENGTH]);
 } command;
 
-typedef struct {
-	
-} command_parameter;
-
 
-extern std::unordered_map<int, std::string> tt_errors;
+//extern std::unordered_map<int, std::string> tt_errors;
 
 std::string _hexToString(DWORD *data, size_t size);
 std::string _hexToString(WORD *data, size_t size);
@@ -101,6 +97,13 @@ struct opcode {
 	};
 }__attribute__((packed));
 
+
+struct tt_error {
+	uint32_t error_code;
+	const char * const error_desc;
+};
+
+
 /* Command functions  */
 void help  (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]);
 void scan  (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]);
@@ -111,20 +114,22 @@ void reset (const char *command, int param_count, char params[MAX_PARAMETERS][MA
 void load  (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]);
 void verify(const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]);
 void bdump (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]);
-void wash  (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]);
+void washc (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]);
 void inst  (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]);
+void reg   (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]);
+
 
 void wmem(DWORD addr, DWORD data);
 void wmemh(DWORD addr, WORD data);
 void wmemb(DWORD addr, BYTE data);
 
-void mem(DWORD startAddr, DWORD length = 16);
-void memh(DWORD startAddr, DWORD length = 32);
-void memb(DWORD startAddr, DWORD length = 64);
+void mem(DWORD startAddr, DWORD length);
+void memh(DWORD startAddr, DWORD length);
+void memb(DWORD startAddr, DWORD length);
 
 void bdump(DWORD startAddr, DWORD length, std::string path);
 
-void wash(WORD size = 16, DWORD addr = 0x40000000, DWORD c = 0);
+void wash(WORD size, DWORD addr, DWORD c);
 void load(std::string path);
 void verify(std::string path); // Really slow because sequential reads are dead slow
 
diff --git a/src/uviemon_reg.c b/src/uviemon_reg.c
new file mode 100644
index 0000000000000000000000000000000000000000..fd625e5d5276ddfd41da54f61770f4bc842d38bb
--- /dev/null
+++ b/src/uviemon_reg.c
@@ -0,0 +1,488 @@
+#include "uviemon_reg.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static int parse_register_number_single(const char reg_num, uint32_t *dest);
+static int parse_register_number(const char * const reg, uint32_t * const reg_num, uint32_t highest_register);
+
+/* Special purpose registers */
+
+static uint32_t get_reg_psr(struct register_desc desc);
+static void set_reg_psr(struct register_desc desc, uint32_t value);
+
+static uint32_t get_reg_tbr(struct register_desc desc);
+static void set_reg_tbr(struct register_desc desc, uint32_t value);
+
+static uint32_t get_reg_wim(struct register_desc desc);
+static void set_reg_wim(struct register_desc desc, uint32_t value);
+
+static uint32_t get_reg_y(struct register_desc desc);
+static void set_reg_y(struct register_desc desc, uint32_t value);
+
+static uint32_t get_reg_pc(struct register_desc desc);
+static void set_reg_pc(struct register_desc desc, uint32_t value);
+
+static uint32_t get_reg_npc(struct register_desc desc);
+static void set_reg_npc(struct register_desc desc, uint32_t value);
+
+static uint32_t get_reg_fsr(struct register_desc desc);
+static void set_reg_fsr(struct register_desc desc, uint32_t value);
+
+static uint32_t get_reg_sp(struct register_desc desc);
+static void set_reg_sp(struct register_desc desc, uint32_t value);
+
+static uint32_t get_reg_fp(struct register_desc desc);
+static void set_reg_fp(struct register_desc desc, uint32_t value);
+
+/* Window registers */
+
+static uint32_t get_reg_global(struct register_desc desc);
+static void set_reg_global(struct register_desc desc, uint32_t value);
+
+static uint32_t get_reg_input(struct register_desc desc);
+static void set_reg_input(struct register_desc desc, uint32_t value);
+
+static uint32_t get_reg_output(struct register_desc desc);
+static void set_reg_output(struct register_desc desc, uint32_t value);
+
+static uint32_t get_reg_local(struct register_desc desc);
+static void set_reg_local(struct register_desc desc, uint32_t value);
+
+/* Floating point registers */
+static union float_value get_reg_float(struct register_desc desc);
+static void set_reg_float(struct register_desc desc, union float_value value);
+
+static union double_value get_reg_double(struct register_desc desc);
+static void set_reg_double(struct register_desc desc, union double_value value);
+
+
+static struct register_func_standard function_handler[] = {
+	{ "inv", none,     NULL,            NULL },
+	{ "psr", standard_reg, &get_reg_psr,    &set_reg_psr },
+	{ "tbr", standard_reg, &get_reg_tbr,    &set_reg_tbr },
+	{ "wim", standard_reg, &get_reg_wim,    &set_reg_wim },
+	{ "y",   standard_reg, &get_reg_y,      &set_reg_y },
+	{ "pc",  standard_reg, &get_reg_pc,     &set_reg_pc },
+	{ "npc", standard_reg, &get_reg_npc,    &set_reg_npc },
+	{ "fsr", standard_reg, &get_reg_fsr,    &set_reg_fsr },
+	{ "sp",  standard_reg, &get_reg_sp,     &set_reg_sp },
+	{ "fp",  standard_reg, &get_reg_fp,     &set_reg_fp },
+	{ "g",   standard_reg, &get_reg_global, &set_reg_global },
+	{ "i",   standard_reg, &get_reg_input,  &set_reg_input },
+	{ "o",   standard_reg, &get_reg_output, &set_reg_output },
+	{ "l",   standard_reg, &get_reg_local,  &set_reg_local }
+};
+
+static struct register_func_float function_handler_float = { "f", float_reg, &get_reg_float, &set_reg_float };
+static struct register_func_double function_handler_double = { "d", double_reg, &get_reg_double, &set_reg_double };
+
+
+
+
+struct register_desc parse_register(const char * const reg, uint32_t cpu)
+{
+	uint32_t param_length = strlen(reg);
+
+	/* start name is invalid in case parsing doesn't work */
+	struct register_desc desc { "inv", standard_reg, cpu, 0, dsu_get_reg_psr(cpu) & 0x1F  };
+
+	/* Special purpose registers */
+	if (strcmp(reg, "psr") == 0) {
+		strcpy(desc.name, "psr");
+		return desc;
+	}
+
+	if (strcmp(reg, "tbr") == 0) {
+		strcpy(desc.name, "tbr");
+		return desc;
+	}
+
+	if (strcmp(reg, "wim") == 0) {
+		strcpy(desc.name, "wim");
+		return desc;
+	}
+
+	if (strcmp(reg, "y") == 0) {
+		strcpy(desc.name, "y");
+		return desc;
+	}
+
+	if (strcmp(reg, "pc") == 0) {
+		strcpy(desc.name, "pc");
+		return desc;
+	}
+
+	if (strcmp(reg, "npc") == 0) {
+		strcpy(desc.name, "npc");
+		return desc;
+	}
+
+	if (strcmp(reg, "fsr") == 0) {
+		strcpy(desc.name, "fsr");
+		return desc;
+	}
+
+	if (strcmp(reg, "sp") == 0) {
+		strcpy(desc.name, "sp");
+		return desc;
+	}
+
+	if (strcmp(reg, "fp") == 0) {
+		strcpy(desc.name, "fp");
+		return desc;
+	}
+
+	/* length must be at least two from here on out */
+	if (param_length < 2)
+		return desc;
+
+	/* Window registers */
+	switch(reg[0]) {
+
+	case 'g':
+		if (param_length != 2)
+			return desc;
+
+		if (parse_register_number_single(reg[1], &desc.reg_num) == -1)
+			return desc;
+
+		strcpy(desc.name, "g");
+		break;
+		
+	case 'i':
+		if (param_length != 2)
+			return desc;
+
+		if (parse_register_number_single(reg[1], &desc.reg_num) == -1)
+			return desc;
+
+		strcpy(desc.name, "i");
+		break;
+		
+	case 'l':
+		if (param_length != 2)
+			return desc;
+
+		if (parse_register_number_single(reg[1], &desc.reg_num) == -1)
+			return desc;
+
+		strcpy(desc.name, "l");
+		break;
+		
+	case 'o':
+		if (param_length != 2)
+			return desc;
+
+		if (parse_register_number_single(reg[1], &desc.reg_num) == -1)
+			return desc;
+
+		strcpy(desc.name, "o");
+		break;
+		
+	case 'f':
+		if (param_length > 3)
+			return desc;
+
+		if (parse_register_number(reg + 1, &desc.reg_num, 31) == -1)
+			return desc;
+
+		desc.type = float_reg;
+		strcpy(desc.name, "f");
+		break;
+
+	case 'd':
+		if (param_length > 3)
+			return desc;
+
+		if (parse_register_number(reg + 1, &desc.reg_num, 12) == -1)
+			return desc;
+
+		desc.type = double_reg;
+		strcpy(desc.name, "d");
+		break;
+	
+	case 'w':
+		/* TODO: needs a bit more checks here */
+		if (parse_register_number_single(reg[1], &desc.window) == -1)
+			return desc;
+
+		if (param_length == 2) {
+			strcpy(desc.name, "w");
+		} else if (param_length == 4) {
+			if (parse_register_number_single(reg[3], &desc.reg_num) == -1)
+				return desc;
+
+			desc.name[0] = reg[2];
+			desc.name[1] = '\0';
+		}
+		
+		break;
+	}
+
+	return desc;
+}
+
+
+struct register_func *get_register_functions(const struct register_desc desc)
+{
+
+	switch(desc.type) {
+		
+
+	case standard_reg:
+		for (uint32_t i = 1; i < (sizeof(function_handler) / sizeof(function_handler[0])); i++) {
+			if (strcmp(desc.name, function_handler[i].name) == 0)
+				return (register_func*)&function_handler[i];
+		}
+
+		return (register_func*)&function_handler[0];
+
+		break;
+
+	case float_reg:
+		return (register_func*)&function_handler_float;
+		break;
+
+	case double_reg:
+		return (register_func*)&function_handler_double;
+		break;
+
+	case none:
+		return (register_func*)&function_handler[0];
+		break;
+	}
+
+	/* should never reach here, but removes warning */
+	return (register_func*)&function_handler[0];
+}
+
+
+void register_print_summary(uint32_t cpu, uint32_t cwp)
+{
+	uint32_t ins[8], locals[8], outs[8], globals[8];
+	
+	dsu_get_input_reg_window(cpu, cwp, ins);
+	dsu_get_local_reg_window(cpu, cwp, locals);
+	dsu_get_output_reg_window(cpu, cwp, outs);
+	dsu_get_global_reg(cpu, globals);
+
+	printf("         %-8s  %-8s  %-8s  %-8s\n", "INS", "LOCALS", "OUTS", "GLOBALS");
+	
+	for(uint32_t i = 0; i < 8; i++) {
+		printf("%6d:  %08X  %08X  %08X  %08X\n", i, ins[i], locals[i], outs[i], globals[i]);
+	}
+	printf("\n");
+
+	printf("   psr: %08X   wim: %08X   tbr: %08X   y: %08X\n\n",
+		   dsu_get_reg_psr(cpu), dsu_get_reg_wim(cpu),
+		   dsu_get_reg_tbr(cpu), dsu_get_reg_y(cpu));
+
+	printf("   pc:  %08X\n", dsu_get_reg_pc(cpu));
+	printf("   npc: %08X\n", dsu_get_reg_npc(cpu));
+	printf("\n\n\n");
+}
+
+
+static int parse_register_number_single(const char reg_num, uint32_t *dest)
+{
+	if (reg_num < '0' || reg_num > '7')
+		return -1;
+
+	*dest = reg_num - '0';
+	return 0;
+}
+
+static int parse_register_number(const char * const reg, uint32_t * const reg_num, uint32_t highest_register)
+{
+	uint32_t len = strlen(reg);
+
+	*reg_num = 0;
+
+	if (len > 4)
+		return -1;
+
+	for(uint32_t i = 1; i < len; i++) {
+		if (reg[i] < '0' || reg[i] > '9')
+			return -1;
+
+		*reg_num += (reg[i] - '0') * 10;
+	}
+
+	*reg_num = *reg_num / 10;
+
+	if (*reg_num > highest_register)
+		return -1;
+	else
+		return 0;
+}
+
+
+/* Special purpose registers */
+
+static uint32_t get_reg_psr(struct register_desc desc)
+{
+	return dsu_get_reg_psr(desc.cpu);
+}
+
+
+static void set_reg_psr(struct register_desc desc, uint32_t value)
+{
+	dsu_set_reg_psr(desc.cpu, value);
+}
+
+static uint32_t get_reg_tbr(struct register_desc desc)
+{
+	return dsu_get_reg_tbr(desc.cpu);
+}
+
+
+static void set_reg_tbr(struct register_desc desc, uint32_t value)
+{
+	dsu_set_reg_tbr(desc.cpu, value);
+}
+
+static uint32_t get_reg_wim(struct register_desc desc)
+{
+	return dsu_get_reg_wim(desc.cpu);
+}
+
+
+static void set_reg_wim(struct register_desc desc, uint32_t value)
+{
+	dsu_set_reg_wim(desc.cpu, value);
+}
+
+static uint32_t get_reg_y(struct register_desc desc)
+{
+	return dsu_get_reg_y(desc.cpu);
+}
+
+
+static void set_reg_y(struct register_desc desc, uint32_t value)
+{
+	dsu_set_reg_y(desc.cpu, value);
+}
+
+static uint32_t get_reg_pc(struct register_desc desc)
+{
+	return dsu_get_reg_pc(desc.cpu);
+}
+
+
+static void set_reg_pc(struct register_desc desc, uint32_t value)
+{
+	dsu_set_reg_pc(desc.cpu, value);
+}
+
+static uint32_t get_reg_npc(struct register_desc desc)
+{
+	return dsu_get_reg_npc(desc.cpu);
+}
+
+
+static void set_reg_npc(struct register_desc desc, uint32_t value)
+{
+	dsu_set_reg_npc(desc.cpu, value);
+}
+
+static uint32_t get_reg_fsr(struct register_desc desc)
+{
+	return dsu_get_reg_fsr(desc.cpu);
+}
+
+
+static void set_reg_fsr(struct register_desc desc, uint32_t value)
+{
+	dsu_set_reg_fsr(desc.cpu, value);
+}
+
+
+static uint32_t get_reg_sp(struct register_desc desc)
+{
+	return dsu_get_reg_sp(desc.cpu, desc.window);
+}
+
+	
+static void set_reg_sp(struct register_desc desc, uint32_t value)
+{
+	dsu_set_reg_sp(desc.cpu, desc.window, value);
+}
+
+static uint32_t get_reg_fp(struct register_desc desc)
+{
+	return dsu_get_reg_fp(desc.cpu, desc.window);
+}
+
+
+static void set_reg_fp(struct register_desc desc, uint32_t value)
+{
+	dsu_set_reg_fp(desc.cpu, desc.window, value);
+}
+	
+/* Window register */
+static uint32_t get_reg_global(struct register_desc desc)
+{
+	return dsu_get_global_reg(desc.cpu, desc.reg_num);  
+}
+
+static void set_reg_global(struct register_desc desc, uint32_t value)
+{
+	dsu_set_global_reg(desc.cpu, desc.reg_num, value);
+}
+
+	
+static uint32_t get_reg_input(struct register_desc desc)
+{
+	return dsu_get_input_reg_single(desc.cpu, desc.window, desc.reg_num);
+}
+
+static void set_reg_input(struct register_desc desc, uint32_t value)
+{
+	dsu_set_input_reg(desc.cpu, desc.window, desc.reg_num, value);
+}
+
+	
+static uint32_t get_reg_output(struct register_desc desc)
+{
+	return dsu_get_output_reg_single(desc.cpu, desc.window, desc.reg_num);
+}
+	
+
+static void set_reg_output(struct register_desc desc, uint32_t value)
+{
+	dsu_set_output_reg(desc.cpu, desc.window, desc.reg_num, value);
+}
+
+static uint32_t get_reg_local(struct register_desc desc)
+{
+	return dsu_get_local_reg_single(desc.cpu, desc.window, desc.reg_num);
+}
+	
+static void set_reg_local(struct register_desc desc, uint32_t value)
+{
+	dsu_set_local_reg(desc.cpu, desc.window, desc.reg_num, value);
+}
+
+/* Floating point register */
+	
+static union float_value get_reg_float(struct register_desc desc)
+{
+	return dsu_get_float_reg(desc.cpu, desc.reg_num);
+}
+	
+static void set_reg_float(struct register_desc desc, union float_value value)
+{
+	dsu_set_float_reg(desc.cpu, desc.reg_num, value);
+}
+
+	
+static union double_value get_reg_double(struct register_desc desc)
+{
+	return dsu_get_double_reg(desc.cpu, desc.reg_num);
+}
+	
+static void set_reg_double(struct register_desc desc, union double_value value)
+{
+	dsu_set_double_reg(desc.cpu, desc.reg_num, value);
+}
diff --git a/src/uviemon_reg.h b/src/uviemon_reg.h
new file mode 100644
index 0000000000000000000000000000000000000000..4f56287e9c7d02f8387eddc96c79e03d39fe301f
--- /dev/null
+++ b/src/uviemon_reg.h
@@ -0,0 +1,56 @@
+#ifndef UVIEMON_REG_H
+#define UVIEMON_REG_H
+
+
+#include "leon3_dsu.h"
+
+enum register_type {
+	none, standard_reg, float_reg, double_reg
+};
+
+struct register_desc {
+	char name[4];
+	enum register_type type;
+	uint32_t cpu;
+	uint32_t reg_num;
+	uint32_t window;
+	
+};
+
+
+struct register_func {
+	char name[4];
+	enum register_type type;
+};
+
+struct register_func_standard {
+	char name[4];
+	enum register_type type;
+	uint32_t (*get_value)(struct register_desc);
+	void (*set_value)(struct register_desc, uint32_t value);
+};
+
+struct register_func_float {
+	char name[4];
+	enum register_type type;
+	union float_value (*get_value)(struct register_desc);
+	void (*set_value)(struct register_desc, union float_value value);
+};
+
+struct register_func_double {
+	char name[4];
+	enum register_type type;
+	union double_value (*get_value)(struct register_desc);
+	void (*set_value)(struct register_desc, union double_value value);
+};
+
+
+
+
+void register_print_summary(uint32_t cpu, uint32_t cwp);
+
+struct register_desc parse_register(const char * const reg, uint32_t cpu);
+struct register_func *get_register_functions(const struct register_desc desc);
+
+
+#endif