Skip to content

Commit 8568d4f

Browse files
aykevldeadprogram
authored andcommitted
esp32: add support for running and debuggin using qemu-esp32
1 parent bd56636 commit 8568d4f

File tree

5 files changed

+57
-9
lines changed

5 files changed

+57
-9
lines changed

builder/build.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,14 @@ import (
3737
// BuildResult is the output of a build. This includes the binary itself and
3838
// some other metadata that is obtained while building the binary.
3939
type BuildResult struct {
40+
// The executable directly from the linker, usually including debug
41+
// information. Used for GDB for example.
42+
Executable string
43+
4044
// A path to the output binary. It will be removed after Build returns, so
4145
// if it should be kept it must be copied or moved away.
46+
// It is often the same as Executable, but differs if the output format is
47+
// .hex for example (instead of the usual ELF).
4248
Binary string
4349

4450
// The directory of the main package. This is useful for testing as the test
@@ -835,7 +841,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
835841
if err != nil {
836842
return err
837843
}
838-
case "esp32", "esp32c3", "esp8266":
844+
case "esp32", "esp32-img", "esp32c3", "esp8266":
839845
// Special format for the ESP family of chips (parsed by the ROM
840846
// bootloader).
841847
tmppath = filepath.Join(dir, "main"+outext)
@@ -867,6 +873,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
867873
}
868874

869875
return action(BuildResult{
876+
Executable: executable,
870877
Binary: tmppath,
871878
MainDir: lprogram.MainPkg().Dir,
872879
ModuleRoot: moduleroot,

builder/esp.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"fmt"
1616
"io/ioutil"
1717
"sort"
18+
"strings"
1819
)
1920

2021
type espImageSegment struct {
@@ -78,15 +79,31 @@ func makeESPFirmareImage(infile, outfile, format string) error {
7879
// An added benefit is that we don't need to check for errors all the time.
7980
outf := &bytes.Buffer{}
8081

82+
// Separate esp32 and esp32-img. The -img suffix indicates we should make an
83+
// image, not just a binary to be flashed at 0x1000 for example.
84+
chip := format
85+
makeImage := false
86+
if strings.HasSuffix(format, "-img") {
87+
makeImage = true
88+
chip = format[:len(format)-len("-img")]
89+
}
90+
91+
if makeImage {
92+
// The bootloader starts at 0x1000, or 4096.
93+
// TinyGo doesn't use a separate bootloader and runs the entire
94+
// application in the bootloader location.
95+
outf.Write(make([]byte, 4096))
96+
}
97+
8198
// Chip IDs. Source:
8299
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L22
83100
chip_id := map[string]uint16{
84101
"esp32": 0x0000,
85102
"esp32c3": 0x0005,
86-
}[format]
103+
}[chip]
87104

88105
// Image header.
89-
switch format {
106+
switch chip {
90107
case "esp32", "esp32c3":
91108
// Header format:
92109
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
@@ -155,12 +172,22 @@ func makeESPFirmareImage(infile, outfile, format string) error {
155172
outf.Write(make([]byte, 15-outf.Len()%16))
156173
outf.WriteByte(checksum)
157174

158-
if format != "esp8266" {
175+
if chip != "esp8266" {
159176
// SHA256 hash (to protect against image corruption, not for security).
160177
hash := sha256.Sum256(outf.Bytes())
161178
outf.Write(hash[:])
162179
}
163180

181+
// QEMU (or more precisely, qemu-system-xtensa from Espressif) expects the
182+
// image to be a certain size.
183+
if makeImage {
184+
// Use a default image size of 4MB.
185+
grow := 4096*1024 - outf.Len()
186+
if grow > 0 {
187+
outf.Write(make([]byte, grow))
188+
}
189+
}
190+
164191
// Write the image to the output file.
165192
return ioutil.WriteFile(outfile, outf.Bytes(), 0666)
166193
}

compileopts/config.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,13 @@ func (c *Config) BinaryFormat(ext string) string {
395395
return c.Target.BinaryFormat
396396
}
397397
return "bin"
398+
case ".img":
399+
// Image file. Only defined for the ESP32 at the moment, where it is a
400+
// full (runnable) image that can be used in the Espressif QEMU fork.
401+
if c.Target.BinaryFormat != "" {
402+
return c.Target.BinaryFormat + "-img"
403+
}
404+
return "bin"
398405
case ".hex":
399406
// Similar to bin, but includes the start address and is thus usually a
400407
// better format.
@@ -507,9 +514,14 @@ func (c *Config) EmulatorName() string {
507514

508515
// EmulatorFormat returns the binary format for the emulator and the associated
509516
// file extension. An empty string means to pass directly whatever the linker
510-
// produces directly without conversion.
517+
// produces directly without conversion (usually ELF format).
511518
func (c *Config) EmulatorFormat() (format, fileExt string) {
512-
return "", ""
519+
switch {
520+
case strings.Contains(c.Target.Emulator, "{img}"):
521+
return "img", ".img"
522+
default:
523+
return "", ""
524+
}
513525
}
514526

515527
// Emulator returns a ready-to-run command to run the given binary in an

main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
634634
// Construct and execute a gdb or lldb command.
635635
// By default: gdb -ex run <binary>
636636
// Exit the debugger with Ctrl-D.
637-
params := []string{result.Binary}
637+
params := []string{result.Executable}
638638
switch debugger {
639639
case "gdb":
640640
if port != "" {
@@ -668,7 +668,7 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
668668
cmd.Stderr = os.Stderr
669669
err = cmd.Run()
670670
if err != nil {
671-
return &commandError{"failed to run " + cmdName + " with", result.Binary, err}
671+
return &commandError{"failed to run " + cmdName + " with", result.Executable, err}
672672
}
673673
return nil
674674
})

targets/esp32.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@
1515
"src/internal/task/task_stack_esp32.S"
1616
],
1717
"binary-format": "esp32",
18-
"flash-command": "esptool.py --chip=esp32 --port {port} write_flash 0x1000 {bin} -ff 80m -fm dout"
18+
"flash-command": "esptool.py --chip=esp32 --port {port} write_flash 0x1000 {bin} -ff 80m -fm dout",
19+
"emulator": "qemu-system-xtensa -machine esp32 -nographic -drive file={img},if=mtd,format=raw",
20+
"gdb": ["xtensa-esp32-elf-gdb"]
1921
}

0 commit comments

Comments
 (0)