From a16b984f06ca52be0785073ee2c21fcae301fff3 Mon Sep 17 00:00:00 2001 From: cheapie Date: Fri, 30 Oct 2026 09:09:20 -0500 Subject: Add console interrupt support --- assembly/extint-test/extint-test.S | 26 ++++++++++++++++++++-- c/inline/Makefile | 20 +++++++++++++++++ c/inline/inline.c | 25 +++++++++++++++++++++ c/inline/rvcontroller.ld | 45 ++++++++++++++++++++++++++++++++++++++ doc/csr.txt | 9 ++++---- rvcontroller.lua | 33 ++++++++++++++++++++-------- 6 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 c/inline/Makefile create mode 100644 c/inline/inline.c create mode 100644 c/inline/rvcontroller.ld diff --git a/assembly/extint-test/extint-test.S b/assembly/extint-test/extint-test.S index c1b872d..68a218c 100644 --- a/assembly/extint-test/extint-test.S +++ b/assembly/extint-test/extint-test.S @@ -4,8 +4,8 @@ la t0,handler csrw mtvec,t0 # Set up trap handler li t0,0x400 csrc mstatush,t0 # Turn off MDT -li t0,0x30000 -csrw mie,t0 # Mask all interrupts except mesecons/digilines +li t0,0x70000 +csrw mie,t0 # Mask all interrupts except mesecons/digilines/console csrw mip,zero # Clear any pending interrupts csrsi mstatus,0x8 # Turn on MIE to enable interrupts @@ -43,12 +43,16 @@ sw x30,120(x31) # and write that back out too csrr t0,mcause # Read why the trap occurred + li t1,0x80000010 # Interrupt 16 = mesecons beq t0,t1,handler_mesecons li t1,0x80000011 # Interrupt 17 = digilines beq t0,t1,handler_digilines +li t1,0x80000012 # Interrupt 18 = console +beq t0,t1,handler_console + j handler_other # Something else handler_mesecons: @@ -100,6 +104,23 @@ ecall # Clear out any other digilines messages j handler_epilogue +handler_console: +li a7,4 +la a0,consolemsg +ecall # Show that this was a console event + +li a7,132 +ecall # Read the first character from the input buffer +li a7,11 +ecall # And print it +li a0,'\n' +ecall # Followed by a line feed + +li a7,131 +ecall # Discard the rest + +j handler_epilogue + handler_other: li a7,4 la a0,unimplementedmsg @@ -140,6 +161,7 @@ waitingmsg: .asciz "Waiting...\n" meseconsmsg: .asciz "Mesecons event!\nInput value: " digilinesmsg: .asciz "Digilines event!\nChannel:\n" digilinesmsg2: .asciz "\nMessage:\n" +consolemsg: .asciz "Console event!\nFirst char: " unimplementedmsg: .asciz "Unimplemented trap!\nmcause: " channelbuf: .asciz " " msgbuf: .asciz " " diff --git a/c/inline/Makefile b/c/inline/Makefile new file mode 100644 index 0000000..4a1fb6e --- /dev/null +++ b/c/inline/Makefile @@ -0,0 +1,20 @@ +all: inline.hex + +inline.o: inline.c + clang -target riscv32-none-elf -I../rvcontroller-libraries -march=rv32imacb_zicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zbkb_zbkx_zcb_zcmp_zcmt -ffreestanding -O3 -c -o inline.o inline.c + +inline.elf: ../rvcontroller-libraries/rvcontroller-init.o ../rvcontroller-libraries/rvcontroller-ecalls.o inline.o + clang -target riscv32-none-elf -T rvcontroller.ld -nostdlib -nostartfiles -Xlinker --no-warn-rwx-segments -o inline.elf ../rvcontroller-libraries/rvcontroller-init.o inline.o ../rvcontroller-libraries/rvcontroller-ecalls.o + +dump: inline.elf + riscv32-none-elf-objdump -d inline.elf + +inline.hex: inline.elf + riscv32-none-elf-objcopy -O ihex inline.elf inline.hex + +load: inline.hex + bash -c "wl-copy < inline.hex" + +clean: + rm -f inline.hex inline.elf inline.o init.o + diff --git a/c/inline/inline.c b/c/inline/inline.c new file mode 100644 index 0000000..c8db8e3 --- /dev/null +++ b/c/inline/inline.c @@ -0,0 +1,25 @@ +#include +#include +#include "rvcontroller-ecalls.h" + +volatile char thischar; + +volatile uint32_t nonblocking_read() { + volatile uint32_t ret; + asm( + "li a7,132 \n\ + ecall \n\ + mv %0,a0 \n" + : "=r" (ret) + : + : "a0" + ); + return ret; +} + +void main() { + while (true) { + thischar = nonblocking_read(); + //printint(thischar); + } +} diff --git a/c/inline/rvcontroller.ld b/c/inline/rvcontroller.ld new file mode 100644 index 0000000..985892b --- /dev/null +++ b/c/inline/rvcontroller.ld @@ -0,0 +1,45 @@ +/* Thanks https://github.com/darklife/darkriscv */ + __heap_size = 0x200; /* required amount of heap */ + __stack_size = 0x800; /* required amount of stack */ + ENTRY(_start); + MEMORY + { + RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000 + } + SECTIONS + { + .text : + { + *(.text.startup) + *(.text) + *(.text) + *(.rodata*) + } > RAM + .data : + { + *(.sbss) + *(.data) + *(.bss) + *(.rela*) + *(COMMON) + } > RAM + + .heap : + { + . = ALIGN(4); + PROVIDE ( end = . ); + _sheap = .; + . = . + __heap_size; + . = ALIGN(4); + _eheap = .; + } >RAM + + .stack : + { + . = ALIGN(4); + _estack = .; + . = . + __stack_size; + . = ALIGN(4); + _sstack = .; + } >RAM + } diff --git a/doc/csr.txt b/doc/csr.txt index fdd7939..3eae14f 100644 --- a/doc/csr.txt +++ b/doc/csr.txt @@ -69,18 +69,19 @@ while some of the platform-use bits have been assigned to additional interrupts. 0x304 - mie (Machine Interrupt-Enable) - 31 18 17 16 15 8 7 6 0 + 31 19 18 17 16 15 8 7 6 0 +---------------------------------------------------------------------+ -| Reserved |MDIE|MMIE| Reserved |MTIE| Reserved | +| Reserved |MCIE|MDIE|MMIE| Reserved |MTIE| Reserved | +---------------------------------------------------------------------+ 0x344 - mie (Machine Interrupt-Pending) - 31 18 17 16 15 8 7 6 0 + 31 19 18 17 16 15 8 7 6 0 +---------------------------------------------------------------------+ -| Reserved |MDIP|MMIP| Reserved |MTIP| Reserved | +| Reserved |MCIE|MDIP|MMIP| Reserved |MTIP| Reserved | +---------------------------------------------------------------------+ * MTIE/MTIP: Machine Timer Interrupt (see RISC-V Machine-Level ISA documentation) * MMIE/MMIP: Machine Mesecons Interrupt - Becomes pending when a mesecons input changes state and remains pending until manually set to 0 * MDIE/MDIP: Machine Digilines Interrupt - Becomes pending when a digilines message is received and remains pending until manually set to 0 +* MCIE/MCIP: Machine Console Interrupt - Becomes pending when a character is received on standard input and remains pending until manually set to 0 diff --git a/rvcontroller.lua b/rvcontroller.lua index 13e4c24..1b787da 100644 --- a/rvcontroller.lua +++ b/rvcontroller.lua @@ -36,20 +36,25 @@ local traptypes = { [0x12] = "Software check", [0x13] = "Hardware error", --0x14-0x80000000 = reserved/custom - [0x8000001] = "Supv soft interrupt", + [0x80000001] = "Supv soft interrupt", --0x80000002 = reserved - [0x8000003] = "Mach soft interrupt", + [0x80000003] = "Mach soft interrupt", --0x80000004 = reserved - [0x8000005] = "Supv timer interrupt", + [0x80000005] = "Supv timer interrupt", --0x80000006 = reserved - [0x8000007] = "Mach timer interrupt", + [0x80000007] = "Mach timer interrupt", --0x80000008 = reserved - [0x8000009] = "Supv ext interrupt", + [0x80000009] = "Supv ext interrupt", --0x8000000a = reserved - [0x800000b] = "Mach ext interrupt", + [0x8000000b] = "Mach ext interrupt", --0x8000000c = reserved - [0x800000d] = "Count over interrupt", - --0x8000000e-0xffffffff = reserved/platform + [0x8000000d] = "Count over interrupt", + --0x8000000e = reserved + --0x8000000f = reserved + [0x80000010] = "Mach mesec interrupt", + [0x80000011] = "Mach dglne interrupt", + [0x80000012] = "Mach cons interrupt", + --0x80000013-0xffffffff = reserved/platform } local fault --non-nil values are for deferred faults that will trap after the instruction finishes @@ -709,7 +714,7 @@ local function checkinterrupts() end mem.csr[0x344] = implodebits(mipbits,32) if not mem.mie then return end - local order = {11,3,7,9,1,5,13,16,17} + local order = {11,3,7,9,1,5,13,16,17,18} for _,i in ipairs(order) do if miebits[i] and mipbits[i] then return trap(0x80000000+i) @@ -3293,6 +3298,16 @@ elseif event.channel == "stdin" then else --No blocking read in progress, buffer the data for nonblocking reads later mem.inputbuf = string.sub(mem.inputbuf..event.msg,1,256) + local mipbits = explodebits(mem.csr[0x344],32) + mipbits[18] = true + mem.csr[0x344] = implodebits(mipbits,32) + local miebits = explodebits(mem.csr[0x304],32) + if miebits[18] and mem.interruptwaiting then + mem.interruptwaiting = false + mem.running = true + digiline_send("monitordisp","CPU started") + interrupt(1/CLOCK_SPEED,"tick") + end end elseif event.channel == "load" then if event.msg.done then -- cgit v1.2.3