aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--builder/build.go9
-rw-r--r--builder/esp.go33
-rw-r--r--compileopts/config.go16
-rw-r--r--main.go4
-rw-r--r--targets/esp32.json4
5 files changed, 57 insertions, 9 deletions
diff --git a/builder/build.go b/builder/build.go
index 45e03875b..6f5e73f9f 100644
--- a/builder/build.go
+++ b/builder/build.go
@@ -37,8 +37,14 @@ import (
// BuildResult is the output of a build. This includes the binary itself and
// some other metadata that is obtained while building the binary.
type BuildResult struct {
+ // The executable directly from the linker, usually including debug
+ // information. Used for GDB for example.
+ Executable string
+
// A path to the output binary. It will be removed after Build returns, so
// if it should be kept it must be copied or moved away.
+ // It is often the same as Executable, but differs if the output format is
+ // .hex for example (instead of the usual ELF).
Binary string
// 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
if err != nil {
return err
}
- case "esp32", "esp32c3", "esp8266":
+ case "esp32", "esp32-img", "esp32c3", "esp8266":
// Special format for the ESP family of chips (parsed by the ROM
// bootloader).
tmppath = filepath.Join(dir, "main"+outext)
@@ -867,6 +873,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
}
return action(BuildResult{
+ Executable: executable,
Binary: tmppath,
MainDir: lprogram.MainPkg().Dir,
ModuleRoot: moduleroot,
diff --git a/builder/esp.go b/builder/esp.go
index 98e375426..bd348b546 100644
--- a/builder/esp.go
+++ b/builder/esp.go
@@ -15,6 +15,7 @@ import (
"fmt"
"io/ioutil"
"sort"
+ "strings"
)
type espImageSegment struct {
@@ -78,15 +79,31 @@ func makeESPFirmareImage(infile, outfile, format string) error {
// An added benefit is that we don't need to check for errors all the time.
outf := &bytes.Buffer{}
+ // Separate esp32 and esp32-img. The -img suffix indicates we should make an
+ // image, not just a binary to be flashed at 0x1000 for example.
+ chip := format
+ makeImage := false
+ if strings.HasSuffix(format, "-img") {
+ makeImage = true
+ chip = format[:len(format)-len("-img")]
+ }
+
+ if makeImage {
+ // The bootloader starts at 0x1000, or 4096.
+ // TinyGo doesn't use a separate bootloader and runs the entire
+ // application in the bootloader location.
+ outf.Write(make([]byte, 4096))
+ }
+
// Chip IDs. Source:
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L22
chip_id := map[string]uint16{
"esp32": 0x0000,
"esp32c3": 0x0005,
- }[format]
+ }[chip]
// Image header.
- switch format {
+ switch chip {
case "esp32", "esp32c3":
// Header format:
// 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 {
outf.Write(make([]byte, 15-outf.Len()%16))
outf.WriteByte(checksum)
- if format != "esp8266" {
+ if chip != "esp8266" {
// SHA256 hash (to protect against image corruption, not for security).
hash := sha256.Sum256(outf.Bytes())
outf.Write(hash[:])
}
+ // QEMU (or more precisely, qemu-system-xtensa from Espressif) expects the
+ // image to be a certain size.
+ if makeImage {
+ // Use a default image size of 4MB.
+ grow := 4096*1024 - outf.Len()
+ if grow > 0 {
+ outf.Write(make([]byte, grow))
+ }
+ }
+
// Write the image to the output file.
return ioutil.WriteFile(outfile, outf.Bytes(), 0666)
}
diff --git a/compileopts/config.go b/compileopts/config.go
index d7dbb41c3..b30e653e3 100644
--- a/compileopts/config.go
+++ b/compileopts/config.go
@@ -395,6 +395,13 @@ func (c *Config) BinaryFormat(ext string) string {
return c.Target.BinaryFormat
}
return "bin"
+ case ".img":
+ // Image file. Only defined for the ESP32 at the moment, where it is a
+ // full (runnable) image that can be used in the Espressif QEMU fork.
+ if c.Target.BinaryFormat != "" {
+ return c.Target.BinaryFormat + "-img"
+ }
+ return "bin"
case ".hex":
// Similar to bin, but includes the start address and is thus usually a
// better format.
@@ -507,9 +514,14 @@ func (c *Config) EmulatorName() string {
// EmulatorFormat returns the binary format for the emulator and the associated
// file extension. An empty string means to pass directly whatever the linker
-// produces directly without conversion.
+// produces directly without conversion (usually ELF format).
func (c *Config) EmulatorFormat() (format, fileExt string) {
- return "", ""
+ switch {
+ case strings.Contains(c.Target.Emulator, "{img}"):
+ return "img", ".img"
+ default:
+ return "", ""
+ }
}
// Emulator returns a ready-to-run command to run the given binary in an
diff --git a/main.go b/main.go
index 0cb8a42c3..ac68100b4 100644
--- a/main.go
+++ b/main.go
@@ -634,7 +634,7 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
// Construct and execute a gdb or lldb command.
// By default: gdb -ex run <binary>
// Exit the debugger with Ctrl-D.
- params := []string{result.Binary}
+ params := []string{result.Executable}
switch debugger {
case "gdb":
if port != "" {
@@ -668,7 +668,7 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
- return &commandError{"failed to run " + cmdName + " with", result.Binary, err}
+ return &commandError{"failed to run " + cmdName + " with", result.Executable, err}
}
return nil
})
diff --git a/targets/esp32.json b/targets/esp32.json
index 78b04cc89..376d457c9 100644
--- a/targets/esp32.json
+++ b/targets/esp32.json
@@ -15,5 +15,7 @@
"src/internal/task/task_stack_esp32.S"
],
"binary-format": "esp32",
- "flash-command": "esptool.py --chip=esp32 --port {port} write_flash 0x1000 {bin} -ff 80m -fm dout"
+ "flash-command": "esptool.py --chip=esp32 --port {port} write_flash 0x1000 {bin} -ff 80m -fm dout",
+ "emulator": "qemu-system-xtensa -machine esp32 -nographic -drive file={img},if=mtd,format=raw",
+ "gdb": ["xtensa-esp32-elf-gdb"]
}