Skip to content

Commit 2a71aa9

Browse files
aykevldeadprogram
authored andcommitted
targets: refactor flash/gdb target configuration
Instead of specifying explicit commands, most of these commands have been replaced by more specific properties. This is work that will be necessary for an eventual -programmer flag to the compiler, with which it is possible to select which programmer to use to flash or debug a chip. That's not very useful for boards that already include a programmer or bootloader for that purpose, but is very useful for novel boards or single-purpose boards that are not already included in TinyGo.
1 parent 52bac4d commit 2a71aa9

23 files changed

+208
-112
lines changed

main.go

Lines changed: 91 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -403,24 +403,34 @@ func Flash(pkgName, target, port string, config *BuildConfig) error {
403403
// determine the type of file to compile
404404
var fileExt string
405405

406-
switch {
407-
case strings.Contains(spec.Flasher, "{hex}"):
406+
switch spec.FlashMethod {
407+
case "command", "":
408+
switch {
409+
case strings.Contains(spec.FlashCommand, "{hex}"):
410+
fileExt = ".hex"
411+
case strings.Contains(spec.FlashCommand, "{elf}"):
412+
fileExt = ".elf"
413+
case strings.Contains(spec.FlashCommand, "{bin}"):
414+
fileExt = ".bin"
415+
case strings.Contains(spec.FlashCommand, "{uf2}"):
416+
fileExt = ".uf2"
417+
default:
418+
return errors.New("invalid target file - did you forget the {hex} token in the 'flash-command' section?")
419+
}
420+
case "msd":
421+
if spec.FlashFilename == "" {
422+
return errors.New("invalid target file: flash-method was set to \"msd\" but no msd-firmware-name was set")
423+
}
424+
fileExt = filepath.Ext(spec.FlashFilename)
425+
case "openocd":
408426
fileExt = ".hex"
409-
case strings.Contains(spec.Flasher, "{elf}"):
410-
fileExt = ".elf"
411-
case strings.Contains(spec.Flasher, "{bin}"):
412-
fileExt = ".bin"
413-
case strings.Contains(spec.Flasher, "{uf2}"):
414-
fileExt = ".uf2"
427+
case "native":
428+
return errors.New("unknown flash method \"native\" - did you miss a -target flag?")
415429
default:
416-
return errors.New("invalid target file - did you forget the {hex} token in the 'flash' section?")
430+
return errors.New("unknown flash method: " + spec.FlashMethod)
417431
}
418432

419433
return Compile(pkgName, fileExt, spec, config, func(tmppath string) error {
420-
if spec.Flasher == "" {
421-
return errors.New("no flash command specified - did you miss a -target flag?")
422-
}
423-
424434
// do we need port reset to put MCU into bootloader mode?
425435
if spec.PortReset == "true" {
426436
err := touchSerialPortAt1200bps(port)
@@ -432,7 +442,25 @@ func Flash(pkgName, target, port string, config *BuildConfig) error {
432442
}
433443

434444
// this flashing method copies the binary data to a Mass Storage Device (msd)
435-
if spec.FlashMethod == "msd" {
445+
switch spec.FlashMethod {
446+
case "", "command":
447+
// Create the command.
448+
flashCmd := spec.FlashCommand
449+
fileToken := "{" + fileExt[1:] + "}"
450+
flashCmd = strings.Replace(flashCmd, fileToken, tmppath, -1)
451+
flashCmd = strings.Replace(flashCmd, "{port}", port, -1)
452+
453+
// Execute the command.
454+
cmd := exec.Command("/bin/sh", "-c", flashCmd)
455+
cmd.Stdout = os.Stdout
456+
cmd.Stderr = os.Stderr
457+
cmd.Dir = sourceDir()
458+
err := cmd.Run()
459+
if err != nil {
460+
return &commandError{"failed to flash", tmppath, err}
461+
}
462+
return nil
463+
case "msd":
436464
switch fileExt {
437465
case ".uf2":
438466
err := flashUF2UsingMSD(spec.FlashVolume, tmppath)
@@ -449,24 +477,23 @@ func Flash(pkgName, target, port string, config *BuildConfig) error {
449477
default:
450478
return errors.New("mass storage device flashing currently only supports uf2 and hex")
451479
}
480+
case "openocd":
481+
args, err := spec.OpenOCDConfiguration()
482+
if err != nil {
483+
return err
484+
}
485+
args = append(args, "-c", "program "+tmppath+" reset exit")
486+
cmd := exec.Command("openocd", args...)
487+
cmd.Stdout = os.Stdout
488+
cmd.Stderr = os.Stderr
489+
err = cmd.Run()
490+
if err != nil {
491+
return &commandError{"failed to flash", tmppath, err}
492+
}
493+
return nil
494+
default:
495+
return fmt.Errorf("unknown flash method: %s", spec.FlashMethod)
452496
}
453-
454-
// Create the command.
455-
flashCmd := spec.Flasher
456-
fileToken := "{" + fileExt[1:] + "}"
457-
flashCmd = strings.Replace(flashCmd, fileToken, tmppath, -1)
458-
flashCmd = strings.Replace(flashCmd, "{port}", port, -1)
459-
460-
// Execute the command.
461-
cmd := exec.Command("/bin/sh", "-c", flashCmd)
462-
cmd.Stdout = os.Stdout
463-
cmd.Stderr = os.Stderr
464-
cmd.Dir = sourceDir()
465-
err := cmd.Run()
466-
if err != nil {
467-
return &commandError{"failed to flash", tmppath, err}
468-
}
469-
return nil
470497
})
471498
}
472499

@@ -485,9 +512,33 @@ func FlashGDB(pkgName, target, port string, ocdOutput bool, config *BuildConfig)
485512
}
486513

487514
return Compile(pkgName, "", spec, config, func(tmppath string) error {
488-
if len(spec.OCDDaemon) != 0 {
515+
// Find a good way to run GDB.
516+
gdbInterface := spec.FlashMethod
517+
switch gdbInterface {
518+
case "msd", "command", "":
519+
if gdbInterface == "" {
520+
gdbInterface = "command"
521+
}
522+
if spec.OpenOCDInterface != "" && spec.OpenOCDTarget != "" {
523+
gdbInterface = "openocd"
524+
}
525+
}
526+
527+
// Run the GDB server, if necessary.
528+
var gdbCommands []string
529+
switch gdbInterface {
530+
case "native":
531+
// Run GDB directly.
532+
gdbCommands = append(gdbCommands, "run")
533+
case "openocd":
534+
gdbCommands = append(gdbCommands, "target remote :3333", "monitor halt", "load", "monitor reset", "c")
535+
489536
// We need a separate debugging daemon for on-chip debugging.
490-
daemon := exec.Command(spec.OCDDaemon[0], spec.OCDDaemon[1:]...)
537+
args, err := spec.OpenOCDConfiguration()
538+
if err != nil {
539+
return err
540+
}
541+
daemon := exec.Command("openocd", args...)
491542
if ocdOutput {
492543
// Make it clear which output is from the daemon.
493544
w := &ColorWriter{
@@ -512,6 +563,10 @@ func FlashGDB(pkgName, target, port string, ocdOutput bool, config *BuildConfig)
512563
// Maybe we should send a .Kill() after x seconds?
513564
daemon.Wait()
514565
}()
566+
case "msd":
567+
return errors.New("gdb is not supported for drag-and-drop programmable devices")
568+
default:
569+
return fmt.Errorf("gdb is not supported with interface %#v", gdbInterface)
515570
}
516571

517572
// Ignore Ctrl-C, it must be passed on to GDB.
@@ -526,7 +581,7 @@ func FlashGDB(pkgName, target, port string, ocdOutput bool, config *BuildConfig)
526581
// By default: gdb -ex run <binary>
527582
// Exit GDB with Ctrl-D.
528583
params := []string{tmppath}
529-
for _, cmd := range spec.GDBCmds {
584+
for _, cmd := range gdbCommands {
530585
params = append(params, "-ex", cmd)
531586
}
532587
cmd := exec.Command(spec.GDB, params...)
@@ -606,7 +661,7 @@ func flashUF2UsingMSD(volume, tmppath string) error {
606661
return err
607662
}
608663
if d == nil {
609-
return errors.New("unable to locate UF2 device:" + volume)
664+
return errors.New("unable to locate UF2 device: " + volume)
610665
}
611666

612667
return moveFile(tmppath, filepath.Dir(d[0])+"/flash.uf2")
@@ -624,7 +679,7 @@ func flashHexUsingMSD(volume, tmppath string) error {
624679
return err
625680
}
626681
if d == nil {
627-
return errors.New("unable to locate device:" + volume)
682+
return errors.New("unable to locate device: " + volume)
628683
}
629684

630685
return moveFile(tmppath, d[0]+"/flash.hex")

target.go

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,32 @@ var TINYGOROOT string
2626
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.TargetOptions.html
2727
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
2828
type TargetSpec struct {
29-
Inherits []string `json:"inherits"`
30-
Triple string `json:"llvm-target"`
31-
CPU string `json:"cpu"`
32-
Features []string `json:"features"`
33-
GOOS string `json:"goos"`
34-
GOARCH string `json:"goarch"`
35-
BuildTags []string `json:"build-tags"`
36-
GC string `json:"gc"`
37-
Scheduler string `json:"scheduler"`
38-
Compiler string `json:"compiler"`
39-
Linker string `json:"linker"`
40-
RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt)
41-
CFlags []string `json:"cflags"`
42-
LDFlags []string `json:"ldflags"`
43-
ExtraFiles []string `json:"extra-files"`
44-
Emulator []string `json:"emulator"`
45-
Flasher string `json:"flash"`
46-
OCDDaemon []string `json:"ocd-daemon"`
47-
GDB string `json:"gdb"`
48-
GDBCmds []string `json:"gdb-initial-cmds"`
49-
PortReset string `json:"flash-1200-bps-reset"`
50-
FlashMethod string `json:"flash-method"`
51-
FlashVolume string `json:"flash-msd-volume-name"`
29+
Inherits []string `json:"inherits"`
30+
Triple string `json:"llvm-target"`
31+
CPU string `json:"cpu"`
32+
Features []string `json:"features"`
33+
GOOS string `json:"goos"`
34+
GOARCH string `json:"goarch"`
35+
BuildTags []string `json:"build-tags"`
36+
GC string `json:"gc"`
37+
Scheduler string `json:"scheduler"`
38+
Compiler string `json:"compiler"`
39+
Linker string `json:"linker"`
40+
RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt)
41+
CFlags []string `json:"cflags"`
42+
LDFlags []string `json:"ldflags"`
43+
ExtraFiles []string `json:"extra-files"`
44+
Emulator []string `json:"emulator"`
45+
FlashCommand string `json:"flash-command"`
46+
OCDDaemon []string `json:"ocd-daemon"`
47+
GDB string `json:"gdb"`
48+
PortReset string `json:"flash-1200-bps-reset"`
49+
FlashMethod string `json:"flash-method"`
50+
FlashVolume string `json:"msd-volume-name"`
51+
FlashFilename string `json:"msd-firmware-name"`
52+
OpenOCDInterface string `json:"openocd-interface"`
53+
OpenOCDTarget string `json:"openocd-target"`
54+
OpenOCDTransport string `json:"openocd-transport"`
5255
}
5356

5457
// copyProperties copies all properties that are set in spec2 into itself.
@@ -91,18 +94,15 @@ func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) {
9194
if len(spec2.Emulator) != 0 {
9295
spec.Emulator = spec2.Emulator
9396
}
94-
if spec2.Flasher != "" {
95-
spec.Flasher = spec2.Flasher
97+
if spec2.FlashCommand != "" {
98+
spec.FlashCommand = spec2.FlashCommand
9699
}
97100
if len(spec2.OCDDaemon) != 0 {
98101
spec.OCDDaemon = spec2.OCDDaemon
99102
}
100103
if spec2.GDB != "" {
101104
spec.GDB = spec2.GDB
102105
}
103-
if len(spec2.GDBCmds) != 0 {
104-
spec.GDBCmds = spec2.GDBCmds
105-
}
106106
if spec2.PortReset != "" {
107107
spec.PortReset = spec2.PortReset
108108
}
@@ -112,6 +112,18 @@ func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) {
112112
if spec2.FlashVolume != "" {
113113
spec.FlashVolume = spec2.FlashVolume
114114
}
115+
if spec2.FlashFilename != "" {
116+
spec.FlashFilename = spec2.FlashFilename
117+
}
118+
if spec2.OpenOCDInterface != "" {
119+
spec.OpenOCDInterface = spec2.OpenOCDInterface
120+
}
121+
if spec2.OpenOCDTarget != "" {
122+
spec.OpenOCDTarget = spec2.OpenOCDTarget
123+
}
124+
if spec2.OpenOCDTransport != "" {
125+
spec.OpenOCDTransport = spec2.OpenOCDTransport
126+
}
115127
}
116128

117129
// load reads a target specification from the JSON in the given io.Reader. It
@@ -248,9 +260,8 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
248260
Compiler: "clang",
249261
Linker: "cc",
250262
GDB: "gdb",
251-
GDBCmds: []string{"run"},
252263
PortReset: "false",
253-
FlashMethod: "command",
264+
FlashMethod: "native",
254265
}
255266
if goos == "darwin" {
256267
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
@@ -277,6 +288,33 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
277288
return &spec, nil
278289
}
279290

291+
// OpenOCDConfiguration returns a list of command line arguments to OpenOCD.
292+
// This list of command-line arguments is based on the various OpenOCD-related
293+
// flags in the target specification.
294+
func (spec *TargetSpec) OpenOCDConfiguration() (args []string, err error) {
295+
if spec.OpenOCDInterface == "" {
296+
return nil, errors.New("OpenOCD programmer not set")
297+
}
298+
if !regexp.MustCompile("^[\\p{L}0-9_-]+$").MatchString(spec.OpenOCDInterface) {
299+
return nil, fmt.Errorf("OpenOCD programmer has an invalid name: %#v", spec.OpenOCDInterface)
300+
}
301+
if spec.OpenOCDTarget == "" {
302+
return nil, errors.New("OpenOCD chip not set")
303+
}
304+
if !regexp.MustCompile("^[\\p{L}0-9_-]+$").MatchString(spec.OpenOCDTarget) {
305+
return nil, fmt.Errorf("OpenOCD target has an invalid name: %#v", spec.OpenOCDTarget)
306+
}
307+
if spec.OpenOCDTransport != "" && spec.OpenOCDTransport != "swd" {
308+
return nil, fmt.Errorf("unknown OpenOCD transport: %#v", spec.OpenOCDTransport)
309+
}
310+
args = []string{"-f", "interface/" + spec.OpenOCDInterface + ".cfg"}
311+
if spec.OpenOCDTransport != "" {
312+
args = append(args, "-c", "transport select "+spec.OpenOCDTransport)
313+
}
314+
args = append(args, "-f", "target/"+spec.OpenOCDTarget+".cfg")
315+
return args, nil
316+
}
317+
280318
// Return the TINYGOROOT, or exit with an error.
281319
func sourceDir() string {
282320
// Use $TINYGOROOT as root, if available.

targets/arduino-nano33.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"inherits": ["atsamd21g18a"],
33
"build-tags": ["sam", "atsamd21g18a", "arduino_nano33"],
4-
"flash": "bossac -d -i -e -w -v -R --port={port} --offset=0x2000 {bin}",
4+
"flash-command": "bossac -d -i -e -w -v -R --port={port} --offset=0x2000 {bin}",
55
"flash-1200-bps-reset": "true"
66
}

targets/arduino.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515
"targets/avr.S",
1616
"src/device/avr/atmega328p.s"
1717
],
18-
"flash": "avrdude -c arduino -p atmega328p -P {port} -U flash:w:{hex}"
18+
"flash-command": "avrdude -c arduino -p atmega328p -P {port} -U flash:w:{hex}"
1919
}

targets/bluepill.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"extra-files": [
1313
"src/device/stm32/stm32f103xx.s"
1414
],
15-
"flash": "openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c 'program {hex} reset exit'",
16-
"ocd-daemon": ["openocd", "-f", "interface/stlink-v2.cfg", "-f", "target/stm32f1x.cfg"],
17-
"gdb-initial-cmds": ["target remote :3333", "monitor halt", "load", "monitor reset", "c"]
15+
"flash-method": "openocd",
16+
"openocd-interface": "stlink-v2",
17+
"openocd-target": "stm32f1x"
1818
}

targets/circuitplay-express.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"inherits": ["atsamd21g18a"],
33
"build-tags": ["sam", "atsamd21g18a", "circuitplay_express"],
4-
"flash": "{uf2}",
54
"flash-1200-bps-reset": "true",
65
"flash-method": "msd",
7-
"flash-msd-volume-name": "CPLAYBOOT"
6+
"msd-volume-name": "CPLAYBOOT",
7+
"msd-firmware-name": "firmware.uf2"
88
}

targets/digispark.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515
"targets/avr.S",
1616
"src/device/avr/attiny85.s"
1717
],
18-
"flash": "micronucleus --run {hex}"
18+
"flash-command": "micronucleus --run {hex}"
1919
}

targets/feather-m0.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"inherits": ["atsamd21g18a"],
33
"build-tags": ["sam", "atsamd21g18a", "feather_m0"],
4-
"flash": "{uf2}",
54
"flash-1200-bps-reset": "true",
65
"flash-method": "msd",
7-
"flash-msd-volume-name": "FEATHERBOOT"
6+
"msd-volume-name": "FEATHERBOOT",
7+
"msd-firmware-name": "firmware.uf2"
88
}

targets/hifive1b.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"ldflags": [
55
"-T", "targets/hifive1b.ld"
66
],
7-
"flash": "{hex}",
87
"flash-method": "msd",
9-
"flash-msd-volume-name": "HiFive"
8+
"msd-volume-name": "HiFive",
9+
"msd-firmware-name": "firmware.hex"
1010
}

0 commit comments

Comments
 (0)