Fix multiline descriptions
Move element description formatting to a function Export struct fields for use in the template Add template helper functions Multiline comments for interrupts and peripherals Export more fields Move comments to the top of each element Do not remove line breaks from descriptions The template code should gracefully handle line breaks now go fmt gen-device-svd.go
Этот коммит содержится в:
родитель
e161d5a82c
коммит
cca0eab3da
1 изменённых файлов: 229 добавлений и 167 удалений
|
@ -83,45 +83,54 @@ type SVDCluster struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
metadata map[string]string
|
Metadata *Metadata
|
||||||
interrupts []*interrupt
|
Interrupts []*Interrupt
|
||||||
peripherals []*peripheral
|
Peripherals []*Peripheral
|
||||||
}
|
}
|
||||||
|
|
||||||
type interrupt struct {
|
type Metadata struct {
|
||||||
|
File string
|
||||||
|
DescriptorSource string
|
||||||
|
Name string
|
||||||
|
NameLower string
|
||||||
|
Description string
|
||||||
|
LicenseBlock string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Interrupt struct {
|
||||||
Name string
|
Name string
|
||||||
HandlerName string
|
HandlerName string
|
||||||
peripheralIndex int
|
PeripheralIndex int
|
||||||
Value int // interrupt number
|
Value int // interrupt number
|
||||||
Description string
|
Description string
|
||||||
}
|
}
|
||||||
|
|
||||||
type peripheral struct {
|
type Peripheral struct {
|
||||||
Name string
|
Name string
|
||||||
GroupName string
|
GroupName string
|
||||||
BaseAddress uint64
|
BaseAddress uint64
|
||||||
Description string
|
Description string
|
||||||
ClusterName string
|
ClusterName string
|
||||||
registers []*PeripheralField
|
Registers []*PeripheralField
|
||||||
subtypes []*peripheral
|
Subtypes []*Peripheral
|
||||||
}
|
}
|
||||||
|
|
||||||
// A PeripheralField is a single field in a peripheral type. It may be a full
|
// A PeripheralField is a single field in a peripheral type. It may be a full
|
||||||
// peripheral or a cluster within a peripheral.
|
// peripheral or a cluster within a peripheral.
|
||||||
type PeripheralField struct {
|
type PeripheralField struct {
|
||||||
name string
|
Name string
|
||||||
address uint64
|
Address uint64
|
||||||
description string
|
Description string
|
||||||
registers []*PeripheralField // contains fields if this is a cluster
|
Registers []*PeripheralField // contains fields if this is a cluster
|
||||||
array int
|
Array int
|
||||||
elementSize int
|
ElementSize int
|
||||||
bitfields []Bitfield
|
Bitfields []Bitfield
|
||||||
}
|
}
|
||||||
|
|
||||||
type Bitfield struct {
|
type Bitfield struct {
|
||||||
name string
|
Name string
|
||||||
description string
|
Description string
|
||||||
value uint32
|
Value uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatText(text string) string {
|
func formatText(text string) string {
|
||||||
|
@ -131,6 +140,14 @@ func formatText(text string) string {
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isMultiline(s string) bool {
|
||||||
|
return strings.Index(s, "\n") >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitLine(s string) []string {
|
||||||
|
return strings.Split(s, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
// Replace characters that are not allowed in a symbol name with a '_'. This is
|
// Replace characters that are not allowed in a symbol name with a '_'. This is
|
||||||
// useful to be able to process SVD files with errors.
|
// useful to be able to process SVD files with errors.
|
||||||
func cleanName(text string) string {
|
func cleanName(text string) string {
|
||||||
|
@ -168,11 +185,11 @@ func readSVD(path, sourceURL string) (*Device, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
peripheralDict := map[string]*peripheral{}
|
peripheralDict := map[string]*Peripheral{}
|
||||||
groups := map[string]*peripheral{}
|
groups := map[string]*Peripheral{}
|
||||||
|
|
||||||
interrupts := make(map[string]*interrupt)
|
interrupts := make(map[string]*Interrupt)
|
||||||
var peripheralsList []*peripheral
|
var peripheralsList []*Peripheral
|
||||||
|
|
||||||
// Some SVD files have peripheral elements derived from a peripheral that
|
// Some SVD files have peripheral elements derived from a peripheral that
|
||||||
// comes later in the file. To make sure this works, sort the peripherals if
|
// comes later in the file. To make sure this works, sort the peripherals if
|
||||||
|
@ -203,13 +220,13 @@ func readSVD(path, sourceURL string) (*Device, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := groups[groupName]; ok || periphEl.DerivedFrom != "" {
|
if _, ok := groups[groupName]; ok || periphEl.DerivedFrom != "" {
|
||||||
var derivedFrom *peripheral
|
var derivedFrom *Peripheral
|
||||||
if periphEl.DerivedFrom != "" {
|
if periphEl.DerivedFrom != "" {
|
||||||
derivedFrom = peripheralDict[periphEl.DerivedFrom]
|
derivedFrom = peripheralDict[periphEl.DerivedFrom]
|
||||||
} else {
|
} else {
|
||||||
derivedFrom = groups[groupName]
|
derivedFrom = groups[groupName]
|
||||||
}
|
}
|
||||||
p := &peripheral{
|
p := &Peripheral{
|
||||||
Name: periphEl.Name,
|
Name: periphEl.Name,
|
||||||
GroupName: derivedFrom.GroupName,
|
GroupName: derivedFrom.GroupName,
|
||||||
Description: description,
|
Description: description,
|
||||||
|
@ -220,8 +237,8 @@ func readSVD(path, sourceURL string) (*Device, error) {
|
||||||
}
|
}
|
||||||
peripheralsList = append(peripheralsList, p)
|
peripheralsList = append(peripheralsList, p)
|
||||||
peripheralDict[p.Name] = p
|
peripheralDict[p.Name] = p
|
||||||
for _, subtype := range derivedFrom.subtypes {
|
for _, subtype := range derivedFrom.Subtypes {
|
||||||
peripheralsList = append(peripheralsList, &peripheral{
|
peripheralsList = append(peripheralsList, &Peripheral{
|
||||||
Name: periphEl.Name + "_" + subtype.ClusterName,
|
Name: periphEl.Name + "_" + subtype.ClusterName,
|
||||||
GroupName: subtype.GroupName,
|
GroupName: subtype.GroupName,
|
||||||
Description: subtype.Description,
|
Description: subtype.Description,
|
||||||
|
@ -231,12 +248,12 @@ func readSVD(path, sourceURL string) (*Device, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &peripheral{
|
p := &Peripheral{
|
||||||
Name: periphEl.Name,
|
Name: periphEl.Name,
|
||||||
GroupName: groupName,
|
GroupName: groupName,
|
||||||
Description: description,
|
Description: description,
|
||||||
BaseAddress: baseAddress,
|
BaseAddress: baseAddress,
|
||||||
registers: []*PeripheralField{},
|
Registers: []*PeripheralField{},
|
||||||
}
|
}
|
||||||
if p.GroupName == "" {
|
if p.GroupName == "" {
|
||||||
p.GroupName = periphEl.Name
|
p.GroupName = periphEl.Name
|
||||||
|
@ -253,7 +270,7 @@ func readSVD(path, sourceURL string) (*Device, error) {
|
||||||
if regName == "" {
|
if regName == "" {
|
||||||
regName = periphEl.Name // fall back to peripheral name
|
regName = periphEl.Name // fall back to peripheral name
|
||||||
}
|
}
|
||||||
p.registers = append(p.registers, parseRegister(regName, register, baseAddress, "")...)
|
p.Registers = append(p.Registers, parseRegister(regName, register, baseAddress, "")...)
|
||||||
}
|
}
|
||||||
for _, cluster := range periphEl.Clusters {
|
for _, cluster := range periphEl.Clusters {
|
||||||
clusterName := strings.Replace(cluster.Name, "[%s]", "", -1)
|
clusterName := strings.Replace(cluster.Name, "[%s]", "", -1)
|
||||||
|
@ -299,12 +316,12 @@ func readSVD(path, sourceURL string) (*Device, error) {
|
||||||
subcpRegisters = append(subcpRegisters, parseRegister(groupName, regEl, baseAddress+subclusterOffset, subclusterPrefix)...)
|
subcpRegisters = append(subcpRegisters, parseRegister(groupName, regEl, baseAddress+subclusterOffset, subclusterPrefix)...)
|
||||||
}
|
}
|
||||||
cpRegisters = append(cpRegisters, &PeripheralField{
|
cpRegisters = append(cpRegisters, &PeripheralField{
|
||||||
name: subclusterName,
|
Name: subclusterName,
|
||||||
address: baseAddress + subclusterOffset,
|
Address: baseAddress + subclusterOffset,
|
||||||
description: subClusterEl.Description,
|
Description: subClusterEl.Description,
|
||||||
registers: subcpRegisters,
|
Registers: subcpRegisters,
|
||||||
array: subdim,
|
Array: subdim,
|
||||||
elementSize: int(subdimIncrement),
|
ElementSize: int(subdimIncrement),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
for _, regEl := range subClusterEl.Registers {
|
for _, regEl := range subClusterEl.Registers {
|
||||||
|
@ -314,19 +331,19 @@ func readSVD(path, sourceURL string) (*Device, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.SliceStable(cpRegisters, func(i, j int) bool {
|
sort.SliceStable(cpRegisters, func(i, j int) bool {
|
||||||
return cpRegisters[i].address < cpRegisters[j].address
|
return cpRegisters[i].Address < cpRegisters[j].Address
|
||||||
})
|
})
|
||||||
clusterPeripheral := &peripheral{
|
clusterPeripheral := &Peripheral{
|
||||||
Name: periphEl.Name + "_" + clusterName,
|
Name: periphEl.Name + "_" + clusterName,
|
||||||
GroupName: groupName + "_" + clusterName,
|
GroupName: groupName + "_" + clusterName,
|
||||||
Description: description + " - " + clusterName,
|
Description: description + " - " + clusterName,
|
||||||
ClusterName: clusterName,
|
ClusterName: clusterName,
|
||||||
BaseAddress: baseAddress,
|
BaseAddress: baseAddress,
|
||||||
registers: cpRegisters,
|
Registers: cpRegisters,
|
||||||
}
|
}
|
||||||
peripheralsList = append(peripheralsList, clusterPeripheral)
|
peripheralsList = append(peripheralsList, clusterPeripheral)
|
||||||
peripheralDict[clusterPeripheral.Name] = clusterPeripheral
|
peripheralDict[clusterPeripheral.Name] = clusterPeripheral
|
||||||
p.subtypes = append(p.subtypes, clusterPeripheral)
|
p.Subtypes = append(p.Subtypes, clusterPeripheral)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dim = -1
|
dim = -1
|
||||||
|
@ -352,15 +369,15 @@ func readSVD(path, sourceURL string) (*Device, error) {
|
||||||
clusterRegisters = append(clusterRegisters, parseRegister(regName, regEl, baseAddress+clusterOffset, clusterPrefix)...)
|
clusterRegisters = append(clusterRegisters, parseRegister(regName, regEl, baseAddress+clusterOffset, clusterPrefix)...)
|
||||||
}
|
}
|
||||||
sort.SliceStable(clusterRegisters, func(i, j int) bool {
|
sort.SliceStable(clusterRegisters, func(i, j int) bool {
|
||||||
return clusterRegisters[i].address < clusterRegisters[j].address
|
return clusterRegisters[i].Address < clusterRegisters[j].Address
|
||||||
})
|
})
|
||||||
if dimIncrement == -1 && len(clusterRegisters) > 0 {
|
if dimIncrement == -1 && len(clusterRegisters) > 0 {
|
||||||
lastReg := clusterRegisters[len(clusterRegisters)-1]
|
lastReg := clusterRegisters[len(clusterRegisters)-1]
|
||||||
lastAddress := lastReg.address
|
lastAddress := lastReg.Address
|
||||||
if lastReg.array != -1 {
|
if lastReg.Array != -1 {
|
||||||
lastAddress = lastReg.address + uint64(lastReg.array*lastReg.elementSize)
|
lastAddress = lastReg.Address + uint64(lastReg.Array*lastReg.ElementSize)
|
||||||
}
|
}
|
||||||
firstAddress := clusterRegisters[0].address
|
firstAddress := clusterRegisters[0].Address
|
||||||
dimIncrement = int(lastAddress - firstAddress)
|
dimIncrement = int(lastAddress - firstAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,22 +385,22 @@ func readSVD(path, sourceURL string) (*Device, error) {
|
||||||
clusterName = strings.ToUpper(clusterName)
|
clusterName = strings.ToUpper(clusterName)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.registers = append(p.registers, &PeripheralField{
|
p.Registers = append(p.Registers, &PeripheralField{
|
||||||
name: clusterName,
|
Name: clusterName,
|
||||||
address: baseAddress + clusterOffset,
|
Address: baseAddress + clusterOffset,
|
||||||
description: cluster.Description,
|
Description: cluster.Description,
|
||||||
registers: clusterRegisters,
|
Registers: clusterRegisters,
|
||||||
array: dim,
|
Array: dim,
|
||||||
elementSize: dimIncrement,
|
ElementSize: dimIncrement,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sort.SliceStable(p.registers, func(i, j int) bool {
|
sort.SliceStable(p.Registers, func(i, j int) bool {
|
||||||
return p.registers[i].address < p.registers[j].address
|
return p.Registers[i].Address < p.Registers[j].Address
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a sorted list of interrupts.
|
// Make a sorted list of interrupts.
|
||||||
interruptList := make([]*interrupt, 0, len(interrupts))
|
interruptList := make([]*Interrupt, 0, len(interrupts))
|
||||||
for _, intr := range interrupts {
|
for _, intr := range interrupts {
|
||||||
interruptList = append(interruptList, intr)
|
interruptList = append(interruptList, intr)
|
||||||
}
|
}
|
||||||
|
@ -391,7 +408,7 @@ func readSVD(path, sourceURL string) (*Device, error) {
|
||||||
if interruptList[i].Value != interruptList[j].Value {
|
if interruptList[i].Value != interruptList[j].Value {
|
||||||
return interruptList[i].Value < interruptList[j].Value
|
return interruptList[i].Value < interruptList[j].Value
|
||||||
}
|
}
|
||||||
return interruptList[i].peripheralIndex < interruptList[j].peripheralIndex
|
return interruptList[i].PeripheralIndex < interruptList[j].PeripheralIndex
|
||||||
})
|
})
|
||||||
|
|
||||||
// Properly format the license block, with comments.
|
// Properly format the license block, with comments.
|
||||||
|
@ -402,16 +419,16 @@ func readSVD(path, sourceURL string) (*Device, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Device{
|
return &Device{
|
||||||
metadata: map[string]string{
|
Metadata: &Metadata{
|
||||||
"file": filepath.Base(path),
|
File: filepath.Base(path),
|
||||||
"descriptorSource": sourceURL,
|
DescriptorSource: sourceURL,
|
||||||
"name": device.Name,
|
Name: device.Name,
|
||||||
"nameLower": strings.ToLower(device.Name),
|
NameLower: strings.ToLower(device.Name),
|
||||||
"description": strings.TrimSpace(device.Description),
|
Description: strings.TrimSpace(device.Description),
|
||||||
"licenseBlock": licenseBlock,
|
LicenseBlock: licenseBlock,
|
||||||
},
|
},
|
||||||
interrupts: interruptList,
|
Interrupts: interruptList,
|
||||||
peripherals: peripheralsList,
|
Peripherals: peripheralsList,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,7 +460,7 @@ func orderPeripherals(input []SVDPeripheral) []*SVDPeripheral {
|
||||||
return sortedPeripherals
|
return sortedPeripherals
|
||||||
}
|
}
|
||||||
|
|
||||||
func addInterrupt(interrupts map[string]*interrupt, name, interruptName string, index int, description string) {
|
func addInterrupt(interrupts map[string]*Interrupt, name, interruptName string, index int, description string) {
|
||||||
if _, ok := interrupts[name]; ok {
|
if _, ok := interrupts[name]; ok {
|
||||||
if interrupts[name].Value != index {
|
if interrupts[name].Value != index {
|
||||||
// Note: some SVD files like the one for STM32H7x7 contain mistakes.
|
// Note: some SVD files like the one for STM32H7x7 contain mistakes.
|
||||||
|
@ -462,10 +479,10 @@ func addInterrupt(interrupts map[string]*interrupt, name, interruptName string,
|
||||||
interrupts[name].Description += " // " + description
|
interrupts[name].Description += " // " + description
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
interrupts[name] = &interrupt{
|
interrupts[name] = &Interrupt{
|
||||||
Name: name,
|
Name: name,
|
||||||
HandlerName: interruptName + "_IRQHandler",
|
HandlerName: interruptName + "_IRQHandler",
|
||||||
peripheralIndex: len(interrupts),
|
PeripheralIndex: len(interrupts),
|
||||||
Value: index,
|
Value: index,
|
||||||
Description: description,
|
Description: description,
|
||||||
}
|
}
|
||||||
|
@ -542,20 +559,20 @@ func parseBitfields(groupName, regName string, fieldEls []*SVDField, bitfieldPre
|
||||||
}
|
}
|
||||||
|
|
||||||
fields = append(fields, Bitfield{
|
fields = append(fields, Bitfield{
|
||||||
name: fmt.Sprintf("%s_%s%s_%s_Pos", groupName, bitfieldPrefix, regName, fieldName),
|
Name: fmt.Sprintf("%s_%s%s_%s_Pos", groupName, bitfieldPrefix, regName, fieldName),
|
||||||
description: fmt.Sprintf("Position of %s field.", fieldName),
|
Description: fmt.Sprintf("Position of %s field.", fieldName),
|
||||||
value: lsb,
|
Value: lsb,
|
||||||
})
|
})
|
||||||
fields = append(fields, Bitfield{
|
fields = append(fields, Bitfield{
|
||||||
name: fmt.Sprintf("%s_%s%s_%s_Msk", groupName, bitfieldPrefix, regName, fieldName),
|
Name: fmt.Sprintf("%s_%s%s_%s_Msk", groupName, bitfieldPrefix, regName, fieldName),
|
||||||
description: fmt.Sprintf("Bit mask of %s field.", fieldName),
|
Description: fmt.Sprintf("Bit mask of %s field.", fieldName),
|
||||||
value: (0xffffffff >> (31 - (msb - lsb))) << lsb,
|
Value: (0xffffffff >> (31 - (msb - lsb))) << lsb,
|
||||||
})
|
})
|
||||||
if lsb == msb { // single bit
|
if lsb == msb { // single bit
|
||||||
fields = append(fields, Bitfield{
|
fields = append(fields, Bitfield{
|
||||||
name: fmt.Sprintf("%s_%s%s_%s", groupName, bitfieldPrefix, regName, fieldName),
|
Name: fmt.Sprintf("%s_%s%s_%s", groupName, bitfieldPrefix, regName, fieldName),
|
||||||
description: fmt.Sprintf("Bit %s.", fieldName),
|
Description: fmt.Sprintf("Bit %s.", fieldName),
|
||||||
value: 1 << lsb,
|
Value: 1 << lsb,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for _, enumEl := range enumeratedValues.EnumeratedValue {
|
for _, enumEl := range enumeratedValues.EnumeratedValue {
|
||||||
|
@ -566,7 +583,7 @@ func parseBitfields(groupName, regName string, fieldEls []*SVDField, bitfieldPre
|
||||||
if !unicode.IsUpper(rune(enumName[0])) && !unicode.IsDigit(rune(enumName[0])) {
|
if !unicode.IsUpper(rune(enumName[0])) && !unicode.IsDigit(rune(enumName[0])) {
|
||||||
enumName = strings.ToUpper(enumName)
|
enumName = strings.ToUpper(enumName)
|
||||||
}
|
}
|
||||||
enumDescription := strings.Replace(enumEl.Description, "\n", " ", -1)
|
enumDescription := formatText(enumEl.Description)
|
||||||
var enumValue uint64
|
var enumValue uint64
|
||||||
var err error
|
var err error
|
||||||
if strings.HasPrefix(enumEl.Value, "0b") {
|
if strings.HasPrefix(enumEl.Value, "0b") {
|
||||||
|
@ -606,7 +623,7 @@ func parseBitfields(groupName, regName string, fieldEls []*SVDField, bitfieldPre
|
||||||
// existing enum bitfield value.
|
// existing enum bitfield value.
|
||||||
enumSeen[enumName] = -1
|
enumSeen[enumName] = -1
|
||||||
for i, field := range fields {
|
for i, field := range fields {
|
||||||
if field.name == enumName {
|
if field.Name == enumName {
|
||||||
fields = append(fields[:i], fields[i+1:]...)
|
fields = append(fields[:i], fields[i+1:]...)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -617,9 +634,9 @@ func parseBitfields(groupName, regName string, fieldEls []*SVDField, bitfieldPre
|
||||||
enumSeen[enumName] = int64(enumValue)
|
enumSeen[enumName] = int64(enumValue)
|
||||||
|
|
||||||
fields = append(fields, Bitfield{
|
fields = append(fields, Bitfield{
|
||||||
name: enumName,
|
Name: enumName,
|
||||||
description: enumDescription,
|
Description: enumDescription,
|
||||||
value: uint32(enumValue),
|
Value: uint32(enumValue),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -643,7 +660,7 @@ func (r *Register) name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Register) description() string {
|
func (r *Register) description() string {
|
||||||
return strings.Replace(r.element.Description, "\n", " ", -1)
|
return formatText(r.element.Description)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Register) address() uint64 {
|
func (r *Register) address() uint64 {
|
||||||
|
@ -748,16 +765,16 @@ func parseRegister(groupName string, regEl *SVDRegister, baseAddress uint64, bit
|
||||||
for i, j := range reg.dimIndex() {
|
for i, j := range reg.dimIndex() {
|
||||||
regAddress := reg.address() + (uint64(i) * dimIncrement)
|
regAddress := reg.address() + (uint64(i) * dimIncrement)
|
||||||
results = append(results, &PeripheralField{
|
results = append(results, &PeripheralField{
|
||||||
name: strings.ToUpper(strings.Replace(reg.name(), "%s", j, -1)),
|
Name: strings.ToUpper(strings.Replace(reg.name(), "%s", j, -1)),
|
||||||
address: regAddress,
|
Address: regAddress,
|
||||||
description: reg.description(),
|
Description: reg.description(),
|
||||||
array: -1,
|
Array: -1,
|
||||||
elementSize: reg.size(),
|
ElementSize: reg.size(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// set first result bitfield
|
// set first result bitfield
|
||||||
shortName := strings.ToUpper(strings.Replace(strings.Replace(reg.name(), "_%s", "", -1), "%s", "", -1))
|
shortName := strings.ToUpper(strings.Replace(strings.Replace(reg.name(), "_%s", "", -1), "%s", "", -1))
|
||||||
results[0].bitfields = parseBitfields(groupName, shortName, regEl.Fields, bitfieldPrefix)
|
results[0].Bitfields = parseBitfields(groupName, shortName, regEl.Fields, bitfieldPrefix)
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -769,18 +786,18 @@ func parseRegister(groupName string, regEl *SVDRegister, baseAddress uint64, bit
|
||||||
|
|
||||||
bitfields := parseBitfields(groupName, regName, regEl.Fields, bitfieldPrefix)
|
bitfields := parseBitfields(groupName, regName, regEl.Fields, bitfieldPrefix)
|
||||||
return []*PeripheralField{&PeripheralField{
|
return []*PeripheralField{&PeripheralField{
|
||||||
name: regName,
|
Name: regName,
|
||||||
address: reg.address(),
|
Address: reg.address(),
|
||||||
description: reg.description(),
|
Description: reg.description(),
|
||||||
bitfields: bitfields,
|
Bitfields: bitfields,
|
||||||
array: reg.dim(),
|
Array: reg.dim(),
|
||||||
elementSize: reg.size(),
|
ElementSize: reg.size(),
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Go module for this device.
|
// The Go module for this device.
|
||||||
func writeGo(outdir string, device *Device, interruptSystem string) error {
|
func writeGo(outdir string, device *Device, interruptSystem string) error {
|
||||||
outf, err := os.Create(filepath.Join(outdir, device.metadata["nameLower"]+".go"))
|
outf, err := os.Create(filepath.Join(outdir, device.Metadata.NameLower+".go"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -788,20 +805,24 @@ func writeGo(outdir string, device *Device, interruptSystem string) error {
|
||||||
w := bufio.NewWriter(outf)
|
w := bufio.NewWriter(outf)
|
||||||
|
|
||||||
maxInterruptValue := 0
|
maxInterruptValue := 0
|
||||||
for _, intr := range device.interrupts {
|
for _, intr := range device.Interrupts {
|
||||||
if intr.Value > maxInterruptValue {
|
if intr.Value > maxInterruptValue {
|
||||||
maxInterruptValue = intr.Value
|
maxInterruptValue = intr.Value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t := template.Must(template.New("go").Parse(`// Automatically generated file. DO NOT EDIT.
|
t := template.Must(template.New("go").Funcs(template.FuncMap{
|
||||||
// Generated by gen-device-svd.go from {{.metadata.file}}, see {{.metadata.descriptorSource}}
|
"bytesNeeded": func(i, j uint64) uint64 { return j - i },
|
||||||
|
"isMultiline": isMultiline,
|
||||||
|
"splitLine": splitLine,
|
||||||
|
}).Parse(`// Automatically generated file. DO NOT EDIT.
|
||||||
|
// Generated by gen-device-svd.go from {{.device.Metadata.File}}, see {{.device.Metadata.DescriptorSource}}
|
||||||
|
|
||||||
// +build {{.pkgName}},{{.metadata.nameLower}}
|
// +build {{.pkgName}},{{.device.Metadata.NameLower}}
|
||||||
|
|
||||||
// {{.metadata.description}}
|
// {{.device.Metadata.Description}}
|
||||||
//
|
//
|
||||||
{{.metadata.licenseBlock}}
|
{{.device.Metadata.LicenseBlock}}
|
||||||
package {{.pkgName}}
|
package {{.pkgName}}
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -812,32 +833,50 @@ import (
|
||||||
|
|
||||||
// Some information about this device.
|
// Some information about this device.
|
||||||
const (
|
const (
|
||||||
DEVICE = "{{.metadata.name}}"
|
DEVICE = "{{.device.Metadata.Name}}"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Interrupt numbers.
|
// Interrupt numbers.
|
||||||
const ({{range .interrupts}}
|
const (
|
||||||
IRQ_{{.Name}} = {{.Value}} // {{.Description}}{{end}}
|
{{- range .device.Interrupts}}
|
||||||
IRQ_max = {{.interruptMax}} // Highest interrupt number on this device.
|
{{- if .Description}}
|
||||||
|
{{- range .Description|splitLine}}
|
||||||
|
// {{.}}
|
||||||
|
{{- end}}
|
||||||
|
{{- end}}
|
||||||
|
IRQ_{{.Name}} = {{.Value}}
|
||||||
|
{{- "\n"}}
|
||||||
|
{{- end}}
|
||||||
|
// Highest interrupt number on this device.
|
||||||
|
IRQ_max = {{.interruptMax}}
|
||||||
)
|
)
|
||||||
|
|
||||||
{{if eq .interruptSystem "hardware"}}
|
{{- if eq .interruptSystem "hardware"}}
|
||||||
// Map interrupt numbers to function names.
|
// Map interrupt numbers to function names.
|
||||||
// These aren't real calls, they're removed by the compiler.
|
// These aren't real calls, they're removed by the compiler.
|
||||||
var ({{range .interrupts}}
|
var (
|
||||||
_ = interrupt.Register(IRQ_{{.Name}}, "{{.HandlerName}}"){{end}}
|
{{- range .device.Interrupts}}
|
||||||
|
_ = interrupt.Register(IRQ_{{.Name}}, "{{.HandlerName}}")
|
||||||
|
{{- end}}
|
||||||
)
|
)
|
||||||
{{end}}
|
{{- end}}
|
||||||
|
|
||||||
// Peripherals.
|
// Peripherals.
|
||||||
var (
|
var (
|
||||||
{{range .peripherals}} {{.Name}} = (*{{.GroupName}}_Type)(unsafe.Pointer(uintptr(0x{{printf "%x" .BaseAddress}}))) // {{.Description}}
|
{{- range .device.Peripherals}}
|
||||||
{{end}})
|
{{- if .Description}}
|
||||||
|
{{- range .Description|splitLine}}
|
||||||
|
// {{.}}
|
||||||
|
{{- end}}
|
||||||
|
{{- end}}
|
||||||
|
{{.Name}} = (*{{.GroupName}}_Type)(unsafe.Pointer(uintptr(0x{{printf "%x" .BaseAddress}})))
|
||||||
|
{{- "\n"}}
|
||||||
|
{{- end}}
|
||||||
|
)
|
||||||
|
|
||||||
`))
|
`))
|
||||||
err = t.Execute(w, map[string]interface{}{
|
err = t.Execute(w, map[string]interface{}{
|
||||||
"metadata": device.metadata,
|
"device": device,
|
||||||
"interrupts": device.interrupts,
|
|
||||||
"peripherals": device.peripherals,
|
|
||||||
"pkgName": filepath.Base(strings.TrimRight(outdir, "/")),
|
"pkgName": filepath.Base(strings.TrimRight(outdir, "/")),
|
||||||
"interruptMax": maxInterruptValue,
|
"interruptMax": maxInterruptValue,
|
||||||
"interruptSystem": interruptSystem,
|
"interruptSystem": interruptSystem,
|
||||||
|
@ -847,16 +886,23 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define peripheral struct types.
|
// Define peripheral struct types.
|
||||||
for _, peripheral := range device.peripherals {
|
for _, peripheral := range device.Peripherals {
|
||||||
if peripheral.registers == nil {
|
if peripheral.Registers == nil {
|
||||||
// This peripheral was derived from another peripheral. No new type
|
// This peripheral was derived from another peripheral. No new type
|
||||||
// needs to be defined for it.
|
// needs to be defined for it.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "\n// %s\ntype %s_Type struct {\n", peripheral.Description, peripheral.GroupName)
|
fmt.Fprintln(w)
|
||||||
|
if peripheral.Description != "" {
|
||||||
|
for _, l := range splitLine(peripheral.Description) {
|
||||||
|
fmt.Fprintf(w, "// %s\n", l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "type %s_Type struct {\n", peripheral.GroupName)
|
||||||
|
|
||||||
address := peripheral.BaseAddress
|
address := peripheral.BaseAddress
|
||||||
for _, register := range peripheral.registers {
|
for _, register := range peripheral.Registers {
|
||||||
if register.registers == nil && address > register.address {
|
if register.Registers == nil && address > register.Address {
|
||||||
// In Nordic SVD files, these registers are deprecated or
|
// In Nordic SVD files, these registers are deprecated or
|
||||||
// duplicates, so can be ignored.
|
// duplicates, so can be ignored.
|
||||||
//fmt.Fprintf(os.Stderr, "skip: %s.%s 0x%x - 0x%x %d\n", peripheral.Name, register.name, address, register.address, register.elementSize)
|
//fmt.Fprintf(os.Stderr, "skip: %s.%s 0x%x - 0x%x %d\n", peripheral.Name, register.name, address, register.address, register.elementSize)
|
||||||
|
@ -864,7 +910,7 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
var regType string
|
var regType string
|
||||||
switch register.elementSize {
|
switch register.ElementSize {
|
||||||
case 8:
|
case 8:
|
||||||
regType = "volatile.Register64"
|
regType = "volatile.Register64"
|
||||||
case 4:
|
case 4:
|
||||||
|
@ -878,24 +924,24 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert padding, if needed
|
// insert padding, if needed
|
||||||
if address < register.address {
|
if address < register.Address {
|
||||||
bytesNeeded := register.address - address
|
bytesNeeded := register.Address - address
|
||||||
if bytesNeeded == 1 {
|
if bytesNeeded == 1 {
|
||||||
w.WriteString("\t_ byte\n")
|
w.WriteString("\t_ byte\n")
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(w, "\t_ [%d]byte\n", bytesNeeded)
|
fmt.Fprintf(w, "\t_ [%d]byte\n", bytesNeeded)
|
||||||
}
|
}
|
||||||
address = register.address
|
address = register.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
lastCluster := false
|
lastCluster := false
|
||||||
if register.registers != nil {
|
if register.Registers != nil {
|
||||||
// This is a cluster, not a register. Create the cluster type.
|
// This is a cluster, not a register. Create the cluster type.
|
||||||
regType = "struct {\n"
|
regType = "struct {\n"
|
||||||
subaddress := register.address
|
subaddress := register.Address
|
||||||
for _, subregister := range register.registers {
|
for _, subregister := range register.Registers {
|
||||||
var subregType string
|
var subregType string
|
||||||
switch subregister.elementSize {
|
switch subregister.ElementSize {
|
||||||
case 8:
|
case 8:
|
||||||
subregType = "volatile.Register64"
|
subregType = "volatile.Register64"
|
||||||
case 4:
|
case 4:
|
||||||
|
@ -909,11 +955,11 @@ var (
|
||||||
panic("unknown element size")
|
panic("unknown element size")
|
||||||
}
|
}
|
||||||
|
|
||||||
if subregister.array != -1 {
|
if subregister.Array != -1 {
|
||||||
subregType = fmt.Sprintf("[%d]%s", subregister.array, subregType)
|
subregType = fmt.Sprintf("[%d]%s", subregister.Array, subregType)
|
||||||
}
|
}
|
||||||
if subaddress != subregister.address {
|
if subaddress != subregister.Address {
|
||||||
bytesNeeded := subregister.address - subaddress
|
bytesNeeded := subregister.Address - subaddress
|
||||||
if bytesNeeded == 1 {
|
if bytesNeeded == 1 {
|
||||||
regType += "\t\t_ byte\n"
|
regType += "\t\t_ byte\n"
|
||||||
} else {
|
} else {
|
||||||
|
@ -922,17 +968,17 @@ var (
|
||||||
subaddress += bytesNeeded
|
subaddress += bytesNeeded
|
||||||
}
|
}
|
||||||
var subregSize uint64
|
var subregSize uint64
|
||||||
if subregister.array != -1 {
|
if subregister.Array != -1 {
|
||||||
subregSize = uint64(subregister.array * subregister.elementSize)
|
subregSize = uint64(subregister.Array * subregister.ElementSize)
|
||||||
} else {
|
} else {
|
||||||
subregSize = uint64(subregister.elementSize)
|
subregSize = uint64(subregister.ElementSize)
|
||||||
}
|
}
|
||||||
subaddress += subregSize
|
subaddress += subregSize
|
||||||
regType += fmt.Sprintf("\t\t%s %s\n", subregister.name, subregType)
|
regType += fmt.Sprintf("\t\t%s %s\n", subregister.Name, subregType)
|
||||||
}
|
}
|
||||||
if register.array != -1 {
|
if register.Array != -1 {
|
||||||
if subaddress != register.address+uint64(register.elementSize) {
|
if subaddress != register.Address+uint64(register.ElementSize) {
|
||||||
bytesNeeded := (register.address + uint64(register.elementSize)) - subaddress
|
bytesNeeded := (register.Address + uint64(register.ElementSize)) - subaddress
|
||||||
if bytesNeeded == 1 {
|
if bytesNeeded == 1 {
|
||||||
regType += "\t_ byte\n"
|
regType += "\t_ byte\n"
|
||||||
} else {
|
} else {
|
||||||
|
@ -946,40 +992,49 @@ var (
|
||||||
address = subaddress
|
address = subaddress
|
||||||
}
|
}
|
||||||
|
|
||||||
if register.array != -1 {
|
if register.Array != -1 {
|
||||||
regType = fmt.Sprintf("[%d]%s", register.array, regType)
|
regType = fmt.Sprintf("[%d]%s", register.Array, regType)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "\t%s %s // 0x%X\n", register.name, regType, register.address-peripheral.BaseAddress)
|
fmt.Fprintf(w, "\t%s %s // 0x%X\n", register.Name, regType, register.Address-peripheral.BaseAddress)
|
||||||
|
|
||||||
// next address
|
// next address
|
||||||
if lastCluster {
|
if lastCluster {
|
||||||
lastCluster = false
|
lastCluster = false
|
||||||
} else if register.array != -1 {
|
} else if register.Array != -1 {
|
||||||
address = register.address + uint64(register.elementSize*register.array)
|
address = register.Address + uint64(register.ElementSize*register.Array)
|
||||||
} else {
|
} else {
|
||||||
address = register.address + uint64(register.elementSize)
|
address = register.Address + uint64(register.ElementSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.WriteString("}\n")
|
w.WriteString("}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define bitfields.
|
// Define bitfields.
|
||||||
for _, peripheral := range device.peripherals {
|
for _, peripheral := range device.Peripherals {
|
||||||
if peripheral.registers == nil {
|
if peripheral.Registers == nil {
|
||||||
// This peripheral was derived from another peripheral. Bitfields are
|
// This peripheral was derived from another peripheral. Bitfields are
|
||||||
// already defined.
|
// already defined.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "\n// Bitfields for %s: %s\nconst(", peripheral.Name, peripheral.Description)
|
fmt.Fprintf(w, "\n// Bitfields for %s", peripheral.Name)
|
||||||
for _, register := range peripheral.registers {
|
if isMultiline(peripheral.Description) {
|
||||||
if len(register.bitfields) != 0 {
|
for _, l := range splitLine(peripheral.Description) {
|
||||||
writeGoRegisterBitfields(w, register, register.name)
|
fmt.Fprintf(w, "\n// %s", l)
|
||||||
}
|
}
|
||||||
if register.registers == nil {
|
} else if peripheral.Description != "" {
|
||||||
|
fmt.Fprintf(w, ": %s", peripheral.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(w, "\nconst(")
|
||||||
|
for _, register := range peripheral.Registers {
|
||||||
|
if len(register.Bitfields) != 0 {
|
||||||
|
writeGoRegisterBitfields(w, register, register.Name)
|
||||||
|
}
|
||||||
|
if register.Registers == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, subregister := range register.registers {
|
for _, subregister := range register.Registers {
|
||||||
writeGoRegisterBitfields(w, subregister, register.name+"."+subregister.name)
|
writeGoRegisterBitfields(w, subregister, register.Name+"."+subregister.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.WriteString(")\n")
|
w.WriteString(")\n")
|
||||||
|
@ -990,22 +1045,29 @@ var (
|
||||||
|
|
||||||
func writeGoRegisterBitfields(w *bufio.Writer, register *PeripheralField, name string) {
|
func writeGoRegisterBitfields(w *bufio.Writer, register *PeripheralField, name string) {
|
||||||
w.WriteString("\n\t// " + name)
|
w.WriteString("\n\t// " + name)
|
||||||
if register.description != "" {
|
if register.Description != "" {
|
||||||
w.WriteString(": " + register.description)
|
if isMultiline(register.Description) {
|
||||||
|
for _, l := range splitLine(register.Description) {
|
||||||
|
w.WriteString("\n\t// " + l)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
w.WriteString(": " + register.Description)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
w.WriteByte('\n')
|
w.WriteByte('\n')
|
||||||
for _, bitfield := range register.bitfields {
|
for _, bitfield := range register.Bitfields {
|
||||||
fmt.Fprintf(w, "\t%s = 0x%x", bitfield.name, bitfield.value)
|
if bitfield.Description != "" {
|
||||||
if bitfield.description != "" {
|
for _, l := range splitLine(bitfield.Description) {
|
||||||
w.WriteString(" // " + bitfield.description)
|
w.WriteString("\t// " + l + "\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
w.WriteByte('\n')
|
fmt.Fprintf(w, "\t%s = 0x%x\n", bitfield.Name, bitfield.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The interrupt vector, which is hard to write directly in Go.
|
// The interrupt vector, which is hard to write directly in Go.
|
||||||
func writeAsm(outdir string, device *Device) error {
|
func writeAsm(outdir string, device *Device) error {
|
||||||
outf, err := os.Create(filepath.Join(outdir, device.metadata["nameLower"]+".s"))
|
outf, err := os.Create(filepath.Join(outdir, device.Metadata.NameLower+".s"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1013,11 +1075,11 @@ func writeAsm(outdir string, device *Device) error {
|
||||||
w := bufio.NewWriter(outf)
|
w := bufio.NewWriter(outf)
|
||||||
|
|
||||||
t := template.Must(template.New("go").Parse(`// Automatically generated file. DO NOT EDIT.
|
t := template.Must(template.New("go").Parse(`// Automatically generated file. DO NOT EDIT.
|
||||||
// Generated by gen-device-svd.go from {{.file}}, see {{.descriptorSource}}
|
// Generated by gen-device-svd.go from {{.File}}, see {{.DescriptorSource}}
|
||||||
|
|
||||||
// {{.description}}
|
// {{.Description}}
|
||||||
//
|
//
|
||||||
{{.licenseBlock}}
|
{{.LicenseBlock}}
|
||||||
|
|
||||||
.syntax unified
|
.syntax unified
|
||||||
|
|
||||||
|
@ -1063,12 +1125,12 @@ Default_Handler:
|
||||||
|
|
||||||
// Extra interrupts for peripherals defined by the hardware vendor.
|
// Extra interrupts for peripherals defined by the hardware vendor.
|
||||||
`))
|
`))
|
||||||
err = t.Execute(w, device.metadata)
|
err = t.Execute(w, device.Metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
num := 0
|
num := 0
|
||||||
for _, intr := range device.interrupts {
|
for _, intr := range device.Interrupts {
|
||||||
if intr.Value == num-1 {
|
if intr.Value == num-1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1096,7 +1158,7 @@ Default_Handler:
|
||||||
IRQ PendSV_Handler
|
IRQ PendSV_Handler
|
||||||
IRQ SysTick_Handler
|
IRQ SysTick_Handler
|
||||||
`)
|
`)
|
||||||
for _, intr := range device.interrupts {
|
for _, intr := range device.Interrupts {
|
||||||
fmt.Fprintf(w, " IRQ %s_IRQHandler\n", intr.Name)
|
fmt.Fprintf(w, " IRQ %s_IRQHandler\n", intr.Name)
|
||||||
}
|
}
|
||||||
return w.Flush()
|
return w.Flush()
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче