all: generate interrupt vector from .svd file

This commit is contained in:
Ayke van Laethem
2018-09-21 14:45:32 +02:00
parent 3c22f5731c
commit 505b1f750d
5 changed files with 128 additions and 9 deletions
+1
View File
@@ -2,3 +2,4 @@ build
src/device/avr/*.go src/device/avr/*.go
src/device/avr/*.ld src/device/avr/*.ld
src/device/nrf/*.go src/device/nrf/*.go
src/device/nrf/*.s
+38 -3
View File
@@ -5,18 +5,53 @@ package runtime
import ( import (
"device/arm" "device/arm"
"device/nrf" "device/nrf"
"unsafe"
) )
type timeUnit int64 type timeUnit int64
const tickMicros = 1024 * 32 const tickMicros = 1024 * 32
//go:export _start //go:linkname systemInit SystemInit
func _start() { func systemInit()
//go:export Reset_Handler
func handleReset() {
systemInit()
main() 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() { 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() { func postinit() {
@@ -119,7 +154,7 @@ func rtc_sleep(ticks uint32) {
} }
//go:export RTC0_IRQHandler //go:export RTC0_IRQHandler
func RTC0_IRQHandler() { func handleRTC0() {
nrf.RTC0.INTENCLR = nrf.RTC0_INTENSET_COMPARE0_Msk nrf.RTC0.INTENCLR = nrf.RTC0_INTENSET_COMPARE0_Msk
nrf.RTC0.EVENTS_COMPARE[0] = 0 nrf.RTC0.EVENTS_COMPARE[0] = 0
rtc_wakeup = true rtc_wakeup = true
+2
View File
@@ -34,6 +34,8 @@ SECTIONS
__StackTop = .; __StackTop = .;
} >RAM } >RAM
_sidata = LOADADDR(.data);
/* This is the initialized data section /* This is the initialized data section
The program executes knowing that the data is in the RAM The program executes knowing that the data is in the RAM
but the loader puts the initial values in the FLASH (inidata). but the loader puts the initial values in the FLASH (inidata).
+1 -1
View File
@@ -2,7 +2,7 @@
"llvm-target": "armv7em-none-eabi", "llvm-target": "armv7em-none-eabi",
"build-tags": ["nrf", "nrf52", "nrf52832", "js", "wasm"], "build-tags": ["nrf", "nrf52", "nrf52832", "js", "wasm"],
"linker": "arm-none-eabi-gcc", "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", "objcopy": "arm-none-eabi-objcopy",
"flash": "nrfjprog -f nrf52 --sectorerase --program {hex} --reset" "flash": "nrfjprog -f nrf52 --sectorerase --program {hex} --reset"
} }
+86 -5
View File
@@ -35,7 +35,7 @@ def readSVD(path):
xml = minidom.parse(path) xml = minidom.parse(path)
root = xml.getElementsByTagName('device')[0] root = xml.getElementsByTagName('device')[0]
deviceName = getText(root.getElementsByTagName('name')[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])) licenseText = formatText(getText(root.getElementsByTagName('licenseText')[0]))
cpu = root.getElementsByTagName('cpu')[0] cpu = root.getElementsByTagName('cpu')[0]
cpuName = getText(cpu.getElementsByTagName('name')[0]) cpuName = getText(cpu.getElementsByTagName('name')[0])
@@ -87,14 +87,16 @@ def readSVD(path):
else: else:
continue 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 = { device.metadata = {
'file': os.path.basename(path), 'file': os.path.basename(path),
'descriptorSource': 'https://github.com/NordicSemiconductor/nrfx/tree/master/mdk', 'descriptorSource': 'https://github.com/NordicSemiconductor/nrfx/tree/master/mdk',
'name': deviceName, 'name': deviceName,
'nameLower': deviceName.lower(), 'nameLower': deviceName.lower(),
'description': deviceDescription, 'description': deviceDescription,
'licenseBlock': '\n// ' + licenseText.replace('\n', '\n// '), 'licenseBlock': licenseBlock,
'arch': ARM_ARCHS[cpuName], 'arch': ARM_ARCHS[cpuName],
'family': getText(root.getElementsByTagName('series')[0]), 'family': getText(root.getElementsByTagName('series')[0]),
} }
@@ -164,7 +166,8 @@ def writeGo(outdir, device):
// +build {pkgName},{nameLower} // +build {pkgName},{nameLower}
// {description} // {description}
// {licenseBlock} //
{licenseBlock}
package {pkgName} package {pkgName}
import "unsafe" import "unsafe"
@@ -183,7 +186,7 @@ const (
) )
'''.format(pkgName=pkgName, **device.metadata)) '''.format(pkgName=pkgName, **device.metadata))
out.write('\n// Interrupts\nconst (\n') out.write('\n// Interrupt numbers\nconst (\n')
for intr in device.interrupts: for intr in device.interrupts:
out.write('\tIRQ_{name} = {index} // {description}\n'.format(**intr)) out.write('\tIRQ_{name} = {index} // {description}\n'.format(**intr))
intrMax = max(map(lambda intr: intr['index'], device.interrupts)) intrMax = max(map(lambda intr: intr['index'], device.interrupts))
@@ -244,11 +247,89 @@ const (
out.write(')\n') 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): def generate(indir, outdir):
for filepath in sorted(glob(indir + '/*.svd')): for filepath in sorted(glob(indir + '/*.svd')):
print(filepath) print(filepath)
device = readSVD(filepath) device = readSVD(filepath)
writeGo(outdir, device) writeGo(outdir, device)
writeAsm(outdir, device)
if __name__ == '__main__': if __name__ == '__main__':