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/*.ld
|
||||
src/device/nrf/*.go
|
||||
src/device/nrf/*.s
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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__':
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче