mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-09-01 10:19:01 +00:00
b420a8be17
* pinout yamls removed * machine: implement default UART pin configuration for Embedfire boards * flash command moved to chip level so VS Code plugin can select bare chip * machine: add support for alternate pin mode configuration * add build targets for embedfire on py32 * add support for embedfire target in GNUmakefile for py32 * lib/py32-svd: remove duplicate DBGMCU.IDCODE CODE field Update submodule to fix duplicate SetIDCODE/GetIDCODE method declarations in the generated py32f002bxx.go device file. * update subproject commit reference in py32-svd * refactor: update CPU frequency handling in machine and runtime packages * refactor: replace ConfigureUARTPin function with direct pin configuration in UART setup * SetAltFunc documentation for GPIO pin alternate functions * refactor: improve UART write and flush error handling with timeout * machine/py32: generalize UART driver to any USART Add a per-instance setup func to the UART type so the driver is no longer hardwired to USART1. DefaultUART stays USART1; add UART2 (USART2) in a separately build-tagged file since py32f002x parts lack USART2. RX IRQ handlers reference runtime-assigned vars to break the init cycle, and setup is assigned in the var initializer so it runs before InitSerial. Add the py32f003_32k_4k target (32K flash / 4K RAM). * Add canonical PY32F002, F003, and F030 density targets Use CMSIS/pyocd device names for target files and build tags. Add all F003 and F030 densities plus F002A/B, correct F002B to 24K flash and its own startup file, fix the F030x8 pyocd target, and update Embedfire inheritance. * Add targets for all PY32 CMSIS devices * Support all PY32 register layout variants * machine/py32: use generated register definitions * machine/py32: fix alternate-function documentation * machine/py32: report the configured CPU frequency * machine/py32: use unsafe.Add for GPIO ports * machine/py32: bound and yield UART polling * machine/py32: configure UART pins from UARTConfig * build: use the current PY32 SVD repository URL * test: cover PY32 UART register layouts * machine/py32: restore dynamic CPU frequency tracking * machine/py32: share the USART TX-ready bit * targets/py32: scale system stacks with RAM * machine/py32: keep clock state internal * targets/py32: normalize generated metadata * machine/py32: normalize GPIO configuration * machine/py32: fix T020 UART setup * machine/py32: reduce clock variant files * machine/py32: clean up UART variants * machine/py32: decouple UART clock capability * lib/py32-svd: use organization repository * runtime/py32: name 24MHz HSI encodings * machine/py32: derive startup clock from capability * machine/py32: use generated USART clock mask * machine/py32: name T020 8-bit UART mode * ci: include PY32 in sharded smoke tests * runtime: remove PY32 HSI frequency workaround
255 lines
7.1 KiB
Go
255 lines
7.1 KiB
Go
// Command gen-py32-targets generates PY32 target and linker definitions from
|
|
// normalized CMSIS-Pack device metadata.
|
|
package main
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"encoding/json"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type device struct {
|
|
Part string
|
|
Family string
|
|
Core string
|
|
FlashStart uint64
|
|
FlashSize uint64
|
|
RAMStart uint64
|
|
RAMSize uint64
|
|
}
|
|
|
|
type target struct {
|
|
Inherits []string `json:"inherits"`
|
|
BuildTags []string `json:"build-tags,omitempty"`
|
|
LinkerScript string `json:"linkerscript,omitempty"`
|
|
ExtraFiles []string `json:"extra-files,omitempty"`
|
|
FlashCommand string `json:"flash-command,omitempty"`
|
|
}
|
|
|
|
var orphanFamilies = map[string]string{
|
|
// This SVD is present in PY32F0xx_DFP, but that pack has no matching PDSC
|
|
// device entry from which a concrete memory configuration can be derived.
|
|
"py32f001xx": "m0",
|
|
}
|
|
|
|
var noGPIOAFRH = map[string]bool{
|
|
"py32f001cxx": true,
|
|
"py32f002bxx": true,
|
|
"py32f002cxx": true,
|
|
"py32f002xxx": true,
|
|
"py32f002zxx": true,
|
|
"py32l020xx": true,
|
|
"py32m010xx": true,
|
|
}
|
|
|
|
var gpioOSPDDER = familySet("py32e407xx", "py32f410xx", "py32l090xx", "py32t090xx", "py32t092xx")
|
|
var gpioClockAHB2 = familySet("py32e407xx", "py32f403xx")
|
|
var gpioClockAHB = familySet("py32f410xx")
|
|
var hsiFSOP = familySet("py32l090xx", "py32t090xx", "py32t092xx")
|
|
var noHSIFS = familySet("py32e407xx", "py32f403xx", "py32f410xx")
|
|
var uartType = familySet("py32t020xx")
|
|
var usartSplitData = familySet("py32e407xx")
|
|
var usartUnnumbered = familySet("py32f410xx")
|
|
var usart1ClockLiteral = familySet("py32f001cxx", "py32f001xx")
|
|
var uartClockAPB2 = familySet("py32e407xx", "py32f403xx", "py32f410xx")
|
|
var uartNoInterrupt = familySet("py32f410xx")
|
|
|
|
func familySet(names ...string) map[string]bool {
|
|
set := make(map[string]bool, len(names))
|
|
for _, name := range names {
|
|
set[name] = true
|
|
}
|
|
return set
|
|
}
|
|
|
|
func familyBuildTags(family string) []string {
|
|
tags := []string{family}
|
|
features := []struct {
|
|
name string
|
|
set map[string]bool
|
|
}{
|
|
{"py32_no_gpio_afrh", noGPIOAFRH},
|
|
{"py32_gpio_ospdder", gpioOSPDDER},
|
|
{"py32_gpio_clock_ahb2", gpioClockAHB2},
|
|
{"py32_gpio_clock_ahb", gpioClockAHB},
|
|
{"py32_hsi_fs_op", hsiFSOP},
|
|
{"py32_no_hsi_fs", noHSIFS},
|
|
{"py32_uart_type", uartType},
|
|
{"py32_usart_split_data", usartSplitData},
|
|
{"py32_usart_unnumbered", usartUnnumbered},
|
|
{"py32_usart1_clock_literal", usart1ClockLiteral},
|
|
{"py32_uart_clock_apb2", uartClockAPB2},
|
|
{"py32_uart_no_interrupt", uartNoInterrupt},
|
|
}
|
|
for _, feature := range features {
|
|
if feature.set[family] {
|
|
tags = append(tags, feature.name)
|
|
}
|
|
}
|
|
return tags
|
|
}
|
|
|
|
var flashCommands = map[string]string{
|
|
"py32f002ax5": "pyocd load -t py32f002ax5 {bin}",
|
|
"py32f002bx5": "pyocd load -t py32f002bx5 {bin}",
|
|
"py32f003x4": "pyocd load -t py32f003x4 {bin}",
|
|
"py32f003x6": "pyocd load -t py32f003x6 {bin}",
|
|
"py32f003x7": "pyocd load -t py32f003x7 {bin}",
|
|
"py32f003x8": "pyocd load -t py32f003x8 {bin}",
|
|
"py32f030x4": "pyocd load -t py32f030x4 {bin}",
|
|
"py32f030x6": "pyocd load -t py32f030x6 {bin}",
|
|
"py32f030x7": "pyocd load -t py32f030x7 {bin}",
|
|
"py32f030x8": "pyocd load -t py32f030x8 {bin}",
|
|
}
|
|
|
|
func main() {
|
|
table := flag.String("table", "tools/gen-py32-targets/devices.csv", "normalized device table")
|
|
out := flag.String("out", "targets", "target output directory")
|
|
flag.Parse()
|
|
|
|
devices, err := readDevices(*table)
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
if err := generate(*out, devices); err != nil {
|
|
fatal(err)
|
|
}
|
|
}
|
|
|
|
func fatal(err error) {
|
|
fmt.Fprintln(os.Stderr, "gen-py32-targets:", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
func readDevices(path string) ([]device, error) {
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
reader := csv.NewReader(file)
|
|
header, err := reader.Read()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
wantHeader := []string{"part", "family", "core", "flash_start", "flash_size", "ram_start", "ram_size"}
|
|
if strings.Join(header, ",") != strings.Join(wantHeader, ",") {
|
|
return nil, fmt.Errorf("unexpected CSV header %q", strings.Join(header, ","))
|
|
}
|
|
|
|
var devices []device
|
|
seen := make(map[string]bool)
|
|
for line := 2; ; line++ {
|
|
record, err := reader.Read()
|
|
if errors.Is(err, io.EOF) {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("line %d: %w", line, err)
|
|
}
|
|
if seen[record[0]] {
|
|
return nil, fmt.Errorf("line %d: duplicate part %q", line, record[0])
|
|
}
|
|
seen[record[0]] = true
|
|
if record[2] != "m0" && record[2] != "m4" {
|
|
return nil, fmt.Errorf("line %d: unsupported core %q", line, record[2])
|
|
}
|
|
values := make([]uint64, 4)
|
|
for i, field := range record[3:] {
|
|
values[i], err = strconv.ParseUint(field, 0, 64)
|
|
if err != nil || values[i] == 0 {
|
|
return nil, fmt.Errorf("line %d: invalid memory value %q", line, field)
|
|
}
|
|
}
|
|
devices = append(devices, device{
|
|
Part: record[0], Family: record[1], Core: record[2],
|
|
FlashStart: values[0], FlashSize: values[1],
|
|
RAMStart: values[2], RAMSize: values[3],
|
|
})
|
|
}
|
|
return devices, nil
|
|
}
|
|
|
|
func systemStackSize(ramSize uint64) uint64 {
|
|
switch {
|
|
case ramSize <= 4*1024:
|
|
return 1024
|
|
case ramSize <= 16*1024:
|
|
return 2 * 1024
|
|
default:
|
|
return 4 * 1024
|
|
}
|
|
}
|
|
|
|
func generate(out string, devices []device) error {
|
|
if err := os.MkdirAll(out, 0o755); err != nil {
|
|
return err
|
|
}
|
|
families := make(map[string]string, len(orphanFamilies))
|
|
for name, core := range orphanFamilies {
|
|
families[name] = core
|
|
}
|
|
for _, device := range devices {
|
|
if core, ok := families[device.Family]; ok && core != device.Core {
|
|
return fmt.Errorf("family %q mixes %s and %s cores", device.Family, core, device.Core)
|
|
}
|
|
families[device.Family] = device.Core
|
|
}
|
|
|
|
familyNames := make([]string, 0, len(families))
|
|
for name := range families {
|
|
familyNames = append(familyNames, name)
|
|
}
|
|
sort.Strings(familyNames)
|
|
for _, family := range familyNames {
|
|
base := "py32"
|
|
if families[family] == "m4" {
|
|
base = "py32-m4"
|
|
}
|
|
spec := target{
|
|
Inherits: []string{base},
|
|
BuildTags: familyBuildTags(family),
|
|
ExtraFiles: []string{"src/device/py32/" + family + ".s"},
|
|
}
|
|
if err := writeJSON(filepath.Join(out, family+".json"), spec); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
for _, device := range devices {
|
|
spec := target{
|
|
Inherits: []string{device.Family},
|
|
BuildTags: []string{device.Part},
|
|
LinkerScript: "targets/" + device.Part + ".ld",
|
|
FlashCommand: flashCommands[device.Part],
|
|
}
|
|
if err := writeJSON(filepath.Join(out, device.Part+".json"), spec); err != nil {
|
|
return err
|
|
}
|
|
stackSize := systemStackSize(device.RAMSize)
|
|
linker := fmt.Sprintf("MEMORY\n{\n FLASH_TEXT (rx) : ORIGIN = %#x, LENGTH = %#x\n RAM (xrw) : ORIGIN = %#x, LENGTH = %#x\n}\n\n_stack_size = %dK;\n\nINCLUDE \"targets/arm.ld\"\n", device.FlashStart, device.FlashSize, device.RAMStart, device.RAMSize, stackSize/1024)
|
|
if err := os.WriteFile(filepath.Join(out, device.Part+".ld"), []byte(linker), 0o644); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeJSON(path string, value any) error {
|
|
data, err := json.MarshalIndent(value, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
data = append(data, '\n')
|
|
return os.WriteFile(path, data, 0o644)
|
|
}
|