diff --git a/software/app/Makefile b/software/app/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..85e777bbf6edb1ddb720bc1e2fe1a07b020d655d
--- /dev/null
+++ b/software/app/Makefile
@@ -0,0 +1,53 @@
+#CROSS_COMPILE_TARGET ?= /home/mattia/riscv-toolchain/riscv/bin/riscv32-elf-
+
+CROSS_COMPILE_TARGET ?= /home/mattia/riscv32-nanolib/gnu-mcu-eclipse/riscv-none-gcc/8.1.0-2-20181019-0952/bin/riscv-none-embed-
+CFLAGS += -mabi=ilp32 -march=rv32im  -Os -ffunction-sections -fdata-sections --specs=nano.specs --specs=nosys.specs -lgcc -lc -Wl,--gc-sections
+
+
+CC =		$(CROSS_COMPILE_TARGET)gcc
+LD =		$(CROSS_COMPILE_TARGET)ld
+OBJDUMP =	$(CROSS_COMPILE_TARGET)objdump
+OBJCOPY =	$(CROSS_COMPILE_TARGET)objcopy
+SIZE =		$(CROSS_COMPILE_TARGET)size
+STRIP =	$(CROSS_COMPILE_TARGET)strip
+
+
+
+all: main-text.hex main-data.hex
+
+crt0.o: crt0.S
+	$(CC) -c -o $@ $(CFLAGS) $<
+
+irq.o: irq.S
+	$(CC) -c -o $@ $(CFLAGS) $<
+
+eth_config.o: eth_config.c
+	$(CC) -c -o $@ $(CFLAGS) $<
+
+uart.o: uart.c
+	$(CC) -c -o $@ $(CFLAGS) $<	
+
+refresh.o: refresh.s
+	$(CC) -c -o $@ $(CFLAGS) $<
+
+main: main.o crt0.o  powerlink.ld irq.o eth_config.o refresh.o uart.o
+	$(CC)  -o $@ -nostartfiles $(CFLAGS) crt0.o main.o irq.o eth_config.o refresh.o uart.o -T powerlink.ld
+
+main-text.bin: main
+	riscv32-elf-objcopy -j .text -O binary $< $@
+
+main-data.bin: main
+	riscv32-elf-objcopy -j .data -O binary $< $@
+
+main-text.hex: main-text.bin
+	riscv32-elf-objcopy -I binary -O ihex $< $@
+
+main-data.hex: main-data.bin
+	riscv32-elf-objcopy -I binary -O ihex $< $@
+
+clean:
+	rm main
+	rm *.o
+	rm *.bin
+	rm *.hex
+
diff --git a/software/app/crt0.S b/software/app/crt0.S
new file mode 100644
index 0000000000000000000000000000000000000000..11bdc95ba85b40059c4ece62b1a389f6189dc9e8
--- /dev/null
+++ b/software/app/crt0.S
@@ -0,0 +1,128 @@
+  .section    .boot, "ax", @progbits
+
+.global _start
+_start:
+    j _entry
+
+.org 0x8
+
+.extern trap_entry
+_exception_entry:
+  j trap_entry
+
+
+_entry:
+	
+  lui	t0,%hi(0x86000000)
+  lw	t0,%lo(0x86000000)(t0)
+  and t0, t0, 1	
+  bnez	t0, _recovery
+  lui	t0,%hi(0x86000000)
+  li t1, 1
+  sw  t1, 0(t0)
+	
+  lui ra, 0
+  lui sp, 0
+  lui gp, 0
+  lui tp, 0
+  lui s0, 0
+  lui s1, 0
+  lui s2, 0
+  lui s3, 0
+  lui s4, 0
+  lui s5, 0
+  lui s6, 0
+  lui s7, 0
+  lui s8, 0
+  lui s9, 0
+  lui s10, 0
+  lui s11, 0
+  lui t0, 0
+  lui t1, 0
+  lui t2, 0
+  lui t3, 0
+  lui t4, 0
+  lui t5, 0
+  lui t6, 0 
+  lui a0, 0
+  lui a1, 0
+  lui a2, 0
+  lui a3, 0
+  lui a4, 0
+  lui a5, 0
+  lui a6, 0
+  lui a7, 0
+  la gp, _gp                 /* Initialize global pointer */
+  la sp, _fstack
+
+/*  la t0, _fexception_stack
+  csrrw t0, mscratch, t0 */
+
+  /* clear the bss segment */
+  la t0, _fbss
+  la t1, _end
+1:
+#ifdef __riscv64
+  sd zero,0(t0)
+  addi t0, t0, 8
+#else
+  sw zero,0(t0)
+  addi t0, t0, 4
+#endif
+  bltu t0, t1, 1b
+  call main
+1:
+  j     1b
+
+_recovery:
+	la	t0, _recov_data
+	sw	ra, 0(t0)	# x1
+	lw	ra, 0(t0)
+	sw	sp, 0(t0)	# x2
+	lw	sp, 0(t0)
+	sw	gp, 0(t0)	# x3
+	lw	gp, 0(t0)
+	sw	tp, 0(t0)	# x4
+	lw	tp, 0(t0)
+	li	t1, 0		# x6
+	li	t2, 0		# x7
+	sw	s0, 0(t0)	# x8
+	lw	s0, 0(t0)
+	sw	s1, 0(t0)	# x9
+	lw	s1, 0(t0)
+	li	a0, 0		# x10
+	li	a1, 0		# x11
+	li	a2, 0		# x12
+	li	a3, 0		# x13
+	li	a4, 0
+	li	a5, 0
+	li	a6, 0
+	li	a7, 0		# x17
+	sw	s2, 0(t0)	# x18
+	lw	s2, 0(t0)
+	sw	s3, 0(t0)	# x19
+	lw	s3, 0(t0)
+	sw	s4, 0(t0)	# x20
+	lw	s4, 0(t0)
+	sw	s5, 0(t0)	# x21
+	lw	s5, 0(t0)
+	sw	s6, 0(t0)	# x22
+	lw	s6, 0(t0)
+	sw	s7, 0(t0)	# x23
+	lw	s7, 0(t0)
+	sw	s8, 0(t0)	# x24
+	lw	s8, 0(t0)
+	sw	s9, 0(t0)	# x25
+	lw	s9, 0(t0)
+	sw	s10, 0(t0)	# x26
+	lw	s10, 0(t0)
+	sw	s11, 0(t0)	# x27
+	lw	s11, 0(t0)
+	li	t3, 0		# x28
+	li	t4, 0		# x29
+	li	t5, 0		# x30
+	li	t6, 0		# x31
+	li	t0, 0
+	ret
+	.data
+_recov_data:	.long 0
diff --git a/software/app/eth_config.c b/software/app/eth_config.c
new file mode 100644
index 0000000000000000000000000000000000000000..7b94e6f0ba32aaa92d55a874613c02e9941b714b
--- /dev/null
+++ b/software/app/eth_config.c
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <string.h>
+#include "eth_config.h"
+#include "uart.h"
+
+
+
+
+
+void eth_send_frame(uint16_t len);
+
+void __attribute__((optimize("O0"))) delay_us(uint16_t us) {
+	uint32_t istrs = ((uint16_t) us ) << 5;
+	while (istrs > 0)
+		istrs--;
+
+}
+
+
+
+volatile uint32_t __attribute__((section (".dma"))) rx_buf0[1516/4];
+volatile uint32_t __attribute__((section (".dma"))) rx_buf1[1516/4];
+
+
+volatile uint32_t tx_buf[1516/4];
+
+static volatile eth_descriptor * rx_descriptor0 = (volatile void *) MAC_REG_RXDESCRIPTOR0;
+static volatile eth_descriptor * rx_descriptor1 = (volatile void *) MAC_REG_RXDESCRIPTOR1;
+static volatile eth_descriptor * tx_descriptor  = (volatile void *) MAC_REG_TXDESCRIPTOR; 
+static volatile uint32_t * mac_config = (volatile void *) MAC_REG_CONFIG;
+
+volatile uint32_t * miim_config = (volatile uint32_t *) MAC_REG_MIICONFIG;
+volatile uint32_t * miim_reg =  (volatile uint32_t *) MAC_REG_MII;
+
+void reset_phy (void) {
+
+	*mac_config = 0x10;
+	delay_us(175);
+	*mac_config = 0x8;
+	delay_us(100);	
+}
+
+void disable_irq () {
+	unsigned t;
+	asm volatile ("csrrci %0, mstatus, %1" : "=r"(t) : "i"(1 << 3));
+}
+
+void enable_irq () {
+	unsigned t;
+  	asm volatile ("csrrsi %0, mstatus, %1" : "=r"(t) : "i"(1 << 3));
+}
+
+void init_mac (void) {
+
+		
+	disable_irq();
+  		
+	*mac_config = MAC_RESET;
+	delay_us(1);
+	*mac_config = MAC_INIT_CONFIG;
+
+	rx_descriptor0->busy = 1;
+	rx_descriptor1->busy = 1;
+	tx_descriptor->busy = 0;
+	
+	*mac_config = MAC_ENABLE_TX | MAC_ENABLE_RX;
+
+	enable_irq();
+
+	print_string("mac init done\n");
+
+}
+
+
+uint32_t link_status = 0;
+
+void link_check (void) {
+uint8_t result;
+
+
+		
+	*miim_config = 1;
+	while(! (*miim_reg & 0x80000000));
+
+ 	if (*miim_reg & 0x700)
+		return;
+
+	if ( (*miim_reg & 0x4))
+		result = 1;
+	else 
+		result = 0;
+
+	if (result == 1 && link_status == 0) {
+		init_mac();
+		print_string("link up\n");
+	
+	link_status = result;
+	}
+
+	if (result == 0 && link_status == 1) {
+		print_string("link dn\n");
+		//*mac_config = 0;
+		
+		link_status = result;
+		reset_phy();
+	}	
+	
+	
+	
+
+}
+
+
+
+volatile uint32_t int_phy_reset = 0;
+volatile uint32_t int_tx_done = 0;
+
+uint8_t eth_loop ()
+{
+	link_check();
+}
+
+
+uint32_t packets_sent = 0;
+
+void eth_send_frame (uint16_t len) {
+
+	int i = 0;
+	tx_descriptor->len = len;
+	tx_descriptor->addr = 0xffff & (uint32_t)tx_buf;
+	tx_descriptor->busy = 1;
+
+	packets_sent++;
+
+	
+}
+
+
+void irq_handler(void)
+{
+	uint16_t len = 0;
+	volatile eth_descriptor * irq_descriptor;
+
+
+
+	if (tx_descriptor->irq) {
+		asm("nop"); 
+		int_tx_done = 1;
+	}
+	
+	if (rx_descriptor0->irq)
+		irq_descriptor = rx_descriptor0;
+	else if (rx_descriptor1->irq) 
+		irq_descriptor = rx_descriptor1;
+
+	len  = irq_descriptor->len - 4;
+	if (len > 1512) while(1) print_word(0xBADBAD00);
+
+
+	memcpy ((void *) tx_buf, (void *) irq_descriptor->addr, len);
+
+
+	if (len > 10)
+		eth_send_frame (len);
+
+         irq_descriptor->busy = 1;
+
+	
+     
+
+
+}
+
+
+
+
+
diff --git a/software/app/eth_config.h b/software/app/eth_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..9a5f526f6d8cb9615da5d55f1df059eb8068ea31
--- /dev/null
+++ b/software/app/eth_config.h
@@ -0,0 +1,27 @@
+#define MAC_REGS_BASE		0x84000000
+#define	MAC_REG_RXDESCRIPTOR0	0x84000000
+#define	MAC_REG_RXDESCRIPTOR1	0x84000004
+#define	MAC_REG_TXDESCRIPTOR	0x84000008
+#define	MAC_REG_CONFIG		0x8400000c
+#define	MAC_REG_MIICONFIG	0x84000010
+#define MAC_REG_MII		0x84000014
+
+
+//#define MII_BUSY	((ETH_REGS->MIISTATUS & 0x02) != 0)
+
+typedef struct 
+{
+	uint8_t busy : 1;
+	const uint8_t fifo_flow_err : 1;
+	const uint8_t irq : 1;
+	uint16_t len : 13;
+	uint16_t addr;
+} eth_descriptor;
+
+
+#define MAC_ENABLE_RX 0x1
+#define MAC_ENABLE_TX 0x2
+#define MAC_RESET     0x8
+
+#define MAC_INIT_CONFIG 0
+
diff --git a/software/app/irq.S b/software/app/irq.S
new file mode 100644
index 0000000000000000000000000000000000000000..520185c3dafc07ce782088656f96c7b7c8a22585
--- /dev/null
+++ b/software/app/irq.S
@@ -0,0 +1,129 @@
+.section .text
+
+.global trap_entry
+trap_entry:
+# 	csrrw	sp,mscratch,sp
+ 	addi	sp,sp,-320
+ 	sw	ra,4(sp)
+ 	sw	gp,12(sp)
+ 	sw	tp,16(sp)
+ 	sw	t0,20(sp)
+ 	sw	t1,24(sp)
+ 	sw	t2,28(sp)
+ 	sw	s0,32(sp)
+ 	sw	s1,36(sp)
+ 	sw	a0,40(sp)
+ 	sw	a1,44(sp)
+ 	sw	a2,48(sp)
+ 	sw	a3,52(sp)
+ 	sw	a4,56(sp)
+ 	sw	a5,60(sp)
+ 	sw	a6,64(sp)
+ 	sw	a7,68(sp)
+ 	sw	s2,72(sp)
+ 	sw	s3,76(sp)
+ 	sw	s4,80(sp)
+ 	sw	s5,84(sp)
+ 	sw	s6,88(sp)
+ 	sw	s7,92(sp)
+ 	sw	s8,96(sp)
+ 	sw	s9,100(sp)
+ 	sw	s10,104(sp)
+ 	sw	s11,108(sp)
+ 	sw	t3,112(sp)
+ 	sw	t4,116(sp)
+ 	sw	t5,120(sp)
+ 	sw	t6,124(sp)
+ 	csrr	t0,mscratch
+ 	csrr	s0,mstatus
+ 	csrr	t1,mepc
+ 	csrr	t2,mbadaddr
+ 	csrr	t3,mcause
+ 	sw	t0,8(sp)
+ 	sw	s0,128(sp)
+ 	sw	t1,132(sp)
+ 	sw	t2,136(sp)
+ 	sw	t3,140(sp)
+ 	li	t0,-1
+ 	sw	t0,144(sp)
+ 	mv	a0,sp
+
+        bgez    t3, .Lexcept
+        jal     irq_handler
+        j       .Lret
+
+.Lexcept:
+        la t0, jump_table
+        sll t3, t3, 2
+        add t0, t0, t3
+        lw t0, 0(t0)
+        jalr t0
+
+.Lret:
+        mv  a0,sp
+ 	lw	t1,128(a0)
+ 	lw	t2,132(a0)
+ 	addi	sp,sp,320
+# 	csrw	mscratch,sp
+ 	csrw	mepc,t2
+ 	lw	ra,4(a0)
+# 	lw	sp,8(a0) ####
+ 	lw	gp,12(a0)
+ 	lw	tp,16(a0)
+ 	lw	t0,20(a0)
+ 	lw	t1,24(a0)
+ 	lw	t2,28(a0)
+ 	lw	s0,32(a0)
+ 	lw	s1,36(a0)
+ 	lw	a1,44(a0)
+ 	lw	a2,48(a0)
+ 	lw	a3,52(a0)
+ 	lw	a4,56(a0)
+ 	lw	a5,60(a0)
+ 	lw	a6,64(a0)
+ 	lw	a7,68(a0)
+ 	lw	s2,72(a0)
+ 	lw	s3,76(a0)
+ 	lw	s4,80(a0)
+ 	lw	s5,84(a0)
+ 	lw	s6,88(a0)
+ 	lw	s7,92(a0)
+ 	lw	s8,96(a0)
+ 	lw	s9,100(a0)
+ 	lw	s10,104(a0)
+ 	lw	s11,108(a0)
+ 	lw	t3,112(a0)
+ 	lw	t4,116(a0)
+ 	lw	t5,120(a0)
+ 	lw	t6,124(a0)
+ 	lw	a0,40(a0)
+ 	mret
+
+        .text
+
+        .weak undefined_handler
+undefined_handler:
+	 j undefined_handler
+
+        .weak undefined_insn_handler
+undefined_insn_handler:
+        j undefined_insn_handler
+
+        .data
+jump_table:
+  .word undefined_handler       # 0: Insn address misaligned
+  .word undefined_handler
+  .word undefined_insn_handler  # 2: Illegal insn
+  .word undefined_handler
+  .word undefined_handler
+  .word undefined_handler
+  .word undefined_handler
+  .word undefined_handler
+  .word undefined_handler
+  .word undefined_handler
+  .word undefined_handler
+  .word undefined_handler
+  .word undefined_handler
+  .word undefined_handler
+  .word undefined_handler
+  .word undefined_handler
diff --git a/software/app/main.c b/software/app/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..3f6b4c8e2c4a2e1752a59477f4d22168ee9dcfe2
--- /dev/null
+++ b/software/app/main.c
@@ -0,0 +1,129 @@
+#include <stdio.h>
+#include "riscv.h"
+#include "eth_config.h"
+#include "uart.h"
+#include "string.h"
+
+
+
+uint32_t memtest_buffer [4096];
+
+unsigned int memtest () {
+	int i = 0;
+	unsigned int res = 0;
+	
+	while (i < sizeof(memtest_buffer) >> 2) {
+		res = res ^ memtest_buffer [i];
+		memtest_buffer[i++] = 0xAAAAAAAA;
+	}
+		
+	return res;	
+	
+	
+}
+
+
+
+
+
+
+unsigned int cnt;
+
+
+char * startup = "Fresh startup!\n";
+
+void main(void)
+{
+unsigned int proc_counter,counter = 0;
+
+volatile int * p_seu = (void*) 0x83000000;
+volatile char  * p_wd = (void*) 0x81000000;
+volatile uint32_t * supervisor = (volatile) (uint32_t *) 0x86000000;
+
+int bert_started = 0;
+uint32_t bert_counter = 0;
+
+print_string("\n\n\n\n");
+
+print_string(startup);
+print_line();
+
+// in case of random PC reset, change content of heap memory to show it
+startup[0] = 'R';
+startup[1] = 'R';
+startup[2] = 'R';
+
+
+print_string("M2S090\n");
+print_line();
+print_string(__DATE__);
+print_line();
+print_string(__TIME__);
+print_line();
+
+
+reset_phy(); 
+init_mac();
+
+unsigned t;
+asm volatile ("csrrci %0, mstatus, %1" : "=r"(t) : "i"(1 << 3));
+
+
+// Enable irq: set mie.meie
+asm volatile ("csrrs %0, mie, %1" : "=r"(t) : "r"(1 << 11));
+asm volatile ("csrrsi %0, mstatus, %1" : "=r"(t) : "i"(1 << 3));
+
+*p_wd = 1; //watchdog
+
+
+
+
+
+while (1) 
+
+{
+	uint32_t seu;
+	counter++;	
+
+	if (counter & 0x8000) {
+		counter = 0;
+		proc_counter++;
+
+		seu = *p_seu++;
+		print_string("cnt: ");
+		print_word(proc_counter);
+		print_string(" seu iram: ");
+		print_word(seu);
+
+		seu = *p_seu;
+		print_string(" seu dram: ");
+		print_word(seu);
+		
+		print_string(" mem: ");
+		print_word(memtest());
+		print_line();
+
+	}
+
+
+
+	eth_loop ();
+	refresh ();
+	uint32_t cpu_status = (*supervisor >> 16) & 0x7;
+	if (cpu_status != 7) {
+		print_string ("cpu not aligned!\n");
+		asm volatile ("csrrci %0, mstatus, %1" : "=r"(t) : "i"(1 << 3));
+		*supervisor = 2; // recovery
+  		asm volatile ("csrrsi %0, mstatus, %1" : "=r"(t) : "i"(1 << 3));
+  		asm volatile ("csrrs %0, mie, %1" : "=r"(t) : "r"(1 << 11));
+	}
+
+
+
+
+	*p_wd = 1;
+
+}
+
+
+}
diff --git a/software/app/powerlink.ld b/software/app/powerlink.ld
new file mode 100644
index 0000000000000000000000000000000000000000..0400ec1db9a344786b43fa081cf140b8683ab3bd
--- /dev/null
+++ b/software/app/powerlink.ld
@@ -0,0 +1,72 @@
+OUTPUT_FORMAT("elf32-littleriscv")
+ENTRY(_start)
+
+MEMORY
+{
+   iram : ORIGIN = 0x00000000, LENGTH = 32K
+   dram : ORIGIN = 0x00010000, LENGTH = 29K
+   dma  : ORIGIN = 0x00010000 + 29K, LENGTH = 3K
+}
+
+
+SECTIONS
+{
+
+  /* Begining of code and text segment */
+  . = 0x00000000;
+  /* text: Program code section */
+  .text :
+  {
+    *(.boot)
+    *(.text)
+    *(.text.*)
+    *(.gnu.linkonce.t.*)
+  } > iram
+
+  /* rodata: Read-only data */
+  .data :
+  {
+    *(.rdata)
+    *(.rodata)
+    *(.rodata.*)
+    *(.gnu.linkonce.r.*)
+    *(.data)
+    *(.data.*)
+    
+    *(.gnu.linkonce.d.*)
+    _edata = .;
+
+    /* Have _gp point to middle of sdata/sbss to maximize displacement range */
+    . = ALIGN(16);
+    _gp = . + 0x800;
+
+    *(.sdata)
+    *(.sdata.*)
+    *(.srodata.*)
+    *(.gnu.linkonce.s.*)
+
+    . = ALIGN(8);
+    _fbss = .;
+
+    *(.sbss)
+    *(.sbss.*)
+    *(.gnu.linkonce.sb.*)
+
+    _bss_start = .;
+
+    *(.bss)
+    *(.bss.*)
+    *(.gnu.linkonce.b.*)
+    *(COMMON)
+
+    _end = ALIGN(8);
+  } > dram
+
+ PROVIDE(_fstack = ORIGIN(dram) + LENGTH(dram) - 4 - 0x1000);
+
+ .dma :
+  {
+    *(.dma)
+    *(.dma.*)
+  } > dma
+}
diff --git a/software/app/refresh.s b/software/app/refresh.s
new file mode 100644
index 0000000000000000000000000000000000000000..c49df942c47c64afa465197330a6dea29d934e16
--- /dev/null
+++ b/software/app/refresh.s
@@ -0,0 +1,73 @@
+.section .text
+
+.global refresh
+refresh:
+
+
+ 	addi	sp,sp,-320
+ 	sw	ra,4(sp)
+	sw	sp,8(sp)
+ 	sw	gp,12(sp)
+ 	sw	tp,16(sp)
+ 	sw	t0,20(sp)
+ 	sw	t1,24(sp)
+ 	sw	t2,28(sp)
+ 	sw	s0,32(sp)
+ 	sw	s1,36(sp)
+ 	sw	a0,40(sp)
+ 	sw	a1,44(sp)
+ 	sw	a2,48(sp)
+ 	sw	a3,52(sp)
+ 	sw	a4,56(sp)
+ 	sw	a5,60(sp)
+ 	sw	a6,64(sp)
+ 	sw	a7,68(sp)
+ 	sw	s2,72(sp)
+ 	sw	s3,76(sp)
+ 	sw	s4,80(sp)
+ 	sw	s5,84(sp)
+ 	sw	s6,88(sp)
+ 	sw	s7,92(sp)
+ 	sw	s8,96(sp)
+ 	sw	s9,100(sp)
+ 	sw	s10,104(sp)
+ 	sw	s11,108(sp)
+ 	sw	t3,112(sp)
+ 	sw	t4,116(sp)
+ 	sw	t5,120(sp)
+ 	sw	t6,124(sp)
+
+ 	lw	ra,4(sp)
+ 	lw	sp,8(sp) ####
+ 	lw	gp,12(sp)
+ 	lw	tp,16(sp)
+ 	lw	t0,20(sp)
+ 	lw	t1,24(sp)
+ 	lw	t2,28(sp)
+ 	lw	s0,32(sp)
+ 	lw	s1,36(sp)
+ 	lw	a1,44(sp)
+ 	lw	a2,48(sp)
+ 	lw	a3,52(sp)
+ 	lw	a4,56(sp)
+ 	lw	a5,60(sp)
+ 	lw	a6,64(sp)
+ 	lw	a7,68(sp)
+ 	lw	s2,72(sp)
+ 	lw	s3,76(sp)
+ 	lw	s4,80(sp)
+ 	lw	s5,84(sp)
+ 	lw	s6,88(sp)
+ 	lw	s7,92(sp)
+ 	lw	s8,96(sp)
+ 	lw	s9,100(sp)
+ 	lw	s10,104(sp)
+ 	lw	s11,108(sp)
+ 	lw	t3,112(sp)
+ 	lw	t4,116(sp)
+ 	lw	t5,120(sp)
+ 	lw	t6,124(sp)
+ 	lw	a0,40(sp)
+ 	addi	sp,sp,320
+	ret
+
diff --git a/software/app/riscv.h b/software/app/riscv.h
new file mode 100644
index 0000000000000000000000000000000000000000..75d2ab9ef9274f111d9106b1797718e28e7c04e5
--- /dev/null
+++ b/software/app/riscv.h
@@ -0,0 +1,37 @@
+#ifndef __RISCV_H
+#define __RISCV_H
+
+#ifdef __GNUC__
+
+#define riscv_read_csr(reg) ({ unsigned long __tmp; \
+  asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
+  __tmp; })
+
+#define riscv_write_csr(reg, val) \
+  asm volatile ("csrw " #reg ", %0" :: "r"(val))
+
+#define riscv_swap_csr(reg, val) ({ long __tmp; \
+  asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \
+  __tmp; })
+
+#define riscv_set_csr(reg, bit) ({ unsigned long __tmp; \
+  if (__builtin_constant_p(bit) && (bit) < 32) \
+    asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
+  else \
+    asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
+  __tmp; })
+
+#define riscv_clear_csr(reg, bit) ({ unsigned long __tmp; \
+  if (__builtin_constant_p(bit) && (bit) < 32) \
+    asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
+  else \
+    asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
+  __tmp; })
+
+#define riscv_rdtime() riscv_read_csr(time)
+#define riscv_rdcycle() riscv_read_csr(cycle)
+#define riscv_rdinstret() riscv_read_csr(instret)
+
+#endif
+
+#endif
diff --git a/software/app/uart.c b/software/app/uart.c
new file mode 100644
index 0000000000000000000000000000000000000000..aa5654f7ebcd20c64bc62e06a63afeaa167ff510
--- /dev/null
+++ b/software/app/uart.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include "uart.h"
+#include "string.h"
+
+void print_line (void)
+{
+	print_char('\n');
+}
+
+void  print_char (char c)  {
+	volatile uart_reg * uart_tx = (uart_reg *) UART_REGS_BASE;
+	while (!uart_tx->flags);
+	uart_tx->buffer = c;
+	uart_tx->flags = 2;
+
+}
+
+void  print_string (char * str) {
+ 	uint8_t len = strlen(str);
+	for (char i=0; i < len; i++) 
+		print_char(str[i]);
+        
+	
+}
+
+
+
+
+void  print_word (uint32_t  word) {
+	int8_t i;
+	uint8_t disp;
+	uint32_t temp;
+	char c;
+	
+	for (i=7; i >= 0; i--) {
+
+	  disp = ((word >> (i<<2)) & 0xf);
+		if (disp <= 9 )
+			c = '0'+ disp;
+		else
+			c = 'A' + disp - 10; 
+ 
+		print_char (c);
+	}
+
+}
diff --git a/software/app/uart.h b/software/app/uart.h
new file mode 100644
index 0000000000000000000000000000000000000000..04ded05eee7ecd83a8bf7d9f090c6466290b4697
--- /dev/null
+++ b/software/app/uart.h
@@ -0,0 +1,16 @@
+#ifndef __UART_H
+
+#define __UART_H
+#define UART_REGS_BASE 0x82000000
+
+void print_line (void);
+void print_char (char c) ;
+void print_word (uint32_t word);
+void print_string (char * str);
+
+typedef struct uart_reg  {
+  uint32_t flags;
+  uint32_t buffer;
+} uart_reg;
+
+#endif