Skip to content

Commit b963831

Browse files
committed
avr: automatically generate interrupt vectors
1 parent 3850530 commit b963831

File tree

5 files changed

+61
-15
lines changed

5 files changed

+61
-15
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ build
22
docs/_build
33
src/device/avr/*.go
44
src/device/avr/*.ld
5+
src/device/avr/*.s
56
src/device/nrf/*.go
67
src/device/nrf/*.s
78
src/device/stm32/*.go

targets/arduino.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"llvm-target": "avr-atmel-none",
3-
"build-tags": ["arduino", "atmega328p", "atmega", "avr8", "avr", "js", "wasm"],
3+
"build-tags": ["arduino", "atmega328p", "atmega", "avr5", "avr", "js", "wasm"],
44
"linker": "avr-gcc",
5-
"pre-link-args": ["-nostartfiles", "-T", "targets/avr.ld", "-Wl,--gc-sections", "targets/avr.S"],
5+
"pre-link-args": ["-nostartfiles", "-mmcu=avr5", "-T", "targets/avr.ld", "-Wl,--gc-sections", "targets/avr.S", "src/device/avr/atmega328p.s"],
66
"objcopy": "avr-objcopy",
77
"flash": "avrdude -c arduino -p atmega328p -P {port} -U flash:w:{hex}"
88
}

targets/avr.S

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
.section .isr
2-
isr:
3-
rjmp reset
4-
5-
.org 0x18 ; WDT
6-
rjmp wdt
1+
; This file provides common code across AVRs that cannot be implemented directly
2+
; in Go.
3+
; The reset vector is device-specific and is generated by tools/gen-device-avr.py.
74

85
; Startup code
9-
.section .reset
10-
.org 26
11-
reset:
6+
.section .text.__vector_RESET
7+
.global __vector_RESET
8+
__vector_RESET:
129
clr r1 ; r1 is expected to be 0 by the C calling convention
1310

1411
; Set up the stack pointer.
@@ -41,10 +38,21 @@ init_data_end:
4138
; need to jump.
4239

4340

41+
; This is the default handler for interrupts, if triggered but not defined.
42+
; Sleep inside so that an accidentally triggered interrupt won't drain the
43+
; battery of a battery-powered device.
44+
.section .text.__vector_default
45+
.global __vector_default
46+
__vector_default:
47+
sleep
48+
rjmp __vector_default
49+
50+
4451
; The only thing this WDT handler really does is disable itself, to get out of
4552
; sleep mode.
46-
.section .text.wdt
47-
wdt:
53+
.section .text.__vector_WDT
54+
.global __vector_WDT
55+
__vector_WDT:
4856
push r16
4957

5058
clr r16

targets/avr.ld

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ SECTIONS
1212
{
1313
.text :
1414
{
15-
KEEP(*(.isr))
16-
KEEP(*(.reset))
15+
KEEP(*(.vectors))
16+
KEEP(*(.text.__vector_RESET))
1717
KEEP(*(.text.main)) /* main must follow the reset handler */
1818
*(.text.*)
1919
*(.rodata)

tools/gen-device-avr.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,42 @@ def writeGo(outdir, device):
201201
out.write('\n')
202202
out.write(')\n')
203203

204+
def writeAsm(outdir, device):
205+
# The interrupt vector, which is hard to write directly in Go.
206+
out = open(outdir + '/' + device.metadata['nameLower'] + '.s', 'w')
207+
out.write('''\
208+
; Automatically generated file. DO NOT EDIT.
209+
; Generated by gen-device-avr.py from {file}, see {descriptorSource}
210+
211+
; Avoid the need for repeated .weak and .set instructions.
212+
.macro IRQ handler
213+
.weak \\handler
214+
.set \\handler, __vector_default
215+
.endm
216+
217+
; The interrupt vector of this device. Must be placed at address 0 by the linker.
218+
.section .vectors
219+
.global __vectors
220+
'''.format(**device.metadata))
221+
num = 0
222+
for intr in device.interrupts:
223+
if intr['index'] < num:
224+
# Some devices have duplicate interrupts, probably for historical
225+
# reasons.
226+
continue
227+
while intr['index'] > num:
228+
out.write(' jmp __vector_default\n')
229+
num += 1
230+
num += 1
231+
out.write(' jmp __vector_{name}\n'.format(**intr))
232+
233+
out.write('''
234+
; Define default implementations for interrupts, redirecting to
235+
; __vector_default when not implemented.
236+
''')
237+
for intr in device.interrupts:
238+
out.write(' IRQ __vector_{name}\n'.format(**intr))
239+
204240
def writeLD(outdir, device):
205241
# Variables for the linker script.
206242
out = open(outdir + '/' + device.metadata['nameLower'] + '.ld', 'w')
@@ -220,6 +256,7 @@ def generate(indir, outdir):
220256
print(filepath)
221257
device = readATDF(filepath)
222258
writeGo(outdir, device)
259+
writeAsm(outdir, device)
223260
writeLD(outdir, device)
224261

225262

0 commit comments

Comments
 (0)