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