all: generate interrupt vector from .svd file

Этот коммит содержится в:
Ayke van Laethem 2018-09-21 14:45:32 +02:00
родитель 3c22f5731c
коммит 505b1f750d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
5 изменённых файлов: 128 добавлений и 9 удалений

1
.gitignore предоставленный
Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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).

Просмотреть файл

@ -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"
} }

Просмотреть файл

@ -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__':