From 505b1f750de1933501b1924a50110ea3b2b68fd9 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 21 Sep 2018 14:45:32 +0200 Subject: [PATCH] all: generate interrupt vector from .svd file --- .gitignore | 1 + src/runtime/runtime_nrf.go | 41 +++++++++++++++-- targets/arm.ld | 2 + targets/pca10040.json | 2 +- tools/gen-device-svd.py | 91 +++++++++++++++++++++++++++++++++++--- 5 files changed, 128 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 4953b648..ff2563eb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build src/device/avr/*.go src/device/avr/*.ld src/device/nrf/*.go +src/device/nrf/*.s diff --git a/src/runtime/runtime_nrf.go b/src/runtime/runtime_nrf.go index 4cd337c3..41ea1c92 100644 --- a/src/runtime/runtime_nrf.go +++ b/src/runtime/runtime_nrf.go @@ -5,18 +5,53 @@ package runtime import ( "device/arm" "device/nrf" + "unsafe" ) type timeUnit int64 const tickMicros = 1024 * 32 -//go:export _start -func _start() { +//go:linkname systemInit SystemInit +func systemInit() + +//go:export Reset_Handler +func handleReset() { + systemInit() main() } +//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 := uintptr(unsafe.Pointer(&_sbss)) + for ptr != uintptr(unsafe.Pointer(&_ebss)) { + *(*uint32)(unsafe.Pointer(ptr)) = 0 + ptr += 4 + } + + // Initialize .data: global variables initialized from flash. + src := uintptr(unsafe.Pointer(&_sidata)) + dst := uintptr(unsafe.Pointer(&_sdata)) + for dst != uintptr(unsafe.Pointer(&_edata)) { + *(*uint32)(unsafe.Pointer(dst)) = *(*uint32)(unsafe.Pointer(src)) + dst += 4 + src += 4 + } } func postinit() { @@ -119,7 +154,7 @@ func rtc_sleep(ticks uint32) { } //go:export RTC0_IRQHandler -func RTC0_IRQHandler() { +func handleRTC0() { nrf.RTC0.INTENCLR = nrf.RTC0_INTENSET_COMPARE0_Msk nrf.RTC0.EVENTS_COMPARE[0] = 0 rtc_wakeup = true diff --git a/targets/arm.ld b/targets/arm.ld index 76a64f1f..dca80f7a 100644 --- a/targets/arm.ld +++ b/targets/arm.ld @@ -34,6 +34,8 @@ SECTIONS __StackTop = .; } >RAM + _sidata = LOADADDR(.data); + /* This is the initialized data section The program executes knowing that the data is in the RAM but the loader puts the initial values in the FLASH (inidata). diff --git a/targets/pca10040.json b/targets/pca10040.json index fc916e4e..17d03769 100644 --- a/targets/pca10040.json +++ b/targets/pca10040.json @@ -2,7 +2,7 @@ "llvm-target": "armv7em-none-eabi", "build-tags": ["nrf", "nrf52", "nrf52832", "js", "wasm"], "linker": "arm-none-eabi-gcc", - "pre-link-args": ["-nostdlib", "-nostartfiles", "-mcpu=cortex-m4", "-mthumb", "-T", "targets/arm.ld", "-Wl,--gc-sections", "-fno-exceptions", "-fno-unwind-tables", "-ffunction-sections", "-fdata-sections", "-Os", "-DNRF52832_XXAA", "-D__STARTUP_CLEAR_BSS", "-Ilib/CMSIS/CMSIS/Include", "lib/nrfx/mdk/gcc_startup_nrf52.S", "lib/nrfx/mdk/system_nrf52.c"], + "pre-link-args": ["-nostdlib", "-nostartfiles", "-mcpu=cortex-m4", "-mthumb", "-T", "targets/arm.ld", "-Wl,--gc-sections", "-fno-exceptions", "-fno-unwind-tables", "-ffunction-sections", "-fdata-sections", "-Os", "-DNRF52832_XXAA", "-Ilib/CMSIS/CMSIS/Include", "lib/nrfx/mdk/system_nrf52.c", "src/device/nrf/nrf52.s"], "objcopy": "arm-none-eabi-objcopy", "flash": "nrfjprog -f nrf52 --sectorerase --program {hex} --reset" } diff --git a/tools/gen-device-svd.py b/tools/gen-device-svd.py index 3103ad62..b2e86ebb 100755 --- a/tools/gen-device-svd.py +++ b/tools/gen-device-svd.py @@ -35,7 +35,7 @@ def readSVD(path): xml = minidom.parse(path) root = xml.getElementsByTagName('device')[0] deviceName = getText(root.getElementsByTagName('name')[0]) - deviceDescription = getText(root.getElementsByTagName('description')[0]) + deviceDescription = getText(root.getElementsByTagName('description')[0]).strip() licenseText = formatText(getText(root.getElementsByTagName('licenseText')[0])) cpu = root.getElementsByTagName('cpu')[0] cpuName = getText(cpu.getElementsByTagName('name')[0]) @@ -87,14 +87,16 @@ def readSVD(path): else: continue - device.interrupts = interrupts.values() # TODO: sort by index + device.interrupts = sorted(interrupts.values(), key=lambda v: v['index']) + licenseBlock = '// ' + licenseText.replace('\n', '\n// ') + licenseBlock = '\n'.join(map(str.rstrip, licenseBlock.split('\n'))) # strip trailing whitespace device.metadata = { 'file': os.path.basename(path), 'descriptorSource': 'https://github.com/NordicSemiconductor/nrfx/tree/master/mdk', 'name': deviceName, 'nameLower': deviceName.lower(), 'description': deviceDescription, - 'licenseBlock': '\n// ' + licenseText.replace('\n', '\n// '), + 'licenseBlock': licenseBlock, 'arch': ARM_ARCHS[cpuName], 'family': getText(root.getElementsByTagName('series')[0]), } @@ -164,7 +166,8 @@ def writeGo(outdir, device): // +build {pkgName},{nameLower} // {description} -// {licenseBlock} +// +{licenseBlock} package {pkgName} import "unsafe" @@ -183,7 +186,7 @@ const ( ) '''.format(pkgName=pkgName, **device.metadata)) - out.write('\n// Interrupts\nconst (\n') + out.write('\n// Interrupt numbers\nconst (\n') for intr in device.interrupts: out.write('\tIRQ_{name} = {index} // {description}\n'.format(**intr)) intrMax = max(map(lambda intr: intr['index'], device.interrupts)) @@ -244,11 +247,89 @@ const ( out.write(')\n') +def writeAsm(outdir, device): + # The interrupt vector, which is hard to write directly in Go. + out = open(outdir + '/' + device.metadata['nameLower'] + '.s', 'w') + out.write('''\ +// Automatically generated file. DO NOT EDIT. +// Generated by gen-device.py from {file}, see {descriptorSource} + +// {description} +// +{licenseBlock} + +.syntax unified + +// This is the default handler for interrupts, if triggered but not defined. +.section .text.Default_Handler +.global Default_Handler +.type Default_Handler, %function +Default_Handler: + wfe + b Default_Handler + +// Avoid the need for repeated .weak and .set instructions. +.macro IRQ handler +.weak \\handler +.set \\handler, Default_Handler +.endm + +.section .isr_vector +.global __isr_vector + // Interrupt vector as defined by Cortex-M, starting with the stack top. + // On reset, SP is initialized with *0x0 and PC is loaded with *0x4, loading + // __StackTop and Reset_Handler. + .long __StackTop + .long Reset_Handler + .long NMI_Handler + .long HardFault_Handler + .long MemoryManagement_Handler + .long BusFault_Handler + .long UsageFault_Handler + .long 0 + .long 0 + .long 0 + .long 0 + .long SVC_Handler + .long DebugMon_Handler + .long 0 + .long PendSV_Handler + .long SysTick_Handler + + // Extra interrupts for peripherals defined by the hardware vendor. +'''.format(**device.metadata)) + num = 0 + for intr in device.interrupts: + if intr['index'] < num: + raise ValueError('interrupt numbers are not sorted or contain a duplicate') + while intr['index'] > num: + out.write(' .long 0\n') + num += 1 + num += 1 + out.write(' .long {name}_IRQHandler\n'.format(**intr)) + + out.write(''' + // Define default implementations for interrupts, redirecting to + // Default_Handler when not implemented. + IRQ NMI_Handler + IRQ HardFault_Handler + IRQ MemoryManagement_Handler + IRQ BusFault_Handler + IRQ UsageFault_Handler + IRQ SVC_Handler + IRQ DebugMon_Handler + IRQ PendSV_Handler + IRQ SysTick_Handler +''') + for intr in device.interrupts: + out.write(' IRQ {name}_IRQHandler\n'.format(**intr)) + def generate(indir, outdir): for filepath in sorted(glob(indir + '/*.svd')): print(filepath) device = readSVD(filepath) writeGo(outdir, device) + writeAsm(outdir, device) if __name__ == '__main__':