github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/tools/gen-device-svd/gen-device-svd.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"encoding/xml"
     6  	"errors"
     7  	"flag"
     8  	"fmt"
     9  	"io/fs"
    10  	"os"
    11  	"path/filepath"
    12  	"regexp"
    13  	"sort"
    14  	"strconv"
    15  	"strings"
    16  	"text/template"
    17  	"unicode"
    18  )
    19  
    20  var validName = regexp.MustCompile("^[a-zA-Z0-9_]+$")
    21  var enumBitSpecifier = regexp.MustCompile("^#x*[01]+[01x]*$")
    22  
    23  type SVDFile struct {
    24  	XMLName     xml.Name `xml:"device"`
    25  	Name        string   `xml:"name"`
    26  	Description string   `xml:"description"`
    27  	LicenseText string   `xml:"licenseText"`
    28  	CPU         *struct {
    29  		Name         string `xml:"name"`
    30  		FPUPresent   bool   `xml:"fpuPresent"`
    31  		NVICPrioBits int    `xml:"nvicPrioBits"`
    32  	} `xml:"cpu"`
    33  	Peripherals []SVDPeripheral `xml:"peripherals>peripheral"`
    34  }
    35  
    36  type SVDPeripheral struct {
    37  	Name        string `xml:"name"`
    38  	Description string `xml:"description"`
    39  	BaseAddress string `xml:"baseAddress"`
    40  	GroupName   string `xml:"groupName"`
    41  	DerivedFrom string `xml:"derivedFrom,attr"`
    42  	Interrupts  []struct {
    43  		Name  string `xml:"name"`
    44  		Index int    `xml:"value"`
    45  	} `xml:"interrupt"`
    46  	Registers []*SVDRegister `xml:"registers>register"`
    47  	Clusters  []*SVDCluster  `xml:"registers>cluster"`
    48  }
    49  
    50  type SVDRegister struct {
    51  	Name          string      `xml:"name"`
    52  	Description   string      `xml:"description"`
    53  	Dim           *string     `xml:"dim"`
    54  	DimIndex      *string     `xml:"dimIndex"`
    55  	DimIncrement  string      `xml:"dimIncrement"`
    56  	Size          *string     `xml:"size"`
    57  	Fields        []*SVDField `xml:"fields>field"`
    58  	Offset        *string     `xml:"offset"`
    59  	AddressOffset *string     `xml:"addressOffset"`
    60  }
    61  
    62  type SVDField struct {
    63  	Name             string  `xml:"name"`
    64  	Description      string  `xml:"description"`
    65  	Lsb              *uint32 `xml:"lsb"`
    66  	Msb              *uint32 `xml:"msb"`
    67  	BitOffset        *uint32 `xml:"bitOffset"`
    68  	BitWidth         *uint32 `xml:"bitWidth"`
    69  	BitRange         *string `xml:"bitRange"`
    70  	EnumeratedValues struct {
    71  		DerivedFrom     string `xml:"derivedFrom,attr"`
    72  		Name            string `xml:"name"`
    73  		EnumeratedValue []struct {
    74  			Name        string `xml:"name"`
    75  			Description string `xml:"description"`
    76  			Value       string `xml:"value"`
    77  		} `xml:"enumeratedValue"`
    78  	} `xml:"enumeratedValues"`
    79  }
    80  
    81  type SVDCluster struct {
    82  	Dim           *int           `xml:"dim"`
    83  	DimIncrement  string         `xml:"dimIncrement"`
    84  	DimIndex      *string        `xml:"dimIndex"`
    85  	Name          string         `xml:"name"`
    86  	Description   string         `xml:"description"`
    87  	Registers     []*SVDRegister `xml:"register"`
    88  	Clusters      []*SVDCluster  `xml:"cluster"`
    89  	AddressOffset string         `xml:"addressOffset"`
    90  }
    91  
    92  type Device struct {
    93  	Metadata       *Metadata
    94  	Interrupts     []*Interrupt
    95  	Peripherals    []*Peripheral
    96  	PeripheralDict map[string]*Peripheral
    97  }
    98  
    99  type Metadata struct {
   100  	File             string
   101  	DescriptorSource string
   102  	Name             string
   103  	NameLower        string
   104  	Description      string
   105  	LicenseBlock     string
   106  
   107  	HasCPUInfo   bool // set if the following fields are populated
   108  	CPUName      string
   109  	FPUPresent   bool
   110  	NVICPrioBits int
   111  }
   112  
   113  type Interrupt struct {
   114  	Name            string
   115  	HandlerName     string
   116  	PeripheralIndex int
   117  	Value           int // interrupt number
   118  	Description     string
   119  }
   120  
   121  type Peripheral struct {
   122  	Name        string
   123  	GroupName   string
   124  	BaseAddress uint64
   125  	Description string
   126  	ClusterName string
   127  	Registers   []*PeripheralField
   128  	Subtypes    []*Peripheral
   129  }
   130  
   131  // A PeripheralField is a single field in a peripheral type. It may be a full
   132  // peripheral or a cluster within a peripheral.
   133  type PeripheralField struct {
   134  	Name         string
   135  	Address      uint64
   136  	Description  string
   137  	Registers    []*PeripheralField // contains fields if this is a cluster
   138  	Array        int
   139  	ElementSize  int
   140  	Constants    []Constant
   141  	ShortName    string     // name stripped of "spaced array" suffix
   142  	Bitfields    []Bitfield // set of bit-fields provided by this
   143  	HasBitfields bool       // set true when Bitfields was set for a first PeripheralField of "spaced array".
   144  }
   145  
   146  type Constant struct {
   147  	Name        string
   148  	Description string
   149  	Value       uint64
   150  }
   151  
   152  type Bitfield struct {
   153  	Name   string
   154  	Offset uint32
   155  	Mask   uint32
   156  }
   157  
   158  func formatText(text string) string {
   159  	text = regexp.MustCompile(`[ \t\n]+`).ReplaceAllString(text, " ") // Collapse whitespace (like in HTML)
   160  	text = strings.ReplaceAll(text, "\\n ", "\n")
   161  	text = strings.TrimSpace(text)
   162  	return text
   163  }
   164  
   165  func isMultiline(s string) bool {
   166  	return strings.Index(s, "\n") >= 0
   167  }
   168  
   169  func splitLine(s string) []string {
   170  	return strings.Split(s, "\n")
   171  }
   172  
   173  // Replace characters that are not allowed in a symbol name with a '_'. This is
   174  // useful to be able to process SVD files with errors.
   175  func cleanName(text string) string {
   176  	if !validName.MatchString(text) {
   177  		result := make([]rune, 0, len(text))
   178  		for _, c := range text {
   179  			if validName.MatchString(string(c)) {
   180  				result = append(result, c)
   181  			} else {
   182  				result = append(result, '_')
   183  			}
   184  		}
   185  		text = string(result)
   186  	}
   187  	if len(text) != 0 && (text[0] >= '0' && text[0] <= '9') {
   188  		// Identifiers may not start with a number.
   189  		// Add an underscore instead.
   190  		text = "_" + text
   191  	}
   192  	return text
   193  }
   194  
   195  func processSubCluster(p *Peripheral, cluster *SVDCluster, clusterOffset uint64, clusterName string, peripheralDict map[string]*Peripheral) []*Peripheral {
   196  	var peripheralsList []*Peripheral
   197  	clusterPrefix := clusterName + "_"
   198  	cpRegisters := []*PeripheralField{}
   199  
   200  	for _, regEl := range cluster.Registers {
   201  		cpRegisters = append(cpRegisters, parseRegister(p.GroupName, regEl, p.BaseAddress+clusterOffset, clusterPrefix)...)
   202  	}
   203  	// handle sub-clusters of registers
   204  	for _, subClusterEl := range cluster.Clusters {
   205  		subclusterName := strings.ReplaceAll(subClusterEl.Name, "[%s]", "")
   206  		subclusterPrefix := subclusterName + "_"
   207  		subclusterOffset, err := strconv.ParseUint(subClusterEl.AddressOffset, 0, 32)
   208  		if err != nil {
   209  			panic(err)
   210  		}
   211  		subdim := *subClusterEl.Dim
   212  		subdimIncrement, err := strconv.ParseInt(subClusterEl.DimIncrement, 0, 32)
   213  		if err != nil {
   214  			panic(err)
   215  		}
   216  
   217  		if subdim > 1 {
   218  			subcpRegisters := []*PeripheralField{}
   219  			for _, regEl := range subClusterEl.Registers {
   220  				subcpRegisters = append(subcpRegisters, parseRegister(p.GroupName, regEl, p.BaseAddress+clusterOffset+subclusterOffset, subclusterPrefix)...)
   221  			}
   222  
   223  			cpRegisters = append(cpRegisters, &PeripheralField{
   224  				Name:        subclusterName,
   225  				Address:     p.BaseAddress + clusterOffset + subclusterOffset,
   226  				Description: subClusterEl.Description,
   227  				Registers:   subcpRegisters,
   228  				Array:       subdim,
   229  				ElementSize: int(subdimIncrement),
   230  				ShortName:   clusterPrefix + subclusterName,
   231  			})
   232  		} else {
   233  			for _, regEl := range subClusterEl.Registers {
   234  				cpRegisters = append(cpRegisters, parseRegister(regEl.Name, regEl, p.BaseAddress+clusterOffset+subclusterOffset, subclusterPrefix)...)
   235  			}
   236  		}
   237  	}
   238  
   239  	sort.SliceStable(cpRegisters, func(i, j int) bool {
   240  		return cpRegisters[i].Address < cpRegisters[j].Address
   241  	})
   242  	clusterPeripheral := &Peripheral{
   243  		Name:        p.Name + "_" + clusterName,
   244  		GroupName:   p.GroupName + "_" + clusterName,
   245  		Description: p.Description + " - " + clusterName,
   246  		ClusterName: clusterName,
   247  		BaseAddress: p.BaseAddress + clusterOffset,
   248  		Registers:   cpRegisters,
   249  	}
   250  	peripheralsList = append(peripheralsList, clusterPeripheral)
   251  	peripheralDict[clusterPeripheral.Name] = clusterPeripheral
   252  	p.Subtypes = append(p.Subtypes, clusterPeripheral)
   253  
   254  	return peripheralsList
   255  }
   256  
   257  func processCluster(p *Peripheral, clusters []*SVDCluster, peripheralDict map[string]*Peripheral) []*Peripheral {
   258  	var peripheralsList []*Peripheral
   259  	for _, cluster := range clusters {
   260  		clusterName := strings.ReplaceAll(cluster.Name, "[%s]", "")
   261  		if cluster.DimIndex != nil {
   262  			clusterName = strings.ReplaceAll(clusterName, "%s", "")
   263  		}
   264  		clusterPrefix := clusterName + "_"
   265  		clusterOffset, err := strconv.ParseUint(cluster.AddressOffset, 0, 32)
   266  		if err != nil {
   267  			panic(err)
   268  		}
   269  		var dim, dimIncrement int
   270  		if cluster.Dim == nil {
   271  			// Nordic SVD have sub-clusters with another sub-clusters.
   272  			if clusterOffset == 0 || len(cluster.Clusters) > 0 {
   273  				peripheralsList = append(peripheralsList, processSubCluster(p, cluster, clusterOffset, clusterName, peripheralDict)...)
   274  				continue
   275  			}
   276  			dim = -1
   277  			dimIncrement = -1
   278  		} else {
   279  			dim = *cluster.Dim
   280  			if dim == 1 {
   281  				dimIncrement = -1
   282  			} else {
   283  				inc, err := strconv.ParseUint(cluster.DimIncrement, 0, 32)
   284  				if err != nil {
   285  					panic(err)
   286  				}
   287  				dimIncrement = int(inc)
   288  			}
   289  		}
   290  		clusterRegisters := []*PeripheralField{}
   291  		for _, regEl := range cluster.Registers {
   292  			regName := p.GroupName
   293  			if regName == "" {
   294  				regName = p.Name
   295  			}
   296  			clusterRegisters = append(clusterRegisters, parseRegister(regName, regEl, p.BaseAddress+clusterOffset, clusterPrefix)...)
   297  		}
   298  		sort.SliceStable(clusterRegisters, func(i, j int) bool {
   299  			return clusterRegisters[i].Address < clusterRegisters[j].Address
   300  		})
   301  		if dimIncrement == -1 && len(clusterRegisters) > 0 {
   302  			lastReg := clusterRegisters[len(clusterRegisters)-1]
   303  			lastAddress := lastReg.Address
   304  			if lastReg.Array != -1 {
   305  				lastAddress = lastReg.Address + uint64(lastReg.Array*lastReg.ElementSize)
   306  			}
   307  			firstAddress := clusterRegisters[0].Address
   308  			dimIncrement = int(lastAddress - firstAddress)
   309  		}
   310  
   311  		if !unicode.IsUpper(rune(clusterName[0])) && !unicode.IsDigit(rune(clusterName[0])) {
   312  			clusterName = strings.ToUpper(clusterName)
   313  		}
   314  
   315  		p.Registers = append(p.Registers, &PeripheralField{
   316  			Name:        clusterName,
   317  			Address:     p.BaseAddress + clusterOffset,
   318  			Description: cluster.Description,
   319  			Registers:   clusterRegisters,
   320  			Array:       dim,
   321  			ElementSize: dimIncrement,
   322  			ShortName:   clusterName,
   323  		})
   324  	}
   325  	sort.SliceStable(p.Registers, func(i, j int) bool {
   326  		return p.Registers[i].Address < p.Registers[j].Address
   327  	})
   328  	return peripheralsList
   329  }
   330  
   331  // Read ARM SVD files.
   332  func readSVD(path, sourceURL string) (*Device, error) {
   333  	// Open the XML file.
   334  	f, err := os.Open(path)
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  	defer f.Close()
   339  	decoder := xml.NewDecoder(f)
   340  	device := &SVDFile{}
   341  	err = decoder.Decode(device)
   342  	if err != nil {
   343  		return nil, err
   344  	}
   345  
   346  	peripheralDict := map[string]*Peripheral{}
   347  	groups := map[string]*Peripheral{}
   348  
   349  	interrupts := make(map[string]*Interrupt)
   350  	var peripheralsList []*Peripheral
   351  
   352  	// Some SVD files have peripheral elements derived from a peripheral that
   353  	// comes later in the file. To make sure this works, sort the peripherals if
   354  	// needed.
   355  	orderedPeripherals := orderPeripherals(device.Peripherals)
   356  
   357  	for _, periphEl := range orderedPeripherals {
   358  		description := formatText(periphEl.Description)
   359  		baseAddress, err := strconv.ParseUint(periphEl.BaseAddress, 0, 64)
   360  		if err != nil {
   361  			return nil, fmt.Errorf("invalid base address: %w", err)
   362  		}
   363  		// Some group names (for example the STM32H7A3x) have an invalid
   364  		// group name. Replace invalid characters with "_".
   365  		groupName := cleanName(periphEl.GroupName)
   366  		if groupName == "" {
   367  			groupName = cleanName(periphEl.Name)
   368  		}
   369  
   370  		for _, interrupt := range periphEl.Interrupts {
   371  			addInterrupt(interrupts, interrupt.Name, interrupt.Name, interrupt.Index, description)
   372  			// As a convenience, also use the peripheral name as the interrupt
   373  			// name. Only do that for the nrf for now, as the stm32 .svd files
   374  			// don't always put interrupts in the correct peripheral...
   375  			if len(periphEl.Interrupts) == 1 && strings.HasPrefix(device.Name, "nrf") {
   376  				addInterrupt(interrupts, periphEl.Name, interrupt.Name, interrupt.Index, description)
   377  			}
   378  		}
   379  
   380  		if _, ok := groups[groupName]; ok || periphEl.DerivedFrom != "" {
   381  			var derivedFrom *Peripheral
   382  			if periphEl.DerivedFrom != "" {
   383  				derivedFrom = peripheralDict[periphEl.DerivedFrom]
   384  			} else {
   385  				derivedFrom = groups[groupName]
   386  			}
   387  			p := &Peripheral{
   388  				Name:        periphEl.Name,
   389  				GroupName:   derivedFrom.GroupName,
   390  				Description: description,
   391  				BaseAddress: baseAddress,
   392  			}
   393  			if p.Description == "" {
   394  				p.Description = derivedFrom.Description
   395  			}
   396  			peripheralsList = append(peripheralsList, p)
   397  			peripheralDict[p.Name] = p
   398  			for _, subtype := range derivedFrom.Subtypes {
   399  				peripheralsList = append(peripheralsList, &Peripheral{
   400  					Name:        periphEl.Name + "_" + subtype.ClusterName,
   401  					GroupName:   subtype.GroupName,
   402  					Description: subtype.Description,
   403  					BaseAddress: baseAddress,
   404  				})
   405  			}
   406  			continue
   407  		}
   408  
   409  		p := &Peripheral{
   410  			Name:        periphEl.Name,
   411  			GroupName:   groupName,
   412  			Description: description,
   413  			BaseAddress: baseAddress,
   414  			Registers:   []*PeripheralField{},
   415  		}
   416  		if p.GroupName == "" {
   417  			p.GroupName = periphEl.Name
   418  		}
   419  		peripheralsList = append(peripheralsList, p)
   420  		peripheralDict[periphEl.Name] = p
   421  
   422  		if _, ok := groups[groupName]; !ok && groupName != "" {
   423  			groups[groupName] = p
   424  		}
   425  
   426  		for _, register := range periphEl.Registers {
   427  			regName := groupName // preferably use the group name
   428  			if regName == "" {
   429  				regName = periphEl.Name // fall back to peripheral name
   430  			}
   431  			p.Registers = append(p.Registers, parseRegister(regName, register, baseAddress, "")...)
   432  		}
   433  		peripheralsList = append(peripheralsList, processCluster(p, periphEl.Clusters, peripheralDict)...)
   434  	}
   435  
   436  	// Make a sorted list of interrupts.
   437  	interruptList := make([]*Interrupt, 0, len(interrupts))
   438  	for _, intr := range interrupts {
   439  		interruptList = append(interruptList, intr)
   440  	}
   441  	sort.SliceStable(interruptList, func(i, j int) bool {
   442  		if interruptList[i].Value != interruptList[j].Value {
   443  			return interruptList[i].Value < interruptList[j].Value
   444  		}
   445  		return interruptList[i].PeripheralIndex < interruptList[j].PeripheralIndex
   446  	})
   447  
   448  	// Properly format the license block, with comments.
   449  	licenseBlock := ""
   450  	if text := formatText(device.LicenseText); text != "" {
   451  		licenseBlock = "//     " + strings.ReplaceAll(text, "\n", "\n//     ")
   452  		licenseBlock = regexp.MustCompile(`\s+\n`).ReplaceAllString(licenseBlock, "\n")
   453  	}
   454  
   455  	// Remove "-" characters from the device name because such characters cannot
   456  	// be used in build tags. Necessary for the ESP32-C3 for example.
   457  	nameLower := strings.ReplaceAll(strings.ToLower(device.Name), "-", "")
   458  	metadata := &Metadata{
   459  		File:             filepath.Base(path),
   460  		DescriptorSource: sourceURL,
   461  		Name:             device.Name,
   462  		NameLower:        nameLower,
   463  		Description:      strings.TrimSpace(device.Description),
   464  		LicenseBlock:     licenseBlock,
   465  	}
   466  	if device.CPU != nil {
   467  		metadata.HasCPUInfo = true
   468  		metadata.CPUName = device.CPU.Name
   469  		metadata.FPUPresent = device.CPU.FPUPresent
   470  		metadata.NVICPrioBits = device.CPU.NVICPrioBits
   471  	}
   472  	return &Device{
   473  		Metadata:       metadata,
   474  		Interrupts:     interruptList,
   475  		Peripherals:    peripheralsList,
   476  		PeripheralDict: peripheralDict,
   477  	}, nil
   478  }
   479  
   480  // orderPeripherals sorts the peripherals so that derived peripherals come after
   481  // base peripherals. This is necessary for some SVD files.
   482  func orderPeripherals(input []SVDPeripheral) []*SVDPeripheral {
   483  	var sortedPeripherals []*SVDPeripheral
   484  	var missingBasePeripherals []*SVDPeripheral
   485  	knownBasePeripherals := map[string]struct{}{}
   486  	for i := range input {
   487  		p := &input[i]
   488  		groupName := p.GroupName
   489  		if groupName == "" {
   490  			groupName = p.Name
   491  		}
   492  		knownBasePeripherals[groupName] = struct{}{}
   493  		if p.DerivedFrom != "" {
   494  			if _, ok := knownBasePeripherals[p.DerivedFrom]; !ok {
   495  				missingBasePeripherals = append(missingBasePeripherals, p)
   496  				continue
   497  			}
   498  		}
   499  		sortedPeripherals = append(sortedPeripherals, p)
   500  	}
   501  
   502  	// Let's hope all base peripherals are now included.
   503  	sortedPeripherals = append(sortedPeripherals, missingBasePeripherals...)
   504  
   505  	return sortedPeripherals
   506  }
   507  
   508  func addInterrupt(interrupts map[string]*Interrupt, name, interruptName string, index int, description string) {
   509  	if _, ok := interrupts[name]; ok {
   510  		if interrupts[name].Value != index {
   511  			// Note: some SVD files like the one for STM32H7x7 contain mistakes.
   512  			// Instead of throwing an error, simply log it.
   513  			fmt.Fprintf(os.Stderr, "interrupt with the same name has different indexes: %s (%d vs %d)\n",
   514  				name, interrupts[name].Value, index)
   515  		}
   516  		parts := strings.Split(interrupts[name].Description, " // ")
   517  		hasDescription := false
   518  		for _, part := range parts {
   519  			if part == description {
   520  				hasDescription = true
   521  			}
   522  		}
   523  		if !hasDescription {
   524  			interrupts[name].Description += " // " + description
   525  		}
   526  	} else {
   527  		interrupts[name] = &Interrupt{
   528  			Name:            name,
   529  			HandlerName:     interruptName + "_IRQHandler",
   530  			PeripheralIndex: len(interrupts),
   531  			Value:           index,
   532  			Description:     description,
   533  		}
   534  	}
   535  }
   536  
   537  func parseBitfields(groupName, regName string, fieldEls []*SVDField, bitfieldPrefix string) ([]Constant, []Bitfield) {
   538  	var fields []Constant
   539  	var bitfields []Bitfield
   540  	enumSeen := map[string]int64{}
   541  	for _, fieldEl := range fieldEls {
   542  		// Some bitfields (like the STM32H7x7) contain invalid bitfield
   543  		// names like "CNT[31]". Replace invalid characters with "_" when
   544  		// needed.
   545  		fieldName := cleanName(fieldEl.Name)
   546  		if !unicode.IsUpper(rune(fieldName[0])) && !unicode.IsDigit(rune(fieldName[0])) {
   547  			fieldName = strings.ToUpper(fieldName)
   548  		}
   549  
   550  		// Find the lsb/msb that is encoded in various ways.
   551  		// Standards are great, that's why there are so many to choose from!
   552  		var lsb, msb uint32
   553  		if fieldEl.Lsb != nil && fieldEl.Msb != nil {
   554  			// try to use lsb/msb tags
   555  			lsb = *fieldEl.Lsb
   556  			msb = *fieldEl.Msb
   557  		} else if fieldEl.BitOffset != nil && fieldEl.BitWidth != nil {
   558  			// try to use bitOffset/bitWidth tags
   559  			lsb = *fieldEl.BitOffset
   560  			msb = *fieldEl.BitWidth + lsb - 1
   561  		} else if fieldEl.BitRange != nil {
   562  			// try use bitRange
   563  			// example string: "[20:16]"
   564  			parts := strings.Split(strings.Trim(*fieldEl.BitRange, "[]"), ":")
   565  			l, err := strconv.ParseUint(parts[1], 0, 32)
   566  			if err != nil {
   567  				panic(err)
   568  			}
   569  			lsb = uint32(l)
   570  			m, err := strconv.ParseUint(parts[0], 0, 32)
   571  			if err != nil {
   572  				panic(err)
   573  			}
   574  			msb = uint32(m)
   575  		} else {
   576  			// this is an error. what to do?
   577  			fmt.Fprintln(os.Stderr, "unable to find lsb/msb in field:", fieldName)
   578  			continue
   579  		}
   580  
   581  		// The enumerated values can be the same as another field, so to avoid
   582  		// duplication SVD files can simply refer to another set of enumerated
   583  		// values in the same register.
   584  		// See: https://www.keil.com/pack/doc/CMSIS/SVD/html/elem_registers.html#elem_enumeratedValues
   585  		enumeratedValues := fieldEl.EnumeratedValues
   586  		if enumeratedValues.DerivedFrom != "" {
   587  			parts := strings.Split(enumeratedValues.DerivedFrom, ".")
   588  			if len(parts) == 1 {
   589  				found := false
   590  				for _, otherFieldEl := range fieldEls {
   591  					if otherFieldEl.EnumeratedValues.Name == parts[0] {
   592  						found = true
   593  						enumeratedValues = otherFieldEl.EnumeratedValues
   594  					}
   595  				}
   596  				if !found {
   597  					fmt.Fprintf(os.Stderr, "Warning: could not find enumeratedValue.derivedFrom of %s for register field %s\n", enumeratedValues.DerivedFrom, fieldName)
   598  				}
   599  			} else {
   600  				// The derivedFrom attribute may also point to enumerated values
   601  				// in other registers and even peripherals, but this feature
   602  				// isn't often used in SVD files.
   603  				fmt.Fprintf(os.Stderr, "TODO: enumeratedValue.derivedFrom to a different register: %s\n", enumeratedValues.DerivedFrom)
   604  			}
   605  		}
   606  
   607  		bitfields = append(bitfields, Bitfield{
   608  			Name:   fieldName,
   609  			Offset: lsb,
   610  			Mask:   (0xffffffff >> (31 - (msb - lsb))) << lsb,
   611  		})
   612  		fields = append(fields, Constant{
   613  			Name:        fmt.Sprintf("%s_%s%s_%s_Pos", groupName, bitfieldPrefix, regName, fieldName),
   614  			Description: fmt.Sprintf("Position of %s field.", fieldName),
   615  			Value:       uint64(lsb),
   616  		})
   617  		fields = append(fields, Constant{
   618  			Name:        fmt.Sprintf("%s_%s%s_%s_Msk", groupName, bitfieldPrefix, regName, fieldName),
   619  			Description: fmt.Sprintf("Bit mask of %s field.", fieldName),
   620  			Value:       (0xffffffffffffffff >> (63 - (msb - lsb))) << lsb,
   621  		})
   622  		if lsb == msb { // single bit
   623  			fields = append(fields, Constant{
   624  				Name:        fmt.Sprintf("%s_%s%s_%s", groupName, bitfieldPrefix, regName, fieldName),
   625  				Description: fmt.Sprintf("Bit %s.", fieldName),
   626  				Value:       1 << lsb,
   627  			})
   628  		}
   629  		for _, enumEl := range enumeratedValues.EnumeratedValue {
   630  			enumName := enumEl.Name
   631  			// Renesas has enum without actual values that we have to skip
   632  			if enumEl.Value == "" {
   633  				continue
   634  			}
   635  
   636  			if strings.EqualFold(enumName, "reserved") || !validName.MatchString(enumName) {
   637  				continue
   638  			}
   639  			if !unicode.IsUpper(rune(enumName[0])) && !unicode.IsDigit(rune(enumName[0])) {
   640  				enumName = strings.ToUpper(enumName)
   641  			}
   642  			enumDescription := formatText(enumEl.Description)
   643  			var enumValue uint64
   644  			var err error
   645  			if strings.HasPrefix(enumEl.Value, "0b") {
   646  				val := strings.TrimPrefix(enumEl.Value, "0b")
   647  				enumValue, err = strconv.ParseUint(val, 2, 64)
   648  			} else {
   649  				enumValue, err = strconv.ParseUint(enumEl.Value, 0, 64)
   650  			}
   651  			if err != nil {
   652  				if enumBitSpecifier.MatchString(enumEl.Value) {
   653  					// NXP and Renesas SVDs use the form #xx1x, #x0xx, etc for values
   654  					enumValue, err = strconv.ParseUint(strings.ReplaceAll(enumEl.Value[1:], "x", "0"), 2, 64)
   655  					if err != nil {
   656  						panic(err)
   657  					}
   658  				} else {
   659  					panic(err)
   660  				}
   661  			}
   662  			enumName = fmt.Sprintf("%s_%s%s_%s_%s", groupName, bitfieldPrefix, regName, fieldName, enumName)
   663  
   664  			// Avoid duplicate values. Duplicate names with the same value are
   665  			// allowed, but the same name with a different value is not. Instead
   666  			// of trying to work around those cases, remove the value entirely
   667  			// as there is probably not one correct answer in such a case.
   668  			// For example, SVD files from NXP have enums limited to 20
   669  			// characters, leading to lots of duplicates when these enum names
   670  			// are long. Nothing here can really fix those cases.
   671  			previousEnumValue, seenBefore := enumSeen[enumName]
   672  			if seenBefore {
   673  				if previousEnumValue < 0 {
   674  					// There was a mismatch before, ignore all equally named fields.
   675  					continue
   676  				}
   677  				if int64(enumValue) != previousEnumValue {
   678  					// There is a mismatch. Mark it as such, and remove the
   679  					// existing enum bitfield value.
   680  					enumSeen[enumName] = -1
   681  					for i, field := range fields {
   682  						if field.Name == enumName {
   683  							fields = append(fields[:i], fields[i+1:]...)
   684  							break
   685  						}
   686  					}
   687  				}
   688  				continue
   689  			}
   690  			enumSeen[enumName] = int64(enumValue)
   691  
   692  			fields = append(fields, Constant{
   693  				Name:        enumName,
   694  				Description: enumDescription,
   695  				Value:       enumValue,
   696  			})
   697  		}
   698  	}
   699  	return fields, bitfields
   700  }
   701  
   702  type Register struct {
   703  	element     *SVDRegister
   704  	baseAddress uint64
   705  }
   706  
   707  func NewRegister(element *SVDRegister, baseAddress uint64) *Register {
   708  	return &Register{
   709  		element:     element,
   710  		baseAddress: baseAddress,
   711  	}
   712  }
   713  
   714  func (r *Register) name() string {
   715  	return strings.ReplaceAll(r.element.Name, "[%s]", "")
   716  }
   717  
   718  func (r *Register) description() string {
   719  	return formatText(r.element.Description)
   720  }
   721  
   722  func (r *Register) address() uint64 {
   723  	offsetString := r.element.Offset
   724  	if offsetString == nil {
   725  		offsetString = r.element.AddressOffset
   726  	}
   727  	addr, err := strconv.ParseUint(*offsetString, 0, 32)
   728  	if err != nil {
   729  		panic(err)
   730  	}
   731  	return r.baseAddress + addr
   732  }
   733  
   734  func (r *Register) dim() int {
   735  	if r.element.Dim == nil {
   736  		return -1 // no dim elements
   737  	}
   738  	dim, err := strconv.ParseInt(*r.element.Dim, 0, 32)
   739  	if err != nil {
   740  		panic(err)
   741  	}
   742  	return int(dim)
   743  }
   744  
   745  func (r *Register) dimIndex() []string {
   746  	defer func() {
   747  		if err := recover(); err != nil {
   748  			fmt.Println("register", r.name())
   749  			panic(err)
   750  		}
   751  	}()
   752  
   753  	dim := r.dim()
   754  	if r.element.DimIndex == nil {
   755  		if dim <= 0 {
   756  			return nil
   757  		}
   758  
   759  		idx := make([]string, dim)
   760  		for i := range idx {
   761  			idx[i] = strconv.FormatInt(int64(i), 10)
   762  		}
   763  		return idx
   764  	}
   765  
   766  	t := strings.Split(*r.element.DimIndex, "-")
   767  	if len(t) == 2 {
   768  		// renesas uses hex letters e.g. A-B
   769  		if strings.Contains("ABCDEFabcdef", t[0]) {
   770  			t[0] = "0x" + t[0]
   771  		}
   772  		if strings.Contains("ABCDEFabcdef", t[1]) {
   773  			t[1] = "0x" + t[1]
   774  		}
   775  
   776  		x, err := strconv.ParseInt(t[0], 0, 32)
   777  		if err != nil {
   778  			panic(err)
   779  		}
   780  		y, err := strconv.ParseInt(t[1], 0, 32)
   781  		if err != nil {
   782  			panic(err)
   783  		}
   784  
   785  		if x < 0 || y < x || y-x != int64(dim-1) {
   786  			panic("invalid dimIndex")
   787  		}
   788  
   789  		idx := make([]string, dim)
   790  		for i := x; i <= y; i++ {
   791  			idx[i-x] = strconv.FormatInt(i, 10)
   792  		}
   793  		return idx
   794  	} else if len(t) > 2 {
   795  		panic("invalid dimIndex")
   796  	}
   797  
   798  	s := strings.Split(*r.element.DimIndex, ",")
   799  	if len(s) != dim {
   800  		panic("invalid dimIndex")
   801  	}
   802  
   803  	return s
   804  }
   805  
   806  func (r *Register) size() int {
   807  	if r.element.Size != nil {
   808  		size, err := strconv.ParseInt(*r.element.Size, 0, 32)
   809  		if err != nil {
   810  			panic(err)
   811  		}
   812  		return int(size) / 8
   813  	}
   814  	return 4
   815  }
   816  
   817  func parseRegister(groupName string, regEl *SVDRegister, baseAddress uint64, bitfieldPrefix string) []*PeripheralField {
   818  	reg := NewRegister(regEl, baseAddress)
   819  
   820  	if reg.dim() != -1 {
   821  		dimIncrement, err := strconv.ParseUint(regEl.DimIncrement, 0, 32)
   822  		if err != nil {
   823  			panic(err)
   824  		}
   825  		if strings.Contains(reg.name(), "%s") {
   826  			// a "spaced array" of registers, special processing required
   827  			// we need to generate a separate register for each "element"
   828  			var results []*PeripheralField
   829  			shortName := strings.ToUpper(strings.ReplaceAll(strings.ReplaceAll(reg.name(), "_%s", ""), "%s", ""))
   830  			for i, j := range reg.dimIndex() {
   831  				regAddress := reg.address() + (uint64(i) * dimIncrement)
   832  				results = append(results, &PeripheralField{
   833  					Name:        strings.ToUpper(strings.ReplaceAll(reg.name(), "%s", j)),
   834  					Address:     regAddress,
   835  					Description: reg.description(),
   836  					Array:       -1,
   837  					ElementSize: reg.size(),
   838  					ShortName:   shortName,
   839  				})
   840  			}
   841  			// set first result bitfield
   842  			results[0].Constants, results[0].Bitfields = parseBitfields(groupName, shortName, regEl.Fields, bitfieldPrefix)
   843  			results[0].HasBitfields = len(results[0].Bitfields) > 0
   844  			for i := 1; i < len(results); i++ {
   845  				results[i].Bitfields = results[0].Bitfields
   846  				results[i].HasBitfields = results[0].HasBitfields
   847  			}
   848  			return results
   849  		}
   850  	}
   851  	regName := reg.name()
   852  	if !unicode.IsUpper(rune(regName[0])) && !unicode.IsDigit(rune(regName[0])) {
   853  		regName = strings.ToUpper(regName)
   854  	}
   855  	regName = cleanName(regName)
   856  
   857  	constants, bitfields := parseBitfields(groupName, regName, regEl.Fields, bitfieldPrefix)
   858  	return []*PeripheralField{&PeripheralField{
   859  		Name:         regName,
   860  		Address:      reg.address(),
   861  		Description:  reg.description(),
   862  		Constants:    constants,
   863  		Array:        reg.dim(),
   864  		ElementSize:  reg.size(),
   865  		ShortName:    regName,
   866  		Bitfields:    bitfields,
   867  		HasBitfields: len(bitfields) > 0,
   868  	}}
   869  }
   870  
   871  // The Go module for this device.
   872  func writeGo(outdir string, device *Device, interruptSystem string) error {
   873  	outf, err := os.Create(filepath.Join(outdir, device.Metadata.NameLower+".go"))
   874  	if err != nil {
   875  		return err
   876  	}
   877  	defer outf.Close()
   878  	w := bufio.NewWriter(outf)
   879  
   880  	maxInterruptValue := 0
   881  	for _, intr := range device.Interrupts {
   882  		if intr.Value > maxInterruptValue {
   883  			maxInterruptValue = intr.Value
   884  		}
   885  	}
   886  
   887  	interruptHandlerMap := make(map[string]*Interrupt)
   888  	var interruptHandlers []*Interrupt
   889  	for _, intr := range device.Interrupts {
   890  		if _, ok := interruptHandlerMap[intr.HandlerName]; !ok {
   891  			interruptHandlerMap[intr.HandlerName] = intr
   892  			interruptHandlers = append(interruptHandlers, intr)
   893  		}
   894  	}
   895  
   896  	t := template.Must(template.New("go").Funcs(template.FuncMap{
   897  		"bytesNeeded": func(i, j uint64) uint64 { return j - i },
   898  		"isMultiline": isMultiline,
   899  		"splitLine":   splitLine,
   900  	}).Parse(`// Automatically generated file. DO NOT EDIT.
   901  // Generated by gen-device-svd.go from {{.device.Metadata.File}}, see {{.device.Metadata.DescriptorSource}}
   902  
   903  //go:build {{.pkgName}} && {{.device.Metadata.NameLower}}
   904  
   905  // {{.device.Metadata.Description}}
   906  //
   907  {{.device.Metadata.LicenseBlock}}
   908  package {{.pkgName}}
   909  
   910  import (
   911  	"runtime/volatile"
   912  	"unsafe"
   913  )
   914  
   915  // Some information about this device.
   916  const (
   917  	Device       = "{{.device.Metadata.Name}}"
   918  {{- if .device.Metadata.HasCPUInfo }}
   919  	CPU          = "{{.device.Metadata.CPUName}}"
   920  	FPUPresent   = {{.device.Metadata.FPUPresent}}
   921  	NVICPrioBits = {{.device.Metadata.NVICPrioBits}}
   922  {{- end }}
   923  )
   924  
   925  // Interrupt numbers.
   926  const (
   927  {{- range .device.Interrupts}}
   928  	{{- if .Description}}
   929  		{{- range .Description|splitLine}}
   930  	// {{.}}
   931  		{{- end}}
   932  	{{- end}}
   933  	IRQ_{{.Name}} = {{.Value}}
   934  	{{- "\n"}}
   935  {{- end}}
   936  	// Highest interrupt number on this device.
   937  	IRQ_max = {{.interruptMax}} 
   938  )
   939  
   940  // Pseudo function call that is replaced by the compiler with the actual
   941  // functions registered through interrupt.New.
   942  //go:linkname callHandlers runtime/interrupt.callHandlers
   943  func callHandlers(num int)
   944  
   945  {{- if eq .interruptSystem "hardware"}}
   946  {{- range .interruptHandlers}}
   947  //export {{.HandlerName}}
   948  func interrupt{{.Name}}() {
   949  	callHandlers(IRQ_{{.Name}})
   950  }
   951  {{- end}}
   952  {{- end}}
   953  
   954  {{- if eq .interruptSystem "software"}}
   955  func HandleInterrupt(num int) {
   956  	switch num {
   957  	{{- range .interruptHandlers}}
   958  	case IRQ_{{.Name}}:
   959  		callHandlers(IRQ_{{.Name}})
   960  	{{- end}}
   961  	}
   962  }
   963  {{- end}}
   964  
   965  // Peripherals.
   966  var (
   967  {{- range .device.Peripherals}}
   968  	{{- if .Description}}
   969  		{{- range .Description|splitLine}}
   970  	// {{.}}
   971  		{{- end}}
   972  	{{- end}}
   973  	{{.Name}} = (*{{.GroupName}}_Type)(unsafe.Pointer(uintptr(0x{{printf "%x" .BaseAddress}})))
   974  	{{- "\n"}}
   975  {{- end}}
   976  )
   977  
   978  `))
   979  	err = t.Execute(w, map[string]interface{}{
   980  		"device":            device,
   981  		"pkgName":           filepath.Base(strings.TrimRight(outdir, "/")),
   982  		"interruptMax":      maxInterruptValue,
   983  		"interruptSystem":   interruptSystem,
   984  		"interruptHandlers": interruptHandlers,
   985  	})
   986  	if err != nil {
   987  		return err
   988  	}
   989  
   990  	// Define peripheral struct types.
   991  	for _, peripheral := range device.Peripherals {
   992  		if peripheral.Registers == nil {
   993  			// This peripheral was derived from another peripheral. No new type
   994  			// needs to be defined for it.
   995  			continue
   996  		}
   997  		fmt.Fprintln(w)
   998  		if peripheral.Description != "" {
   999  			for _, l := range splitLine(peripheral.Description) {
  1000  				fmt.Fprintf(w, "// %s\n", l)
  1001  			}
  1002  		}
  1003  		fmt.Fprintf(w, "type %s_Type struct {\n", peripheral.GroupName)
  1004  
  1005  		address := peripheral.BaseAddress
  1006  		type clusterInfo struct {
  1007  			name        string
  1008  			description string
  1009  			address     uint64
  1010  			size        uint64
  1011  			registers   []*PeripheralField
  1012  		}
  1013  		clusters := []clusterInfo{}
  1014  		for _, register := range peripheral.Registers {
  1015  			if register.Registers == nil && address > register.Address {
  1016  				// In Nordic SVD files, these registers are deprecated or
  1017  				// duplicates, so can be ignored.
  1018  				//fmt.Fprintf(os.Stderr, "skip: %s.%s 0x%x - 0x%x %d\n", peripheral.Name, register.name, address, register.address, register.elementSize)
  1019  				// remove bit fields from such register
  1020  				register.Bitfields = nil
  1021  				continue
  1022  			}
  1023  
  1024  			var regType string
  1025  			switch register.ElementSize {
  1026  			case 8:
  1027  				regType = "volatile.Register64"
  1028  			case 4:
  1029  				regType = "volatile.Register32"
  1030  			case 2:
  1031  				regType = "volatile.Register16"
  1032  			case 1:
  1033  				regType = "volatile.Register8"
  1034  			default:
  1035  				regType = "volatile.Register32"
  1036  			}
  1037  
  1038  			// insert padding, if needed
  1039  			if address < register.Address {
  1040  				bytesNeeded := register.Address - address
  1041  				if bytesNeeded == 1 {
  1042  					w.WriteString("\t_ byte\n")
  1043  				} else {
  1044  					fmt.Fprintf(w, "\t_ [%d]byte\n", bytesNeeded)
  1045  				}
  1046  				address = register.Address
  1047  			}
  1048  
  1049  			lastCluster := false
  1050  			if register.Registers != nil {
  1051  				// This is a cluster, not a register. Create the cluster type.
  1052  				regType = peripheral.GroupName + "_" + register.Name
  1053  				clusters = append(clusters, clusterInfo{regType, register.Description, register.Address, uint64(register.ElementSize), register.Registers})
  1054  				regType = regType + "_Type"
  1055  				subaddress := register.Address
  1056  				for _, subregister := range register.Registers {
  1057  
  1058  					if subaddress != subregister.Address {
  1059  						bytesNeeded := subregister.Address - subaddress
  1060  						subaddress += bytesNeeded
  1061  					}
  1062  					var subregSize uint64
  1063  					if subregister.Array != -1 {
  1064  						subregSize = uint64(subregister.Array * subregister.ElementSize)
  1065  					} else {
  1066  						subregSize = uint64(subregister.ElementSize)
  1067  					}
  1068  					subaddress += subregSize
  1069  				}
  1070  				if register.Array == -1 {
  1071  					lastCluster = true
  1072  				}
  1073  				address = subaddress
  1074  			}
  1075  
  1076  			if register.Array != -1 {
  1077  				regType = fmt.Sprintf("[%d]%s", register.Array, regType)
  1078  			}
  1079  			fmt.Fprintf(w, "\t%s %s // 0x%X\n", register.Name, regType, register.Address-peripheral.BaseAddress)
  1080  
  1081  			// next address
  1082  			if lastCluster {
  1083  				lastCluster = false
  1084  			} else if register.Array != -1 {
  1085  				address = register.Address + uint64(register.ElementSize*register.Array)
  1086  			} else {
  1087  				address = register.Address + uint64(register.ElementSize)
  1088  			}
  1089  		}
  1090  		w.WriteString("}\n")
  1091  
  1092  		for _, register := range peripheral.Registers {
  1093  			regName := register.Name
  1094  			writeGoRegisterBitfieldType(w, register, peripheral.GroupName, regName)
  1095  		}
  1096  
  1097  		// Define clusters
  1098  		for i := 0; i < len(clusters); i++ {
  1099  			cluster := clusters[i]
  1100  			if len(cluster.registers) == 0 {
  1101  				continue
  1102  			}
  1103  
  1104  			if _, ok := device.PeripheralDict[cluster.name]; ok {
  1105  				continue
  1106  			}
  1107  
  1108  			fmt.Fprintln(w)
  1109  			if cluster.description != "" {
  1110  				for _, l := range splitLine(cluster.description) {
  1111  					fmt.Fprintf(w, "// %s\n", l)
  1112  				}
  1113  			}
  1114  			fmt.Fprintf(w, "type %s_Type struct {\n", cluster.name)
  1115  
  1116  			address := cluster.address
  1117  
  1118  			for _, register := range cluster.registers {
  1119  				if register.Registers == nil && address > register.Address {
  1120  					// In Nordic SVD files, these registers are deprecated or
  1121  					// duplicates, so can be ignored.
  1122  					//fmt.Fprintf(os.Stderr, "skip: %s.%s 0x%x - 0x%x %d\n", peripheral.Name, register.name, address, register.address, register.elementSize)
  1123  					continue
  1124  				}
  1125  				var regType string
  1126  				switch register.ElementSize {
  1127  				case 8:
  1128  					regType = "volatile.Register64"
  1129  				case 4:
  1130  					regType = "volatile.Register32"
  1131  				case 2:
  1132  					regType = "volatile.Register16"
  1133  				case 1:
  1134  					regType = "volatile.Register8"
  1135  				default:
  1136  					regType = "volatile.Register32"
  1137  				}
  1138  
  1139  				// insert padding, if needed
  1140  				if address < register.Address {
  1141  					bytesNeeded := register.Address - address
  1142  					if bytesNeeded == 1 {
  1143  						w.WriteString("\t_ byte\n")
  1144  					} else {
  1145  						fmt.Fprintf(w, "\t_ [%d]byte\n", bytesNeeded)
  1146  					}
  1147  					address = register.Address
  1148  				}
  1149  
  1150  				lastCluster := false
  1151  				if register.Registers != nil {
  1152  					// This is a cluster, not a register. Create the cluster type.
  1153  					regType = peripheral.GroupName + "_" + register.Name
  1154  					clusters = append(clusters, clusterInfo{regType, register.Description, register.Address, uint64(register.ElementSize), register.Registers})
  1155  					regType = regType + "_Type"
  1156  
  1157  					subaddress := register.Address
  1158  					for _, subregister := range register.Registers {
  1159  						if subaddress != subregister.Address {
  1160  							bytesNeeded := subregister.Address - subaddress
  1161  							subaddress += bytesNeeded
  1162  						}
  1163  						var subregSize uint64
  1164  						if subregister.Array != -1 {
  1165  							subregSize = uint64(subregister.Array * subregister.ElementSize)
  1166  						} else {
  1167  							subregSize = uint64(subregister.ElementSize)
  1168  						}
  1169  						subaddress += subregSize
  1170  					}
  1171  					if register.Array == -1 {
  1172  						lastCluster = true
  1173  					}
  1174  					address = subaddress
  1175  				}
  1176  
  1177  				if register.Array != -1 {
  1178  					regType = fmt.Sprintf("[%d]%s", register.Array, regType)
  1179  				}
  1180  				fmt.Fprintf(w, "\t%s %s // 0x%X\n", register.Name, regType, register.Address-peripheral.BaseAddress)
  1181  
  1182  				// next address
  1183  				if lastCluster {
  1184  					lastCluster = false
  1185  				} else if register.Array != -1 {
  1186  					address = register.Address + uint64(register.ElementSize*register.Array)
  1187  				} else {
  1188  					address = register.Address + uint64(register.ElementSize)
  1189  				}
  1190  			}
  1191  			// make sure the structure is full
  1192  			if cluster.size > (address - cluster.registers[0].Address) {
  1193  				bytesNeeded := cluster.size - (address - cluster.registers[0].Address)
  1194  				if bytesNeeded == 1 {
  1195  					w.WriteString("\t_ byte\n")
  1196  				} else {
  1197  					fmt.Fprintf(w, "\t_ [%d]byte\n", bytesNeeded)
  1198  				}
  1199  			} else if cluster.size != (address - cluster.registers[0].Address) {
  1200  				println("peripheral:", peripheral.Name, "cluster:", cluster.name, "size:", cluster.size, "struct size:", (address - cluster.registers[0].Address))
  1201  			}
  1202  			w.WriteString("}\n")
  1203  
  1204  			for _, register := range cluster.registers {
  1205  				regName := register.Name
  1206  				if register.Array == -1 {
  1207  					writeGoRegisterBitfieldType(w, register, cluster.name, regName)
  1208  				}
  1209  			}
  1210  		}
  1211  	}
  1212  
  1213  	// Define bitfields.
  1214  	for _, peripheral := range device.Peripherals {
  1215  		if peripheral.Registers == nil {
  1216  			// This peripheral was derived from another peripheral. Constants are
  1217  			// already defined.
  1218  			continue
  1219  		}
  1220  		fmt.Fprintf(w, "\n// Constants for %s", peripheral.Name)
  1221  		if isMultiline(peripheral.Description) {
  1222  			for _, l := range splitLine(peripheral.Description) {
  1223  				fmt.Fprintf(w, "\n// %s", l)
  1224  			}
  1225  		} else if peripheral.Description != "" {
  1226  			fmt.Fprintf(w, ": %s", peripheral.Description)
  1227  		}
  1228  
  1229  		fmt.Fprint(w, "\nconst(")
  1230  		for _, register := range peripheral.Registers {
  1231  			if len(register.Constants) != 0 {
  1232  				writeGoRegisterConstants(w, register, register.Name)
  1233  			}
  1234  			if register.Registers == nil {
  1235  				continue
  1236  			}
  1237  			for _, subregister := range register.Registers {
  1238  				writeGoRegisterConstants(w, subregister, register.Name+"."+subregister.Name)
  1239  			}
  1240  		}
  1241  		w.WriteString(")\n")
  1242  	}
  1243  
  1244  	return w.Flush()
  1245  }
  1246  
  1247  func writeGoRegisterConstants(w *bufio.Writer, register *PeripheralField, name string) {
  1248  	w.WriteString("\n\t// " + name)
  1249  	if register.Description != "" {
  1250  		if isMultiline(register.Description) {
  1251  			for _, l := range splitLine(register.Description) {
  1252  				w.WriteString("\n\t// " + l)
  1253  			}
  1254  		} else {
  1255  			w.WriteString(": " + register.Description)
  1256  		}
  1257  	}
  1258  	w.WriteByte('\n')
  1259  	for _, bitfield := range register.Constants {
  1260  		if bitfield.Description != "" {
  1261  			for _, l := range splitLine(bitfield.Description) {
  1262  				w.WriteString("\t// " + l + "\n")
  1263  			}
  1264  		}
  1265  		fmt.Fprintf(w, "\t%s = 0x%x\n", bitfield.Name, bitfield.Value)
  1266  	}
  1267  }
  1268  
  1269  func writeGoRegisterBitfieldType(w *bufio.Writer, register *PeripheralField, peripheralName, registerName string) {
  1270  	if len(register.Bitfields) == 0 {
  1271  		return
  1272  	}
  1273  	w.WriteString("\n// " + peripheralName + "." + registerName)
  1274  	if register.Description != "" {
  1275  		if isMultiline(register.Description) {
  1276  			for _, l := range splitLine(register.Description) {
  1277  				w.WriteString("\n\t// " + l)
  1278  			}
  1279  		} else {
  1280  			w.WriteString(": " + register.Description)
  1281  		}
  1282  	}
  1283  	w.WriteByte('\n')
  1284  	var bitSize int
  1285  	var maxMask uint32
  1286  	switch register.ElementSize {
  1287  	case 8:
  1288  		bitSize = 64
  1289  		maxMask = 0xffffffff
  1290  		// maxMask = 0xffffffffffffffff // TODO how to handle 64-bit fields
  1291  	case 4:
  1292  		bitSize = 32
  1293  		maxMask = 0xffffffff
  1294  	case 2:
  1295  		bitSize = 16
  1296  		maxMask = 0xffff
  1297  	case 1:
  1298  		bitSize = 8
  1299  		maxMask = 0xff
  1300  	default:
  1301  		bitSize = 32
  1302  		maxMask = 0xffffffff
  1303  	}
  1304  
  1305  	typeName := fmt.Sprintf("%s_Type", peripheralName)
  1306  
  1307  	for _, bitfield := range register.Bitfields {
  1308  		idxArg := ""
  1309  		regAccess := "&o." + registerName + ".Reg"
  1310  		if register.Array != -1 {
  1311  			idxArg = "idx int, "
  1312  			regAccess = "&o." + registerName + "[idx].Reg"
  1313  		}
  1314  		var funcSuffix string
  1315  		if maxMask == bitfield.Mask || registerName == bitfield.Name {
  1316  			funcSuffix = registerName
  1317  		} else {
  1318  			funcSuffix = registerName + "_" + bitfield.Name
  1319  		}
  1320  		fmt.Fprintf(w, "func (o *%s) Set%s(%s value uint%d) {\n", typeName, funcSuffix, idxArg, bitSize)
  1321  		if maxMask == bitfield.Mask {
  1322  			fmt.Fprintf(w, "\tvolatile.StoreUint%d(%s, value)\n", bitSize, regAccess)
  1323  		} else if bitfield.Offset > 0 {
  1324  			fmt.Fprintf(w, "\tvolatile.StoreUint%d(%s, volatile.LoadUint%d(%s)&^(0x%x)|value<<%d)\n", bitSize, regAccess, bitSize, regAccess, bitfield.Mask, bitfield.Offset)
  1325  		} else {
  1326  			fmt.Fprintf(w, "\tvolatile.StoreUint%d(%s, volatile.LoadUint%d(%s)&^(0x%x)|value)\n", bitSize, regAccess, bitSize, regAccess, bitfield.Mask)
  1327  		}
  1328  		w.WriteString("}\n")
  1329  		fmt.Fprintf(w, "func (o *%s) Get%s(%s) uint%d {\n", typeName, funcSuffix, idxArg, bitSize)
  1330  		if maxMask == bitfield.Mask {
  1331  			fmt.Fprintf(w, "\treturn volatile.LoadUint%d(%s)\n", bitSize, regAccess)
  1332  		} else if bitfield.Offset > 0 {
  1333  			fmt.Fprintf(w, "\treturn (volatile.LoadUint%d(%s)&0x%x) >> %d\n", bitSize, regAccess, bitfield.Mask, bitfield.Offset)
  1334  		} else {
  1335  			fmt.Fprintf(w, "\treturn volatile.LoadUint%d(%s)&0x%x\n", bitSize, regAccess, bitfield.Mask)
  1336  		}
  1337  		w.WriteString("}\n")
  1338  	}
  1339  }
  1340  
  1341  // The interrupt vector, which is hard to write directly in Go.
  1342  func writeAsm(outdir string, device *Device) error {
  1343  	outf, err := os.Create(filepath.Join(outdir, device.Metadata.NameLower+".s"))
  1344  	if err != nil {
  1345  		return err
  1346  	}
  1347  	defer outf.Close()
  1348  	w := bufio.NewWriter(outf)
  1349  
  1350  	t := template.Must(template.New("go").Parse(`// Automatically generated file. DO NOT EDIT.
  1351  // Generated by gen-device-svd.go from {{.File}}, see {{.DescriptorSource}}
  1352  
  1353  // {{.Description}}
  1354  //
  1355  {{.LicenseBlock}}
  1356  
  1357  .syntax unified
  1358  
  1359  // This is the default handler for interrupts, if triggered but not defined.
  1360  .section .text.Default_Handler
  1361  .global  Default_Handler
  1362  .type    Default_Handler, %function
  1363  Default_Handler:
  1364      wfe
  1365      b    Default_Handler
  1366  .size Default_Handler, .-Default_Handler
  1367  
  1368  // Avoid the need for repeated .weak and .set instructions.
  1369  .macro IRQ handler
  1370      .weak  \handler
  1371      .set   \handler, Default_Handler
  1372  .endm
  1373  
  1374  // Must set the "a" flag on the section:
  1375  // https://svnweb.freebsd.org/base/stable/11/sys/arm/arm/locore-v4.S?r1=321049&r2=321048&pathrev=321049
  1376  // https://sourceware.org/binutils/docs/as/Section.html#ELF-Version
  1377  .section .isr_vector, "a", %progbits
  1378  .global  __isr_vector
  1379  __isr_vector:
  1380      // Interrupt vector as defined by Cortex-M, starting with the stack top.
  1381      // On reset, SP is initialized with *0x0 and PC is loaded with *0x4, loading
  1382      // _stack_top and Reset_Handler.
  1383      .long _stack_top
  1384      .long Reset_Handler
  1385      .long NMI_Handler
  1386      .long HardFault_Handler
  1387      .long MemoryManagement_Handler
  1388      .long BusFault_Handler
  1389      .long UsageFault_Handler
  1390      .long 0
  1391      .long 0
  1392      .long 0
  1393      .long 0
  1394      .long SVC_Handler
  1395      .long DebugMon_Handler
  1396      .long 0
  1397      .long PendSV_Handler
  1398      .long SysTick_Handler
  1399  
  1400      // Extra interrupts for peripherals defined by the hardware vendor.
  1401  `))
  1402  	err = t.Execute(w, device.Metadata)
  1403  	if err != nil {
  1404  		return err
  1405  	}
  1406  	num := 0
  1407  	for _, intr := range device.Interrupts {
  1408  		if intr.Value == num-1 {
  1409  			continue
  1410  		}
  1411  		if intr.Value < num {
  1412  			panic("interrupt numbers are not sorted")
  1413  		}
  1414  		for intr.Value > num {
  1415  			w.WriteString("    .long 0\n")
  1416  			num++
  1417  		}
  1418  		num++
  1419  		fmt.Fprintf(w, "    .long %s\n", intr.HandlerName)
  1420  	}
  1421  
  1422  	w.WriteString(`
  1423      // Define default implementations for interrupts, redirecting to
  1424      // Default_Handler when not implemented.
  1425      IRQ NMI_Handler
  1426      IRQ HardFault_Handler
  1427      IRQ MemoryManagement_Handler
  1428      IRQ BusFault_Handler
  1429      IRQ UsageFault_Handler
  1430      IRQ SVC_Handler
  1431      IRQ DebugMon_Handler
  1432      IRQ PendSV_Handler
  1433      IRQ SysTick_Handler
  1434  `)
  1435  	for _, intr := range device.Interrupts {
  1436  		fmt.Fprintf(w, "    IRQ %s_IRQHandler\n", intr.Name)
  1437  	}
  1438  	w.WriteString(`
  1439  .size __isr_vector, .-__isr_vector
  1440  `)
  1441  	return w.Flush()
  1442  }
  1443  
  1444  func generate(indir, outdir, sourceURL, interruptSystem string) error {
  1445  	if _, err := os.Stat(indir); errors.Is(err, fs.ErrNotExist) {
  1446  		fmt.Fprintln(os.Stderr, "cannot find input directory:", indir)
  1447  		os.Exit(1)
  1448  	}
  1449  	os.MkdirAll(outdir, 0777)
  1450  
  1451  	infiles, err := filepath.Glob(filepath.Join(indir, "*.svd"))
  1452  	if err != nil {
  1453  		fmt.Fprintln(os.Stderr, "could not read .svd files:", err)
  1454  		os.Exit(1)
  1455  	}
  1456  	sort.Strings(infiles)
  1457  	for _, infile := range infiles {
  1458  		fmt.Println(infile)
  1459  		device, err := readSVD(infile, sourceURL)
  1460  		if err != nil {
  1461  			return fmt.Errorf("failed to read: %w", err)
  1462  		}
  1463  		err = writeGo(outdir, device, interruptSystem)
  1464  		if err != nil {
  1465  			return fmt.Errorf("failed to write Go file: %w", err)
  1466  		}
  1467  		switch interruptSystem {
  1468  		case "software":
  1469  			// Nothing to do.
  1470  		case "hardware":
  1471  			err = writeAsm(outdir, device)
  1472  			if err != nil {
  1473  				return fmt.Errorf("failed to write assembly file: %w", err)
  1474  			}
  1475  		default:
  1476  			return fmt.Errorf("unknown interrupt system: %s", interruptSystem)
  1477  		}
  1478  	}
  1479  	return nil
  1480  }
  1481  
  1482  func main() {
  1483  	sourceURL := flag.String("source", "<unknown>", "source SVD file")
  1484  	interruptSystem := flag.String("interrupts", "hardware", "interrupt system in use (software, hardware)")
  1485  	flag.Parse()
  1486  	if flag.NArg() != 2 {
  1487  		fmt.Fprintln(os.Stderr, "provide exactly two arguments: input directory (with .svd files) and output directory for generated files")
  1488  		flag.PrintDefaults()
  1489  		return
  1490  	}
  1491  	indir := flag.Arg(0)
  1492  	outdir := flag.Arg(1)
  1493  	err := generate(indir, outdir, *sourceURL, *interruptSystem)
  1494  	if err != nil {
  1495  		fmt.Fprintln(os.Stderr, err)
  1496  		os.Exit(1)
  1497  	}
  1498  }