avr: update gen-device-avr tool to support newer AVRs

This refactors gen-device-avr to output two different formats: one for
all the existing AVR chips (that don't really have the concept of a
peripheral, just a bunch of registers), and one for all the new chips
like the ATtiny1616 (tinyAVR 1-series and 2-series) that have
peripherals like the Cortex-M chips with type structs and instances.

I checked the generated code for all the AVR chips we have support for
(atmega1280, atmega1284p, atmega2560, atmega328p, atmega32u4, attiny85)
and while the generated Go code did change, it looks safe to me.
Этот коммит содержится в:
Ayke van Laethem 2023-05-17 23:08:55 +02:00 коммит произвёл Ron Evans
родитель b43bd9e62a
коммит 4d11d552db

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

@ -30,27 +30,31 @@ type AVRToolsDeviceFile struct {
Size string `xml:"size,attr"` Size string `xml:"size,attr"`
} `xml:"memory-segment"` } `xml:"memory-segment"`
} `xml:"address-spaces>address-space"` } `xml:"address-spaces>address-space"`
PeripheralInstances []struct {
Name string `xml:"name,attr"`
Caption string `xml:"caption,attr"`
RegisterGroup struct {
NameInModule string `xml:"name-in-module,attr"`
Offset string `xml:"offset,attr"`
} `xml:"register-group"`
} `xml:"peripherals>module>instance"`
Interrupts []*XMLInterrupt `xml:"interrupts>interrupt"` Interrupts []*XMLInterrupt `xml:"interrupts>interrupt"`
} `xml:"devices>device"` } `xml:"devices>device"`
Modules []struct { PeripheralRegisterGroups []struct {
Name string `xml:"name,attr"` Name string `xml:"name,attr"`
Caption string `xml:"caption,attr"` Caption string `xml:"caption,attr"`
RegisterGroup struct { Registers []struct {
Name string `xml:"name,attr"` Name string `xml:"name,attr"`
Caption string `xml:"caption,attr"` Caption string `xml:"caption,attr"`
Registers []struct { Offset string `xml:"offset,attr"`
Name string `xml:"name,attr"` Size uint64 `xml:"size,attr"`
Caption string `xml:"caption,attr"` Bitfields []struct {
Offset string `xml:"offset,attr"` Name string `xml:"name,attr"`
Size int `xml:"size,attr"` Caption string `xml:"caption,attr"`
Bitfields []struct { Mask string `xml:"mask,attr"`
Name string `xml:"name,attr"` } `xml:"bitfield"`
Caption string `xml:"caption,attr"` } `xml:"register"`
Mask string `xml:"mask,attr"` } `xml:"modules>module>register-group"`
} `xml:"bitfield"`
} `xml:"register"`
} `xml:"register-group"`
} `xml:"modules>module"`
} }
type XMLInterrupt struct { type XMLInterrupt struct {
@ -61,9 +65,11 @@ type XMLInterrupt struct {
} }
type Device struct { type Device struct {
metadata map[string]interface{} metadata map[string]interface{}
interrupts []Interrupt interrupts []Interrupt
peripherals []*Peripheral types []*PeripheralType
instances []*PeripheralInstance
oldStyle bool
} }
// AddressSpace is the Go version of an XML element like the following: // AddressSpace is the Go version of an XML element like the following:
@ -94,22 +100,30 @@ type Interrupt struct {
Caption string Caption string
} }
type Peripheral struct { // Peripheral instance, for example PORTB
type PeripheralInstance struct {
Name string
Caption string
Address uint64
Type *PeripheralType
}
// Peripheral type, for example PORT (if it's shared between different
// instances, which is the case for new-style ATDF files).
type PeripheralType struct {
Name string Name string
Caption string Caption string
Registers []*Register Registers []*Register
Instances []*PeripheralInstance
} }
// Single register or struct field in a peripheral type.
type Register struct { type Register struct {
Caption string Caption string
Variants []RegisterVariant Name string
Bitfields []Bitfield Type string
peripheral *Peripheral Offset uint64 // offset, only for old-style ATDF files
} Bitfields []Bitfield
type RegisterVariant struct {
Name string
Address int64
} }
type Bitfield struct { type Bitfield struct {
@ -159,86 +173,155 @@ func readATDF(path string) (*Device, error) {
} }
} }
allRegisters := map[string]*Register{} // There appear to be two kinds of devices and ATDF files: those before
// ~2017 and those introduced as part of the tinyAVR (1 and 2 series).
var peripherals []*Peripheral // The newer devices are structured slightly differently, with peripherals
for _, el := range xml.Modules { // laid out more like Cortex-M chips and one or more instances per chip.
peripheral := &Peripheral{ // Older designs basically just have a bunch of registers with little
Name: el.Name, // structure in them.
Caption: el.Caption, // The code generated for these chips is quite different:
// * For old-style chips we'll generate a bunch of registers without
// peripherals (e.g. PORTB, DDRB, etc).
// * For new-style chips we'll generate proper peripheral structs like we
// do for Cortex-M chips.
oldStyle := true
for _, instanceEl := range device.PeripheralInstances {
if instanceEl.RegisterGroup.NameInModule == "" {
continue
} }
peripherals = append(peripherals, peripheral) offset, err := strconv.ParseUint(instanceEl.RegisterGroup.Offset, 0, 16)
if err != nil {
return nil, fmt.Errorf("failed to parse offset %#v of peripheral %s: %v", instanceEl.RegisterGroup.Offset, instanceEl.Name, err)
}
if offset != 0 {
oldStyle = false
}
}
regElGroup := el.RegisterGroup // Read all peripheral types.
for _, regEl := range regElGroup.Registers { var types []*PeripheralType
regOffset, err := strconv.ParseInt(regEl.Offset, 0, 64) typeMap := make(map[string]*PeripheralType)
allRegisters := map[string]*Register{}
for _, registerGroupEl := range xml.PeripheralRegisterGroups {
var regs []*Register
regEls := registerGroupEl.Registers
if !oldStyle {
// We only need to sort registers when we're generating peripheral
// structs.
sort.SliceStable(regEls, func(i, j int) bool {
return regEls[i].Offset < regEls[j].Offset
})
}
addReg := func(reg *Register) {
if oldStyle {
// Check for duplicate registers (they happen).
if reg2 := allRegisters[reg.Name]; reg2 != nil {
return
}
allRegisters[reg.Name] = reg
}
regs = append(regs, reg)
}
offset := uint64(0)
for _, regEl := range regEls {
regOffset, err := strconv.ParseUint(regEl.Offset, 0, 64)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to parse offset %#v of register %s: %v", regEl.Offset, regEl.Name, err) return nil, fmt.Errorf("failed to parse offset %#v of register %s: %v", regEl.Offset, regEl.Name, err)
} }
reg := &Register{ if !oldStyle {
Caption: regEl.Caption, // Add some padding to the gap in the struct, if needed.
peripheral: peripheral, if offset < regOffset {
} regs = append(regs, &Register{
switch regEl.Size { Name: "_",
case 1: Type: fmt.Sprintf("[%d]volatile.Register8", regOffset-offset),
reg.Variants = []RegisterVariant{ })
{ offset = regOffset
Name: regEl.Name,
Address: regOffset,
},
} }
case 2:
reg.Variants = []RegisterVariant{ // Check for overlapping registers.
{ if offset > regOffset {
Name: regEl.Name + "L", return nil, fmt.Errorf("register %s in peripheral %s overlaps with another register", regEl.Name, registerGroupEl.Name)
Address: regOffset,
},
{
Name: regEl.Name + "H",
Address: regOffset + 1,
},
} }
default:
// TODO
continue
} }
var bitfields []Bitfield
for _, bitfieldEl := range regEl.Bitfields { for _, bitfieldEl := range regEl.Bitfields {
mask := bitfieldEl.Mask maskString := bitfieldEl.Mask
if len(mask) == 2 { if len(maskString) == 2 {
// Two devices (ATtiny102 and ATtiny104) appear to have an // Two devices (ATtiny102 and ATtiny104) appear to have an
// error in the bitfields, leaving out the '0x' prefix. // error in the bitfields, leaving out the '0x' prefix.
mask = "0x" + mask maskString = "0x" + maskString
} }
maskInt, err := strconv.ParseUint(mask, 0, 32) mask, err := strconv.ParseUint(maskString, 0, 32)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to parse mask %#v of bitfield %s: %v", mask, bitfieldEl.Name, err) return nil, fmt.Errorf("failed to parse mask %#v of bitfield %s: %v", maskString, bitfieldEl.Name, err)
} }
reg.Bitfields = append(reg.Bitfields, Bitfield{ name := regEl.Name + "_" + bitfieldEl.Name
Name: regEl.Name + "_" + bitfieldEl.Name, if !oldStyle {
name = registerGroupEl.Name + "_" + name
}
bitfields = append(bitfields, Bitfield{
Name: name,
Caption: bitfieldEl.Caption, Caption: bitfieldEl.Caption,
Mask: uint(maskInt), Mask: uint(mask),
}) })
} }
if firstReg, ok := allRegisters[regEl.Name]; ok { switch regEl.Size {
// merge bit fields with previous register case 1:
merged := append(firstReg.Bitfields, reg.Bitfields...) addReg(&Register{
firstReg.Bitfields = make([]Bitfield, 0, len(merged)) Name: regEl.Name,
m := make(map[string]interface{}) Type: "volatile.Register8",
for _, field := range merged { Caption: regEl.Caption,
if _, ok := m[field.Name]; !ok { Offset: regOffset,
m[field.Name] = nil Bitfields: bitfields,
firstReg.Bitfields = append(firstReg.Bitfields, field) })
} case 2:
} addReg(&Register{
continue Name: regEl.Name + "L",
} else { Type: "volatile.Register8",
allRegisters[regEl.Name] = reg Caption: regEl.Caption + " (lower bits)",
Offset: regOffset + 0,
})
addReg(&Register{
Name: regEl.Name + "H",
Type: "volatile.Register8",
Caption: regEl.Caption + " (upper bits)",
Offset: regOffset + 1,
})
default:
panic("todo: unknown size")
} }
offset += regEl.Size
peripheral.Registers = append(peripheral.Registers, reg)
} }
periphType := &PeripheralType{
Name: registerGroupEl.Name,
Caption: registerGroupEl.Caption,
Registers: regs,
}
types = append(types, periphType)
typeMap[periphType.Name] = periphType
}
// Read all peripheral instances.
var instances []*PeripheralInstance
for _, instanceEl := range device.PeripheralInstances {
if instanceEl.RegisterGroup.NameInModule == "" {
continue
}
offset, err := strconv.ParseUint(instanceEl.RegisterGroup.Offset, 0, 16)
if err != nil {
return nil, fmt.Errorf("failed to parse offset %#v of peripheral %s: %v", instanceEl.RegisterGroup.Offset, instanceEl.Name, err)
}
periphType := typeMap[instanceEl.RegisterGroup.NameInModule]
instance := &PeripheralInstance{
Name: instanceEl.Name,
Caption: instanceEl.Caption,
Address: offset,
Type: periphType,
}
instances = append(instances, instance)
periphType.Instances = append(periphType.Instances, instance)
} }
ramStart := int64(0) ramStart := int64(0)
@ -298,8 +381,10 @@ func readATDF(path string) (*Device, error) {
"ramSize": ramSize, "ramSize": ramSize,
"numInterrupts": len(device.Interrupts), "numInterrupts": len(device.Interrupts),
}, },
interrupts: interrupts, interrupts: interrupts,
peripherals: peripherals, types: types,
instances: instances,
oldStyle: oldStyle,
}, nil }, nil
} }
@ -358,25 +443,52 @@ func interrupt{{.Name}}() {
} }
{{- end}} {{- end}}
{{if .oldStyle -}}
// Peripherals. // Peripherals.
var ({{range .peripherals}} var (
{{- range .instances}}
// {{.Caption}} // {{.Caption}}
{{range .Registers}}{{range .Variants}} {{.Name}} = (*volatile.Register8)(unsafe.Pointer(uintptr(0x{{printf "%x" .Address}}))) {{range .Type.Registers -}}
{{end}}{{end}}{{end}}) {{if ne .Name "_" -}}
{{.Name}} = (*{{.Type}})(unsafe.Pointer(uintptr(0x{{printf "%x" .Offset}})))
{{end -}}
{{end -}}
{{end}})
{{else}}
// Peripherals instances.
var (
{{- range .instances -}}
{{.Name}} = (*{{.Type.Name}}_Type)(unsafe.Pointer(uintptr(0x{{printf "%x" .Address}})))
{{- if .Caption}}// {{.Caption}}{{end}}
{{end -}}
)
// Peripheral type definitions.
{{range .types}}
type {{.Name}}_Type struct {
{{range .Registers -}}
{{.Name}} {{.Type}} {{if .Caption}} // {{.Caption}} {{end}}
{{end -}}
}
{{end}}
{{end}}
`)) `))
err = t.Execute(w, map[string]interface{}{ err = t.Execute(w, map[string]interface{}{
"metadata": device.metadata, "metadata": device.metadata,
"pkgName": filepath.Base(strings.TrimRight(outdir, "/")), "pkgName": filepath.Base(strings.TrimRight(outdir, "/")),
"interrupts": device.interrupts, "interrupts": device.interrupts,
"interruptMax": maxInterruptNum, "interruptMax": maxInterruptNum,
"peripherals": device.peripherals, "instances": device.instances,
"types": device.types,
"oldStyle": device.oldStyle,
}) })
if err != nil { if err != nil {
return err return err
} }
// Write bitfields. // Write bitfields.
for _, peripheral := range device.peripherals { for _, peripheral := range device.types {
// Only write bitfields when there are any. // Only write bitfields when there are any.
numFields := 0 numFields := 0
for _, r := range peripheral.Registers { for _, r := range peripheral.Registers {
@ -391,13 +503,11 @@ var ({{range .peripherals}}
if len(register.Bitfields) == 0 { if len(register.Bitfields) == 0 {
continue continue
} }
for _, variant := range register.Variants { fmt.Fprintf(w, "\n\t// %s", register.Name)
fmt.Fprintf(w, "\n\t// %s", variant.Name) if register.Caption != "" {
if register.Caption != "" { fmt.Fprintf(w, ": %s", register.Caption)
fmt.Fprintf(w, ": %s", register.Caption)
}
fmt.Fprintf(w, "\n")
} }
fmt.Fprintf(w, "\n")
allBits := map[string]interface{}{} allBits := map[string]interface{}{}
for _, bitfield := range register.Bitfields { for _, bitfield := range register.Bitfields {
if bits.OnesCount(bitfield.Mask) == 1 { if bits.OnesCount(bitfield.Mask) == 1 {