mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-03 18:47:47 +00:00
a04db67ea9
See the following bug: https://bugs.llvm.org/show_bug.cgi?id=42881 I think this is a bug in LLVM, but the code in question wasn't the best code anyway. By fixing this, about 16 bytes of code are saved on ARM chips (and much more on AVR).
112 lines
2.8 KiB
Go
112 lines
2.8 KiB
Go
// +build cortexm
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"device/arm"
|
|
"unsafe"
|
|
)
|
|
|
|
//go:extern _sbss
|
|
var _sbss unsafe.Pointer
|
|
|
|
//go:extern _ebss
|
|
var _ebss unsafe.Pointer
|
|
|
|
//go:extern _sdata
|
|
var _sdata unsafe.Pointer
|
|
|
|
//go:extern _sidata
|
|
var _sidata unsafe.Pointer
|
|
|
|
//go:extern _edata
|
|
var _edata unsafe.Pointer
|
|
|
|
func preinit() {
|
|
// Initialize .bss: zero-initialized global variables.
|
|
ptr := unsafe.Pointer(&_sbss)
|
|
for ptr != unsafe.Pointer(&_ebss) {
|
|
*(*uint32)(ptr) = 0
|
|
ptr = unsafe.Pointer(uintptr(ptr) + 4)
|
|
}
|
|
|
|
// Initialize .data: global variables initialized from flash.
|
|
src := unsafe.Pointer(&_sidata)
|
|
dst := unsafe.Pointer(&_sdata)
|
|
for dst != unsafe.Pointer(&_edata) {
|
|
*(*uint32)(dst) = *(*uint32)(src)
|
|
dst = unsafe.Pointer(uintptr(dst) + 4)
|
|
src = unsafe.Pointer(uintptr(src) + 4)
|
|
}
|
|
}
|
|
|
|
func abort() {
|
|
// disable all interrupts
|
|
arm.DisableInterrupts()
|
|
|
|
// lock up forever
|
|
for {
|
|
arm.Asm("wfi")
|
|
}
|
|
}
|
|
|
|
// The stack layout at the moment an interrupt occurs.
|
|
// Registers can be accessed if the stack pointer is cast to a pointer to this
|
|
// struct.
|
|
type interruptStack struct {
|
|
R0 uintptr
|
|
R1 uintptr
|
|
R2 uintptr
|
|
R3 uintptr
|
|
R12 uintptr
|
|
LR uintptr
|
|
PC uintptr
|
|
PSR uintptr
|
|
}
|
|
|
|
// This function is called at HardFault.
|
|
// Before this function is called, the stack pointer is reset to the initial
|
|
// stack pointer (loaded from addres 0x0) and the previous stack pointer is
|
|
// passed as an argument to this function. This allows for easy inspection of
|
|
// the stack the moment a HardFault occurs, but it means that the stack will be
|
|
// corrupted by this function and thus this handler must not attempt to recover.
|
|
//
|
|
// For details, see:
|
|
// https://community.arm.com/developer/ip-products/system/f/embedded-forum/3257/debugging-a-cortex-m0-hard-fault
|
|
// https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
|
|
//go:export handleHardFault
|
|
func handleHardFault(sp *interruptStack) {
|
|
print("fatal error: ")
|
|
if uintptr(unsafe.Pointer(sp)) < 0x20000000 {
|
|
print("stack overflow")
|
|
} else {
|
|
// TODO: try to find the cause of the hard fault. Especially on
|
|
// Cortex-M3 and higher it is possible to find more detailed information
|
|
// in special status registers.
|
|
print("HardFault")
|
|
}
|
|
print(" with sp=", sp)
|
|
if uintptr(unsafe.Pointer(&sp.PC)) >= 0x20000000 {
|
|
// Only print the PC if it points into memory.
|
|
// It may not point into memory during a stack overflow, so check that
|
|
// first before accessing the stack.
|
|
print(" pc=", sp.PC)
|
|
}
|
|
println()
|
|
abort()
|
|
}
|
|
|
|
// Implement memset for LLVM and compiler-rt.
|
|
//go:export memset
|
|
func libc_memset(ptr unsafe.Pointer, c byte, size uintptr) {
|
|
for i := uintptr(0); i < size; i++ {
|
|
*(*byte)(unsafe.Pointer(uintptr(ptr) + i)) = c
|
|
}
|
|
}
|
|
|
|
// Implement memmove for LLVM and compiler-rt.
|
|
//go:export memmove
|
|
func libc_memmove(dst, src unsafe.Pointer, size uintptr) {
|
|
memmove(dst, src, size)
|
|
}
|