riscv: add bare-bones interrupt support
This commit adds support for timer interrupts, replacing the busy loop that was used before. It is perhaps the most simple interrupt to implement and should serve as the basis for further interrupt support in RISC-V.
Этот коммит содержится в:
родитель
360923abbf
коммит
b9cdfd9e9a
3 изменённых файлов: 102 добавлений и 3 удалений
|
@ -5,8 +5,56 @@
|
||||||
_start:
|
_start:
|
||||||
// Load the stack pointer.
|
// Load the stack pointer.
|
||||||
la sp, _stack_top
|
la sp, _stack_top
|
||||||
|
|
||||||
// Load the globals pointer. The program will load pointers relative to this
|
// Load the globals pointer. The program will load pointers relative to this
|
||||||
// register, so it must be set to the right value on startup.
|
// register, so it must be set to the right value on startup.
|
||||||
// See: https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/#the-gp-global-pointer-register
|
// See: https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/#the-gp-global-pointer-register
|
||||||
la gp, __global_pointer$
|
la gp, __global_pointer$
|
||||||
|
|
||||||
|
// Jump to runtime.main
|
||||||
call main
|
call main
|
||||||
|
|
||||||
|
.section .text.handleInterruptASM
|
||||||
|
.global handleInterruptASM
|
||||||
|
.type handleInterruptASM,@function
|
||||||
|
handleInterruptASM:
|
||||||
|
// Save and restore all registers, because the hardware only saves/restores
|
||||||
|
// the pc.
|
||||||
|
// Note: we have to do this in assembly because the "interrupt"="machine"
|
||||||
|
// attribute is broken in LLVM: https://bugs.llvm.org/show_bug.cgi?id=42984
|
||||||
|
addi sp, sp, -64
|
||||||
|
sw ra, 60(sp)
|
||||||
|
sw t0, 56(sp)
|
||||||
|
sw t1, 52(sp)
|
||||||
|
sw t2, 48(sp)
|
||||||
|
sw a0, 44(sp)
|
||||||
|
sw a1, 40(sp)
|
||||||
|
sw a2, 36(sp)
|
||||||
|
sw a3, 32(sp)
|
||||||
|
sw a4, 28(sp)
|
||||||
|
sw a5, 24(sp)
|
||||||
|
sw a6, 20(sp)
|
||||||
|
sw a7, 16(sp)
|
||||||
|
sw t3, 12(sp)
|
||||||
|
sw t4, 8(sp)
|
||||||
|
sw t5, 4(sp)
|
||||||
|
sw t6, 0(sp)
|
||||||
|
call handleInterrupt
|
||||||
|
lw t6, 0(sp)
|
||||||
|
lw t5, 4(sp)
|
||||||
|
lw t4, 8(sp)
|
||||||
|
lw t3, 12(sp)
|
||||||
|
lw a7, 16(sp)
|
||||||
|
lw a6, 20(sp)
|
||||||
|
lw a5, 24(sp)
|
||||||
|
lw a4, 28(sp)
|
||||||
|
lw a3, 32(sp)
|
||||||
|
lw a2, 36(sp)
|
||||||
|
lw a1, 40(sp)
|
||||||
|
lw a0, 44(sp)
|
||||||
|
lw t2, 48(sp)
|
||||||
|
lw t1, 52(sp)
|
||||||
|
lw t0, 56(sp)
|
||||||
|
lw ra, 60(sp)
|
||||||
|
addi sp, sp, 64
|
||||||
|
mret
|
||||||
|
|
|
@ -9,7 +9,9 @@ import (
|
||||||
"machine"
|
"machine"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"device/riscv"
|
||||||
"device/sifive"
|
"device/sifive"
|
||||||
|
"runtime/volatile"
|
||||||
)
|
)
|
||||||
|
|
||||||
type timeUnit int64
|
type timeUnit int64
|
||||||
|
@ -31,12 +33,47 @@ var _edata unsafe.Pointer
|
||||||
|
|
||||||
//go:export main
|
//go:export main
|
||||||
func main() {
|
func main() {
|
||||||
|
// Zero the PLIC enable bits on startup: they are not zeroed at reset.
|
||||||
|
sifive.PLIC.ENABLE[0].Set(0)
|
||||||
|
sifive.PLIC.ENABLE[1].Set(0)
|
||||||
|
|
||||||
|
// Set the interrupt address.
|
||||||
|
// Note that this address must be aligned specially, otherwise the MODE bits
|
||||||
|
// of MTVEC won't be zero.
|
||||||
|
riscv.MTVEC.Set(uintptr(unsafe.Pointer(&handleInterruptASM)))
|
||||||
|
|
||||||
|
// Enable global interrupts now that they've been set up.
|
||||||
|
riscv.MSTATUS.SetBits(1 << 3) // MIE
|
||||||
|
|
||||||
preinit()
|
preinit()
|
||||||
initAll()
|
initAll()
|
||||||
callMain()
|
callMain()
|
||||||
abort()
|
abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:extern handleInterruptASM
|
||||||
|
var handleInterruptASM [0]uintptr
|
||||||
|
|
||||||
|
//export handleInterrupt
|
||||||
|
func handleInterrupt() {
|
||||||
|
cause := riscv.MCAUSE.Get()
|
||||||
|
code := uint(cause &^ (1 << 31))
|
||||||
|
if cause&(1<<31) != 0 {
|
||||||
|
// Topmost bit is set, which means that it is an interrupt.
|
||||||
|
switch code {
|
||||||
|
case 7: // Machine timer interrupt
|
||||||
|
// Signal timeout.
|
||||||
|
timerWakeup.Set(1)
|
||||||
|
// Disable the timer, to avoid triggering the interrupt right after
|
||||||
|
// this interrupt returns.
|
||||||
|
riscv.MIE.ClearBits(1 << 7) // MTIE bit
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: handle exceptions in a similar was as HardFault is handled on
|
||||||
|
// Cortex-M (by printing an error message with instruction address).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
pric_init()
|
pric_init()
|
||||||
machine.UART0.Configure(machine.UARTConfig{})
|
machine.UART0.Configure(machine.UARTConfig{})
|
||||||
|
@ -81,6 +118,8 @@ func putchar(c byte) {
|
||||||
|
|
||||||
const asyncScheduler = false
|
const asyncScheduler = false
|
||||||
|
|
||||||
|
var timerWakeup volatile.Register8
|
||||||
|
|
||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
// Combining the low bits and the high bits yields a time span of over 270
|
// Combining the low bits and the high bits yields a time span of over 270
|
||||||
// years without counter rollover.
|
// years without counter rollover.
|
||||||
|
@ -99,7 +138,16 @@ func ticks() timeUnit {
|
||||||
}
|
}
|
||||||
|
|
||||||
func sleepTicks(d timeUnit) {
|
func sleepTicks(d timeUnit) {
|
||||||
target := ticks() + d
|
target := uint64(ticks() + d)
|
||||||
for ticks() < target {
|
sifive.CLINT.MTIMECMPH.Set(uint32(target >> 32))
|
||||||
|
sifive.CLINT.MTIMECMP.Set(uint32(target))
|
||||||
|
riscv.MIE.SetBits(1 << 7) // MTIE
|
||||||
|
for {
|
||||||
|
if timerWakeup.Get() != 0 {
|
||||||
|
timerWakeup.Set(0)
|
||||||
|
// Disable timer.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
riscv.Asm("wfi")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,10 @@ SECTIONS
|
||||||
{
|
{
|
||||||
.text :
|
.text :
|
||||||
{
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
KEEP(*(.init))
|
KEEP(*(.init))
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.text.handleInterruptASM)
|
||||||
*(.text)
|
*(.text)
|
||||||
*(.text.*)
|
*(.text.*)
|
||||||
*(.rodata)
|
*(.rodata)
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче