all: generate interrupt vector from .svd file
Этот коммит содержится в:
родитель
3c22f5731c
коммит
505b1f750d
5 изменённых файлов: 128 добавлений и 9 удалений
1
.gitignore
предоставленный
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__':
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче