esp32: add support for running and debuggin using qemu-esp32

Этот коммит содержится в:
Ayke van Laethem 2022-04-22 18:57:40 +02:00 коммит произвёл Ron Evans
родитель bd56636d58
коммит 8568d4f625
5 изменённых файлов: 57 добавлений и 9 удалений

Просмотреть файл

@ -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,

Просмотреть файл

@ -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)
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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
})

Просмотреть файл

@ -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"]
}