mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-07 12:33:42 +00:00
maixbit (uart): serial is working with echo example
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// +build tinygo.riscv
|
||||
// +build tinygo.riscv32
|
||||
|
||||
package runtime
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
// +build tinygo.riscv64
|
||||
|
||||
package runtime
|
||||
|
||||
import "device/riscv"
|
||||
|
||||
const GOARCH = "arm64" // riscv pretends to be arm
|
||||
|
||||
// The bitness of the CPU (e.g. 8, 32, 64).
|
||||
const TargetBits = 64
|
||||
|
||||
// Align on word boundary.
|
||||
func align(ptr uintptr) uintptr {
|
||||
return (ptr + 7) &^ 7
|
||||
}
|
||||
|
||||
func getCurrentStackPointer() uintptr {
|
||||
return riscv.AsmFull("mv {}, sp", nil)
|
||||
}
|
||||
|
||||
// Documentation:
|
||||
// * https://llvm.org/docs/Atomics.html
|
||||
// * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html
|
||||
//
|
||||
// In the case of RISC-V, some operations may be implemented with libcalls if
|
||||
// the operation is too big to be handled by assembly. Officially, these calls
|
||||
// should be implemented with a lock-free algorithm but as (as of this time) all
|
||||
// supported RISC-V chips have a single hart, we can simply disable interrupts
|
||||
// to get the same behavior.
|
||||
|
||||
//export __atomic_load_8
|
||||
func __atomic_load_8(ptr *uint64, ordering int32) uint64 {
|
||||
mask := riscv.DisableInterrupts()
|
||||
value := *ptr
|
||||
riscv.EnableInterrupts(mask)
|
||||
return value
|
||||
}
|
||||
|
||||
//export __atomic_store_8
|
||||
func __atomic_store_8(ptr *uint64, value uint64, ordering int32) {
|
||||
mask := riscv.DisableInterrupts()
|
||||
*ptr = value
|
||||
riscv.EnableInterrupts(mask)
|
||||
}
|
||||
|
||||
//export __atomic_exchange_8
|
||||
func __atomic_exchange_8(ptr *uint64, value uint64, ordering int32) uint64 {
|
||||
mask := riscv.DisableInterrupts()
|
||||
oldValue := *ptr
|
||||
*ptr = value
|
||||
riscv.EnableInterrupts(mask)
|
||||
return oldValue
|
||||
}
|
||||
|
||||
//export __atomic_compare_exchange_8
|
||||
func __atomic_compare_exchange_8(ptr, expected *uint64, desired uint64, success_ordering, failure_ordering int32) bool {
|
||||
mask := riscv.DisableInterrupts()
|
||||
oldValue := *ptr
|
||||
success := oldValue == *expected
|
||||
if success {
|
||||
*ptr = desired
|
||||
} else {
|
||||
*expected = oldValue
|
||||
}
|
||||
riscv.EnableInterrupts(mask)
|
||||
return success
|
||||
}
|
||||
|
||||
//export __atomic_fetch_add_8
|
||||
func __atomic_fetch_add_8(ptr *uint64, value uint64, ordering int32) uint64 {
|
||||
mask := riscv.DisableInterrupts()
|
||||
oldValue := *ptr
|
||||
*ptr = oldValue + value
|
||||
riscv.EnableInterrupts(mask)
|
||||
return oldValue
|
||||
}
|
||||
|
||||
// The safest thing to do here would just be to disable interrupts for
|
||||
// procPin/procUnpin. Note that a global variable is safe in this case, as any
|
||||
// access to procPinnedMask will happen with interrupts disabled.
|
||||
|
||||
var procPinnedMask uintptr
|
||||
|
||||
//go:linkname procPin sync/atomic.runtime_procPin
|
||||
func procPin() {
|
||||
procPinnedMask = riscv.DisableInterrupts()
|
||||
}
|
||||
|
||||
//go:linkname procUnpin sync/atomic.runtime_procUnpin
|
||||
func procUnpin() {
|
||||
riscv.EnableInterrupts(procPinnedMask)
|
||||
}
|
||||
+24
-14
@@ -20,15 +20,11 @@ func postinit() {}
|
||||
//export main
|
||||
func main() {
|
||||
|
||||
// Only use one core for the moment
|
||||
if riscv.MHARTID.Get() == 0 {
|
||||
// Zero the PLIC enable bits at startup.
|
||||
for i := 0; i < ((kendryte.IRQ_max + 32) / 32); i++ {
|
||||
kendryte.PLIC.TARGET_ENABLES[0].ENABLE[i].Set(0) // core 0
|
||||
}
|
||||
// Both harts should disable all interrupts on startup.
|
||||
initPLIC()
|
||||
|
||||
// Zero the PLIC threshold bits to allow all interrupts.
|
||||
kendryte.PLIC.TARGETS[0].THRESHOLD.Set(0)
|
||||
// Only use one hart for the moment.
|
||||
if riscv.MHARTID.Get() == 0 {
|
||||
|
||||
// Reset all interrupt source priorities to zero.
|
||||
for i := 0; i < kendryte.IRQ_max; i++ {
|
||||
@@ -56,14 +52,26 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func initPLIC() {
|
||||
hartId := riscv.MHARTID.Get()
|
||||
|
||||
// Zero the PLIC enable bits at startup.
|
||||
for i := 0; i < ((kendryte.IRQ_max + 32) / 32); i++ {
|
||||
kendryte.PLIC.TARGET_ENABLES[hartId].ENABLE[i].Set(0)
|
||||
}
|
||||
|
||||
// Zero the PLIC threshold bits to allow all interrupts.
|
||||
kendryte.PLIC.TARGETS[hartId].THRESHOLD.Set(0)
|
||||
}
|
||||
|
||||
//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 {
|
||||
code := uint64(cause &^ (1 << 63))
|
||||
if cause&(1<<63) != 0 {
|
||||
// Topmost bit is set, which means that it is an interrupt.
|
||||
switch code {
|
||||
case 7: // Machine timer interrupt
|
||||
@@ -73,12 +81,14 @@ func handleInterrupt() {
|
||||
// this interrupt returns.
|
||||
riscv.MIE.ClearBits(1 << 7) // MTIE bit
|
||||
case 11: // Machine external interrupt
|
||||
hartId := riscv.MHARTID.Get()
|
||||
|
||||
// Claim this interrupt.
|
||||
id := kendryte.PLIC.TARGETS[0].CLAIM.Get()
|
||||
id := kendryte.PLIC.TARGETS[hartId].CLAIM.Get()
|
||||
// Call the interrupt handler, if any is registered for this ID.
|
||||
callInterruptHandler(int(0))
|
||||
callInterruptHandler(int(id))
|
||||
// Complete this interrupt.
|
||||
kendryte.PLIC.TARGETS[0].CLAIM.Set(id)
|
||||
kendryte.PLIC.TARGETS[hartId].CLAIM.Set(id)
|
||||
}
|
||||
} else {
|
||||
// Topmost bit is clear, so it is an exception of some sort.
|
||||
@@ -133,7 +143,7 @@ func sleepTicks(d timeUnit) {
|
||||
// handleException is called from the interrupt handler for any exception.
|
||||
// Exceptions can be things like illegal instructions, invalid memory
|
||||
// read/write, and similar issues.
|
||||
func handleException(code uint) {
|
||||
func handleException(code uint64) {
|
||||
// For a list of exception codes, see:
|
||||
// https://content.riscv.org/wp-content/uploads/2019/08/riscv-privileged-20190608-1.pdf#page=49
|
||||
print("fatal error: exception with mcause=")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build tinygo.riscv
|
||||
// +build tinygo.riscv32
|
||||
|
||||
package runtime
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// +build tinygo.riscv64
|
||||
|
||||
package runtime
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//go:extern _sbss
|
||||
var _sbss [0]byte
|
||||
|
||||
//go:extern _ebss
|
||||
var _ebss [0]byte
|
||||
|
||||
//go:extern _sdata
|
||||
var _sdata [0]byte
|
||||
|
||||
//go:extern _sidata
|
||||
var _sidata [0]byte
|
||||
|
||||
//go:extern _edata
|
||||
var _edata [0]byte
|
||||
|
||||
func preinit() {
|
||||
// Initialize .bss: zero-initialized global variables.
|
||||
ptr := unsafe.Pointer(&_sbss)
|
||||
for ptr != unsafe.Pointer(&_ebss) {
|
||||
*(*uint64)(ptr) = 0
|
||||
ptr = unsafe.Pointer(uintptr(ptr) + 8)
|
||||
}
|
||||
|
||||
// Initialize .data: global variables initialized from flash.
|
||||
src := unsafe.Pointer(&_sidata)
|
||||
dst := unsafe.Pointer(&_sdata)
|
||||
for dst != unsafe.Pointer(&_edata) {
|
||||
*(*uint64)(dst) = *(*uint64)(src)
|
||||
dst = unsafe.Pointer(uintptr(dst) + 8)
|
||||
src = unsafe.Pointer(uintptr(src) + 8)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
.section .text.tinygo_scanCurrentStack
|
||||
.global tinygo_scanCurrentStack
|
||||
.type tinygo_scanCurrentStack, %function
|
||||
tinygo_scanCurrentStack:
|
||||
// Push callee-saved registers onto the stack.
|
||||
addi sp, sp, -128
|
||||
sd ra, 120(sp)
|
||||
sd s11, 112(sp)
|
||||
sd s10, 104(sp)
|
||||
sd s9, 96(sp)
|
||||
sd s8, 88(sp)
|
||||
sd s7, 80(sp)
|
||||
sd s6, 72(sp)
|
||||
sd s5, 64(sp)
|
||||
sd s4, 56(sp)
|
||||
sd s3, 48(sp)
|
||||
sd s2, 40(sp)
|
||||
sd s1, 32(sp)
|
||||
sd s0, 24(sp)
|
||||
|
||||
// Scan the stack.
|
||||
mv a0, sp
|
||||
call tinygo_scanstack
|
||||
|
||||
// Restore return address.
|
||||
ld ra, 60(sp)
|
||||
|
||||
// Restore stack state.
|
||||
addi sp, sp, 128
|
||||
|
||||
// Return to the caller.
|
||||
ret
|
||||
Reference in New Issue
Block a user