diff --git a/seminaries/qtrvsim/uart-echo-irq/.gitignore b/seminaries/qtrvsim/uart-echo-irq/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4824444e20d13bf53111f400c5ce4b0397cf1d36
--- /dev/null
+++ b/seminaries/qtrvsim/uart-echo-irq/.gitignore
@@ -0,0 +1,5 @@
+*.o
+depend
+uart-echo-irq
+
+
diff --git a/seminaries/qtrvsim/uart-echo-irq/Makefile b/seminaries/qtrvsim/uart-echo-irq/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..16bca1b2e213916ab068f9308a315a870ae9ee27
--- /dev/null
+++ b/seminaries/qtrvsim/uart-echo-irq/Makefile
@@ -0,0 +1,78 @@
+ARCH=riscv64-unknown-elf
+
+
+SOURCES = uart-echo-irq.S
+TARGET_EXE = uart-echo-irq
+
+CC=$(ARCH)-gcc
+CXX=$(ARCH)-g++
+AS=$(ARCH)-as
+LD=$(ARCH)-ld
+OBJCOPY=$(ARCH)-objcopy
+
+ARCHFLAGS += -mabi=ilp32
+ARCHFLAGS += -march=rv32i
+ARCHFLAGS += -fno-lto
+
+CFLAGS  += -ggdb -Os -Wall
+CXXFLAGS+= -ggdb -Os -Wall
+AFLAGS  += -ggdb
+LDFLAGS += -ggdb
+LDFLAGS += -nostartfiles
+LDFLAGS += -nostdlib
+LDFLAGS += -static
+#LDFLAGS += -specs=/opt/musl/riscv64-linux-gnu/lib/musl-gcc.specs
+
+LOADLIBES += -lgcc
+
+CFLAGS  += $(ARCHFLAGS)
+CXXFLAGS+= $(ARCHFLAGS)
+AFLAGS  += $(ARCHFLAGS)
+LDFLAGS += $(ARCHFLAGS)
+
+OBJECTS += $(filter %.o,$(SOURCES:%.S=%.o))
+OBJECTS += $(filter %.o,$(SOURCES:%.c=%.o))
+OBJECTS += $(filter %.o,$(SOURCES:%.cpp=%.o))
+
+all : default
+
+.PHONY : default clean dep all
+
+%.o:%.S
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $@
+
+%.o:%.c
+	$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
+
+%.o:%.cpp
+	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
+
+%.s:%.c
+	$(CC) $(CFLAGS) $(CPPFLAGS) -S $< -o $@
+
+default : $(TARGET_EXE)
+
+$(TARGET_EXE) : $(OBJECTS)
+	$(CC) $(LDFLAGS) $^ $(LOADLIBES) -o $@
+
+dep: depend
+
+depend: $(SOURCES) $(glob *.h)
+	echo '# autogenerated dependencies' > depend
+ifneq ($(filter %.S,$(SOURCES)),)
+	$(CC)  -D__ASSEMBLY__ $(AFLAGS) -w -E -M $(filter %.S,$(SOURCES)) \
+	  >> depend
+endif
+ifneq ($(filter %.c,$(SOURCES)),)
+	$(CC) $(CFLAGS) $(CPPFLAGS) -w -E -M $(filter %.c,$(SOURCES)) \
+	  >> depend
+endif
+ifneq ($(filter %.cpp,$(SOURCES)),)
+	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -w -E -M $(filter %.cpp,$(SOURCES)) \
+	  >> depend
+endif
+
+clean:
+	rm -f *.o *.a $(OBJECTS) $(TARGET_EXE) depend
+
+-include depend
diff --git a/seminaries/qtrvsim/uart-echo-irq/uart-echo-irq.S b/seminaries/qtrvsim/uart-echo-irq/uart-echo-irq.S
new file mode 100644
index 0000000000000000000000000000000000000000..441c1ff223e4ab735b46098b1958f6fddc2fafa5
--- /dev/null
+++ b/seminaries/qtrvsim/uart-echo-irq/uart-echo-irq.S
@@ -0,0 +1,140 @@
+.globl  _start
+.option norelax
+
+// Serial port/terminal registers
+// There is mirror of this region at address 0xffff0000
+// to match QtSpim and Mars emulators
+
+.equ SERIAL_PORT_BASE,      0xffffc000 // base address of serial port region
+
+.equ SERP_RX_ST_REG,        0xffffc000 // Receiver status register
+.equ SERP_RX_ST_REG_o,          0x0000 // Offset of RX_ST_REG
+.equ SERP_RX_ST_REG_READY_m,       0x1 // Data byte is ready to be read
+.equ SERP_RX_ST_REG_IE_m,          0x2 // Enable Rx ready interrupt
+
+.equ SERP_RX_DATA_REG,      0xffffc004 // Received data byte in 8 LSB bits
+.equ SERP_RX_DATA_REG_o,        0x0004 // Offset of RX_DATA_REG
+
+.equ SERP_TX_ST_REG,        0xffffc008 // Transmitter status register
+.equ SERP_TX_ST_REG_o,          0x0008 // Offset of TX_ST_REG
+.equ SERP_TX_ST_REG_READY_m,       0x1 // Transmitter can accept next byte
+.equ SERP_TX_ST_REG_IE_m,          0x2 // Enable Tx ready interrupt
+
+.equ SERP_TX_DATA_REG,      0xffffc00c // Write word to send 8 LSB bits to terminal
+.equ SERP_TX_DATA_REG_o,        0x000c // Offset of TX_DATA_REG
+
+
+// Memory mapped peripheral for dial knobs input,
+// LED and RGB LEDs output designed to match
+// MZ_APO education Zynq based board developed
+// by Petr Porazil and Pavel Pisa at PiKRON.com company
+
+.equ SPILED_REG_BASE,       0xffffc100 // base of SPILED port region
+
+.equ SPILED_REG_LED_LINE,   0xffffc104 // 32 bit word mapped as output
+.equ SPILED_REG_LED_LINE_o,     0x0004 // Offset of the LED_LINE
+.equ SPILED_REG_LED_RGB1,   0xffffc110 // RGB LED 1 color components
+.equ SPILED_REG_LED_RGB1_o,     0x0010 // Offset of LED_RGB1
+.equ SPILED_REG_LED_RGB2,   0xffffc114 // RGB LED 2 color components
+.equ SPILED_REG_LED_RGB2_o,     0x0014 // Offset of LED_RGB2
+.equ SPILED_REG_KNOBS_8BIT, 0xffffc124 // Three 8 bit knob values
+.equ SPILED_REG_KNOBS_8BIT_o,   0x0024 // Offset of KNOBS_8BIT
+
+// simolified subsed of the Task Control Block
+.equ    TCB_SP, 0                       // task stack pointer
+.equ    TCB_RA, 4                       // task return address
+.equ    TCB_T0, 8
+.equ    TCB_A0, 12
+
+.text
+
+_start: 
+        addi    a0, zero, 0x101
+        la      t0, skip
+        csrrw   zero, mepc, t0
+        mret    // test exception ret
+
+        addi    a0, zero, 0x105
+        addi    a0, zero, 0x106
+skip:
+        addi    a0, zero, 0x107
+        csrrs   t0, mepc, zero
+
+        ebreak
+
+        la      t0, handle_exception
+        csrrw   zero, mtvec, t0
+
+        la      t0, task_control_block
+        csrrw   zero, mscratch, t0
+
+        csrrsi   zero,mstatus,8 //MIE=1
+
+        addi    t0, zero, 16 // UART RX
+        addi    t1, zero, 1
+        sll     t1, t1, t0  // bit mask
+        csrrs   zero, mie, t1
+
+        li      a0, SERIAL_PORT_BASE
+        li      t0, SERP_RX_ST_REG_IE_m
+        sw      t0, SERP_RX_ST_REG_o(a0)
+
+        // Background task
+        addi    t0, zero, 0x0001
+        li      a0, SPILED_REG_BASE
+loop:
+        csrrs t1, mepc, zero // check
+        sw      t1, SPILED_REG_LED_LINE_o(a0)
+        srl     t2, t0, 31
+        sll     t0, t0, 1
+        or      t0, t0, t2
+        lw      t2, SPILED_REG_KNOBS_8BIT_o(a0)
+        sw      t2, SPILED_REG_LED_RGB1_o(a0)
+        xori    t2, t2, -1
+        sw      t2, SPILED_REG_LED_RGB2_o(a0)
+        beq     zero, zero, loop
+
+handle_exception:
+        csrrw   tp, mscratch, tp                // store previous and take system tp
+        sw      sp, TCB_SP(tp)                  // store stack pointer
+        sw      ra, TCB_RA(tp)                  // store return address
+        sw      t0, TCB_T0(tp)                  // store rest of clobberable regs
+        sw      a0, TCB_A0(tp)
+        //...
+        csrr    t0, mcause                              // is it Rx interrupt?
+        blt             t0, zero, handle_irq    // branch to interrupts processing
+        //...
+        // handle synchronous exception
+
+ret_from_exception:
+        lw      sp, TCB_SP(tp)                  // restore stack pointer
+        lw      ra, TCB_RA(tp)                  // restore return address
+        lw      t0, TCB_T0(tp)                  // restore rest of clobberable regs
+        lw      a0, TCB_A0(tp)
+        ///...
+        csrrw   tp, mscratch, tp                // Swap back TCB to mscratch
+        mret                                    // Return from exception pc <= mepc
+
+handle_irq:                                     // t0 mcause
+        slli    t0, t0, 2                       // shift out sign, left sources * 4
+        /* the t0 would be used to point into irq handlers table */
+        /* check only for UART RX interupt for simplicity 8 */ 
+        addi    a0, zero, 16 * 4                // UART RX is the first platform irq
+        beq     t0, a0, handle_uart_rx_irq      // it is UART RX
+        /* mask out unknown sources */
+        srli    t0, t0, 2                       // make t0 back simple source index
+        addi    a0, zero, 1
+        sll     a0, a0, t0                      // generate bit mask for source
+        csrrc   zero, mie, a0                   // mie = mie & ~a0
+        j       ret_from_exception
+
+handle_uart_rx_irq:
+        li      a0, SERIAL_PORT_BASE            // Setup base of UART
+        lw      t0, SERP_RX_DATA_REG_o(a0)      // Read received character
+        sw      t0, SERP_TX_DATA_REG_o(a0)      // echo it back to terminal
+        j       ret_from_exception
+
+.data
+
+task_control_block:
+        .skip   64