mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-03 02:27:48 +00:00
0757ccc657
* tools/gen-device-svd: orderPeripherals: prevent skipping base peripherals derived by name Recent SVDs from stm32-rs, like the one for stm32u595, define derivedFrom attributes that do not refer to a peripheral group name, but to a peripheral name. For instance, the peripheral I2C5 may be derived from "I2C1", not from "I2C". The previous algorithm records, in case the group name is non-empty, only the group name in the knownBasePeripherals map, not the name of the peripheral itself. So in case of the base peripheral I2C1 with group name I2C: although the peripheral gets added to the sorted list, it would be added to knownBasePeripherals with the group name "I2C" as key, not with "I2C1". A following peripheral, I2C5, derived from I2C1, with an empty group name, would be recorded as known with key "I2C5", but omitted from the sorted list, because "I2C1" is not recognized as known. The following peripheral SEC_I2C5, derived from I2C5, with empty group name, would be added to both the knownPeripherals map and the sorted list. So if, later, the sorted list is examined, it would find SEC_I2C5 earlier than its base peripheral I2C5, which would be missing from "peripheralDict", resulting in a nil pointer access. This patch makes sure that, to stay with the example, that "I2C1" is recorded as known too (not only the group name "I2C"), so that "I2C5" won't be skipped anymore, preventing the program from crashing. * tools/gen-device-svd: orderPeripherals: ensure ordered content of missingBasePeripherals After the first run, missingBasePeripherals may contain peripherals with dependencies that are not guaranteed to be in proper order. This change implements additional loop runs that try to reduce the size of the missingBasePeripherals as far as possible. [With recent SVDs from stm32-rs this change will not produce different results, though (since these source files contain already properly ordered peripherals).] * tools/gen-device-svd: Register: move dim array decoding to utility type dimArray This allows encoding of dim increment and array indices to be re-used by other elements supporting dim arrays. This change just restructures parts of register specific code, it does not change the output of the program. * tools/gen-device-svd: parseBitfields: support field dim arrays Patched SVD files from stm32-rs recently contain many fields with dim array parameters and names containing %s (like "CC%sIF"). This change adjusts parseBitfields so that these field elements get resolved. * tools/gen-device-svd: SVDField: allow multiple enumeratedValues In recent patched SVD files from stm32-rs there may be two enumeratedValues elements per SVDField, not just one. The SVD specification allows up to two entries (they may be used to define different enums for read and write access). This change extends SVDField and parseBitfields so that two enumeratedValues are processed like a single one. * tools/gen-device-svd: orderPeripherals: sort peripherals of same group with larger number of registers/bitfields first In group "TIM" there may be general purpose timers like TIM16 and advanced timers like TIM1. The advanced peripheral may contain a larger number of registers than the general purpose ones. TIM1 may contain CCR1..CCR4, SMCR and OR1, while TIM16 only knows about CCR1. Unfortunately in some SVDs, like the one for stm32g031, TIM16 is defined before TIM1. Since register and bitfield constants are generated taking only the first peripheral of a group into account, the resulting .go file may lack definitions for e.g. CCR2..CCR4, SMCR, and OR1. This change adjusts orderPeripherals so that, to stay with the example, a peripheral like TIM1 will be moved in front of TIM16, resulting in an output file containing the larger set of definitions. * tools/gen-device-svd: SVDEnumeration: support isDefault Recent SVD files created by stm32-rs use "isDefault" in enumeratedValue elements for purposes like the Div1 enum for clock prescaler registers without specifying a specific value. Previously, these enumeratedValues would be skipped because of the enumEl.Value == 0 condition, and the corresponding const definitions like "RCC_CFGR2_PPRE2_Div1 = 0x0" would be missing from the resulting .go files, so existing code relying on these constants would not compile anymore. This change adds a utility type enumDefaultResolver that helps finding an actual value that is unused by the enumeratedValues that are defined for the field. More examples for values marked as "isDefault", along with their resolved values: DAC_CR_WAVE1_Triangle => 2 IWDG_PR_PR_DivideBy256 => 6 DAC_CR_MAMP2_Amp4095 => 0xb * tools/gen-device-svd: support derivedFrom attribute at field level This ensures that some more constants are included in the .go files that would otherwise be skipped (like e.g. ADC_SMPR2_SMP1_Cycles* of some STM32 devices), which prevented compilation of some programs. To avoid extending a lot of func argument lists, and since there is no context.Context in use yet, this change introduces a global derivationContext. * tools/gen-device-svd: tweak: stm32: ensure USART_ISR_TXE/TXFNF are present * tools/gen-device-svd: stm32: ensure CCMR*_Output alternate registers are sorted first * tools/gen-device-svd: stm32: add IWDG peripheral alias if SVD defines IWDG1
125 lines
3.3 KiB
Go
125 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
)
|
|
|
|
func tweakDevice(d *Device, pkgName string) {
|
|
if pkgName != "stm32" {
|
|
// no-op for device types that do not need tweaks
|
|
return
|
|
}
|
|
|
|
// Source file machine_stm32_iwdg.go relies on the presence of
|
|
// a register IWDG. On some devices, though, like the h723,
|
|
// there are two registers, IWDG1 and IWDG2. In this case we
|
|
// define an alias IWDG for IWDG1.
|
|
addUnnumberedAlias(d, "IWDG", "IWDG1")
|
|
|
|
for _, p := range d.Peripherals {
|
|
switch p.GroupName {
|
|
case "TIM":
|
|
// SVDs like stm32l4r5.svd define CCMR*_Input and _Output
|
|
// alternate registers, with _Input sorted before _Output.
|
|
// This would result in the _Output fields missing from the
|
|
// TIM_type struct definition, hence compilation would fail.
|
|
// Therefore we adjust the order of these alternate registers
|
|
// accordingly.
|
|
stm32EnsureCCMROrder(p.Registers)
|
|
|
|
case "USART":
|
|
isr := p.lookupRegister("ISR")
|
|
if isr == nil {
|
|
continue
|
|
}
|
|
|
|
// Some of the upstream SVD files, like the one for stm32wl5x_cm4,
|
|
// lack FIFO enabled variants of the USART ISR register,
|
|
// even if the register manual defines them. To make sure
|
|
// that TXFNF is not missing from the generated .go files,
|
|
// we add TXFNF here in case FIFOEN is present.
|
|
if p.lookupRegister("CR1").hasBitfield("FIFOEN") {
|
|
stm32EnsureBit(isr, "TXFNF", "TXE", "USART_ISR_")
|
|
}
|
|
|
|
// Svdtools handles the presence of alternate USART ISR registers,
|
|
// like in case of the stm32l4r5, adjusting names like "ISR_enabled"
|
|
// to "ISR", deleting "ISR_disabled" or "ISR_ALTERNATE" register definitions
|
|
// from the SVD.
|
|
// As this would result in USART_ISR_TXE definitions missing in the
|
|
// generated .go file, a constant for TXE is added here
|
|
// in case TXFNF is defined.
|
|
stm32EnsureBit(isr, "TXE", "TXFNF", "USART_ISR_")
|
|
}
|
|
}
|
|
}
|
|
|
|
func addUnnumberedAlias(d *Device, dest, src string) {
|
|
if _, ok := d.PeripheralDict[dest]; !ok {
|
|
if p := d.PeripheralDict[src]; p != nil {
|
|
p.Alias = dest
|
|
}
|
|
}
|
|
}
|
|
|
|
func stm32EnsureCCMROrder(registers []*PeripheralField) {
|
|
for i, r := range registers {
|
|
if i > 0 {
|
|
prev := registers[i-1]
|
|
if r.Address == prev.Address {
|
|
// alternate field
|
|
if strings.HasPrefix(prev.Name, "CCMR") && strings.HasPrefix(r.Name, "CCMR") && strings.HasSuffix(r.Name, "_Output") {
|
|
// swap register pointers
|
|
registers[i-1], registers[i] = r, prev
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func stm32EnsureBit(reg *PeripheralField, want, have, prefix string) {
|
|
iWant := -1
|
|
iHave := -1
|
|
wantConst := prefix + want
|
|
haveConst := prefix + have
|
|
for i := range reg.Constants {
|
|
f := ®.Constants[i]
|
|
if f.Name == wantConst {
|
|
iWant = i
|
|
break
|
|
}
|
|
if f.Name == haveConst {
|
|
iHave = i
|
|
break
|
|
}
|
|
}
|
|
if iHave != -1 && iWant == -1 {
|
|
iWant = iHave + 1
|
|
reg.Constants = slices.Insert(reg.Constants, iWant, reg.Constants[iHave])
|
|
reg.Constants[iWant].Name = wantConst
|
|
reg.Constants[iWant].Description = "Bit " + want + ". (added by gen-device-svd)"
|
|
}
|
|
}
|
|
|
|
func (p *Peripheral) lookupRegister(name string) *PeripheralField {
|
|
for _, r := range p.Registers {
|
|
if r.Name == name {
|
|
return r
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *PeripheralField) hasBitfield(name string) bool {
|
|
if r == nil {
|
|
return false
|
|
}
|
|
for i := range r.Bitfields {
|
|
if r.Bitfields[i].Name == name {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|